| title | Plugin Runtime |
|---|---|
| description | Plugin Runtime protocol schemas |
{/*
Defines the protocol for dynamic plugin loading, unloading, and discovery
at runtime. Addresses the "Dynamic Loading" gap in the microkernel architecture
by enabling plugins to be loaded and unloaded without restarting the kernel.
Inspired by:
-
OSGi Dynamic Module System (bundle lifecycle)
-
Kubernetes Operator pattern (reconciliation loop)
This protocol enables:
-
Runtime load/unload of plugins without kernel restart
-
Plugin discovery from registries and local filesystem
-
Safe unload with dependency awareness
import { DynamicLoadRequestSchema, DynamicPluginOperationSchema, DynamicPluginResultSchema, DynamicUnloadRequestSchema, PluginSourceSchema } from '@objectstack/spec/kernel';
import type { DynamicLoadRequest, DynamicPluginOperation, DynamicPluginResult, DynamicUnloadRequest, PluginSource } from '@objectstack/spec/kernel';
// Validate data
const result = DynamicLoadRequestSchema.parse(data);Request to dynamically load a plugin at runtime
| Property | Type | Required | Description |
|---|---|---|---|
| pluginId | string |
✅ | Unique plugin identifier |
| source | { type: Enum<'npm' | 'local' | 'url' | 'registry' | 'git'>; location: string; version?: string; integrity?: string } |
✅ | Plugin source location for dynamic resolution |
| activationEvents | any |
optional | [REMOVED] dynamicLoadRequest.activationEvents was removed in @objectstack/spec 17.0.0 (#4657, ADR-0049) — no runtime ever read it: every plugin activates immediately on load, so the declared lazy-activation window never existed. Delete the key; eager activation is the only behaviour there has ever been. Lazy activation, if built, returns via the enforce route of ADR-0049 with a vocabulary its executor actually honours. |
| config | Record<string, any> |
optional | Runtime configuration overrides |
| priority | integer |
✅ | Loading priority (lower is higher) |
| sandbox | boolean |
✅ | Run in an isolated sandbox |
| timeout | integer |
✅ | Maximum time to complete loading in ms |
Runtime plugin operation type
loadunloadreloadenabledisable
Result of a dynamic plugin operation
| Property | Type | Required | Description |
|---|---|---|---|
| success | boolean |
✅ | |
| operation | Enum<'load' | 'unload' | 'reload' | 'enable' | 'disable'> |
✅ | Runtime plugin operation type |
| pluginId | string |
✅ | |
| durationMs | integer |
optional | |
| version | string |
optional | |
| error | { code: string; message: string; details?: Record<string, any> } |
optional | |
| warnings | string[] |
optional |
Request to dynamically unload a plugin at runtime
| Property | Type | Required | Description |
|---|---|---|---|
| pluginId | string |
✅ | Plugin to unload |
| strategy | Enum<'graceful' | 'forceful' | 'drain'> |
✅ | How to handle in-flight work during unload |
| timeout | integer |
✅ | Maximum time to complete unloading in ms |
| cleanupCache | boolean |
✅ | Remove cached code and assets after unload |
| dependentAction | Enum<'cascade' | 'warn' | 'block'> |
✅ | How to handle plugins that depend on this one |
Plugin source location for dynamic resolution
| Property | Type | Required | Description |
|---|---|---|---|
| type | Enum<'npm' | 'local' | 'url' | 'registry' | 'git'> |
✅ | Plugin source type |
| location | string |
✅ | Package name, file path, URL, or git repository |
| version | string |
optional | Semver version range (e.g., "^1.0.0") |
| integrity | string |
optional | Subresource Integrity hash (e.g., "sha384-...") |