Simplify plugin runtime and cleanup lifecycle

This commit is contained in:
Dotta
2026-03-13 16:58:29 -05:00
parent 80cdbdbd47
commit 12ccfc2c9a
21 changed files with 120 additions and 838 deletions

View File

@@ -65,10 +65,10 @@ const plugin = definePlugin({
async setup(ctx) {
ctx.logger.info(`${PLUGIN_NAME} plugin setup`);
// Expose the current plugin config so UI components can read the
// commentAnnotationMode setting and hide themselves when disabled.
// Expose the current plugin config so UI components can read operator
// settings from the canonical instance config store.
ctx.data.register("plugin-config", async () => {
const config = await ctx.state.get({ scopeKind: "instance", stateKey: "config" }) as Record<string, unknown> | null;
const config = await ctx.config.get();
return {
showFilesInSidebar: config?.showFilesInSidebar === true,
commentAnnotationMode: config?.commentAnnotationMode ?? "both",

View File

@@ -220,7 +220,7 @@ The same set of values is used as **slot types** (where a component mounts) and
#### `page`
A full-page extension mounted at `/plugins/:pluginId` (global) or `/:company/plugins/:pluginId` (company-scoped). Use this for rich, standalone plugin experiences such as dashboards, configuration wizards, or multi-step workflows. Receives `PluginPageProps` with `context.companyId` set to the active company. Requires the `ui.page.register` capability.
A full-page extension mounted at `/plugins/:pluginId` (global) or `/:company/plugins/:pluginId` (company-context route). Use this for rich, standalone plugin experiences such as dashboards, configuration wizards, or multi-step workflows. Receives `PluginPageProps` with `context.companyId` set to the active company. Requires the `ui.page.register` capability.
#### `sidebar`

View File

@@ -177,8 +177,6 @@ export type {
PluginRecord,
PluginStateRecord,
PluginConfig,
PluginCompanySettings,
CompanyPluginAvailability,
PluginEntityRecord,
PluginEntityQuery,
PluginJobRecord,
@@ -305,9 +303,6 @@ export {
installPluginSchema,
upsertPluginConfigSchema,
patchPluginConfigSchema,
upsertPluginCompanySettingsSchema,
updateCompanyPluginAvailabilitySchema,
listCompanyPluginAvailabilitySchema,
updatePluginStatusSchema,
uninstallPluginSchema,
pluginStateScopeKeySchema,
@@ -324,9 +319,6 @@ export {
type InstallPlugin,
type UpsertPluginConfig,
type PatchPluginConfig,
type UpsertPluginCompanySettings,
type UpdateCompanyPluginAvailability,
type ListCompanyPluginAvailability,
type UpdatePluginStatus,
type UninstallPlugin,
type PluginStateScopeKey,

View File

@@ -95,8 +95,6 @@ export type {
PluginRecord,
PluginStateRecord,
PluginConfig,
PluginCompanySettings,
CompanyPluginAvailability,
PluginEntityRecord,
PluginEntityQuery,
PluginJobRecord,

View File

@@ -343,67 +343,6 @@ export interface PluginConfig {
updatedAt: Date;
}
// ---------------------------------------------------------------------------
// Company Plugin Availability / Settings
// ---------------------------------------------------------------------------
/**
* Domain type for a plugin's company-scoped settings row as persisted in the
* `plugin_company_settings` table.
*
* This is separate from instance-wide `PluginConfig`: the plugin remains
* installed globally, while each company can store its own plugin settings and
* availability state independently.
*/
export interface PluginCompanySettings {
/** UUID primary key. */
id: string;
/** FK to `companies.id`. */
companyId: string;
/** FK to `plugins.id`. */
pluginId: string;
/** Explicit availability override for this company/plugin pair. */
enabled: boolean;
/** Company-scoped plugin settings payload. */
settingsJson: Record<string, unknown>;
/** Most recent company-scoped validation or availability error, if any. */
lastError: string | null;
/** Timestamp when the settings row was created. */
createdAt: Date;
/** Timestamp of the most recent settings update. */
updatedAt: Date;
}
/**
* API response shape describing whether a plugin is available to a specific
* company and, when present, the company-scoped settings row backing that
* availability.
*/
export interface CompanyPluginAvailability {
companyId: string;
pluginId: string;
/** Stable manifest/plugin key for display and route generation. */
pluginKey: string;
/** Human-readable plugin name. */
pluginDisplayName: string;
/** Current instance-wide plugin lifecycle status. */
pluginStatus: PluginStatus;
/**
* Whether the plugin is currently available to the company.
* When no `plugin_company_settings` row exists yet, the plugin is enabled
* by default for the company.
*/
available: boolean;
/** Company-scoped settings, defaulting to an empty object when unavailable. */
settingsJson: Record<string, unknown>;
/** Most recent company-scoped error, if any. */
lastError: string | null;
/** Present when availability is backed by a persisted settings row. */
createdAt: Date | null;
/** Present when availability is backed by a persisted settings row. */
updatedAt: Date | null;
}
/**
* Query filter for `ctx.entities.list`.
*/

View File

@@ -151,9 +151,6 @@ export {
installPluginSchema,
upsertPluginConfigSchema,
patchPluginConfigSchema,
upsertPluginCompanySettingsSchema,
updateCompanyPluginAvailabilitySchema,
listCompanyPluginAvailabilitySchema,
updatePluginStatusSchema,
uninstallPluginSchema,
pluginStateScopeKeySchema,
@@ -170,9 +167,6 @@ export {
type InstallPlugin,
type UpsertPluginConfig,
type PatchPluginConfig,
type UpsertPluginCompanySettings,
type UpdateCompanyPluginAvailability,
type ListCompanyPluginAvailability,
type UpdatePluginStatus,
type UninstallPlugin,
type PluginStateScopeKey,

View File

@@ -577,48 +577,6 @@ export const patchPluginConfigSchema = z.object({
export type PatchPluginConfig = z.infer<typeof patchPluginConfigSchema>;
// ---------------------------------------------------------------------------
// Company plugin availability / settings schemas
// ---------------------------------------------------------------------------
/**
* Schema for creating or replacing company-scoped plugin settings.
*
* Company-specific settings are stored separately from instance-level
* `plugin_config`, allowing the host to expose a company availability toggle
* without changing the global install state of the plugin.
*/
export const upsertPluginCompanySettingsSchema = z.object({
settingsJson: z.record(z.unknown()).optional().default({}),
lastError: z.string().nullable().optional(),
});
export type UpsertPluginCompanySettings = z.infer<typeof upsertPluginCompanySettingsSchema>;
/**
* Schema for mutating a plugin's availability for a specific company.
*
* `available=false` lets callers disable access without uninstalling the
* plugin globally. Optional `settingsJson` supports carrying company-specific
* configuration alongside the availability update.
*/
export const updateCompanyPluginAvailabilitySchema = z.object({
available: z.boolean(),
settingsJson: z.record(z.unknown()).optional(),
lastError: z.string().nullable().optional(),
});
export type UpdateCompanyPluginAvailability = z.infer<typeof updateCompanyPluginAvailabilitySchema>;
/**
* Query schema for company plugin availability list endpoints.
*/
export const listCompanyPluginAvailabilitySchema = z.object({
available: z.boolean().optional(),
});
export type ListCompanyPluginAvailability = z.infer<typeof listCompanyPluginAvailabilitySchema>;
// ---------------------------------------------------------------------------
// Plugin status update
// ---------------------------------------------------------------------------