> ## Documentation Index
> Fetch the complete documentation index at: https://ngquct-worktree-statusbar-redesign.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Plugin Registry

> How the plugin registry works, manifest format, and publishing plugins

# Plugin Registry

The plugin registry is a JSON manifest hosted at [github.com/TableProApp/plugins](https://github.com/TableProApp/plugins). TablePro fetches it to populate **Settings > Plugins > Browse** and to handle auto-install when a user selects a database type with no loaded driver.

## Manifest Format

The registry file (`plugins.json`):

```json theme={null}
{
  "schemaVersion": 1,
  "plugins": [
    // ... plugin entries
  ]
}
```

## Entry Fields

| Field                 | Type      | Required | Description                                                                                                 |
| --------------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| `id`                  | string    | Yes      | Bundle identifier (e.g., `com.TablePro.OracleDriver`)                                                       |
| `name`                | string    | Yes      | Display name                                                                                                |
| `version`             | string    | Yes      | Semantic version                                                                                            |
| `summary`             | string    | Yes      | One-line description                                                                                        |
| `author`              | object    | Yes      | `{ "name": "...", "url": "..." }`                                                                           |
| `homepage`            | string    | No       | Project URL                                                                                                 |
| `category`            | string    | Yes      | `database-driver`, `export-format`, `import-format`, `theme`, `other`                                       |
| `databaseTypeIds`     | \[string] | No       | Maps to `DatabaseType.pluginTypeId`. Used for auto-install.                                                 |
| `downloadURL`         | string    | No\*     | Direct URL to `.zip`                                                                                        |
| `sha256`              | string    | No\*     | SHA-256 hex of ZIP                                                                                          |
| `binaries`            | \[object] | No       | Per-arch entries with `architecture` (`arm64` or `x86_64`), `downloadURL`, and `sha256`. See example below. |
| `minAppVersion`       | string    | No       | Minimum TablePro version                                                                                    |
| `minPluginKitVersion` | int       | No       | Minimum PluginKit version (currently 2)                                                                     |
| `iconName`            | string    | No       | SF Symbol name                                                                                              |
| `isVerified`          | bool      | Yes      | Verified by TablePro team                                                                                   |

<Note>
  Either `downloadURL`/`sha256` (flat fields) or the `binaries` array is required. When `binaries` is present, the app picks the matching architecture. Flat fields act as fallback for older app versions.
</Note>

## Example Entry

A complete entry for the Oracle driver plugin:

```json theme={null}
{
  "id": "com.TablePro.OracleDriver",
  "name": "Oracle Driver",
  "version": "1.0.0",
  "summary": "Oracle Database 12c+ driver via OracleNIO",
  "author": { "name": "TablePro", "url": "https://tablepro.app" },
  "homepage": "https://docs.tablepro.app/databases/oracle",
  "category": "database-driver",
  "databaseTypeIds": ["Oracle"],
  "binaries": [
    { "architecture": "arm64", "downloadURL": "https://github.com/TableProApp/TablePro/releases/download/plugin-oracle-v1.0.0/OracleDriver-arm64.zip", "sha256": "<sha256>" },
    { "architecture": "x86_64", "downloadURL": "https://github.com/TableProApp/TablePro/releases/download/plugin-oracle-v1.0.0/OracleDriver-x86_64.zip", "sha256": "<sha256>" }
  ],
  "minAppVersion": "0.17.0",
  "minPluginKitVersion": 2,
  "iconName": "server.rack",
  "isVerified": true
}
```

## databaseTypeIds Mapping

The `databaseTypeIds` field tells the app which registry plugin to install when a user picks a database type that has no loaded driver.

| DatabaseType                      | pluginTypeId   |
| --------------------------------- | -------------- |
| MySQL, MariaDB                    | `"MySQL"`      |
| PostgreSQL, Redshift, CockroachDB | `"PostgreSQL"` |
| SQLite                            | `"SQLite"`     |
| MongoDB                           | `"MongoDB"`    |
| Redis                             | `"Redis"`      |
| SQL Server                        | `"SQL Server"` |
| Oracle                            | `"Oracle"`     |
| ClickHouse                        | `"ClickHouse"` |

## Publishing a Plugin

Tag the commit and push:

```bash theme={null}
git tag plugin-oracle-v1.0.0 && git push --tags
```

CI builds both architectures, signs the bundles, creates a GitHub release, and updates the registry manifest. The app fetches the updated manifest on the next **Browse** visit.

## Auto-Install Flow

<Steps>
  <Step title="User selects a database type with no loaded driver" />

  <Step title="App fetches registry, finds plugin by databaseTypeIds" />

  <Step title="Downloads ZIP, verifies SHA-256" />

  <Step title="Extracts bundle, verifies code signature, loads plugin" />
</Steps>

## Plugin Compatibility

Every plugin binary declares the PluginKit version it was built against (`pluginKitVersion`). The app declares two values in `PluginManager.swift`:

* `currentPluginKitVersion`: the version the running app ships.
* `minimumCompatiblePluginKitVersion`: the oldest version the app still loads.

TableProPluginKit is built with Swift Library Evolution, so a plugin built against any version in `[minimum, current]` loads under the app and the runtime fills in any newer requirement from its default. The app accepts that whole range instead of an exact match.

When you change PluginKit:

* **Additive change** (a new requirement with a default, a new field on a non-frozen type): leave both versions alone. Installed plugins keep loading; the registry needs no re-publish.
* **Breaking change** (a removed or changed requirement, a frozen-layout change, a requirement without a default): raise `currentPluginKitVersion` and `minimumCompatiblePluginKitVersion` together, then run `scripts/release-all-plugins.sh <newVersion>` so the registry carries binaries for the new version before the app ships.

The registry serves the newest binary whose `pluginKitVersion` is in the app's range, so an additive bump is served by the existing binaries with no re-publish. After a breaking bump, `scripts/check-registry-readiness.py --floor <min> --current <current>` (run by the app release workflow) fails the release until every database driver has a compatible binary, so the app never ships ahead of its plugins.

If a connection's driver is installed but its binary predates a breaking bump, opening the connection refreshes the registry and updates the driver in the background, then proceeds. The app does not block on this; if a compatible binary is not published yet, the connection reports that it is updating and retries on its own (on a timer and when the network returns), so no quit and reopen is needed.

The manifest is served through jsDelivr (`cdn.jsdelivr.net/gh/TableProApp/plugins@main/plugins.json`) and purged on each publish, so a new binary is visible within seconds rather than waiting out a CDN cache.

Drivers that most users reach for are bundled inside the app and ship in lockstep, so they never depend on the registry. Reserve registry-only distribution for the long tail, where a short, non-blocking update on first connect is acceptable.

## Theme Distribution

Themes use the same manifest format with `category: "theme"`. Key differences from driver plugins:

* Pure JSON data, no executable code
* No code signing required
* No `.tableplugin` bundle
* ZIP contains `.json` files (valid `ThemeDefinition`)
* Installed to `~/Library/Application Support/TablePro/Themes/Registry/`
* Theme packs (multiple themes in one ZIP) are supported

Example entry:

```json theme={null}
{
  "id": "com.example.monokai-theme",
  "name": "Monokai Theme",
  "version": "1.0.0",
  "summary": "Classic Monokai color scheme for TablePro",
  "author": { "name": "Theme Author" },
  "category": "theme",
  "downloadURL": "https://example.com/monokai-theme.zip",
  "sha256": "<sha256-of-zip>",
  "iconName": "paintpalette",
  "isVerified": false
}
```

## Custom Registry URL

For enterprise or private registries:

```bash theme={null}
# Set custom URL
defaults write com.TablePro com.TablePro.customRegistryURL "https://your-registry.example.com/plugins.json"

# Revert to default
defaults delete com.TablePro com.TablePro.customRegistryURL
```

The app invalidates its ETag cache when the registry URL changes, forcing a fresh fetch on the next Browse visit.
