@termix-ssh/plugin-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/cli/commands/build.mjs +246 -0
- package/cli/commands/migrations.mjs +248 -0
- package/cli/commands/pack.mjs +42 -0
- package/cli/commands/sign.mjs +83 -0
- package/cli/commands/test.mjs +33 -0
- package/cli/commands/validate.mjs +215 -0
- package/cli/index.mjs +65 -0
- package/cli/lib/changelog.mjs +126 -0
- package/cli/lib/externals.mjs +46 -0
- package/cli/lib/plugin-dir.mjs +29 -0
- package/cli/lib/signing.mjs +86 -0
- package/cli/lib/static-url-imports.mjs +54 -0
- package/cli/lib/tmxplug.mjs +106 -0
- package/cli/patches/guacamole-common-js-flush.cjs +76 -0
- package/cli/patches/xterm-android-ime.cjs +130 -0
- package/client.d.ts +13 -0
- package/dist/backend.d.ts +1777 -0
- package/dist/backend.js +84 -0
- package/dist/capabilities.d.ts +38 -0
- package/dist/capabilities.js +71 -0
- package/dist/db.d.ts +112 -0
- package/dist/db.js +189 -0
- package/dist/ddl.d.ts +76 -0
- package/dist/ddl.js +678 -0
- package/dist/desktop.d.ts +346 -0
- package/dist/desktop.js +5 -0
- package/dist/frontend.d.ts +1206 -0
- package/dist/frontend.js +388 -0
- package/dist/host/chunk-F3SDZDDG.js +6017 -0
- package/dist/host/chunk-XGWE7BTJ.js +90 -0
- package/dist/host/chunk-XH5NXL6Y.js +56314 -0
- package/dist/host/chunk-YC2MAKSP.js +14 -0
- package/dist/host/linked-server-FZGWQW32.js +12 -0
- package/dist/host/rbac-api-6KDMBVDZ.js +52 -0
- package/dist/host/testing-host.js +414 -0
- package/dist/host/theme.css +91 -0
- package/dist/host/types/src/types/auth-protocols.d.ts +10 -0
- package/dist/host/types/src/types/connection-log.d.ts +13 -0
- package/dist/host/types/src/types/credential-sidebar-preferences.d.ts +38 -0
- package/dist/host/types/src/types/host-defaults.d.ts +60 -0
- package/dist/host/types/src/types/host-sidebar-preferences.d.ts +55 -0
- package/dist/host/types/src/types/index.d.ts +298 -0
- package/dist/host/types/src/types/keybindings.d.ts +27 -0
- package/dist/host/types/src/types/ui-preferences.d.ts +102 -0
- package/dist/host/types/src/types/ui-types.d.ts +260 -0
- package/dist/host/types/src/ui/api/admin-user-data-api.d.ts +11 -0
- package/dist/host/types/src/ui/api/auth-methods-api.d.ts +63 -0
- package/dist/host/types/src/ui/api/credential-sidebar-preferences-api.d.ts +3 -0
- package/dist/host/types/src/ui/api/credentials-api.d.ts +56 -0
- package/dist/host/types/src/ui/api/dashboard-api.d.ts +23 -0
- package/dist/host/types/src/ui/api/external-account-api.d.ts +8 -0
- package/dist/host/types/src/ui/api/host-sidebar-preferences-api.d.ts +3 -0
- package/dist/host/types/src/ui/api/host-status-api.d.ts +11 -0
- package/dist/host/types/src/ui/api/open-tabs-api.d.ts +74 -0
- package/dist/host/types/src/ui/api/plugins-api.d.ts +128 -0
- package/dist/host/types/src/ui/api/rbac-api.d.ts +167 -0
- package/dist/host/types/src/ui/api/settings-api.d.ts +22 -0
- package/dist/host/types/src/ui/api/ssh-host-management-api.d.ts +65 -0
- package/dist/host/types/src/ui/api/sync-api.d.ts +93 -0
- package/dist/host/types/src/ui/api/system-status-api.d.ts +49 -0
- package/dist/host/types/src/ui/api/ui-preferences-api.d.ts +8 -0
- package/dist/host/types/src/ui/api/user-management-api.d.ts +80 -0
- package/dist/host/types/src/ui/auth/Auth.d.ts +12 -0
- package/dist/host/types/src/ui/auth/auth-bits.d.ts +11 -0
- package/dist/host/types/src/ui/auth/silent-signin.d.ts +2 -0
- package/dist/host/types/src/ui/components/FullScreenAppWrapper.d.ts +9 -0
- package/dist/host/types/src/ui/components/alert-dialog.d.ts +14 -0
- package/dist/host/types/src/ui/components/alert.d.ts +9 -0
- package/dist/host/types/src/ui/components/badge.d.ts +9 -0
- package/dist/host/types/src/ui/components/button.d.ts +13 -0
- package/dist/host/types/src/ui/components/card-grid/CardGridCanvas.d.ts +22 -0
- package/dist/host/types/src/ui/components/card-grid/layout-utils.d.ts +26 -0
- package/dist/host/types/src/ui/components/card-grid/types.d.ts +29 -0
- package/dist/host/types/src/ui/components/card-masonry.d.ts +16 -0
- package/dist/host/types/src/ui/components/card.d.ts +11 -0
- package/dist/host/types/src/ui/components/charts/BarSeries.d.ts +16 -0
- package/dist/host/types/src/ui/components/charts/LineChart.d.ts +17 -0
- package/dist/host/types/src/ui/components/charts/RadialGauge.d.ts +18 -0
- package/dist/host/types/src/ui/components/charts/Sparkline.d.ts +22 -0
- package/dist/host/types/src/ui/components/charts/StatRow.d.ts +15 -0
- package/dist/host/types/src/ui/components/charts/geometry.d.ts +20 -0
- package/dist/host/types/src/ui/components/charts/index.d.ts +4 -0
- package/dist/host/types/src/ui/components/checkbox.d.ts +4 -0
- package/dist/host/types/src/ui/components/connection/ConnectionGate.d.ts +56 -0
- package/dist/host/types/src/ui/components/connection/ConnectionLogPanel.d.ts +9 -0
- package/dist/host/types/src/ui/components/connection/ConnectionScreen.d.ts +34 -0
- package/dist/host/types/src/ui/components/connection/connection-status.d.ts +1 -0
- package/dist/host/types/src/ui/components/data-view.d.ts +32 -0
- package/dist/host/types/src/ui/components/dialog.d.ts +17 -0
- package/dist/host/types/src/ui/components/dropdown-menu.d.ts +29 -0
- package/dist/host/types/src/ui/components/empty-state.d.ts +19 -0
- package/dist/host/types/src/ui/components/form-fields.d.ts +115 -0
- package/dist/host/types/src/ui/components/input.d.ts +3 -0
- package/dist/host/types/src/ui/components/kbd.d.ts +12 -0
- package/dist/host/types/src/ui/components/label.d.ts +4 -0
- package/dist/host/types/src/ui/components/manager-card.d.ts +25 -0
- package/dist/host/types/src/ui/components/meter.d.ts +14 -0
- package/dist/host/types/src/ui/components/metric-card.d.ts +18 -0
- package/dist/host/types/src/ui/components/panel-layout.d.ts +83 -0
- package/dist/host/types/src/ui/components/password-input.d.ts +4 -0
- package/dist/host/types/src/ui/components/popover.d.ts +7 -0
- package/dist/host/types/src/ui/components/scroll-area.d.ts +5 -0
- package/dist/host/types/src/ui/components/section-card.d.ts +29 -0
- package/dist/host/types/src/ui/components/select.d.ts +15 -0
- package/dist/host/types/src/ui/components/select2.d.ts +8 -0
- package/dist/host/types/src/ui/components/separator.d.ts +4 -0
- package/dist/host/types/src/ui/components/sheet.d.ts +14 -0
- package/dist/host/types/src/ui/components/sidebar.d.ts +69 -0
- package/dist/host/types/src/ui/components/skeleton.d.ts +2 -0
- package/dist/host/types/src/ui/components/slider.d.ts +4 -0
- package/dist/host/types/src/ui/components/sonner.d.ts +4 -0
- package/dist/host/types/src/ui/components/surface/prompt-styles.d.ts +4 -0
- package/dist/host/types/src/ui/components/surface/surface-scope.d.ts +79 -0
- package/dist/host/types/src/ui/components/switch.d.ts +4 -0
- package/dist/host/types/src/ui/components/tab-strip.d.ts +19 -0
- package/dist/host/types/src/ui/components/tabs.d.ts +7 -0
- package/dist/host/types/src/ui/components/textarea.d.ts +4 -0
- package/dist/host/types/src/ui/components/theme-provider.d.ts +14 -0
- package/dist/host/types/src/ui/components/tooltip.d.ts +7 -0
- package/dist/host/types/src/ui/contexts/BrandingContext.d.ts +15 -0
- package/dist/host/types/src/ui/contexts/UiPreferencesContext.d.ts +38 -0
- package/dist/host/types/src/ui/contexts/branding-document.d.ts +10 -0
- package/dist/host/types/src/ui/dashboard/dashboard-cards-registry.d.ts +30 -0
- package/dist/host/types/src/ui/hooks/use-action-slot.d.ts +10 -0
- package/dist/host/types/src/ui/hooks/use-adaptive-polling.d.ts +5 -0
- package/dist/host/types/src/ui/hooks/use-mobile.d.ts +1 -0
- package/dist/host/types/src/ui/hooks/use-permissions.d.ts +29 -0
- package/dist/host/types/src/ui/hooks/use-status-color-scheme.d.ts +12 -0
- package/dist/host/types/src/ui/hooks/use-sync-status.d.ts +4 -0
- package/dist/host/types/src/ui/hooks/useSshAuthProviders.d.ts +17 -0
- package/dist/host/types/src/ui/i18n/i18n.d.ts +52 -0
- package/dist/host/types/src/ui/lib/ServerStatusContext.d.ts +33 -0
- package/dist/host/types/src/ui/lib/adaptive-polling.d.ts +29 -0
- package/dist/host/types/src/ui/lib/adaptive-resource-budget.d.ts +39 -0
- package/dist/host/types/src/ui/lib/app-keyboard-shortcuts.d.ts +8 -0
- package/dist/host/types/src/ui/lib/base-path.d.ts +1 -0
- package/dist/host/types/src/ui/lib/clipboard-provider.d.ts +9 -0
- package/dist/host/types/src/ui/lib/clipboard.d.ts +20 -0
- package/dist/host/types/src/ui/lib/connection-origin.d.ts +47 -0
- package/dist/host/types/src/ui/lib/db-health-monitor.d.ts +34 -0
- package/dist/host/types/src/ui/lib/device-id.d.ts +1 -0
- package/dist/host/types/src/ui/lib/electron.d.ts +1 -0
- package/dist/host/types/src/ui/lib/embedded-server-status.d.ts +15 -0
- package/dist/host/types/src/ui/lib/error-message.d.ts +9 -0
- package/dist/host/types/src/ui/lib/frontend-logger.d.ts +67 -0
- package/dist/host/types/src/ui/lib/global-shortcut-handler.d.ts +3 -0
- package/dist/host/types/src/ui/lib/host-defaults-context.d.ts +48 -0
- package/dist/host/types/src/ui/lib/hosts-request-cache.d.ts +9 -0
- package/dist/host/types/src/ui/lib/keybinding-match.d.ts +3 -0
- package/dist/host/types/src/ui/lib/linked-server.d.ts +10 -0
- package/dist/host/types/src/ui/lib/local-adaptive-engine.d.ts +40 -0
- package/dist/host/types/src/ui/lib/permissions.d.ts +16 -0
- package/dist/host/types/src/ui/lib/plugin-i18n.d.ts +11 -0
- package/dist/host/types/src/ui/lib/plugin-icon.d.ts +11 -0
- package/dist/host/types/src/ui/lib/plugin-transport.d.ts +50 -0
- package/dist/host/types/src/ui/lib/registry.d.ts +29 -0
- package/dist/host/types/src/ui/lib/rem.d.ts +7 -0
- package/dist/host/types/src/ui/lib/remote-server-api.d.ts +11 -0
- package/dist/host/types/src/ui/lib/server-status-store.d.ts +37 -0
- package/dist/host/types/src/ui/lib/sync-events.d.ts +2 -0
- package/dist/host/types/src/ui/lib/sync-status.d.ts +6 -0
- package/dist/host/types/src/ui/lib/tab-jump-hotkey.d.ts +4 -0
- package/dist/host/types/src/ui/lib/theme.d.ts +21 -0
- package/dist/host/types/src/ui/lib/ttl-request-cache.d.ts +10 -0
- package/dist/host/types/src/ui/lib/usage-color.d.ts +5 -0
- package/dist/host/types/src/ui/lib/utils.d.ts +2 -0
- package/dist/host/types/src/ui/lib/visible-interval.d.ts +5 -0
- package/dist/host/types/src/ui/lib/widget-title.d.ts +8 -0
- package/dist/host/types/src/ui/lib/ws-auth.d.ts +1 -0
- package/dist/host/types/src/ui/main-axios.d.ts +170 -0
- package/dist/host/types/src/ui/plugin-host/PluginViewPlaceholder.d.ts +13 -0
- package/dist/host/types/src/ui/plugin-host/app.d.ts +18 -0
- package/dist/host/types/src/ui/plugin-host/auth-registry.d.ts +50 -0
- package/dist/host/types/src/ui/plugin-host/bridge.d.ts +26 -0
- package/dist/host/types/src/ui/plugin-host/component-registry.d.ts +24 -0
- package/dist/host/types/src/ui/plugin-host/desktop.d.ts +7 -0
- package/dist/host/types/src/ui/plugin-host/extension-registry.d.ts +16 -0
- package/dist/host/types/src/ui/plugin-host/host-scope.d.ts +26 -0
- package/dist/host/types/src/ui/plugin-host/loader.d.ts +52 -0
- package/dist/host/types/src/ui/plugin-host/plugin-store.d.ts +40 -0
- package/dist/host/types/src/ui/plugin-host/scope.d.ts +20 -0
- package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +99 -0
- package/dist/host/types/src/ui/plugin-host/shell-bridge.d.ts +67 -0
- package/dist/host/types/src/ui/plugin-host/view-ownership.d.ts +31 -0
- package/dist/host/types/src/ui/settings/HostPluginSections.d.ts +31 -0
- package/dist/host/types/src/ui/settings/SettingsFields.d.ts +22 -0
- package/dist/host/types/src/ui/settings/host-feature-tabs.d.ts +11 -0
- package/dist/host/types/src/ui/settings/settings-components.d.ts +32 -0
- package/dist/host/types/src/ui/settings/settings-fields-util.d.ts +11 -0
- package/dist/host/types/src/ui/shell/ActionSlot.d.ts +41 -0
- package/dist/host/types/src/ui/shell/TabContext.d.ts +30 -0
- package/dist/host/types/src/ui/shell/action-registry.d.ts +99 -0
- package/dist/host/types/src/ui/shell/keybinding-registry.d.ts +62 -0
- package/dist/host/types/src/ui/shell/palette-registry.d.ts +55 -0
- package/dist/host/types/src/ui/shell/panel-registry.d.ts +24 -0
- package/dist/host/types/src/ui/shell/tab-registry.d.ts +92 -0
- package/dist/host/types/src/ui/sidebar/HostManagerTabs.d.ts +65 -0
- package/dist/host/types/src/ui/sidebar/host-contributions.d.ts +72 -0
- package/dist/host/types/src/ui/sidebar/host-defaults/catalog.d.ts +17 -0
- package/dist/host/types/src/ui/sidebar/host-protocols.d.ts +49 -0
- package/dist/host/types/src/ui/sidebar/quick-connect-host.d.ts +21 -0
- package/dist/host/types/src/ui/sidebar/rail-items.d.ts +103 -0
- package/dist/host/types/src/ui/ssh/connection-log/ConnectionLogContext.d.ts +17 -0
- package/dist/host/types/src/ui/ssh/dialogs/BrowserSignInDialog.d.ts +18 -0
- package/dist/host/types/src/ui/ssh/dialogs/HostKeyVerificationDialog.d.ts +17 -0
- package/dist/host/types/src/ui/ssh/dialogs/PassphraseDialog.d.ts +15 -0
- package/dist/host/types/src/ui/ssh/dialogs/SSHAuthDialog.d.ts +20 -0
- package/dist/host/types/src/ui/ssh/dialogs/TOTPDialog.d.ts +13 -0
- package/dist/host/ui.d.ts +1 -0
- package/dist/host/ui.js +31754 -0
- package/dist/host/use-permissions-NULZL43J.js +18 -0
- package/dist/host-commands.d.ts +89 -0
- package/dist/host-commands.js +387 -0
- package/dist/manifest.d.ts +461 -0
- package/dist/manifest.js +1499 -0
- package/dist/settings.d.ts +43 -0
- package/dist/settings.js +168 -0
- package/dist/ssh-certs.d.ts +25 -0
- package/dist/ssh-certs.js +234 -0
- package/dist/ssh-options.d.ts +23 -0
- package/dist/ssh-options.js +1 -0
- package/dist/table-builder.d.ts +26 -0
- package/dist/table-builder.js +87 -0
- package/dist/testing/safe-ports.d.ts +10 -0
- package/dist/testing/safe-ports.js +59 -0
- package/dist/testing/setup.d.ts +7 -0
- package/dist/testing/setup.js +146 -0
- package/dist/testing.d.ts +537 -0
- package/dist/testing.js +1451 -0
- package/dist/vitest-preset.d.ts +54 -0
- package/dist/vitest-preset.js +96 -0
- package/package.json +143 -0
- package/schema/changelog.schema.json +67 -0
- package/schema/manifest.schema.json +1160 -0
- package/tsconfig.plugin.json +31 -0
package/dist/backend.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend contract: what a plugin's activate(ctx) receives.
|
|
3
|
+
*
|
|
4
|
+
* These are types only. Core builds the real object in
|
|
5
|
+
* src/backend/plugins/ctx.ts and injects it at activation, so the SDK stays a
|
|
6
|
+
* description of the contract rather than an implementation a plugin could
|
|
7
|
+
* reach around.
|
|
8
|
+
*
|
|
9
|
+
* ctx.ssh is the part of step B's host surface that A8 needed early, so plugin
|
|
10
|
+
* transports could leave core's internals behind.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Thrown when a plugin calls a guarded member without the capability.
|
|
14
|
+
*
|
|
15
|
+
* Two things must be true: the manifest declares it, and it is granted. A
|
|
16
|
+
* grant for something the manifest never declared is ignored, so widening a
|
|
17
|
+
* plugin's reach always needs a new manifest the user can see.
|
|
18
|
+
*/
|
|
19
|
+
export class PluginCapabilityError extends Error {
|
|
20
|
+
code = "EPLUGINCAP";
|
|
21
|
+
pluginId;
|
|
22
|
+
capability;
|
|
23
|
+
constructor(pluginId, capability) {
|
|
24
|
+
super(`Plugin "${pluginId}" is not granted the "${capability}" capability. ` +
|
|
25
|
+
`Declare it in the manifest's capabilities array and grant it in the plugin's settings.`);
|
|
26
|
+
this.name = "PluginCapabilityError";
|
|
27
|
+
this.pluginId = pluginId;
|
|
28
|
+
this.capability = capability;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Thrown by a login method or second factor to refuse a sign-in with a
|
|
33
|
+
* message the user can see. `code` is a stable id the login screen can map to
|
|
34
|
+
* its own text; `status` is the HTTP status for form methods.
|
|
35
|
+
*/
|
|
36
|
+
export class LoginMethodError extends Error {
|
|
37
|
+
status;
|
|
38
|
+
code;
|
|
39
|
+
constructor(message, status = 401, code) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "LoginMethodError";
|
|
42
|
+
this.status = status;
|
|
43
|
+
this.code = code;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Every key PluginHostCreateInput and PluginHostUpdateInput accept. */
|
|
47
|
+
export const PLUGIN_HOST_INPUT_KEYS = [
|
|
48
|
+
"name",
|
|
49
|
+
"ip",
|
|
50
|
+
"port",
|
|
51
|
+
"username",
|
|
52
|
+
"authType",
|
|
53
|
+
"credentialId",
|
|
54
|
+
"overrideCredentialUsername",
|
|
55
|
+
"connectionType",
|
|
56
|
+
"tags",
|
|
57
|
+
"folder",
|
|
58
|
+
"pin",
|
|
59
|
+
"notes",
|
|
60
|
+
"jumpHosts",
|
|
61
|
+
"enableSsh",
|
|
62
|
+
"sshPort",
|
|
63
|
+
"statusCheckEnabled",
|
|
64
|
+
"statusCheckInterval",
|
|
65
|
+
"forceKeyboardInteractive",
|
|
66
|
+
"sshOptions",
|
|
67
|
+
"pluginSettings",
|
|
68
|
+
];
|
|
69
|
+
/** Thrown by ctx.ssh.startInteraction when no provider can start it. */
|
|
70
|
+
export class PluginSshInteractionError extends Error {
|
|
71
|
+
constructor(message) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = "PluginSshInteractionError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Identity helper that gives a plugin entry its types without importing the
|
|
78
|
+
* runtime. Everything a plugin creates belongs inside activate: the module is
|
|
79
|
+
* cached by the ESM loader, so disable-then-enable re-runs activate on the
|
|
80
|
+
* same module object.
|
|
81
|
+
*/
|
|
82
|
+
export function definePlugin(plugin) {
|
|
83
|
+
return plugin;
|
|
84
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a plugin's code may do.
|
|
3
|
+
*
|
|
4
|
+
* A capability is declared in the manifest and checked by the SDK method that
|
|
5
|
+
* needs it. It is not a user permission: those stay in core RBAC and are dotted
|
|
6
|
+
* (hosts.view), while capabilities are colon-separated (hosts:read) so the two
|
|
7
|
+
* can never be confused in a grant table or a log line.
|
|
8
|
+
*
|
|
9
|
+
* Adding one means an entry here plus the SDK method that checks it. The i18n
|
|
10
|
+
* keys resolve against core's en.json under plugins.capabilities.<id>.
|
|
11
|
+
*
|
|
12
|
+
* The copy those keys carry describes the consequence to the person deciding,
|
|
13
|
+
* not the mechanism. "Run commands on your servers", not "grants ssh:connect".
|
|
14
|
+
*/
|
|
15
|
+
export type CapabilityRisk = "low" | "medium" | "high" | "critical";
|
|
16
|
+
export interface CapabilityInfo {
|
|
17
|
+
id: string;
|
|
18
|
+
risk: CapabilityRisk;
|
|
19
|
+
/** i18n key for the short consequence, e.g. "Run commands on your servers". */
|
|
20
|
+
titleKey: string;
|
|
21
|
+
/** i18n key for the qualifying sentence under the title. */
|
|
22
|
+
consequenceKey: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Ordered critical -> low. The install and review UI reads this order directly
|
|
26
|
+
* so the worst line is never folded into a summary row.
|
|
27
|
+
*/
|
|
28
|
+
export declare const CAPABILITY_CATALOG: readonly CapabilityInfo[];
|
|
29
|
+
export declare const CAPABILITY_IDS: readonly string[];
|
|
30
|
+
/**
|
|
31
|
+
* Kept as a string rather than a union of the catalog ids: a capability is
|
|
32
|
+
* data the runtime checks at load time, and a union here would force every
|
|
33
|
+
* caller holding a manifest value to cast.
|
|
34
|
+
*/
|
|
35
|
+
export type Capability = string;
|
|
36
|
+
export declare function isKnownCapability(capability: string): boolean;
|
|
37
|
+
export declare function getCapabilityInfo(capability: string): CapabilityInfo | undefined;
|
|
38
|
+
export declare const CAPABILITY_RISK_ORDER: readonly CapabilityRisk[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a plugin's code may do.
|
|
3
|
+
*
|
|
4
|
+
* A capability is declared in the manifest and checked by the SDK method that
|
|
5
|
+
* needs it. It is not a user permission: those stay in core RBAC and are dotted
|
|
6
|
+
* (hosts.view), while capabilities are colon-separated (hosts:read) so the two
|
|
7
|
+
* can never be confused in a grant table or a log line.
|
|
8
|
+
*
|
|
9
|
+
* Adding one means an entry here plus the SDK method that checks it. The i18n
|
|
10
|
+
* keys resolve against core's en.json under plugins.capabilities.<id>.
|
|
11
|
+
*
|
|
12
|
+
* The copy those keys carry describes the consequence to the person deciding,
|
|
13
|
+
* not the mechanism. "Run commands on your servers", not "grants ssh:connect".
|
|
14
|
+
*/
|
|
15
|
+
function entry(id, risk) {
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
risk,
|
|
19
|
+
titleKey: `plugins.capabilities.${id}.title`,
|
|
20
|
+
consequenceKey: `plugins.capabilities.${id}.consequence`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Ordered critical -> low. The install and review UI reads this order directly
|
|
25
|
+
* so the worst line is never folded into a summary row.
|
|
26
|
+
*/
|
|
27
|
+
export const CAPABILITY_CATALOG = [
|
|
28
|
+
entry("credentials:read", "critical"),
|
|
29
|
+
entry("system:tls", "critical"),
|
|
30
|
+
entry("ssh:connect", "high"),
|
|
31
|
+
entry("process:spawn", "high"),
|
|
32
|
+
entry("users:write", "high"),
|
|
33
|
+
entry("users:impersonate", "high"),
|
|
34
|
+
entry("db:core-refs", "high"),
|
|
35
|
+
entry("auth:provide", "high"),
|
|
36
|
+
entry("device:serial", "high"),
|
|
37
|
+
entry("notify:hub", "high"),
|
|
38
|
+
entry("hosts:write", "medium"),
|
|
39
|
+
entry("credentials:use", "medium"),
|
|
40
|
+
entry("credentials:write", "medium"),
|
|
41
|
+
entry("network:outbound", "medium"),
|
|
42
|
+
entry("network:serve", "medium"),
|
|
43
|
+
entry("network:broadcast", "medium"),
|
|
44
|
+
entry("users:read", "medium"),
|
|
45
|
+
entry("events:core", "medium"),
|
|
46
|
+
entry("notify:send", "medium"),
|
|
47
|
+
entry("audit:read", "medium"),
|
|
48
|
+
entry("desktop:window", "medium"),
|
|
49
|
+
entry("hosts:read", "low"),
|
|
50
|
+
entry("db:own", "low"),
|
|
51
|
+
entry("kv:own", "low"),
|
|
52
|
+
entry("files:own", "low"),
|
|
53
|
+
entry("secrets:own", "low"),
|
|
54
|
+
entry("settings:read-core", "low"),
|
|
55
|
+
entry("plugins:read", "low"),
|
|
56
|
+
entry("ui:surface", "low"),
|
|
57
|
+
];
|
|
58
|
+
export const CAPABILITY_IDS = CAPABILITY_CATALOG.map((capability) => capability.id);
|
|
59
|
+
const BY_ID = new Map(CAPABILITY_CATALOG.map((capability) => [capability.id, capability]));
|
|
60
|
+
export function isKnownCapability(capability) {
|
|
61
|
+
return BY_ID.has(capability);
|
|
62
|
+
}
|
|
63
|
+
export function getCapabilityInfo(capability) {
|
|
64
|
+
return BY_ID.get(capability);
|
|
65
|
+
}
|
|
66
|
+
export const CAPABILITY_RISK_ORDER = [
|
|
67
|
+
"critical",
|
|
68
|
+
"high",
|
|
69
|
+
"medium",
|
|
70
|
+
"low",
|
|
71
|
+
];
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table definitions a plugin owns.
|
|
3
|
+
*
|
|
4
|
+
* A definition is a plain descriptor, not a live Drizzle table. Core turns it
|
|
5
|
+
* into one at runtime (src/backend/plugins/table-builder.ts) and emits the DDL
|
|
6
|
+
* for whichever dialect the server is on, which keeps this entry a description
|
|
7
|
+
* of the contract rather than an implementation a plugin could reach around.
|
|
8
|
+
*
|
|
9
|
+
* Why one table object and three DDL emitters, rather than three table
|
|
10
|
+
* objects: the sqlite-core definitions already encode correctly for every
|
|
11
|
+
* engine at query time. text and integer encode as themselves; a boolean
|
|
12
|
+
* writes 1/0, which Postgres and MySQL both accept; real is a plain number.
|
|
13
|
+
* What genuinely differs between the engines is DDL. See the header of
|
|
14
|
+
* scripts/generate-dialect-schema.cjs, which this mapping is taken from.
|
|
15
|
+
*/
|
|
16
|
+
export type PluginColumnType = "id" | "text" | "varchar" | "integer" | "bigint" | "real" | "boolean" | "timestamp" | "json" | "encryptedText" | "refUser" | "refHost";
|
|
17
|
+
export interface PluginColumn {
|
|
18
|
+
readonly type: PluginColumnType;
|
|
19
|
+
/** varchar only. The ceiling MySQL can index. */
|
|
20
|
+
readonly length?: number;
|
|
21
|
+
readonly notNull?: boolean;
|
|
22
|
+
readonly primaryKey?: boolean;
|
|
23
|
+
readonly unique?: boolean;
|
|
24
|
+
readonly defaultValue?: string | number | boolean | null;
|
|
25
|
+
/** timestamp only: default CURRENT_TIMESTAMP. */
|
|
26
|
+
readonly defaultNow?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** The longest string MySQL will index, and so the width of every key column. */
|
|
29
|
+
export declare const KEY_LENGTH = 255;
|
|
30
|
+
interface Builder<T extends PluginColumn = PluginColumn> {
|
|
31
|
+
notNull: () => Builder<T>;
|
|
32
|
+
primaryKey: () => Builder<T>;
|
|
33
|
+
unique: () => Builder<T>;
|
|
34
|
+
default: (value: string | number | boolean | null) => Builder<T>;
|
|
35
|
+
defaultNow: () => Builder<T>;
|
|
36
|
+
readonly column: PluginColumn;
|
|
37
|
+
}
|
|
38
|
+
/** Auto-incrementing surrogate key: integer on sqlite, serial, auto_increment. */
|
|
39
|
+
export declare const id: () => Builder<PluginColumn>;
|
|
40
|
+
/** Unbounded string. Never indexable: MySQL cannot index TEXT. */
|
|
41
|
+
export declare const text: () => Builder<PluginColumn>;
|
|
42
|
+
/** Bounded string. Indexable on every engine. */
|
|
43
|
+
export declare const varchar: (length?: number) => Builder<PluginColumn>;
|
|
44
|
+
export declare const integer: () => Builder<PluginColumn>;
|
|
45
|
+
export declare const bigint: () => Builder<PluginColumn>;
|
|
46
|
+
/** Floating point. A plain number on every engine. Never indexable. */
|
|
47
|
+
export declare const real: () => Builder<PluginColumn>;
|
|
48
|
+
export declare const boolean: () => Builder<PluginColumn>;
|
|
49
|
+
/** Stored as text on every engine. See src/backend/database/repositories/sql-timestamp.ts. */
|
|
50
|
+
export declare const timestamp: () => Builder<PluginColumn>;
|
|
51
|
+
/** JSON held as text. Never indexable, for the same reason as text(). */
|
|
52
|
+
export declare const json: () => Builder<PluginColumn>;
|
|
53
|
+
/** Text encrypted with the owning user's key before it is written. */
|
|
54
|
+
export declare const encryptedText: () => Builder<PluginColumn>;
|
|
55
|
+
/** Foreign key to users.id, cascading on delete. */
|
|
56
|
+
export declare const refUser: () => Builder<PluginColumn>;
|
|
57
|
+
/** Foreign key to ssh_data.id, cascading on delete. */
|
|
58
|
+
export declare const refHost: () => Builder<PluginColumn>;
|
|
59
|
+
export interface PluginTableIndex {
|
|
60
|
+
readonly name: string;
|
|
61
|
+
readonly columns: readonly string[];
|
|
62
|
+
readonly unique?: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface PluginTableOptions {
|
|
65
|
+
readonly indexes?: readonly PluginTableIndex[];
|
|
66
|
+
readonly uniques?: readonly PluginTableIndex[];
|
|
67
|
+
}
|
|
68
|
+
export interface PluginTableDefinition {
|
|
69
|
+
/** The unprefixed name as the plugin wrote it. */
|
|
70
|
+
readonly name: string;
|
|
71
|
+
readonly columns: Readonly<Record<string, PluginColumn>>;
|
|
72
|
+
readonly indexes: readonly PluginTableIndex[];
|
|
73
|
+
/** A legacy core table this definition takes over by rename. See adoptLegacyTable. */
|
|
74
|
+
readonly adopts?: string;
|
|
75
|
+
}
|
|
76
|
+
type Columns = Record<string, Builder | PluginColumn>;
|
|
77
|
+
/**
|
|
78
|
+
* Declares a table this plugin owns.
|
|
79
|
+
*
|
|
80
|
+
* The name is unprefixed here; core prefixes it with p_<plugin id>_ when the
|
|
81
|
+
* definition is registered, so a plugin cannot name a table into another
|
|
82
|
+
* plugin's namespace or into core's.
|
|
83
|
+
*/
|
|
84
|
+
export declare function defineTable(name: string, columns: Columns, options?: PluginTableOptions): PluginTableDefinition;
|
|
85
|
+
/** p_<id with - as _>_ - the prefix every table a plugin owns carries. */
|
|
86
|
+
export declare function tablePrefix(pluginId: string): string;
|
|
87
|
+
/** The physical table name for a definition owned by a plugin. */
|
|
88
|
+
export declare function prefixedTableName(pluginId: string, name: string): string;
|
|
89
|
+
/**
|
|
90
|
+
* Legacy core tables, and the one plugin allowed to adopt each.
|
|
91
|
+
*
|
|
92
|
+
* Adoption is how a feature keeps its rows when it moves out of core: the
|
|
93
|
+
* table is renamed into the plugin's namespace rather than copied. One owner
|
|
94
|
+
* per table, because two plugins adopting the same one would mean whichever
|
|
95
|
+
* activated second found it already gone.
|
|
96
|
+
*
|
|
97
|
+
* Shared with the CLI so a migration that reaches for someone else's table is
|
|
98
|
+
* caught at build time as well as at activation.
|
|
99
|
+
*/
|
|
100
|
+
export declare const LEGACY_TABLE_OWNERS: Readonly<Record<string, string>>;
|
|
101
|
+
/**
|
|
102
|
+
* Marks a definition as the new home of a legacy core table.
|
|
103
|
+
*
|
|
104
|
+
* The migration the CLI writes for it renames the legacy table into the
|
|
105
|
+
* plugin's namespace, and creates it first when there is none (a fresh
|
|
106
|
+
* install), so both paths end with the same table. Keep the legacy column and
|
|
107
|
+
* index names in the definition: the rename carries the old indexes across,
|
|
108
|
+
* and reusing their names is what stops the migration from creating a second
|
|
109
|
+
* copy of each.
|
|
110
|
+
*/
|
|
111
|
+
export declare function adoptLegacyTable(legacyName: string, definition: PluginTableDefinition): PluginTableDefinition;
|
|
112
|
+
export {};
|
package/dist/db.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table definitions a plugin owns.
|
|
3
|
+
*
|
|
4
|
+
* A definition is a plain descriptor, not a live Drizzle table. Core turns it
|
|
5
|
+
* into one at runtime (src/backend/plugins/table-builder.ts) and emits the DDL
|
|
6
|
+
* for whichever dialect the server is on, which keeps this entry a description
|
|
7
|
+
* of the contract rather than an implementation a plugin could reach around.
|
|
8
|
+
*
|
|
9
|
+
* Why one table object and three DDL emitters, rather than three table
|
|
10
|
+
* objects: the sqlite-core definitions already encode correctly for every
|
|
11
|
+
* engine at query time. text and integer encode as themselves; a boolean
|
|
12
|
+
* writes 1/0, which Postgres and MySQL both accept; real is a plain number.
|
|
13
|
+
* What genuinely differs between the engines is DDL. See the header of
|
|
14
|
+
* scripts/generate-dialect-schema.cjs, which this mapping is taken from.
|
|
15
|
+
*/
|
|
16
|
+
/** The longest string MySQL will index, and so the width of every key column. */
|
|
17
|
+
export const KEY_LENGTH = 255;
|
|
18
|
+
function builder(column) {
|
|
19
|
+
const next = (patch) => builder({ ...column, ...patch });
|
|
20
|
+
return {
|
|
21
|
+
column,
|
|
22
|
+
notNull: () => next({ notNull: true }),
|
|
23
|
+
primaryKey: () => next({ primaryKey: true, notNull: true }),
|
|
24
|
+
unique: () => next({ unique: true }),
|
|
25
|
+
default: (defaultValue) => next({ defaultValue }),
|
|
26
|
+
defaultNow: () => next({ defaultNow: true }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Auto-incrementing surrogate key: integer on sqlite, serial, auto_increment. */
|
|
30
|
+
export const id = () => builder({ type: "id", primaryKey: true, notNull: true });
|
|
31
|
+
/** Unbounded string. Never indexable: MySQL cannot index TEXT. */
|
|
32
|
+
export const text = () => builder({ type: "text" });
|
|
33
|
+
/** Bounded string. Indexable on every engine. */
|
|
34
|
+
export const varchar = (length = KEY_LENGTH) => builder({ type: "varchar", length });
|
|
35
|
+
export const integer = () => builder({ type: "integer" });
|
|
36
|
+
export const bigint = () => builder({ type: "bigint" });
|
|
37
|
+
/** Floating point. A plain number on every engine. Never indexable. */
|
|
38
|
+
export const real = () => builder({ type: "real" });
|
|
39
|
+
export const boolean = () => builder({ type: "boolean" });
|
|
40
|
+
/** Stored as text on every engine. See src/backend/database/repositories/sql-timestamp.ts. */
|
|
41
|
+
export const timestamp = () => builder({ type: "timestamp" });
|
|
42
|
+
/** JSON held as text. Never indexable, for the same reason as text(). */
|
|
43
|
+
export const json = () => builder({ type: "json" });
|
|
44
|
+
/** Text encrypted with the owning user's key before it is written. */
|
|
45
|
+
export const encryptedText = () => builder({ type: "encryptedText" });
|
|
46
|
+
/** Foreign key to users.id, cascading on delete. */
|
|
47
|
+
export const refUser = () => builder({ type: "refUser", length: KEY_LENGTH, notNull: true });
|
|
48
|
+
/** Foreign key to ssh_data.id, cascading on delete. */
|
|
49
|
+
export const refHost = () => builder({ type: "refHost", notNull: true });
|
|
50
|
+
/** Columns that can never carry an index, because MySQL cannot index them. */
|
|
51
|
+
const UNINDEXABLE = new Set([
|
|
52
|
+
"text",
|
|
53
|
+
"json",
|
|
54
|
+
"encryptedText",
|
|
55
|
+
]);
|
|
56
|
+
const NAME_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
57
|
+
function unwrap(value) {
|
|
58
|
+
return "column" in value ? value.column : value;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Declares a table this plugin owns.
|
|
62
|
+
*
|
|
63
|
+
* The name is unprefixed here; core prefixes it with p_<plugin id>_ when the
|
|
64
|
+
* definition is registered, so a plugin cannot name a table into another
|
|
65
|
+
* plugin's namespace or into core's.
|
|
66
|
+
*/
|
|
67
|
+
export function defineTable(name, columns, options = {}) {
|
|
68
|
+
if (!NAME_PATTERN.test(name)) {
|
|
69
|
+
throw new Error(`Table name "${name}" must be lower snake_case and start with a letter`);
|
|
70
|
+
}
|
|
71
|
+
const resolved = {};
|
|
72
|
+
for (const [key, value] of Object.entries(columns)) {
|
|
73
|
+
resolved[key] = unwrap(value);
|
|
74
|
+
}
|
|
75
|
+
if (Object.keys(resolved).length === 0) {
|
|
76
|
+
throw new Error(`Table "${name}" declares no columns`);
|
|
77
|
+
}
|
|
78
|
+
const indexes = [
|
|
79
|
+
...(options.uniques ?? []).map((entry) => ({ ...entry, unique: true })),
|
|
80
|
+
...(options.indexes ?? []),
|
|
81
|
+
];
|
|
82
|
+
// Checked here rather than at migration time so the error names the table
|
|
83
|
+
// and column while the author is still looking at the definition.
|
|
84
|
+
for (const index of indexes) {
|
|
85
|
+
if (!NAME_PATTERN.test(index.name)) {
|
|
86
|
+
throw new Error(`Index name "${index.name}" must be lower snake_case and start with a letter`);
|
|
87
|
+
}
|
|
88
|
+
if (index.columns.length === 0) {
|
|
89
|
+
throw new Error(`Index "${index.name}" names no columns`);
|
|
90
|
+
}
|
|
91
|
+
for (const column of index.columns) {
|
|
92
|
+
const declared = resolved[column];
|
|
93
|
+
if (!declared) {
|
|
94
|
+
throw new Error(`Index "${index.name}" names "${column}", which table "${name}" does not declare`);
|
|
95
|
+
}
|
|
96
|
+
if (UNINDEXABLE.has(declared.type)) {
|
|
97
|
+
throw new Error(`Index "${index.name}" covers "${column}", a ${declared.type} column. ` +
|
|
98
|
+
`MySQL cannot index an unbounded column: use varchar(n) instead.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { name, columns: resolved, indexes };
|
|
103
|
+
}
|
|
104
|
+
/** p_<id with - as _>_ - the prefix every table a plugin owns carries. */
|
|
105
|
+
export function tablePrefix(pluginId) {
|
|
106
|
+
return `p_${pluginId.replace(/-/g, "_")}_`;
|
|
107
|
+
}
|
|
108
|
+
/** The physical table name for a definition owned by a plugin. */
|
|
109
|
+
export function prefixedTableName(pluginId, name) {
|
|
110
|
+
return `${tablePrefix(pluginId)}${name}`;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Legacy core tables, and the one plugin allowed to adopt each.
|
|
114
|
+
*
|
|
115
|
+
* Adoption is how a feature keeps its rows when it moves out of core: the
|
|
116
|
+
* table is renamed into the plugin's namespace rather than copied. One owner
|
|
117
|
+
* per table, because two plugins adopting the same one would mean whichever
|
|
118
|
+
* activated second found it already gone.
|
|
119
|
+
*
|
|
120
|
+
* Shared with the CLI so a migration that reaches for someone else's table is
|
|
121
|
+
* caught at build time as well as at activation.
|
|
122
|
+
*/
|
|
123
|
+
export const LEGACY_TABLE_OWNERS = {
|
|
124
|
+
fleets: "fleets",
|
|
125
|
+
fleet_members: "fleets",
|
|
126
|
+
fleet_inventory: "fleets",
|
|
127
|
+
user_workspaces: "workspaces",
|
|
128
|
+
network_topology: "network-topology",
|
|
129
|
+
snippets: "snippets",
|
|
130
|
+
snippet_folders: "snippets",
|
|
131
|
+
snippet_access: "snippets",
|
|
132
|
+
c2s_tunnel_presets: "tunnels",
|
|
133
|
+
command_history: "ssh-terminal",
|
|
134
|
+
file_manager_recent: "file-manager",
|
|
135
|
+
file_manager_pinned: "file-manager",
|
|
136
|
+
file_manager_shortcuts: "file-manager",
|
|
137
|
+
transfer_recent: "file-manager",
|
|
138
|
+
tmux_session_tags: "tmux-monitor",
|
|
139
|
+
session_shares: "session-sharing",
|
|
140
|
+
session_share_participants: "session-sharing",
|
|
141
|
+
collab_rooms: "session-sharing",
|
|
142
|
+
collab_room_members: "session-sharing",
|
|
143
|
+
session_recordings: "session-recording",
|
|
144
|
+
host_metrics_preferences: "host-metrics",
|
|
145
|
+
host_health_checks: "host-metrics",
|
|
146
|
+
host_health_history: "host-metrics",
|
|
147
|
+
host_metrics_history: "host-metrics",
|
|
148
|
+
proxmox_stats_preferences: "proxmox",
|
|
149
|
+
proxmox_node_history: "proxmox",
|
|
150
|
+
automations: "automations",
|
|
151
|
+
automation_trigger_state: "automations",
|
|
152
|
+
automation_schedules: "automations",
|
|
153
|
+
automation_runs: "automations",
|
|
154
|
+
automation_run_steps: "automations",
|
|
155
|
+
automation_channels: "automations",
|
|
156
|
+
ai_providers: "ai",
|
|
157
|
+
ai_conversations: "ai",
|
|
158
|
+
ai_messages: "ai",
|
|
159
|
+
ai_proposals: "ai",
|
|
160
|
+
homepage_items: "homepage",
|
|
161
|
+
homepage_layouts: "homepage",
|
|
162
|
+
dashboard_service_links: "homepage",
|
|
163
|
+
secret_sources: "secret-sources",
|
|
164
|
+
opkssh_tokens: "opkssh",
|
|
165
|
+
vault_profiles: "vault",
|
|
166
|
+
vault_tokens: "vault",
|
|
167
|
+
termix_identities: "termix-identity",
|
|
168
|
+
termix_identity_keys: "termix-identity",
|
|
169
|
+
termix_identity_ca: "termix-identity",
|
|
170
|
+
webauthn_credentials: "webauthn",
|
|
171
|
+
sso_providers: "sso",
|
|
172
|
+
dismissed_alerts: "alerts",
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Marks a definition as the new home of a legacy core table.
|
|
176
|
+
*
|
|
177
|
+
* The migration the CLI writes for it renames the legacy table into the
|
|
178
|
+
* plugin's namespace, and creates it first when there is none (a fresh
|
|
179
|
+
* install), so both paths end with the same table. Keep the legacy column and
|
|
180
|
+
* index names in the definition: the rename carries the old indexes across,
|
|
181
|
+
* and reusing their names is what stops the migration from creating a second
|
|
182
|
+
* copy of each.
|
|
183
|
+
*/
|
|
184
|
+
export function adoptLegacyTable(legacyName, definition) {
|
|
185
|
+
if (!Object.prototype.hasOwnProperty.call(LEGACY_TABLE_OWNERS, legacyName)) {
|
|
186
|
+
throw new Error(`"${legacyName}" is not a legacy core table a plugin may adopt. See LEGACY_TABLE_OWNERS.`);
|
|
187
|
+
}
|
|
188
|
+
return { ...definition, adopts: legacyName };
|
|
189
|
+
}
|
package/dist/ddl.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DDL a table definition becomes, per dialect.
|
|
3
|
+
*
|
|
4
|
+
* Lives in the SDK because two things need the identical mapping: the CLI,
|
|
5
|
+
* which writes a plugin's migration files, and the server, which applies them.
|
|
6
|
+
* A second copy would drift and produce a migration the runner could not
|
|
7
|
+
* reproduce.
|
|
8
|
+
*
|
|
9
|
+
* The mapping itself is the one scripts/generate-dialect-schema.cjs applies to
|
|
10
|
+
* core's schema, kept deliberately in step with it.
|
|
11
|
+
*/
|
|
12
|
+
import type { PluginColumn, PluginTableDefinition } from "./db.js";
|
|
13
|
+
/** Which engine the DDL is for. Matches core's DatabaseDialect exactly. */
|
|
14
|
+
export type SqlDialect = "sqlite" | "postgres" | "mysql";
|
|
15
|
+
/** The core tables a plugin may point a foreign key at, and nothing else. */
|
|
16
|
+
export declare const REFERENCEABLE: {
|
|
17
|
+
readonly refUser: {
|
|
18
|
+
readonly table: "users";
|
|
19
|
+
readonly column: "id";
|
|
20
|
+
};
|
|
21
|
+
readonly refHost: {
|
|
22
|
+
readonly table: "ssh_data";
|
|
23
|
+
readonly column: "id";
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/** The SQL column name for a declared property. */
|
|
27
|
+
export declare function columnName(property: string, column?: PluginColumn): string;
|
|
28
|
+
/** Every column that carries a key, and so must be indexable on MySQL. */
|
|
29
|
+
export declare function keyedColumns(definition: PluginTableDefinition): ReadonlySet<string>;
|
|
30
|
+
/** The CREATE TABLE and CREATE INDEX statements for one definition. */
|
|
31
|
+
export declare function createTableSql(dialect: SqlDialect, pluginId: string, definition: PluginTableDefinition): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Takes over a legacy core table by renaming it into the plugin's namespace.
|
|
34
|
+
*
|
|
35
|
+
* A plain SQL migration cannot ask whether the legacy table exists, so it
|
|
36
|
+
* creates it first when it does not (a fresh install) and then renames either
|
|
37
|
+
* way. Both paths end with the same table and the same rows.
|
|
38
|
+
*
|
|
39
|
+
* Indexes are created on the legacy name with IF NOT EXISTS before the rename,
|
|
40
|
+
* which is why an adopted definition keeps the legacy index names: an index
|
|
41
|
+
* that already exists is left alone and follows the table. MySQL has no
|
|
42
|
+
* CREATE INDEX IF NOT EXISTS, so there none are emitted. That is safe because
|
|
43
|
+
* every legacy table reached MySQL through core's drizzle migrations, which
|
|
44
|
+
* already created its indexes.
|
|
45
|
+
*/
|
|
46
|
+
export declare function adoptTableSql(dialect: SqlDialect, pluginId: string, definition: PluginTableDefinition): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Splits a migration file into statements.
|
|
49
|
+
*
|
|
50
|
+
* Deliberately simple: statements end at a semicolon that is not inside a
|
|
51
|
+
* string literal or a comment. A plugin needing more than that should put the
|
|
52
|
+
* logic in its own code, not in DDL.
|
|
53
|
+
*/
|
|
54
|
+
export declare function splitStatements(source: string): string[];
|
|
55
|
+
/** DROP statement for a definition, for removePluginData. */
|
|
56
|
+
export declare function dropTableSql(dialect: SqlDialect, pluginId: string, definition: PluginTableDefinition): string;
|
|
57
|
+
/** The ALTER that adds one newly declared column. */
|
|
58
|
+
export declare function addColumnSql(dialect: SqlDialect, pluginId: string, definition: PluginTableDefinition, property: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Every problem with the tables a migration writes to.
|
|
61
|
+
*
|
|
62
|
+
* The check has to hold against a plugin that is trying, not only one that
|
|
63
|
+
* made a typo, so it reads each statement the way the engine does rather
|
|
64
|
+
* than matching one pattern: a comment between a keyword and a name, bracket
|
|
65
|
+
* quoting, a second name in a DROP list, a schema-qualified name and
|
|
66
|
+
* `ALTER ... RENAME TO users` are all seen. Reads (FROM, JOIN, REFERENCES)
|
|
67
|
+
* are allowed; writes outside the plugin's prefix are not.
|
|
68
|
+
*
|
|
69
|
+
* `ownedLegacy` lists the legacy core tables this plugin adopts.
|
|
70
|
+
*/
|
|
71
|
+
export declare function findUnownedTableWrites(pluginId: string, sql: string, ownedLegacy?: ReadonlySet<string>, ownedIndexes?: ReadonlySet<string>): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Names of the indexes a plugin's migrations create on its own tables, so a
|
|
74
|
+
* later DROP INDEX with no ON clause can be checked against them.
|
|
75
|
+
*/
|
|
76
|
+
export declare function collectOwnedIndexes(pluginId: string, sqls: readonly string[], ownedLegacy?: ReadonlySet<string>): Set<string>;
|