-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathplugin-runtime.zod.ts
More file actions
361 lines (314 loc) · 11.1 KB
/
plugin-runtime.zod.ts
File metadata and controls
361 lines (314 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
import { z } from 'zod';
/**
* # Plugin Runtime Management Protocol
*
* 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)
* - VS Code Extension Host (activation events)
*
* This protocol enables:
* - Runtime load/unload of plugins without kernel restart
* - Plugin discovery from registries and local filesystem
* - Activation events (load plugin only when needed)
* - Safe unload with dependency awareness
*/
/**
* Dynamic Plugin Operation Type
* Operations that can be performed on plugins at runtime
*/
export const DynamicPluginOperationSchema = z.enum([
'load', // Load and initialize a plugin at runtime
'unload', // Gracefully unload a running plugin
'reload', // Unload then load (e.g., version upgrade)
'enable', // Enable a loaded but disabled plugin
'disable', // Disable a running plugin without unloading
]).describe('Runtime plugin operation type');
/**
* Plugin Source
* Where to resolve a plugin for dynamic loading
*/
export const PluginSourceSchema = z.object({
/**
* Source type
*/
type: z.enum([
'npm', // npm registry package
'local', // Local filesystem path
'url', // Remote URL (tarball or module)
'registry', // ObjectStack plugin registry
'git', // Git repository
]).describe('Plugin source type'),
/**
* Source location (package name, path, URL, or git repo)
*/
location: z.string().describe('Package name, file path, URL, or git repository'),
/**
* Version constraint (semver range)
*/
version: z.string().optional().describe('Semver version range (e.g., "^1.0.0")'),
/**
* Integrity hash for verification
*/
integrity: z.string().optional().describe('Subresource Integrity hash (e.g., "sha384-...")'),
}).describe('Plugin source location for dynamic resolution');
/**
* Activation Event
* Defines when a dynamically available plugin should be activated.
* Plugins remain dormant until an activation event fires.
*/
export const ActivationEventSchema = z.object({
/**
* Event type
*/
type: z.enum([
'onCommand', // Activate when a specific command is executed
'onRoute', // Activate when a URL route is matched
'onObject', // Activate when a specific object type is accessed
'onEvent', // Activate when a system event fires
'onService', // Activate when a service is requested
'onSchedule', // Activate on a cron schedule
'onStartup', // Activate immediately on kernel startup
]).describe('Trigger type for lazy activation'),
/**
* Pattern to match (command name, route glob, object name, event pattern, etc.)
*/
pattern: z.string().describe('Match pattern for the activation trigger'),
}).describe('Lazy activation trigger for a dynamic plugin');
/**
* Dynamic Load Request
* Request to load a plugin at runtime
*/
export const DynamicLoadRequestSchema = z.object({
/**
* Plugin identifier to load
*/
pluginId: z.string().describe('Unique plugin identifier'),
/**
* Plugin source
*/
source: PluginSourceSchema,
/**
* Activation events (if omitted, plugin activates immediately)
*/
activationEvents: z.array(ActivationEventSchema).optional()
.describe('Lazy activation triggers; if omitted plugin starts immediately'),
/**
* Configuration overrides for the plugin
*/
config: z.record(z.string(), z.unknown()).optional()
.describe('Runtime configuration overrides'),
/**
* Loading priority (lower = higher priority)
*/
priority: z.number().int().min(0).default(100)
.describe('Loading priority (lower is higher)'),
/**
* Whether to enable sandboxing for this dynamically loaded plugin
*/
sandbox: z.boolean().default(false)
.describe('Run in an isolated sandbox'),
/**
* Timeout for the load operation in milliseconds
*/
timeout: z.number().int().min(1000).default(60000)
.describe('Maximum time to complete loading in ms'),
}).describe('Request to dynamically load a plugin at runtime');
/**
* Dynamic Unload Request
* Request to unload a plugin at runtime
*/
export const DynamicUnloadRequestSchema = z.object({
/**
* Plugin identifier to unload
*/
pluginId: z.string().describe('Plugin to unload'),
/**
* Unload strategy
*/
strategy: z.enum([
'graceful', // Wait for in-flight requests, then unload
'forceful', // Unload immediately, cancel pending work
'drain', // Stop accepting new work, finish existing, then unload
]).default('graceful').describe('How to handle in-flight work during unload'),
/**
* Timeout for the unload operation in milliseconds
*/
timeout: z.number().int().min(1000).default(30000)
.describe('Maximum time to complete unloading in ms'),
/**
* Whether to remove cached artifacts
*/
cleanupCache: z.boolean().default(false)
.describe('Remove cached code and assets after unload'),
/**
* Action for dependents: plugins that depend on this one
*/
dependentAction: z.enum([
'cascade', // Also unload dependent plugins
'warn', // Warn about dependents but proceed
'block', // Block unload if dependents exist
]).default('block').describe('How to handle plugins that depend on this one'),
}).describe('Request to dynamically unload a plugin at runtime');
/**
* Dynamic Plugin Operation Result
* Result of a dynamic load/unload/reload operation
*/
export const DynamicPluginResultSchema = z.object({
/**
* Whether the operation succeeded
*/
success: z.boolean(),
/**
* The operation that was performed
*/
operation: DynamicPluginOperationSchema,
/**
* Plugin identifier
*/
pluginId: z.string(),
/**
* Operation duration in milliseconds
*/
durationMs: z.number().int().min(0).optional(),
/**
* Resulting plugin version (for load/reload)
*/
version: z.string().optional(),
/**
* Error details if operation failed
*/
error: z.object({
code: z.string().describe('Machine-readable error code'),
message: z.string().describe('Human-readable error message'),
details: z.record(z.string(), z.unknown()).optional(),
}).optional(),
/**
* Warnings (e.g., dependents affected)
*/
warnings: z.array(z.string()).optional(),
}).describe('Result of a dynamic plugin operation');
/**
* Plugin Discovery Source
* Defines where to discover available plugins at runtime
*/
export const PluginDiscoverySourceSchema = z.object({
/**
* Discovery source type
*/
type: z.enum([
'registry', // ObjectStack plugin registry API
'npm', // npm registry search
'directory', // Local filesystem directory scan
'url', // Remote manifest URL
]).describe('Discovery source type'),
/**
* Source endpoint or path
*/
endpoint: z.string().describe('Registry URL, directory path, or manifest URL'),
/**
* Polling interval in milliseconds (0 = manual only)
*/
pollInterval: z.number().int().min(0).default(0)
.describe('How often to re-scan for new plugins (0 = manual)'),
/**
* Filter criteria for discovered plugins
*/
filter: z.object({
/**
* Only discover plugins matching these tags
*/
tags: z.array(z.string()).optional(),
/**
* Only discover plugins from these vendors
*/
vendors: z.array(z.string()).optional(),
/**
* Minimum trust level
*/
minTrustLevel: z.enum(['verified', 'trusted', 'community', 'untrusted']).optional(),
}).optional(),
}).describe('Source for runtime plugin discovery');
/**
* Plugin Discovery Configuration
* Controls how the kernel discovers available plugins at runtime
*/
export const PluginDiscoveryConfigSchema = z.object({
/**
* Enable runtime plugin discovery
*/
enabled: z.boolean().default(false),
/**
* Discovery sources
*/
sources: z.array(PluginDiscoverySourceSchema).default([]),
/**
* Auto-load discovered plugins matching criteria
*/
autoLoad: z.boolean().default(false)
.describe('Automatically load newly discovered plugins'),
/**
* Require approval before loading discovered plugins
*/
requireApproval: z.boolean().default(true)
.describe('Require admin approval before loading discovered plugins'),
}).describe('Runtime plugin discovery configuration');
/**
* Dynamic Loading Configuration
* Top-level configuration for the dynamic plugin loading subsystem
*/
export const DynamicLoadingConfigSchema = z.object({
/**
* Enable dynamic loading/unloading at runtime
*/
enabled: z.boolean().default(false)
.describe('Enable runtime load/unload of plugins'),
/**
* Maximum number of dynamically loaded plugins
*/
maxDynamicPlugins: z.number().int().min(1).default(50)
.describe('Upper limit on runtime-loaded plugins'),
/**
* Plugin discovery configuration
*/
discovery: PluginDiscoveryConfigSchema.optional(),
/**
* Default sandbox policy for dynamically loaded plugins
*/
defaultSandbox: z.boolean().default(true)
.describe('Sandbox dynamically loaded plugins by default'),
/**
* Allowed plugin sources (empty = all allowed)
*/
allowedSources: z.array(z.enum(['npm', 'local', 'url', 'registry', 'git'])).optional()
.describe('Restrict which source types are permitted'),
/**
* Require integrity verification for remote plugins
*/
requireIntegrity: z.boolean().default(true)
.describe('Require integrity hash verification for remote sources'),
/**
* Global timeout for dynamic operations in milliseconds
*/
operationTimeout: z.number().int().min(1000).default(60000)
.describe('Default timeout for load/unload operations in ms'),
}).describe('Dynamic plugin loading subsystem configuration');
// Export types
export type DynamicPluginOperation = z.infer<typeof DynamicPluginOperationSchema>;
export type PluginSource = z.infer<typeof PluginSourceSchema>;
export type ActivationEvent = z.infer<typeof ActivationEventSchema>;
export type DynamicLoadRequest = z.infer<typeof DynamicLoadRequestSchema>;
export type DynamicUnloadRequest = z.infer<typeof DynamicUnloadRequestSchema>;
export type DynamicPluginResult = z.infer<typeof DynamicPluginResultSchema>;
export type PluginDiscoverySource = z.infer<typeof PluginDiscoverySourceSchema>;
export type PluginDiscoveryConfig = z.infer<typeof PluginDiscoveryConfigSchema>;
export type DynamicLoadingConfig = z.infer<typeof DynamicLoadingConfigSchema>;
// Export input types for schemas with defaults
export type DynamicLoadRequestInput = z.input<typeof DynamicLoadRequestSchema>;
export type DynamicUnloadRequestInput = z.input<typeof DynamicUnloadRequestSchema>;
export type DynamicLoadingConfigInput = z.input<typeof DynamicLoadingConfigSchema>;