Plugin Registry
The plugin registry is a JSON manifest (plugins.json) hosted at github.com/TableProApp/plugins. TablePro fetches it to populate Settings > Plugins > Browse and to auto-install a driver when a user selects a database type with no loaded plugin. This page covers the manifest and publishing pipeline; for install and update behavior in the app, see Plugins & Themes. To build a plugin, see Plugin Development.
Manifest Format
schemaVersion than it supports and falls back to its cached copy.
Entry Fields
Each entry in
binaries:
v1 manifests carried top-level
downloadURL, sha256, and minPluginKitVersion instead of binaries. The app still decodes them as a fallback: when binaries is absent it synthesizes one entry per architecture, using minPluginKitVersion as the binary’s pluginKitVersion. New entries must use binaries.Binary Selection
For a database driver, the app filtersbinaries to the current architecture, keeps those whose pluginKitVersion falls within [minimumCompatiblePluginKitVersion, currentPluginKitVersion] (both declared in PluginManager.swift, both 18 as of 0.57.0), and installs the highest. A driver binary without pluginKitVersion never resolves, and install fails with noCompatibleBinary.
Themes carry no native code, so they match on architecture only.
Example Entry
Plugin Metadata
The optionalmetadata object makes a registry plugin self-describing: the app uses it to render the connection form, sidebar, and editor for a database type before the plugin is installed. Registry driver entries should carry it, or users see a bare form until the download completes. update-registry.py preserves an existing metadata block across releases; edit it by hand in the registry repo.
The full field list is
RegistryPluginMetadata in TablePro/Core/Plugins/Registry/RegistryModels.swift.
Registry Plugins and databaseTypeIds
databaseTypeIds tells the app which plugin to install when a user picks a database type with no loaded driver. Tag names must match resolve_plugin_info() in .github/workflows/build-plugin.yml. Note the non-obvious tags for Cloudflare D1 and etcd.
Bundled plugins (MySQL, PostgreSQL, SQLite, ClickHouse, Redis, and the import/export formats) ship inside the app and are never published to the registry.
Publishing a Plugin
Tag the commit and push that one tag:tags input takes comma-separated tag:pluginKitVersion pairs; when :pluginKitVersion is omitted, the workflow reads currentPluginKitVersion from PluginManager.swift:
TableProPluginKitVersion matches the release label, creates a GitHub release, re-verifies the published assets, and updates plugins.json via .github/scripts/update-registry.py (atomic write with a rebase-and-retry loop against concurrent matrix jobs).
PluginKit Compatibility
TableProPluginKit builds with Swift Library Evolution, so a plugin built against any PluginKit version in the app’s[minimum, current] range loads, and the runtime fills newer requirements from their defaults. What that means for releases:
- Additive change (new requirement with a default, new field on a non-frozen type): no version bump, no re-publish. Existing binaries keep serving.
- Breaking change (removed or changed requirement, frozen-layout change, requirement without a default): raise
currentPluginKitVersionandminimumCompatiblePluginKitVersiontogether, then runscripts/release-all-plugins.sh <newVersion>. It bumps each registry plugin’s patch version and fires oneworkflow_dispatchso all plugins build as a parallel matrix. - The app release workflow runs
scripts/check-registry-readiness.py --floor <min> --current <current>and fails the release until every database driver has a compatible binary, so the app never ships ahead of its plugins. - Retention:
update-registry.pykeeps binaries for the two newest PluginKit versions per plugin (--keep-kit-versions 2). Older binaries are pruned, so users two or more PluginKit versions behind hitnoCompatibleBinaryand need to update the app.
Caching
The app fetches the manifest fromraw.githubusercontent.com/TableProApp/plugins/main/plugins.json, which caches at the edge for about five minutes. Every fetch revalidates with a conditional request, the list refreshes at launch and when the plugin browser opens (throttled to one check per five minutes), and an install prompt forces a fresh fetch before reporting a plugin as missing. CI also purges the jsDelivr cache after each registry push for older app versions that still fetch from there. A newly published plugin is visible in the app within minutes.
Theme Distribution
Themes use the same manifest format withcategory: "theme". Differences from driver plugins:
- Pure JSON data, no executable code, no code signing, no
.tablepluginbundle - ZIP contains
.jsonfiles (validThemeDefinition); theme packs with multiple themes are supported - Installed to
~/Library/Application Support/TablePro/Themes/Registry/ - No
pluginKitVersionneeded; binaries match on architecture only, and the flat v1 fields still work
