Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/create-plugin/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { scaffold } from "./scaffold";
import { titleCase, validateDbType, validateName, validateQuote } from "./validate";

const PACKAGE_VERSION = "0.1.0";
const PLUGIN_API_VERSION = "0.1.0";
const PLUGIN_API_VERSION = "0.2.0";
const MIN_TABULARIS_VERSION = "0.9.20";

function main(argv: string[]): number {
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ assertHostCompat(); // throws if the running Tabularis is older than MIN_HOST_VE
| Package version | Minimum Tabularis | Notes |
|-----------------|-------------------|-------|
| `0.1.0` | `0.1.0` (see host `HOST_API_VERSION`) | Initial release |
| `0.2.0` | `0.2.0` | Secure per-connection plugin fields in the connection modal |

## Slot reference

Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tabularis/plugin-api",
"version": "0.1.1",
"version": "0.2.0",
"description": "Public API surface for Tabularis plugin UI extensions.",
"license": "Apache-2.0",
"homepage": "https://github.com/TabularisDB/tabularis/tree/main/packages/plugin-api",
Expand Down
7 changes: 7 additions & 0 deletions packages/plugin-api/src/slots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ export type SlotContextMap = {
extra: Record<string, string>;
/** Update one extra field. Pass an empty string to clear it. */
setExtraField: (key: string, value: string) => void;
/** Plugin-owned secrets. Existing values are represented by metadata only. */
secretFields?: Record<
string,
{ value: string; hasStoredValue: boolean; dirty: boolean }
>;
/** Set a secret for Test/Save. An empty value explicitly clears it. */
setSecretField?: (key: string, value: string) => void;
};
};

Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-api/src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
* API version of this package. Must match the version field of package.json.
* Bump when the host API shape changes in a way that plugin bundles can observe.
*/
export const API_VERSION = "0.1.1";
export const API_VERSION = "0.2.0";

/**
* Minimum Tabularis host version that exposes an API compatible with this package.
* The host sets `window.__TABULARIS_API_VERSION__`; `assertHostCompat()` uses this
* constant to decide whether the active host is new enough.
*/
export const MIN_HOST_VERSION = "0.1.0";
export const MIN_HOST_VERSION = "0.2.0";
14 changes: 13 additions & 1 deletion plugins/PLUGIN_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ One manifest tells Tabularis everything about your plugin — and, when you publ
| `capabilities` | object | Feature flags (see below). |
| `data_types` | array | List of supported data types (see below). |
| `type_mappings` | object \| null | Optional map of generic inferred type names to driver-specific types. Used during paste/import to map generic types (e.g. `DATETIME`) to driver-native equivalents (e.g. `TIMESTAMP`). See [Type Mappings](#type-mappings) below. |
| `connection_fields` | object | Optional hide, label, and placeholder overrides for the common `host`, `port`, `username`, `password`, and `database` fields. Omitted fields preserve the standard UI. |

### Capabilities

Expand Down Expand Up @@ -338,7 +339,7 @@ Add an optional `ui_extensions` array to your manifest:
| `settings.plugin.actions` | Per-plugin actions in Settings modal | `targetPluginId` | Diagnostics, re-auth buttons |
| `settings.plugin.before_settings` | Content above plugin settings form | `targetPluginId` | OAuth panels, status banners |
| `connection-modal.connection_content` | Inside the connection form | `driver` | Custom connection fields |
| `connection-modal.extra_fields` | Below host/port in the connection form | `driver`, `extra`, `setExtraField` | Plugin-specific connection fields (e.g. AWS region) |
| `connection-modal.extra_fields` | Below host/port in the connection form | `driver`, `extra`, `setExtraField`, `secretFields`, `setSecretField` | Plugin-specific connection fields, including values stored per connection in the OS keychain |

### SlotContext

Expand All @@ -358,6 +359,17 @@ interface SlotContext {
}
```

For `connection-modal.extra_fields`, `setSecretField(key, value)` keeps the
value out of `connections.json` and stores it under the saved connection in the
OS keychain. Passing an empty value explicitly clears the entry. On edit,
`secretFields[key]` exposes only `{ value, hasStoredValue, dirty }`: an existing
secret is represented by `hasStoredValue` and is never returned to plugin UI.
At runtime the host resolves stored values into `ConnectionParams.extra` before
calling the driver, so the JSON-RPC method shapes remain backward compatible.
Both properties are optional in the public TypeScript contract. A plugin that
also supports older hosts must guard their presence; a plugin that requires
secure fields can call `assertHostCompat()` before rendering.

### Building UI Extension Bundles

Plugin UI components must be pre-built as **IIFE bundles** (Immediately Invoked Function Expression). The host provides `React`, `ReactJSXRuntime`, and the plugin API as globals — your bundle must **not** bundle its own copies of these.
Expand Down
28 changes: 28 additions & 0 deletions plugins/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,34 @@
}
}
},
"connection_fields": {
"type": "object",
"description": "Optional presentation overrides for host-owned connection fields. Omitted fields keep the standard Tabularis behavior.",
"additionalProperties": false,
"patternProperties": {
"^(host|port|username|password|database)$": {
"type": "object",
"additionalProperties": false,
"properties": {
"hidden": {
"type": "boolean",
"default": false,
"description": "Hide this field for the driver."
},
"label": {
"type": "string",
"maxLength": 80,
"description": "Driver-specific label."
},
"placeholder": {
"type": "string",
"maxLength": 200,
"description": "Driver-specific input placeholder."
}
}
}
}
},
"interpreter": {
"type": "string",
"description": "Optional interpreter for script-based plugins (e.g. python3)."
Expand Down
Loading