@xnetjs/plugins 0.0.2
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/LICENSE +21 -0
- package/README.md +203 -0
- package/dist/index.d.ts +2047 -0
- package/dist/index.js +2640 -0
- package/dist/services/node.d.ts +583 -0
- package/dist/services/node.js +1055 -0
- package/package.json +56 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2047 @@
|
|
|
1
|
+
import * as _xnetjs_data from '@xnetjs/data';
|
|
2
|
+
import { SchemaIRI, NodeStore, NodeState } from '@xnetjs/data';
|
|
3
|
+
import { Extension } from '@tiptap/core';
|
|
4
|
+
import { ComponentType } from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Core types for the plugin system
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A resource that can be disposed/cleaned up
|
|
12
|
+
*/
|
|
13
|
+
interface Disposable$1 {
|
|
14
|
+
dispose(): void;
|
|
15
|
+
}
|
|
16
|
+
type Platform = 'web' | 'electron' | 'mobile';
|
|
17
|
+
interface PluginPermissions {
|
|
18
|
+
schemas?: {
|
|
19
|
+
read?: SchemaIRI[] | '*';
|
|
20
|
+
write?: SchemaIRI[] | '*';
|
|
21
|
+
create?: SchemaIRI[];
|
|
22
|
+
};
|
|
23
|
+
capabilities?: {
|
|
24
|
+
/** Network access: true for all, or array of allowed domains */
|
|
25
|
+
network?: boolean | string[];
|
|
26
|
+
/** Storage scope: 'local' (plugin only) or 'shared' (visible to other plugins) */
|
|
27
|
+
storage?: 'local' | 'shared';
|
|
28
|
+
/** Clipboard access */
|
|
29
|
+
clipboard?: boolean;
|
|
30
|
+
/** System notifications */
|
|
31
|
+
notifications?: boolean;
|
|
32
|
+
/** Spawn child processes (Electron only) */
|
|
33
|
+
processes?: boolean;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
interface PlatformCapabilities {
|
|
37
|
+
platform: Platform;
|
|
38
|
+
features: {
|
|
39
|
+
views: boolean;
|
|
40
|
+
editorExtensions: boolean;
|
|
41
|
+
slashCommands: boolean;
|
|
42
|
+
services: boolean;
|
|
43
|
+
processes: boolean;
|
|
44
|
+
localAPI: boolean;
|
|
45
|
+
filesystem: boolean;
|
|
46
|
+
clipboard: boolean;
|
|
47
|
+
notifications: boolean;
|
|
48
|
+
p2pSync: boolean;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
declare function getPlatformCapabilities(platform: Platform): PlatformCapabilities;
|
|
52
|
+
interface ExtensionStorage {
|
|
53
|
+
get<T>(key: string): T | undefined;
|
|
54
|
+
set<T>(key: string, value: T): void;
|
|
55
|
+
delete(key: string): void;
|
|
56
|
+
keys(): string[];
|
|
57
|
+
}
|
|
58
|
+
declare function createExtensionStorage(): ExtensionStorage;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Contribution types and registry for plugin-provided extensions
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
interface ViewContribution {
|
|
65
|
+
/** Unique view type identifier */
|
|
66
|
+
type: string;
|
|
67
|
+
/** Display name */
|
|
68
|
+
name: string;
|
|
69
|
+
/** Icon (Lucide icon name or component) */
|
|
70
|
+
icon?: string | ComponentType;
|
|
71
|
+
/** React component for rendering the view */
|
|
72
|
+
component: ComponentType<ViewProps>;
|
|
73
|
+
/** Schema IRIs this view supports (empty = all) */
|
|
74
|
+
supportedSchemas?: string[];
|
|
75
|
+
}
|
|
76
|
+
interface ViewProps {
|
|
77
|
+
nodeId: string;
|
|
78
|
+
schemaId: string;
|
|
79
|
+
}
|
|
80
|
+
interface CommandContribution {
|
|
81
|
+
/** Unique command ID */
|
|
82
|
+
id: string;
|
|
83
|
+
/** Display name */
|
|
84
|
+
name: string;
|
|
85
|
+
/** Description for command palette */
|
|
86
|
+
description?: string;
|
|
87
|
+
/** Keyboard shortcut (e.g., 'Mod-Shift-P') */
|
|
88
|
+
keybinding?: string;
|
|
89
|
+
/** Search keywords for fuzzy matching */
|
|
90
|
+
keywords?: string[];
|
|
91
|
+
/** Icon (Lucide icon name) */
|
|
92
|
+
icon?: string;
|
|
93
|
+
/** Command handler */
|
|
94
|
+
execute: () => void | Promise<void>;
|
|
95
|
+
/** Whether command is currently enabled */
|
|
96
|
+
when?: () => boolean;
|
|
97
|
+
}
|
|
98
|
+
interface SlashCommandContribution {
|
|
99
|
+
/** Unique command ID */
|
|
100
|
+
id: string;
|
|
101
|
+
/** Display name in slash menu */
|
|
102
|
+
name: string;
|
|
103
|
+
/** Description shown in menu */
|
|
104
|
+
description?: string;
|
|
105
|
+
/** Search aliases */
|
|
106
|
+
aliases?: string[];
|
|
107
|
+
/** Icon (Lucide icon name) */
|
|
108
|
+
icon?: string;
|
|
109
|
+
/** Insert content or execute action */
|
|
110
|
+
execute: (props: SlashCommandContext) => void;
|
|
111
|
+
}
|
|
112
|
+
interface SlashCommandContext {
|
|
113
|
+
editor: unknown;
|
|
114
|
+
range: {
|
|
115
|
+
from: number;
|
|
116
|
+
to: number;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Toolbar button contribution for the editor
|
|
121
|
+
*/
|
|
122
|
+
interface ToolbarContribution {
|
|
123
|
+
/** Icon name (Lucide) or React component */
|
|
124
|
+
icon: string | ComponentType;
|
|
125
|
+
/** Tooltip/title text */
|
|
126
|
+
title: string;
|
|
127
|
+
/** Toolbar section: format, insert, block, or custom */
|
|
128
|
+
group?: 'format' | 'insert' | 'block' | 'custom';
|
|
129
|
+
/** Check if button should appear active */
|
|
130
|
+
isActive?: (editor: unknown) => boolean;
|
|
131
|
+
/** Button click handler */
|
|
132
|
+
action: (editor: unknown) => void;
|
|
133
|
+
/** Keyboard shortcut display (e.g., 'Mod-Shift-H') */
|
|
134
|
+
shortcut?: string;
|
|
135
|
+
}
|
|
136
|
+
interface EditorContribution {
|
|
137
|
+
/** Unique extension ID */
|
|
138
|
+
id: string;
|
|
139
|
+
/** TipTap extension (Extension, Node, or Mark) */
|
|
140
|
+
extension: Extension;
|
|
141
|
+
/** Optional toolbar button for this extension */
|
|
142
|
+
toolbar?: ToolbarContribution;
|
|
143
|
+
/** Priority for extension ordering (lower = earlier, default: 100) */
|
|
144
|
+
priority?: number;
|
|
145
|
+
}
|
|
146
|
+
interface SidebarContribution {
|
|
147
|
+
/** Unique item ID */
|
|
148
|
+
id: string;
|
|
149
|
+
/** Display name */
|
|
150
|
+
name: string;
|
|
151
|
+
/** Icon (Lucide icon name or React component) */
|
|
152
|
+
icon: string | ComponentType;
|
|
153
|
+
/** Position in sidebar: top, bottom, or within a section */
|
|
154
|
+
position?: 'top' | 'bottom' | 'section';
|
|
155
|
+
/** Section name for 'section' position */
|
|
156
|
+
section?: string;
|
|
157
|
+
/** Priority within position (lower = higher) */
|
|
158
|
+
priority?: number;
|
|
159
|
+
/** Dynamic badge (e.g., unread count) */
|
|
160
|
+
badge?: () => string | number | null;
|
|
161
|
+
/** Click handler or route path */
|
|
162
|
+
action: (() => void) | string;
|
|
163
|
+
/** Optional panel component to render */
|
|
164
|
+
panel?: ComponentType;
|
|
165
|
+
}
|
|
166
|
+
interface PropertyHandlerContribution {
|
|
167
|
+
/** Property type this handler manages */
|
|
168
|
+
type: string;
|
|
169
|
+
/** Handler implementation */
|
|
170
|
+
handler: PropertyHandler;
|
|
171
|
+
}
|
|
172
|
+
interface PropertyHandler {
|
|
173
|
+
/** Render the property cell in table view */
|
|
174
|
+
Cell: ComponentType<PropertyCellProps>;
|
|
175
|
+
/** Render the property editor */
|
|
176
|
+
Editor: ComponentType<PropertyEditorProps>;
|
|
177
|
+
/** Parse string input to property value */
|
|
178
|
+
parse?: (input: string) => unknown;
|
|
179
|
+
/** Format value for display */
|
|
180
|
+
format?: (value: unknown) => string;
|
|
181
|
+
/** Validate value */
|
|
182
|
+
validate?: (value: unknown) => boolean;
|
|
183
|
+
}
|
|
184
|
+
interface PropertyCellProps {
|
|
185
|
+
value: unknown;
|
|
186
|
+
config?: Record<string, unknown>;
|
|
187
|
+
}
|
|
188
|
+
interface PropertyEditorProps {
|
|
189
|
+
value: unknown;
|
|
190
|
+
onChange: (value: unknown) => void;
|
|
191
|
+
config?: Record<string, unknown>;
|
|
192
|
+
}
|
|
193
|
+
interface BlockContribution {
|
|
194
|
+
/** Block type identifier */
|
|
195
|
+
type: string;
|
|
196
|
+
/** Display name */
|
|
197
|
+
name: string;
|
|
198
|
+
/** React component */
|
|
199
|
+
component: ComponentType<BlockProps>;
|
|
200
|
+
}
|
|
201
|
+
interface BlockProps {
|
|
202
|
+
node: unknown;
|
|
203
|
+
updateAttributes: (attrs: Record<string, unknown>) => void;
|
|
204
|
+
}
|
|
205
|
+
interface SettingContribution {
|
|
206
|
+
/** Setting section ID */
|
|
207
|
+
id: string;
|
|
208
|
+
/** Section title */
|
|
209
|
+
title: string;
|
|
210
|
+
/** Description for the settings panel */
|
|
211
|
+
description?: string;
|
|
212
|
+
/** Icon (Lucide icon name) */
|
|
213
|
+
icon?: string;
|
|
214
|
+
/** Which settings section this belongs to */
|
|
215
|
+
section?: 'general' | 'appearance' | 'plugins' | 'data' | 'network';
|
|
216
|
+
/** Settings panel component */
|
|
217
|
+
component: ComponentType<SettingsPanelProps>;
|
|
218
|
+
}
|
|
219
|
+
interface SettingsPanelProps {
|
|
220
|
+
/** Plugin's key-value storage */
|
|
221
|
+
storage: {
|
|
222
|
+
get: <T>(key: string) => T | undefined;
|
|
223
|
+
set: <T>(key: string, value: T) => void;
|
|
224
|
+
keys: () => string[];
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
interface SchemaContribution {
|
|
228
|
+
/** The schema definition */
|
|
229
|
+
schema: unknown;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* A registry for typed contributions with change notifications
|
|
233
|
+
*/
|
|
234
|
+
declare class TypedRegistry<T extends {
|
|
235
|
+
id?: string;
|
|
236
|
+
type?: string;
|
|
237
|
+
}> {
|
|
238
|
+
private items;
|
|
239
|
+
private listeners;
|
|
240
|
+
register(item: T): Disposable$1;
|
|
241
|
+
unregister(key: string): boolean;
|
|
242
|
+
get(key: string): T | undefined;
|
|
243
|
+
getAll(): T[];
|
|
244
|
+
has(key: string): boolean;
|
|
245
|
+
get size(): number;
|
|
246
|
+
onChange(listener: () => void): () => void;
|
|
247
|
+
private notify;
|
|
248
|
+
clear(): void;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Central registry for all plugin contributions
|
|
252
|
+
*/
|
|
253
|
+
declare class ContributionRegistry {
|
|
254
|
+
readonly views: TypedRegistry<ViewContribution>;
|
|
255
|
+
readonly commands: TypedRegistry<CommandContribution>;
|
|
256
|
+
readonly slashCommands: TypedRegistry<SlashCommandContribution>;
|
|
257
|
+
readonly sidebar: TypedRegistry<SidebarContribution>;
|
|
258
|
+
readonly editor: TypedRegistry<EditorContribution>;
|
|
259
|
+
readonly propertyHandlers: TypedRegistry<PropertyHandlerContribution>;
|
|
260
|
+
readonly blocks: TypedRegistry<BlockContribution>;
|
|
261
|
+
readonly settings: TypedRegistry<SettingContribution>;
|
|
262
|
+
/**
|
|
263
|
+
* Clear all registries (for cleanup/testing)
|
|
264
|
+
*/
|
|
265
|
+
clear(): void;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* NodeStore middleware chain for pre/post change hooks
|
|
270
|
+
*/
|
|
271
|
+
|
|
272
|
+
interface PendingChange {
|
|
273
|
+
type: 'create' | 'update' | 'delete' | 'restore';
|
|
274
|
+
nodeId: string;
|
|
275
|
+
schemaIRI?: string;
|
|
276
|
+
payload?: Record<string, unknown>;
|
|
277
|
+
meta?: Record<string, unknown>;
|
|
278
|
+
}
|
|
279
|
+
interface NodeChangeEvent {
|
|
280
|
+
change: PendingChange;
|
|
281
|
+
node: unknown;
|
|
282
|
+
isRemote: boolean;
|
|
283
|
+
}
|
|
284
|
+
interface NodeStoreMiddleware {
|
|
285
|
+
/** Unique middleware ID */
|
|
286
|
+
id: string;
|
|
287
|
+
/** Priority (lower = runs first, default 100) */
|
|
288
|
+
priority?: number;
|
|
289
|
+
/**
|
|
290
|
+
* Called before a change is applied.
|
|
291
|
+
* Can modify the change, reject by throwing, or pass through.
|
|
292
|
+
*/
|
|
293
|
+
beforeChange?(change: PendingChange, next: () => Promise<unknown>): Promise<unknown>;
|
|
294
|
+
/**
|
|
295
|
+
* Called after a change is applied (observe only, cannot modify).
|
|
296
|
+
*/
|
|
297
|
+
afterChange?(event: NodeChangeEvent): void;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Manages a chain of middleware for NodeStore operations
|
|
301
|
+
*/
|
|
302
|
+
declare class MiddlewareChain {
|
|
303
|
+
private middlewares;
|
|
304
|
+
/**
|
|
305
|
+
* Add a middleware to the chain
|
|
306
|
+
*/
|
|
307
|
+
add(middleware: NodeStoreMiddleware): Disposable$1;
|
|
308
|
+
/**
|
|
309
|
+
* Remove a middleware by ID
|
|
310
|
+
*/
|
|
311
|
+
remove(id: string): boolean;
|
|
312
|
+
/**
|
|
313
|
+
* Get all registered middlewares
|
|
314
|
+
*/
|
|
315
|
+
getAll(): NodeStoreMiddleware[];
|
|
316
|
+
/**
|
|
317
|
+
* Execute beforeChange hooks in priority order
|
|
318
|
+
*/
|
|
319
|
+
executeBefore(change: PendingChange, apply: () => Promise<unknown>): Promise<unknown>;
|
|
320
|
+
/**
|
|
321
|
+
* Execute afterChange hooks (errors are caught and logged)
|
|
322
|
+
*/
|
|
323
|
+
executeAfter(event: NodeChangeEvent): void;
|
|
324
|
+
/**
|
|
325
|
+
* Clear all middlewares
|
|
326
|
+
*/
|
|
327
|
+
clear(): void;
|
|
328
|
+
/**
|
|
329
|
+
* Get the number of registered middlewares
|
|
330
|
+
*/
|
|
331
|
+
get size(): number;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* ExtensionContext - The API surface available to plugins
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
interface PluginNodeChangeEvent {
|
|
339
|
+
type: 'create' | 'update' | 'delete';
|
|
340
|
+
nodeId: string;
|
|
341
|
+
node?: NodeState;
|
|
342
|
+
changes?: Record<string, {
|
|
343
|
+
old: unknown;
|
|
344
|
+
new: unknown;
|
|
345
|
+
}>;
|
|
346
|
+
}
|
|
347
|
+
type PluginNodeChangeListener = (event: PluginNodeChangeEvent) => void;
|
|
348
|
+
interface QueryFilter {
|
|
349
|
+
where?: Record<string, unknown>;
|
|
350
|
+
limit?: number;
|
|
351
|
+
offset?: number;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Context provided to plugins during activation.
|
|
355
|
+
* All registration methods return Disposables that are auto-disposed on deactivation.
|
|
356
|
+
*/
|
|
357
|
+
interface ExtensionContext {
|
|
358
|
+
/** Plugin ID */
|
|
359
|
+
readonly pluginId: string;
|
|
360
|
+
/** Current platform */
|
|
361
|
+
readonly platform: Platform;
|
|
362
|
+
/** NodeStore instance */
|
|
363
|
+
readonly store: NodeStore;
|
|
364
|
+
/** Query nodes by schema (async) */
|
|
365
|
+
query(schema: SchemaIRI, filter?: QueryFilter): Promise<NodeState[]>;
|
|
366
|
+
/** Subscribe to node changes */
|
|
367
|
+
subscribe(schema: SchemaIRI | null, callback: PluginNodeChangeListener): Disposable$1;
|
|
368
|
+
/** Register a custom schema */
|
|
369
|
+
registerSchema(schema: unknown): Disposable$1;
|
|
370
|
+
/** Register a custom view type */
|
|
371
|
+
registerView(view: ViewContribution): Disposable$1;
|
|
372
|
+
/** Register a property type handler */
|
|
373
|
+
registerPropertyHandler(type: string, handler: PropertyHandlerContribution['handler']): Disposable$1;
|
|
374
|
+
/** Register a command */
|
|
375
|
+
registerCommand(command: CommandContribution): Disposable$1;
|
|
376
|
+
/** Register a sidebar item */
|
|
377
|
+
registerSidebarItem(item: SidebarContribution): Disposable$1;
|
|
378
|
+
/** Register a TipTap editor extension */
|
|
379
|
+
registerEditorExtension(ext: EditorContribution): Disposable$1;
|
|
380
|
+
/** Register a slash command */
|
|
381
|
+
registerSlashCommand(cmd: SlashCommandContribution): Disposable$1;
|
|
382
|
+
/** Register a custom block type */
|
|
383
|
+
registerBlockType(block: BlockContribution): Disposable$1;
|
|
384
|
+
/** Add middleware to NodeStore */
|
|
385
|
+
addMiddleware(middleware: NodeStoreMiddleware): Disposable$1;
|
|
386
|
+
/** Plugin-private storage */
|
|
387
|
+
readonly storage: ExtensionStorage;
|
|
388
|
+
/** Platform capabilities */
|
|
389
|
+
readonly capabilities: PlatformCapabilities;
|
|
390
|
+
/** Auto-cleanup list - disposed when plugin deactivates */
|
|
391
|
+
readonly subscriptions: Disposable$1[];
|
|
392
|
+
}
|
|
393
|
+
interface CreateContextOptions {
|
|
394
|
+
pluginId: string;
|
|
395
|
+
store: NodeStore;
|
|
396
|
+
contributions: ContributionRegistry;
|
|
397
|
+
platform: Platform;
|
|
398
|
+
middlewareChain?: {
|
|
399
|
+
add(middleware: NodeStoreMiddleware): Disposable$1;
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Create an ExtensionContext for a plugin
|
|
404
|
+
*/
|
|
405
|
+
declare function createExtensionContext(options: CreateContextOptions): ExtensionContext;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Plugin manifest types and validation
|
|
409
|
+
*/
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Plugin manifest - defines what a plugin provides and how it integrates
|
|
413
|
+
*/
|
|
414
|
+
interface XNetExtension {
|
|
415
|
+
/** Unique plugin ID (reverse-domain format: 'com.example.my-plugin') */
|
|
416
|
+
id: string;
|
|
417
|
+
/** Human-readable plugin name */
|
|
418
|
+
name: string;
|
|
419
|
+
/** Semantic version */
|
|
420
|
+
version: string;
|
|
421
|
+
/** Plugin description */
|
|
422
|
+
description?: string;
|
|
423
|
+
/** Author name or organization */
|
|
424
|
+
author?: string;
|
|
425
|
+
/** Minimum compatible xNet version */
|
|
426
|
+
xnetVersion?: string;
|
|
427
|
+
/** Platforms this plugin supports (default: all) */
|
|
428
|
+
platforms?: Platform[];
|
|
429
|
+
/** Permission declarations */
|
|
430
|
+
permissions?: PluginPermissions;
|
|
431
|
+
/** Static contributions declared in manifest */
|
|
432
|
+
contributes?: PluginContributions;
|
|
433
|
+
/** Called when plugin is activated */
|
|
434
|
+
activate?(ctx: ExtensionContext): void | Promise<void>;
|
|
435
|
+
/** Called when plugin is deactivated */
|
|
436
|
+
deactivate?(): void | Promise<void>;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Contributions a plugin can declare
|
|
440
|
+
*/
|
|
441
|
+
interface PluginContributions {
|
|
442
|
+
schemas?: SchemaContribution[];
|
|
443
|
+
views?: ViewContribution[];
|
|
444
|
+
editorExtensions?: EditorContribution[];
|
|
445
|
+
propertyHandlers?: PropertyHandlerContribution[];
|
|
446
|
+
blocks?: BlockContribution[];
|
|
447
|
+
commands?: CommandContribution[];
|
|
448
|
+
settings?: SettingContribution[];
|
|
449
|
+
sidebarItems?: SidebarContribution[];
|
|
450
|
+
slashCommands?: SlashCommandContribution[];
|
|
451
|
+
}
|
|
452
|
+
declare class PluginValidationError extends Error {
|
|
453
|
+
readonly issues: string[];
|
|
454
|
+
constructor(message: string, issues: string[]);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Validate a plugin manifest
|
|
458
|
+
* @throws PluginValidationError if validation fails
|
|
459
|
+
*/
|
|
460
|
+
declare function validateManifest(manifest: unknown): XNetExtension;
|
|
461
|
+
/**
|
|
462
|
+
* Define a plugin extension with type checking
|
|
463
|
+
*/
|
|
464
|
+
declare function defineExtension(manifest: XNetExtension): XNetExtension;
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Keyboard Shortcut Manager
|
|
468
|
+
*
|
|
469
|
+
* Handles registration and execution of keyboard shortcuts from plugins.
|
|
470
|
+
*/
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Manages keyboard shortcuts for commands.
|
|
474
|
+
*
|
|
475
|
+
* Shortcuts are specified in the format: "Mod-Shift-K" where:
|
|
476
|
+
* - Mod = Cmd on Mac, Ctrl elsewhere
|
|
477
|
+
* - Shift, Alt, Ctrl, Meta are modifier keys
|
|
478
|
+
* - The last part is the key name (e.g., K, Enter, Escape)
|
|
479
|
+
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```typescript
|
|
482
|
+
* const manager = new ShortcutManager()
|
|
483
|
+
*
|
|
484
|
+
* manager.register({
|
|
485
|
+
* id: 'my-command',
|
|
486
|
+
* name: 'My Command',
|
|
487
|
+
* keybinding: 'Mod-Shift-P',
|
|
488
|
+
* execute: () => console.log('Executed!')
|
|
489
|
+
* })
|
|
490
|
+
*
|
|
491
|
+
* // Attach to window
|
|
492
|
+
* window.addEventListener('keydown', (e) => manager.handleKeyDown(e))
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
declare class ShortcutManager {
|
|
496
|
+
private shortcuts;
|
|
497
|
+
private enabled;
|
|
498
|
+
/**
|
|
499
|
+
* Register a command with a keyboard shortcut.
|
|
500
|
+
*
|
|
501
|
+
* @param command - Command with keybinding
|
|
502
|
+
* @returns Disposable to unregister the shortcut
|
|
503
|
+
*/
|
|
504
|
+
register(command: CommandContribution): Disposable$1;
|
|
505
|
+
/**
|
|
506
|
+
* Unregister a command by ID.
|
|
507
|
+
*/
|
|
508
|
+
unregister(commandId: string): boolean;
|
|
509
|
+
/**
|
|
510
|
+
* Handle a keyboard event.
|
|
511
|
+
*
|
|
512
|
+
* @param event - Keyboard event
|
|
513
|
+
* @returns True if a shortcut was triggered
|
|
514
|
+
*/
|
|
515
|
+
handleKeyDown(event: KeyboardEvent): boolean;
|
|
516
|
+
/**
|
|
517
|
+
* Enable or disable shortcut handling.
|
|
518
|
+
*/
|
|
519
|
+
setEnabled(enabled: boolean): void;
|
|
520
|
+
/**
|
|
521
|
+
* Check if shortcuts are enabled.
|
|
522
|
+
*/
|
|
523
|
+
isEnabled(): boolean;
|
|
524
|
+
/**
|
|
525
|
+
* Get all registered shortcuts.
|
|
526
|
+
*/
|
|
527
|
+
getAll(): CommandContribution[];
|
|
528
|
+
/**
|
|
529
|
+
* Get the shortcut for a command ID.
|
|
530
|
+
*/
|
|
531
|
+
getShortcut(commandId: string): string | undefined;
|
|
532
|
+
/**
|
|
533
|
+
* Format a keybinding for display (using platform-specific symbols).
|
|
534
|
+
*/
|
|
535
|
+
formatForDisplay(keybinding: string): string;
|
|
536
|
+
/**
|
|
537
|
+
* Normalize a keybinding string for consistent lookup.
|
|
538
|
+
*/
|
|
539
|
+
private normalize;
|
|
540
|
+
/**
|
|
541
|
+
* Convert normalized form back to display form.
|
|
542
|
+
*/
|
|
543
|
+
private denormalize;
|
|
544
|
+
/**
|
|
545
|
+
* Convert a keyboard event to a normalized string.
|
|
546
|
+
*/
|
|
547
|
+
private eventToString;
|
|
548
|
+
/**
|
|
549
|
+
* Clear all registered shortcuts.
|
|
550
|
+
*/
|
|
551
|
+
clear(): void;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Get or create the global ShortcutManager instance.
|
|
555
|
+
*/
|
|
556
|
+
declare function getShortcutManager(): ShortcutManager;
|
|
557
|
+
/**
|
|
558
|
+
* Install the global shortcut manager on the window.
|
|
559
|
+
* Call this once at app startup.
|
|
560
|
+
*/
|
|
561
|
+
declare function installShortcutHandler(): () => void;
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* PluginRegistry - Central coordinator for plugin lifecycle
|
|
565
|
+
*/
|
|
566
|
+
|
|
567
|
+
type PluginStatus = 'installed' | 'active' | 'disabled' | 'error';
|
|
568
|
+
interface RegisteredPlugin {
|
|
569
|
+
manifest: XNetExtension;
|
|
570
|
+
status: PluginStatus;
|
|
571
|
+
context?: ExtensionContext;
|
|
572
|
+
error?: Error;
|
|
573
|
+
}
|
|
574
|
+
declare class PluginError extends Error {
|
|
575
|
+
constructor(message: string);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Manages plugin lifecycle: install, activate, deactivate, uninstall
|
|
579
|
+
*/
|
|
580
|
+
declare class PluginRegistry {
|
|
581
|
+
private store;
|
|
582
|
+
private platform;
|
|
583
|
+
private plugins;
|
|
584
|
+
private contributions;
|
|
585
|
+
private middleware;
|
|
586
|
+
private listeners;
|
|
587
|
+
constructor(store: NodeStore, platform: Platform);
|
|
588
|
+
/**
|
|
589
|
+
* Install and activate a plugin
|
|
590
|
+
*/
|
|
591
|
+
install(manifest: XNetExtension): Promise<void>;
|
|
592
|
+
/**
|
|
593
|
+
* Activate an installed plugin
|
|
594
|
+
*/
|
|
595
|
+
activate(pluginId: string): Promise<void>;
|
|
596
|
+
/**
|
|
597
|
+
* Deactivate an active plugin
|
|
598
|
+
*/
|
|
599
|
+
deactivate(pluginId: string): Promise<void>;
|
|
600
|
+
/**
|
|
601
|
+
* Uninstall a plugin (deactivates first if active)
|
|
602
|
+
*/
|
|
603
|
+
uninstall(pluginId: string): Promise<void>;
|
|
604
|
+
/**
|
|
605
|
+
* Get all registered plugins
|
|
606
|
+
*/
|
|
607
|
+
getAll(): RegisteredPlugin[];
|
|
608
|
+
/**
|
|
609
|
+
* Get a specific plugin
|
|
610
|
+
*/
|
|
611
|
+
get(pluginId: string): RegisteredPlugin | undefined;
|
|
612
|
+
/**
|
|
613
|
+
* Check if a plugin is installed
|
|
614
|
+
*/
|
|
615
|
+
has(pluginId: string): boolean;
|
|
616
|
+
/**
|
|
617
|
+
* Rehydrate a plugin loaded from store with a live manifest.
|
|
618
|
+
*
|
|
619
|
+
* When plugins are persisted via `install()`, the manifest is serialized
|
|
620
|
+
* with `JSON.stringify()`, which strips non-serializable values like
|
|
621
|
+
* TipTap Extension instances, React components, and functions. When
|
|
622
|
+
* `loadFromStore()` deserializes with `JSON.parse()`, these values are
|
|
623
|
+
* lost and the plugin's contributions (e.g., editor extensions) are broken.
|
|
624
|
+
*
|
|
625
|
+
* For bundled plugins, the `BundledPluginInstaller` has access to the live
|
|
626
|
+
* manifest objects. This method replaces the deserialized manifest with the
|
|
627
|
+
* live one and re-registers its static contributions so that extension
|
|
628
|
+
* objects with methods (like `renderHTML`, `addNodeView`) are properly
|
|
629
|
+
* available to the editor.
|
|
630
|
+
*/
|
|
631
|
+
rehydrate(liveManifest: XNetExtension): Promise<void>;
|
|
632
|
+
/**
|
|
633
|
+
* Get contribution registry
|
|
634
|
+
*/
|
|
635
|
+
getContributions(): ContributionRegistry;
|
|
636
|
+
/**
|
|
637
|
+
* Get middleware chain
|
|
638
|
+
*/
|
|
639
|
+
getMiddleware(): MiddlewareChain;
|
|
640
|
+
/**
|
|
641
|
+
* Subscribe to plugin changes
|
|
642
|
+
*/
|
|
643
|
+
onChange(listener: () => void): Disposable$1;
|
|
644
|
+
private notify;
|
|
645
|
+
private registerStaticContributions;
|
|
646
|
+
/**
|
|
647
|
+
* Load and activate plugins from stored Nodes
|
|
648
|
+
*/
|
|
649
|
+
loadFromStore(): Promise<void>;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Plugin schema - stores plugin metadata as Nodes for P2P sync
|
|
654
|
+
*/
|
|
655
|
+
declare const PluginSchema: _xnetjs_data.DefinedSchema<{
|
|
656
|
+
/** Unique plugin identifier (reverse-domain format) */
|
|
657
|
+
pluginId: _xnetjs_data.PropertyBuilder<string>;
|
|
658
|
+
/** Human-readable name */
|
|
659
|
+
name: _xnetjs_data.PropertyBuilder<string>;
|
|
660
|
+
/** Semantic version */
|
|
661
|
+
version: _xnetjs_data.PropertyBuilder<string>;
|
|
662
|
+
/** Plugin description */
|
|
663
|
+
description: _xnetjs_data.PropertyBuilder<string>;
|
|
664
|
+
/** Author name or organization */
|
|
665
|
+
author: _xnetjs_data.PropertyBuilder<string>;
|
|
666
|
+
/** Whether plugin is enabled */
|
|
667
|
+
enabled: _xnetjs_data.PropertyBuilder<boolean>;
|
|
668
|
+
/** JSON-serialized manifest */
|
|
669
|
+
manifest: _xnetjs_data.PropertyBuilder<string>;
|
|
670
|
+
/** Plugin source (URL or inline bundle) */
|
|
671
|
+
source: _xnetjs_data.PropertyBuilder<string>;
|
|
672
|
+
/** JSON-serialized permissions */
|
|
673
|
+
permissions: _xnetjs_data.PropertyBuilder<string>;
|
|
674
|
+
/** Installation timestamp */
|
|
675
|
+
installedAt: _xnetjs_data.PropertyBuilder<number>;
|
|
676
|
+
}>;
|
|
677
|
+
type PluginNode = {
|
|
678
|
+
id: string;
|
|
679
|
+
schemaId: string;
|
|
680
|
+
pluginId: string;
|
|
681
|
+
name: string;
|
|
682
|
+
version: string;
|
|
683
|
+
description?: string;
|
|
684
|
+
author?: string;
|
|
685
|
+
enabled: boolean;
|
|
686
|
+
manifest: string;
|
|
687
|
+
source?: string;
|
|
688
|
+
permissions?: string;
|
|
689
|
+
installedAt?: number;
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Script schema - stores user-created scripts as Nodes for P2P sync
|
|
694
|
+
*
|
|
695
|
+
* Scripts are the simplest plugin type (Layer 1) - single functions that
|
|
696
|
+
* transform or react to data. They run in a sandboxed environment with
|
|
697
|
+
* no network, DOM, or import access.
|
|
698
|
+
*/
|
|
699
|
+
/**
|
|
700
|
+
* Script trigger types:
|
|
701
|
+
* - manual: Run via UI button or command
|
|
702
|
+
* - onChange: Run when a node matching inputSchema changes
|
|
703
|
+
* - onView: Run when computing a column value (lazy evaluation)
|
|
704
|
+
* - scheduled: Run on a cron schedule (future)
|
|
705
|
+
*/
|
|
706
|
+
type ScriptTriggerType = 'manual' | 'onChange' | 'onView' | 'scheduled';
|
|
707
|
+
/**
|
|
708
|
+
* Script output types:
|
|
709
|
+
* - value: Returns a computed value (for computed columns)
|
|
710
|
+
* - mutation: Returns partial node to merge into target
|
|
711
|
+
* - decoration: Returns visual decorations/tags
|
|
712
|
+
* - void: Side-effect only (logging, etc.)
|
|
713
|
+
*/
|
|
714
|
+
type ScriptOutputType = 'value' | 'mutation' | 'decoration' | 'void';
|
|
715
|
+
/**
|
|
716
|
+
* Script schema for user-created scripts.
|
|
717
|
+
*
|
|
718
|
+
* Scripts are stored as Nodes and sync via P2P like any other data.
|
|
719
|
+
* They can be created manually, via AI generation, or imported.
|
|
720
|
+
*
|
|
721
|
+
* @example
|
|
722
|
+
* ```typescript
|
|
723
|
+
* // Create a tax calculator script
|
|
724
|
+
* await store.create(ScriptSchema, {
|
|
725
|
+
* name: 'Calculate Tax',
|
|
726
|
+
* description: 'Adds 8% tax to subtotal',
|
|
727
|
+
* code: '(node) => node.subtotal * 0.08',
|
|
728
|
+
* triggerType: 'onView',
|
|
729
|
+
* outputType: 'value',
|
|
730
|
+
* inputSchema: 'xnet://myapp/Invoice',
|
|
731
|
+
* enabled: true
|
|
732
|
+
* })
|
|
733
|
+
* ```
|
|
734
|
+
*/
|
|
735
|
+
declare const ScriptSchema: _xnetjs_data.DefinedSchema<{
|
|
736
|
+
/** Human-readable script name */
|
|
737
|
+
name: _xnetjs_data.PropertyBuilder<string>;
|
|
738
|
+
/** Description of what the script does */
|
|
739
|
+
description: _xnetjs_data.PropertyBuilder<string>;
|
|
740
|
+
/** The script code (JavaScript expression or arrow function) */
|
|
741
|
+
code: _xnetjs_data.PropertyBuilder<string>;
|
|
742
|
+
/** When the script should execute */
|
|
743
|
+
triggerType: _xnetjs_data.PropertyBuilder<"manual" | "onChange" | "onView" | "scheduled">;
|
|
744
|
+
/** For onChange trigger: which property to watch (empty = any) */
|
|
745
|
+
triggerProperty: _xnetjs_data.PropertyBuilder<string>;
|
|
746
|
+
/** For scheduled trigger: cron expression */
|
|
747
|
+
triggerCron: _xnetjs_data.PropertyBuilder<string>;
|
|
748
|
+
/** Schema IRI this script operates on (e.g., 'xnet://myapp/Task') */
|
|
749
|
+
inputSchema: _xnetjs_data.PropertyBuilder<string>;
|
|
750
|
+
/** What the script returns */
|
|
751
|
+
outputType: _xnetjs_data.PropertyBuilder<"value" | "mutation" | "decoration" | "void">;
|
|
752
|
+
/** Whether the script is active */
|
|
753
|
+
enabled: _xnetjs_data.PropertyBuilder<boolean>;
|
|
754
|
+
/** Last execution error message (null if last run succeeded) */
|
|
755
|
+
lastError: _xnetjs_data.PropertyBuilder<string>;
|
|
756
|
+
/** Timestamp of last execution */
|
|
757
|
+
lastRun: _xnetjs_data.PropertyBuilder<number>;
|
|
758
|
+
}>;
|
|
759
|
+
/**
|
|
760
|
+
* Type-safe representation of a Script node
|
|
761
|
+
*/
|
|
762
|
+
interface ScriptNode {
|
|
763
|
+
id: string;
|
|
764
|
+
schemaId: string;
|
|
765
|
+
name: string;
|
|
766
|
+
description?: string;
|
|
767
|
+
code: string;
|
|
768
|
+
triggerType: ScriptTriggerType;
|
|
769
|
+
triggerProperty?: string;
|
|
770
|
+
triggerCron?: string;
|
|
771
|
+
inputSchema?: string;
|
|
772
|
+
outputType: ScriptOutputType;
|
|
773
|
+
enabled: boolean;
|
|
774
|
+
lastError?: string;
|
|
775
|
+
lastRun?: number;
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Type guard to check if a node is a Script
|
|
779
|
+
*/
|
|
780
|
+
declare function isScriptNode(node: unknown): node is ScriptNode;
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* ScriptContext - Safe API surface for user scripts
|
|
784
|
+
*
|
|
785
|
+
* Provides a frozen, read-only context with utility functions.
|
|
786
|
+
* Scripts cannot modify nodes directly - they return values/mutations
|
|
787
|
+
* that the runtime applies.
|
|
788
|
+
*/
|
|
789
|
+
/**
|
|
790
|
+
* A flat node representation (simplified for script access)
|
|
791
|
+
*/
|
|
792
|
+
interface FlatNode {
|
|
793
|
+
id: string;
|
|
794
|
+
schemaIRI: string;
|
|
795
|
+
[key: string]: unknown;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Format helper functions (no side effects)
|
|
799
|
+
*/
|
|
800
|
+
interface FormatHelpers {
|
|
801
|
+
/** Format a timestamp as a date string */
|
|
802
|
+
date: (timestamp: number, options?: Intl.DateTimeFormatOptions) => string;
|
|
803
|
+
/** Format a number with options */
|
|
804
|
+
number: (value: number, options?: Intl.NumberFormatOptions) => string;
|
|
805
|
+
/** Format a number as currency */
|
|
806
|
+
currency: (value: number, currency?: string, locale?: string) => string;
|
|
807
|
+
/** Format a timestamp as relative time (e.g., "5m ago") */
|
|
808
|
+
relative: (timestamp: number) => string;
|
|
809
|
+
/** Format bytes as human-readable size */
|
|
810
|
+
bytes: (bytes: number) => string;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Math helper functions (pure functions)
|
|
814
|
+
*/
|
|
815
|
+
interface MathHelpers {
|
|
816
|
+
/** Sum an array of numbers */
|
|
817
|
+
sum: (values: number[]) => number;
|
|
818
|
+
/** Average of an array of numbers */
|
|
819
|
+
avg: (values: number[]) => number;
|
|
820
|
+
/** Minimum value */
|
|
821
|
+
min: (values: number[]) => number;
|
|
822
|
+
/** Maximum value */
|
|
823
|
+
max: (values: number[]) => number;
|
|
824
|
+
/** Round to decimal places */
|
|
825
|
+
round: (value: number, decimals?: number) => number;
|
|
826
|
+
/** Clamp value between min and max */
|
|
827
|
+
clamp: (value: number, min: number, max: number) => number;
|
|
828
|
+
/** Absolute value */
|
|
829
|
+
abs: (value: number) => number;
|
|
830
|
+
/** Floor */
|
|
831
|
+
floor: (value: number) => number;
|
|
832
|
+
/** Ceiling */
|
|
833
|
+
ceil: (value: number) => number;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Text helper functions (pure functions)
|
|
837
|
+
*/
|
|
838
|
+
interface TextHelpers {
|
|
839
|
+
/** Convert to URL-safe slug */
|
|
840
|
+
slugify: (text: string) => string;
|
|
841
|
+
/** Truncate with ellipsis */
|
|
842
|
+
truncate: (text: string, maxLength: number) => string;
|
|
843
|
+
/** Capitalize first letter */
|
|
844
|
+
capitalize: (text: string) => string;
|
|
845
|
+
/** Title case */
|
|
846
|
+
titleCase: (text: string) => string;
|
|
847
|
+
/** Check if text contains search (case-insensitive) */
|
|
848
|
+
contains: (text: string, search: string) => boolean;
|
|
849
|
+
/** Simple template substitution: {key} replaced by vars[key] */
|
|
850
|
+
template: (template: string, vars: Record<string, unknown>) => string;
|
|
851
|
+
/** Trim whitespace */
|
|
852
|
+
trim: (text: string) => string;
|
|
853
|
+
/** Convert to lowercase */
|
|
854
|
+
lower: (text: string) => string;
|
|
855
|
+
/** Convert to uppercase */
|
|
856
|
+
upper: (text: string) => string;
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Array helper functions (pure functions)
|
|
860
|
+
*/
|
|
861
|
+
interface ArrayHelpers {
|
|
862
|
+
/** Get first element */
|
|
863
|
+
first: <T>(items: T[]) => T | undefined;
|
|
864
|
+
/** Get last element */
|
|
865
|
+
last: <T>(items: T[]) => T | undefined;
|
|
866
|
+
/** Sort by property */
|
|
867
|
+
sortBy: <T>(items: T[], key: keyof T, desc?: boolean) => T[];
|
|
868
|
+
/** Group by property */
|
|
869
|
+
groupBy: <T>(items: T[], key: keyof T) => Record<string, T[]>;
|
|
870
|
+
/** Unique values */
|
|
871
|
+
unique: <T>(items: T[]) => T[];
|
|
872
|
+
/** Count items */
|
|
873
|
+
count: <T>(items: T[]) => number;
|
|
874
|
+
/** Filter truthy */
|
|
875
|
+
compact: <T>(items: (T | null | undefined)[]) => T[];
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* The context object passed to scripts.
|
|
879
|
+
* All properties and nested objects are frozen (immutable).
|
|
880
|
+
*/
|
|
881
|
+
interface ScriptContext {
|
|
882
|
+
/** The current node being processed (read-only, frozen) */
|
|
883
|
+
node: Readonly<FlatNode>;
|
|
884
|
+
/**
|
|
885
|
+
* Query sibling nodes by schema.
|
|
886
|
+
* Returns a frozen array of frozen nodes.
|
|
887
|
+
*/
|
|
888
|
+
nodes: (schemaIRI?: string) => ReadonlyArray<Readonly<FlatNode>>;
|
|
889
|
+
/** Current timestamp in milliseconds */
|
|
890
|
+
now: () => number;
|
|
891
|
+
/** Format helpers */
|
|
892
|
+
format: Readonly<FormatHelpers>;
|
|
893
|
+
/** Math helpers */
|
|
894
|
+
math: Readonly<MathHelpers>;
|
|
895
|
+
/** Text helpers */
|
|
896
|
+
text: Readonly<TextHelpers>;
|
|
897
|
+
/** Array helpers */
|
|
898
|
+
array: Readonly<ArrayHelpers>;
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Create a frozen ScriptContext for sandbox execution.
|
|
902
|
+
*
|
|
903
|
+
* @param node - The current node being processed
|
|
904
|
+
* @param queryFn - Function to query other nodes by schema
|
|
905
|
+
* @returns A frozen ScriptContext
|
|
906
|
+
*
|
|
907
|
+
* @example
|
|
908
|
+
* ```typescript
|
|
909
|
+
* const context = createScriptContext(
|
|
910
|
+
* targetNode,
|
|
911
|
+
* (schema) => store.list({ schemaIRI: schema })
|
|
912
|
+
* )
|
|
913
|
+
*
|
|
914
|
+
* const result = await sandbox.execute(code, context)
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
declare function createScriptContext(node: FlatNode, queryFn: (schemaIRI?: string) => FlatNode[]): ScriptContext;
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* AST Validator - Security checks for user scripts
|
|
921
|
+
*
|
|
922
|
+
* Parses JavaScript code and validates against forbidden patterns
|
|
923
|
+
* to ensure scripts cannot escape the sandbox.
|
|
924
|
+
*/
|
|
925
|
+
interface ValidationResult {
|
|
926
|
+
/** Whether the script passed validation */
|
|
927
|
+
valid: boolean;
|
|
928
|
+
/** List of validation errors (empty if valid) */
|
|
929
|
+
errors: string[];
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Validate a script's AST for forbidden patterns.
|
|
933
|
+
*
|
|
934
|
+
* Checks for:
|
|
935
|
+
* - Forbidden global variable access
|
|
936
|
+
* - Import/export statements
|
|
937
|
+
* - Dynamic import()
|
|
938
|
+
* - Async/await (scripts must be synchronous)
|
|
939
|
+
* - new Function() constructor
|
|
940
|
+
* - Forbidden property access (__proto__, constructor, etc.)
|
|
941
|
+
* - with statements
|
|
942
|
+
* - eval calls
|
|
943
|
+
*
|
|
944
|
+
* @param code - JavaScript code to validate
|
|
945
|
+
* @returns Validation result with errors if any
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```typescript
|
|
949
|
+
* const result = validateScriptAST('(node) => node.amount * 1.08')
|
|
950
|
+
* if (!result.valid) {
|
|
951
|
+
* console.error('Invalid script:', result.errors)
|
|
952
|
+
* }
|
|
953
|
+
* ```
|
|
954
|
+
*/
|
|
955
|
+
declare function validateScriptAST(code: string): ValidationResult;
|
|
956
|
+
/**
|
|
957
|
+
* Quick check if code is likely safe (doesn't do full AST parse).
|
|
958
|
+
* Use this for fast rejection before full validation.
|
|
959
|
+
*/
|
|
960
|
+
declare function quickSafetyCheck(code: string): boolean;
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* ScriptSandbox - Isolated execution environment for user scripts
|
|
964
|
+
*
|
|
965
|
+
* Executes scripts with:
|
|
966
|
+
* - AST validation before execution
|
|
967
|
+
* - Timeout protection
|
|
968
|
+
* - Global shadowing to prevent escape
|
|
969
|
+
* - Output sanitization
|
|
970
|
+
*/
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Duck-typed telemetry interface to avoid circular dependencies.
|
|
974
|
+
*/
|
|
975
|
+
interface TelemetryReporter {
|
|
976
|
+
reportPerformance(metricName: string, durationMs: number): void;
|
|
977
|
+
reportUsage(metricName: string, count: number): void;
|
|
978
|
+
reportCrash(error: Error, context?: Record<string, unknown>): void;
|
|
979
|
+
}
|
|
980
|
+
interface SandboxOptions {
|
|
981
|
+
/** Maximum execution time in milliseconds (default: 1000) */
|
|
982
|
+
timeoutMs?: number;
|
|
983
|
+
/** Whether to run AST validation (default: true) */
|
|
984
|
+
validateAST?: boolean;
|
|
985
|
+
/** Optional telemetry reporter */
|
|
986
|
+
telemetry?: TelemetryReporter;
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Error thrown when a script fails validation or execution
|
|
990
|
+
*/
|
|
991
|
+
declare class ScriptError extends Error {
|
|
992
|
+
details: string[];
|
|
993
|
+
constructor(message: string, details: string[]);
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Error thrown when a script times out
|
|
997
|
+
*/
|
|
998
|
+
declare class ScriptTimeoutError extends ScriptError {
|
|
999
|
+
constructor(timeoutMs: number);
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Error thrown when a script fails AST validation
|
|
1003
|
+
*/
|
|
1004
|
+
declare class ScriptValidationError extends ScriptError {
|
|
1005
|
+
constructor(errors: string[]);
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Sandbox for executing user scripts safely.
|
|
1009
|
+
*
|
|
1010
|
+
* Scripts are validated via AST analysis and executed in an environment
|
|
1011
|
+
* where dangerous globals are shadowed to undefined.
|
|
1012
|
+
*
|
|
1013
|
+
* @example
|
|
1014
|
+
* ```typescript
|
|
1015
|
+
* const sandbox = new ScriptSandbox({ timeoutMs: 500 })
|
|
1016
|
+
*
|
|
1017
|
+
* const context = createScriptContext(node, queryFn)
|
|
1018
|
+
* const result = await sandbox.execute('(node) => node.amount * 1.08', context)
|
|
1019
|
+
* ```
|
|
1020
|
+
*/
|
|
1021
|
+
declare class ScriptSandbox {
|
|
1022
|
+
private options;
|
|
1023
|
+
constructor(options?: SandboxOptions);
|
|
1024
|
+
/**
|
|
1025
|
+
* Execute a script in the sandbox.
|
|
1026
|
+
*
|
|
1027
|
+
* @param code - JavaScript code (expression or arrow function)
|
|
1028
|
+
* @param context - The frozen ScriptContext
|
|
1029
|
+
* @returns The script's return value (sanitized)
|
|
1030
|
+
* @throws ScriptValidationError if AST validation fails
|
|
1031
|
+
* @throws ScriptTimeoutError if execution exceeds timeout
|
|
1032
|
+
* @throws ScriptError for other execution errors
|
|
1033
|
+
*/
|
|
1034
|
+
execute(code: string, context: ScriptContext): Promise<unknown>;
|
|
1035
|
+
/**
|
|
1036
|
+
* Execute a script synchronously (for computed columns).
|
|
1037
|
+
* Use with caution - no timeout protection in sync mode.
|
|
1038
|
+
*/
|
|
1039
|
+
executeSync(code: string, context: ScriptContext): unknown;
|
|
1040
|
+
/**
|
|
1041
|
+
* Create an isolated function from user code.
|
|
1042
|
+
*
|
|
1043
|
+
* The function receives context values as arguments and has dangerous
|
|
1044
|
+
* globals shadowed to undefined in its scope.
|
|
1045
|
+
*/
|
|
1046
|
+
private createIsolatedFunction;
|
|
1047
|
+
/**
|
|
1048
|
+
* Execute a function with a timeout.
|
|
1049
|
+
*/
|
|
1050
|
+
private executeWithTimeout;
|
|
1051
|
+
/**
|
|
1052
|
+
* Sanitize script output to ensure only safe values are returned.
|
|
1053
|
+
*
|
|
1054
|
+
* Allowed types: null, undefined, string, number, boolean, plain objects, arrays
|
|
1055
|
+
* Stripped: functions, symbols, circular references, dunder properties
|
|
1056
|
+
*/
|
|
1057
|
+
private sanitizeOutput;
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Quick execution with default options.
|
|
1061
|
+
*/
|
|
1062
|
+
declare function executeScript(code: string, context: ScriptContext): Promise<unknown>;
|
|
1063
|
+
/**
|
|
1064
|
+
* Validate script code without executing.
|
|
1065
|
+
*/
|
|
1066
|
+
declare function validateScript(code: string): {
|
|
1067
|
+
valid: boolean;
|
|
1068
|
+
errors: string[];
|
|
1069
|
+
};
|
|
1070
|
+
|
|
1071
|
+
/**
|
|
1072
|
+
* ScriptRunner - Reactive script execution system
|
|
1073
|
+
*
|
|
1074
|
+
* Manages script lifecycle:
|
|
1075
|
+
* - Registers scripts based on their trigger type
|
|
1076
|
+
* - Executes scripts when triggers fire
|
|
1077
|
+
* - Handles errors gracefully
|
|
1078
|
+
* - Updates script status (lastRun, lastError)
|
|
1079
|
+
*/
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* Minimal store interface for the script runner.
|
|
1083
|
+
* This avoids a hard dependency on @xnetjs/data.
|
|
1084
|
+
*/
|
|
1085
|
+
interface ScriptStore {
|
|
1086
|
+
/** List nodes matching a query */
|
|
1087
|
+
list(query: {
|
|
1088
|
+
schemaIRI?: string;
|
|
1089
|
+
}): FlatNode[];
|
|
1090
|
+
/** Update a node by ID */
|
|
1091
|
+
update(id: string, payload: Partial<Record<string, unknown>>): Promise<void> | void;
|
|
1092
|
+
/** Subscribe to node changes */
|
|
1093
|
+
subscribe(callback: (event: ScriptNodeChangeEvent) => void): () => void;
|
|
1094
|
+
}
|
|
1095
|
+
interface ScriptNodeChangeEvent {
|
|
1096
|
+
type: 'create' | 'update' | 'delete';
|
|
1097
|
+
node?: FlatNode;
|
|
1098
|
+
change: {
|
|
1099
|
+
payload?: Record<string, unknown>;
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
interface ScriptRunnerOptions {
|
|
1103
|
+
/** Store instance */
|
|
1104
|
+
store: ScriptStore;
|
|
1105
|
+
/** Sandbox options */
|
|
1106
|
+
sandboxOptions?: {
|
|
1107
|
+
timeoutMs?: number;
|
|
1108
|
+
validateAST?: boolean;
|
|
1109
|
+
};
|
|
1110
|
+
/** Optional telemetry reporter */
|
|
1111
|
+
telemetry?: TelemetryReporter;
|
|
1112
|
+
}
|
|
1113
|
+
interface ScriptExecutionResult {
|
|
1114
|
+
/** Whether execution succeeded */
|
|
1115
|
+
success: boolean;
|
|
1116
|
+
/** The script's return value (if successful) */
|
|
1117
|
+
result?: unknown;
|
|
1118
|
+
/** Error message (if failed) */
|
|
1119
|
+
error?: string;
|
|
1120
|
+
/** Execution time in milliseconds */
|
|
1121
|
+
durationMs: number;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Manages reactive script execution.
|
|
1125
|
+
*
|
|
1126
|
+
* @example
|
|
1127
|
+
* ```typescript
|
|
1128
|
+
* const runner = new ScriptRunner({ store })
|
|
1129
|
+
*
|
|
1130
|
+
* // Start listening for triggers
|
|
1131
|
+
* await runner.start()
|
|
1132
|
+
*
|
|
1133
|
+
* // Execute a script manually
|
|
1134
|
+
* const result = await runner.executeManual(code, targetNode)
|
|
1135
|
+
*
|
|
1136
|
+
* // Stop all listeners
|
|
1137
|
+
* runner.stop()
|
|
1138
|
+
* ```
|
|
1139
|
+
*/
|
|
1140
|
+
declare class ScriptRunner {
|
|
1141
|
+
private sandbox;
|
|
1142
|
+
private store;
|
|
1143
|
+
private subscriptions;
|
|
1144
|
+
private scriptSubscriptions;
|
|
1145
|
+
private started;
|
|
1146
|
+
private telemetry?;
|
|
1147
|
+
constructor(options: ScriptRunnerOptions);
|
|
1148
|
+
/**
|
|
1149
|
+
* Start the script runner.
|
|
1150
|
+
* Registers all enabled scripts and sets up triggers.
|
|
1151
|
+
*/
|
|
1152
|
+
start(): Promise<void>;
|
|
1153
|
+
/**
|
|
1154
|
+
* Stop the script runner.
|
|
1155
|
+
* Removes all triggers and subscriptions.
|
|
1156
|
+
*/
|
|
1157
|
+
stop(): void;
|
|
1158
|
+
/**
|
|
1159
|
+
* Execute a script manually for testing/preview.
|
|
1160
|
+
* Does not update lastRun/lastError on the script node.
|
|
1161
|
+
*/
|
|
1162
|
+
executeManual(code: string, node: FlatNode): Promise<ScriptExecutionResult>;
|
|
1163
|
+
/**
|
|
1164
|
+
* Execute a script as a computed value (synchronous).
|
|
1165
|
+
* Used for computed columns in table views.
|
|
1166
|
+
*/
|
|
1167
|
+
computeValue(code: string, node: FlatNode): unknown;
|
|
1168
|
+
/**
|
|
1169
|
+
* Register a script and set up its trigger.
|
|
1170
|
+
*/
|
|
1171
|
+
private registerScript;
|
|
1172
|
+
/**
|
|
1173
|
+
* Unregister a script's trigger.
|
|
1174
|
+
*/
|
|
1175
|
+
private unregisterScript;
|
|
1176
|
+
/**
|
|
1177
|
+
* Register an onChange trigger for a script.
|
|
1178
|
+
*/
|
|
1179
|
+
private registerOnChangeTrigger;
|
|
1180
|
+
/**
|
|
1181
|
+
* Execute a script and handle results.
|
|
1182
|
+
*/
|
|
1183
|
+
private executeScript;
|
|
1184
|
+
/**
|
|
1185
|
+
* Handle changes to script nodes.
|
|
1186
|
+
*/
|
|
1187
|
+
private handleScriptChange;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* AI Prompt Builder for Script Generation
|
|
1192
|
+
*
|
|
1193
|
+
* Creates structured prompts that guide AI models to generate
|
|
1194
|
+
* valid, sandboxed scripts for xNet.
|
|
1195
|
+
*/
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* Schema property definition (simplified for prompt building)
|
|
1199
|
+
*/
|
|
1200
|
+
interface SchemaProperty {
|
|
1201
|
+
name: string;
|
|
1202
|
+
type: string;
|
|
1203
|
+
required?: boolean;
|
|
1204
|
+
description?: string;
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Schema definition for prompt context
|
|
1208
|
+
*/
|
|
1209
|
+
interface SchemaDefinition {
|
|
1210
|
+
name: string;
|
|
1211
|
+
schemaIRI: string;
|
|
1212
|
+
properties: SchemaProperty[];
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Request for AI script generation
|
|
1216
|
+
*/
|
|
1217
|
+
interface AIScriptRequest {
|
|
1218
|
+
/** Natural language description of what the script should do */
|
|
1219
|
+
intent: string;
|
|
1220
|
+
/** Schema definition with available fields */
|
|
1221
|
+
schema: SchemaDefinition;
|
|
1222
|
+
/** Expected output type */
|
|
1223
|
+
outputType: ScriptOutputType;
|
|
1224
|
+
/** Suggested trigger type */
|
|
1225
|
+
triggerType?: ScriptTriggerType;
|
|
1226
|
+
/** Sample data nodes for context */
|
|
1227
|
+
examples?: FlatNode[];
|
|
1228
|
+
/** Additional constraints or requirements */
|
|
1229
|
+
constraints?: string[];
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Build a complete prompt for AI script generation.
|
|
1233
|
+
*
|
|
1234
|
+
* @param request - The script generation request
|
|
1235
|
+
* @returns Complete prompt string for the AI model
|
|
1236
|
+
*
|
|
1237
|
+
* @example
|
|
1238
|
+
* ```typescript
|
|
1239
|
+
* const prompt = buildScriptPrompt({
|
|
1240
|
+
* intent: 'Calculate total with 8% tax',
|
|
1241
|
+
* schema: {
|
|
1242
|
+
* name: 'Invoice',
|
|
1243
|
+
* schemaIRI: 'xnet://myapp/Invoice',
|
|
1244
|
+
* properties: [
|
|
1245
|
+
* { name: 'subtotal', type: 'number', required: true },
|
|
1246
|
+
* { name: 'taxRate', type: 'number' }
|
|
1247
|
+
* ]
|
|
1248
|
+
* },
|
|
1249
|
+
* outputType: 'value'
|
|
1250
|
+
* })
|
|
1251
|
+
* ```
|
|
1252
|
+
*/
|
|
1253
|
+
declare function buildScriptPrompt(request: AIScriptRequest): string;
|
|
1254
|
+
/**
|
|
1255
|
+
* Build a retry prompt when the first attempt fails validation.
|
|
1256
|
+
*
|
|
1257
|
+
* @param originalPrompt - The original prompt
|
|
1258
|
+
* @param errors - Validation errors from the first attempt
|
|
1259
|
+
* @returns Updated prompt with error feedback
|
|
1260
|
+
*/
|
|
1261
|
+
declare function buildRetryPrompt(originalPrompt: string, errors: string[]): string;
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* AI Provider Abstraction
|
|
1265
|
+
*
|
|
1266
|
+
* Defines a common interface for AI providers and includes
|
|
1267
|
+
* implementations for Anthropic, OpenAI, and local (Ollama).
|
|
1268
|
+
*/
|
|
1269
|
+
/**
|
|
1270
|
+
* Common interface for AI text generation providers
|
|
1271
|
+
*/
|
|
1272
|
+
interface AIProvider {
|
|
1273
|
+
/** Provider name for display/logging */
|
|
1274
|
+
readonly name: string;
|
|
1275
|
+
/**
|
|
1276
|
+
* Generate text from a prompt.
|
|
1277
|
+
*
|
|
1278
|
+
* @param prompt - The input prompt
|
|
1279
|
+
* @returns Generated text response
|
|
1280
|
+
* @throws Error if generation fails
|
|
1281
|
+
*/
|
|
1282
|
+
generate(prompt: string): Promise<string>;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Options for configuring AI providers
|
|
1286
|
+
*/
|
|
1287
|
+
interface AIProviderOptions {
|
|
1288
|
+
/** API key (for cloud providers) */
|
|
1289
|
+
apiKey?: string;
|
|
1290
|
+
/** Base URL (for self-hosted or proxy) */
|
|
1291
|
+
baseUrl?: string;
|
|
1292
|
+
/** Model to use */
|
|
1293
|
+
model?: string;
|
|
1294
|
+
/** Maximum tokens to generate */
|
|
1295
|
+
maxTokens?: number;
|
|
1296
|
+
/** Temperature (0-1, higher = more creative) */
|
|
1297
|
+
temperature?: number;
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* AI provider type identifier
|
|
1301
|
+
*/
|
|
1302
|
+
type AIProviderType = 'anthropic' | 'openai' | 'ollama' | 'custom';
|
|
1303
|
+
/**
|
|
1304
|
+
* Configuration for selecting an AI provider
|
|
1305
|
+
*/
|
|
1306
|
+
interface AIProviderConfig {
|
|
1307
|
+
type: AIProviderType;
|
|
1308
|
+
options: AIProviderOptions;
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* Error thrown when AI generation fails
|
|
1312
|
+
*/
|
|
1313
|
+
declare class AIGenerationError extends Error {
|
|
1314
|
+
readonly provider: string;
|
|
1315
|
+
readonly cause?: unknown | undefined;
|
|
1316
|
+
constructor(message: string, provider: string, cause?: unknown | undefined);
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* AI provider for Anthropic's Claude models.
|
|
1320
|
+
*
|
|
1321
|
+
* @example
|
|
1322
|
+
* ```typescript
|
|
1323
|
+
* const provider = new AnthropicProvider({ apiKey: 'sk-...' })
|
|
1324
|
+
* const response = await provider.generate('Hello!')
|
|
1325
|
+
* ```
|
|
1326
|
+
*/
|
|
1327
|
+
declare class AnthropicProvider implements AIProvider {
|
|
1328
|
+
readonly name = "Anthropic";
|
|
1329
|
+
private apiKey;
|
|
1330
|
+
private baseUrl;
|
|
1331
|
+
private model;
|
|
1332
|
+
private maxTokens;
|
|
1333
|
+
private temperature;
|
|
1334
|
+
constructor(options: AIProviderOptions);
|
|
1335
|
+
generate(prompt: string): Promise<string>;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* AI provider for OpenAI's GPT models.
|
|
1339
|
+
*
|
|
1340
|
+
* @example
|
|
1341
|
+
* ```typescript
|
|
1342
|
+
* const provider = new OpenAIProvider({ apiKey: 'sk-...' })
|
|
1343
|
+
* const response = await provider.generate('Hello!')
|
|
1344
|
+
* ```
|
|
1345
|
+
*/
|
|
1346
|
+
declare class OpenAIProvider implements AIProvider {
|
|
1347
|
+
readonly name = "OpenAI";
|
|
1348
|
+
private apiKey;
|
|
1349
|
+
private baseUrl;
|
|
1350
|
+
private model;
|
|
1351
|
+
private maxTokens;
|
|
1352
|
+
private temperature;
|
|
1353
|
+
constructor(options: AIProviderOptions);
|
|
1354
|
+
generate(prompt: string): Promise<string>;
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* AI provider for local Ollama instance.
|
|
1358
|
+
*
|
|
1359
|
+
* @example
|
|
1360
|
+
* ```typescript
|
|
1361
|
+
* const provider = new OllamaProvider({ baseUrl: 'http://localhost:11434' })
|
|
1362
|
+
* const response = await provider.generate('Hello!')
|
|
1363
|
+
* ```
|
|
1364
|
+
*/
|
|
1365
|
+
declare class OllamaProvider implements AIProvider {
|
|
1366
|
+
readonly name = "Ollama";
|
|
1367
|
+
private baseUrl;
|
|
1368
|
+
private model;
|
|
1369
|
+
private temperature;
|
|
1370
|
+
constructor(options?: AIProviderOptions);
|
|
1371
|
+
generate(prompt: string): Promise<string>;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Create an AI provider from configuration.
|
|
1375
|
+
*
|
|
1376
|
+
* @param config - Provider configuration
|
|
1377
|
+
* @returns Configured AI provider instance
|
|
1378
|
+
*
|
|
1379
|
+
* @example
|
|
1380
|
+
* ```typescript
|
|
1381
|
+
* const provider = createAIProvider({
|
|
1382
|
+
* type: 'anthropic',
|
|
1383
|
+
* options: { apiKey: 'sk-...' }
|
|
1384
|
+
* })
|
|
1385
|
+
* ```
|
|
1386
|
+
*/
|
|
1387
|
+
declare function createAIProvider(config: AIProviderConfig): AIProvider;
|
|
1388
|
+
/**
|
|
1389
|
+
* Check if Ollama is available locally.
|
|
1390
|
+
*
|
|
1391
|
+
* @param baseUrl - Ollama base URL (default: http://localhost:11434)
|
|
1392
|
+
* @returns True if Ollama is responding
|
|
1393
|
+
*/
|
|
1394
|
+
declare function isOllamaAvailable(baseUrl?: string): Promise<boolean>;
|
|
1395
|
+
/**
|
|
1396
|
+
* List available Ollama models.
|
|
1397
|
+
*
|
|
1398
|
+
* @param baseUrl - Ollama base URL
|
|
1399
|
+
* @returns Array of model names
|
|
1400
|
+
*/
|
|
1401
|
+
declare function listOllamaModels(baseUrl?: string): Promise<string[]>;
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* Script Generator - AI-powered script generation with validation
|
|
1405
|
+
*
|
|
1406
|
+
* Uses AI to generate scripts from natural language descriptions,
|
|
1407
|
+
* validates them against the sandbox rules, and provides retry logic.
|
|
1408
|
+
*/
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Response from AI script generation
|
|
1412
|
+
*/
|
|
1413
|
+
interface AIScriptResponse {
|
|
1414
|
+
/** The generated script code */
|
|
1415
|
+
code: string;
|
|
1416
|
+
/** AI-generated explanation of what the script does */
|
|
1417
|
+
explanation: string;
|
|
1418
|
+
/** Suggested name for the script */
|
|
1419
|
+
suggestedName: string;
|
|
1420
|
+
/** Suggested trigger type */
|
|
1421
|
+
suggestedTrigger: ScriptTriggerType;
|
|
1422
|
+
/** Whether the code passed validation */
|
|
1423
|
+
validated: boolean;
|
|
1424
|
+
/** Number of generation attempts */
|
|
1425
|
+
attempts: number;
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Options for the ScriptGenerator
|
|
1429
|
+
*/
|
|
1430
|
+
interface ScriptGeneratorOptions {
|
|
1431
|
+
/** Maximum number of retry attempts on validation failure */
|
|
1432
|
+
maxRetries?: number;
|
|
1433
|
+
/** Whether to throw on final validation failure (default: false, returns invalid code) */
|
|
1434
|
+
throwOnValidationFailure?: boolean;
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Error thrown when script generation fails
|
|
1438
|
+
*/
|
|
1439
|
+
declare class ScriptGenerationError extends Error {
|
|
1440
|
+
readonly validationErrors?: string[] | undefined;
|
|
1441
|
+
readonly attempts?: number | undefined;
|
|
1442
|
+
constructor(message: string, validationErrors?: string[] | undefined, attempts?: number | undefined);
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* Generates validated scripts from natural language using AI.
|
|
1446
|
+
*
|
|
1447
|
+
* @example
|
|
1448
|
+
* ```typescript
|
|
1449
|
+
* const generator = new ScriptGenerator(aiProvider, { maxRetries: 2 })
|
|
1450
|
+
*
|
|
1451
|
+
* const response = await generator.generate({
|
|
1452
|
+
* intent: 'Calculate total with 8% tax',
|
|
1453
|
+
* schema: invoiceSchema,
|
|
1454
|
+
* outputType: 'value'
|
|
1455
|
+
* })
|
|
1456
|
+
*
|
|
1457
|
+
* if (response.validated) {
|
|
1458
|
+
* // Use response.code
|
|
1459
|
+
* }
|
|
1460
|
+
* ```
|
|
1461
|
+
*/
|
|
1462
|
+
declare class ScriptGenerator {
|
|
1463
|
+
private ai;
|
|
1464
|
+
private maxRetries;
|
|
1465
|
+
private throwOnValidationFailure;
|
|
1466
|
+
constructor(ai: AIProvider, options?: ScriptGeneratorOptions);
|
|
1467
|
+
/**
|
|
1468
|
+
* Generate a script from a natural language request.
|
|
1469
|
+
*
|
|
1470
|
+
* @param request - The script generation request
|
|
1471
|
+
* @returns Generated script response
|
|
1472
|
+
* @throws ScriptGenerationError if throwOnValidationFailure is true and validation fails
|
|
1473
|
+
*/
|
|
1474
|
+
generate(request: AIScriptRequest): Promise<AIScriptResponse>;
|
|
1475
|
+
/**
|
|
1476
|
+
* Extract code from AI response (strips markdown fences, etc.)
|
|
1477
|
+
*/
|
|
1478
|
+
private extractCode;
|
|
1479
|
+
/**
|
|
1480
|
+
* Generate an explanation for the script
|
|
1481
|
+
*/
|
|
1482
|
+
private generateExplanation;
|
|
1483
|
+
/**
|
|
1484
|
+
* Generate a name from the intent
|
|
1485
|
+
*/
|
|
1486
|
+
private generateName;
|
|
1487
|
+
/**
|
|
1488
|
+
* Infer the best trigger type from the request
|
|
1489
|
+
*/
|
|
1490
|
+
private inferTrigger;
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Convenience function for one-off script generation.
|
|
1494
|
+
*
|
|
1495
|
+
* @param provider - AI provider to use
|
|
1496
|
+
* @param request - Script generation request
|
|
1497
|
+
* @returns Generated script response
|
|
1498
|
+
*/
|
|
1499
|
+
declare function generateScript(provider: AIProvider, request: AIScriptRequest): Promise<AIScriptResponse>;
|
|
1500
|
+
|
|
1501
|
+
/**
|
|
1502
|
+
* Service Plugin Types
|
|
1503
|
+
*
|
|
1504
|
+
* Defines the types for background service plugins that run as separate processes.
|
|
1505
|
+
* These are primarily used in Electron but the types are shared.
|
|
1506
|
+
*/
|
|
1507
|
+
/**
|
|
1508
|
+
* Process configuration for a service
|
|
1509
|
+
*/
|
|
1510
|
+
interface ServiceProcessConfig {
|
|
1511
|
+
/** Executable command (e.g., 'node', 'python', 'ollama') */
|
|
1512
|
+
command: string;
|
|
1513
|
+
/** Command arguments */
|
|
1514
|
+
args?: string[];
|
|
1515
|
+
/** Working directory */
|
|
1516
|
+
cwd?: string;
|
|
1517
|
+
/** Environment variables */
|
|
1518
|
+
env?: Record<string, string>;
|
|
1519
|
+
/** Run in shell (for PATH resolution) */
|
|
1520
|
+
shell?: boolean;
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Health check configuration
|
|
1524
|
+
*/
|
|
1525
|
+
interface ServiceHealthCheck {
|
|
1526
|
+
/** Type of health check */
|
|
1527
|
+
type: 'http' | 'stdout' | 'tcp';
|
|
1528
|
+
/** URL to check for HTTP health checks */
|
|
1529
|
+
url?: string;
|
|
1530
|
+
/** Port to check for TCP health checks */
|
|
1531
|
+
port?: number;
|
|
1532
|
+
/** Regex pattern to match in stdout */
|
|
1533
|
+
pattern?: string;
|
|
1534
|
+
/** Interval between checks in milliseconds (default: 5000) */
|
|
1535
|
+
intervalMs?: number;
|
|
1536
|
+
/** Timeout for each check in milliseconds (default: 5000) */
|
|
1537
|
+
timeoutMs?: number;
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Lifecycle configuration for a service
|
|
1541
|
+
*/
|
|
1542
|
+
interface ServiceLifecycle {
|
|
1543
|
+
/** Restart policy */
|
|
1544
|
+
restart: 'always' | 'on-failure' | 'never';
|
|
1545
|
+
/** Maximum number of restarts (default: 5) */
|
|
1546
|
+
maxRestarts?: number;
|
|
1547
|
+
/** Delay between restarts in milliseconds (default: 1000) */
|
|
1548
|
+
restartDelayMs?: number;
|
|
1549
|
+
/** Timeout for service startup in milliseconds (default: 10000) */
|
|
1550
|
+
startTimeoutMs?: number;
|
|
1551
|
+
/** Health check configuration */
|
|
1552
|
+
healthCheck?: ServiceHealthCheck;
|
|
1553
|
+
/** Graceful shutdown timeout in milliseconds (default: 5000) */
|
|
1554
|
+
shutdownTimeoutMs?: number;
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Communication configuration for a service
|
|
1558
|
+
*/
|
|
1559
|
+
interface ServiceCommunication {
|
|
1560
|
+
/** Communication protocol */
|
|
1561
|
+
protocol: 'stdio' | 'http' | 'websocket' | 'ipc';
|
|
1562
|
+
/** Port for HTTP/WebSocket (0 = auto-assign) */
|
|
1563
|
+
port?: number;
|
|
1564
|
+
/** Host address (default: '127.0.0.1') */
|
|
1565
|
+
host?: string;
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Capabilities provided by a service
|
|
1569
|
+
*/
|
|
1570
|
+
interface ServiceProvides {
|
|
1571
|
+
/** MCP tool definitions */
|
|
1572
|
+
mcp?: {
|
|
1573
|
+
tools: string[];
|
|
1574
|
+
};
|
|
1575
|
+
/** HTTP API routes */
|
|
1576
|
+
api?: {
|
|
1577
|
+
routes: string[];
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Complete service definition
|
|
1582
|
+
*/
|
|
1583
|
+
interface ServiceDefinition {
|
|
1584
|
+
/** Unique service identifier */
|
|
1585
|
+
id: string;
|
|
1586
|
+
/** Human-readable name */
|
|
1587
|
+
name: string;
|
|
1588
|
+
/** Optional description */
|
|
1589
|
+
description?: string;
|
|
1590
|
+
/** Process configuration */
|
|
1591
|
+
process: ServiceProcessConfig;
|
|
1592
|
+
/** Lifecycle configuration */
|
|
1593
|
+
lifecycle: ServiceLifecycle;
|
|
1594
|
+
/** Communication configuration */
|
|
1595
|
+
communication: ServiceCommunication;
|
|
1596
|
+
/** Capabilities this service provides */
|
|
1597
|
+
provides?: ServiceProvides;
|
|
1598
|
+
}
|
|
1599
|
+
/**
|
|
1600
|
+
* Service state
|
|
1601
|
+
*/
|
|
1602
|
+
type ServiceState = 'starting' | 'running' | 'stopping' | 'stopped' | 'error';
|
|
1603
|
+
/**
|
|
1604
|
+
* Service status
|
|
1605
|
+
*/
|
|
1606
|
+
interface ServiceStatus {
|
|
1607
|
+
/** Service ID */
|
|
1608
|
+
id: string;
|
|
1609
|
+
/** Current state */
|
|
1610
|
+
state: ServiceState;
|
|
1611
|
+
/** Process ID (when running) */
|
|
1612
|
+
pid?: number;
|
|
1613
|
+
/** Port (when running with HTTP/WebSocket) */
|
|
1614
|
+
port?: number;
|
|
1615
|
+
/** Timestamp when service started */
|
|
1616
|
+
startedAt?: number;
|
|
1617
|
+
/** Last error message */
|
|
1618
|
+
lastError?: string;
|
|
1619
|
+
/** Number of restarts since initial start */
|
|
1620
|
+
restartCount: number;
|
|
1621
|
+
/** Uptime in milliseconds (if running) */
|
|
1622
|
+
uptime?: number;
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1625
|
+
* Event emitted when service status changes
|
|
1626
|
+
*/
|
|
1627
|
+
interface ServiceStatusEvent {
|
|
1628
|
+
serviceId: string;
|
|
1629
|
+
status: ServiceStatus;
|
|
1630
|
+
previousState?: ServiceState;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Event emitted when service outputs data
|
|
1634
|
+
*/
|
|
1635
|
+
interface ServiceOutputEvent {
|
|
1636
|
+
serviceId: string;
|
|
1637
|
+
stream: 'stdout' | 'stderr';
|
|
1638
|
+
data: string;
|
|
1639
|
+
timestamp: number;
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Client interface for interacting with services from the renderer process
|
|
1643
|
+
*/
|
|
1644
|
+
interface ServiceClient {
|
|
1645
|
+
/** Start a service */
|
|
1646
|
+
start(definition: ServiceDefinition): Promise<ServiceStatus>;
|
|
1647
|
+
/** Stop a service */
|
|
1648
|
+
stop(serviceId: string): Promise<void>;
|
|
1649
|
+
/** Restart a service */
|
|
1650
|
+
restart(serviceId: string): Promise<ServiceStatus>;
|
|
1651
|
+
/** Get service status */
|
|
1652
|
+
status(serviceId: string): Promise<ServiceStatus | undefined>;
|
|
1653
|
+
/** Get all service statuses */
|
|
1654
|
+
listAll(): Promise<ServiceStatus[]>;
|
|
1655
|
+
/** Call a service via HTTP */
|
|
1656
|
+
call<T>(serviceId: string, method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', path: string, body?: unknown): Promise<T>;
|
|
1657
|
+
/** Subscribe to status changes */
|
|
1658
|
+
onStatusChange(serviceId: string, callback: (status: ServiceStatus) => void): () => void;
|
|
1659
|
+
/** Subscribe to service output */
|
|
1660
|
+
onOutput(serviceId: string, callback: (event: ServiceOutputEvent) => void): () => void;
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* Events emitted by the ProcessManager
|
|
1664
|
+
*/
|
|
1665
|
+
interface ProcessManagerEvents {
|
|
1666
|
+
'service:status': (event: ServiceStatusEvent) => void;
|
|
1667
|
+
'service:output': (event: ServiceOutputEvent) => void;
|
|
1668
|
+
'service:error': (event: {
|
|
1669
|
+
serviceId: string;
|
|
1670
|
+
error: Error;
|
|
1671
|
+
}) => void;
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Interface for the process manager (implemented in Electron main process)
|
|
1675
|
+
*/
|
|
1676
|
+
interface IProcessManager {
|
|
1677
|
+
/** Start a service */
|
|
1678
|
+
start(definition: ServiceDefinition): Promise<ServiceStatus>;
|
|
1679
|
+
/** Stop a service */
|
|
1680
|
+
stop(serviceId: string): Promise<void>;
|
|
1681
|
+
/** Restart a service */
|
|
1682
|
+
restart(serviceId: string): Promise<ServiceStatus>;
|
|
1683
|
+
/** Get service status */
|
|
1684
|
+
getStatus(serviceId: string): ServiceStatus | undefined;
|
|
1685
|
+
/** Get all service statuses */
|
|
1686
|
+
getAllStatuses(): ServiceStatus[];
|
|
1687
|
+
/** Stop all services */
|
|
1688
|
+
stopAll(): Promise<void>;
|
|
1689
|
+
/** Subscribe to events */
|
|
1690
|
+
on<K extends keyof ProcessManagerEvents>(event: K, listener: ProcessManagerEvents[K]): void;
|
|
1691
|
+
/** Unsubscribe from events */
|
|
1692
|
+
off<K extends keyof ProcessManagerEvents>(event: K, listener: ProcessManagerEvents[K]): void;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
/**
|
|
1696
|
+
* Local HTTP API Server
|
|
1697
|
+
*
|
|
1698
|
+
* Provides a REST API for external integrations (N8N, MCP, etc.) to interact
|
|
1699
|
+
* with xNet data. Runs on localhost only (port 31415 by default).
|
|
1700
|
+
*
|
|
1701
|
+
* This is designed to run in the Electron main process.
|
|
1702
|
+
*/
|
|
1703
|
+
/**
|
|
1704
|
+
* Node store interface (minimal subset needed by API)
|
|
1705
|
+
*/
|
|
1706
|
+
interface NodeStoreAPI {
|
|
1707
|
+
get(id: string): Promise<NodeData | null>;
|
|
1708
|
+
list(options?: {
|
|
1709
|
+
schemaId?: string;
|
|
1710
|
+
limit?: number;
|
|
1711
|
+
offset?: number;
|
|
1712
|
+
}): Promise<NodeData[]>;
|
|
1713
|
+
create(options: {
|
|
1714
|
+
schemaId: string;
|
|
1715
|
+
properties: Record<string, unknown>;
|
|
1716
|
+
}): Promise<NodeData>;
|
|
1717
|
+
update(id: string, options: {
|
|
1718
|
+
properties: Record<string, unknown>;
|
|
1719
|
+
}): Promise<NodeData>;
|
|
1720
|
+
delete(id: string): Promise<void>;
|
|
1721
|
+
subscribe(listener: (event: NodeChangeEventData) => void): () => void;
|
|
1722
|
+
}
|
|
1723
|
+
/**
|
|
1724
|
+
* Schema registry interface (minimal subset needed by API)
|
|
1725
|
+
*/
|
|
1726
|
+
interface SchemaRegistryAPI {
|
|
1727
|
+
getAllIRIs(): string[];
|
|
1728
|
+
get(iri: string): Promise<SchemaData | null>;
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Node data returned by API
|
|
1732
|
+
*/
|
|
1733
|
+
interface NodeData {
|
|
1734
|
+
id: string;
|
|
1735
|
+
schemaId: string;
|
|
1736
|
+
properties: Record<string, unknown>;
|
|
1737
|
+
deleted: boolean;
|
|
1738
|
+
createdAt: number;
|
|
1739
|
+
updatedAt: number;
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Schema data returned by API
|
|
1743
|
+
*/
|
|
1744
|
+
interface SchemaData {
|
|
1745
|
+
iri: string;
|
|
1746
|
+
name: string;
|
|
1747
|
+
properties: Record<string, unknown>;
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Node change event data
|
|
1751
|
+
*/
|
|
1752
|
+
interface NodeChangeEventData {
|
|
1753
|
+
change: {
|
|
1754
|
+
type: string;
|
|
1755
|
+
};
|
|
1756
|
+
node: NodeData | null;
|
|
1757
|
+
isRemote: boolean;
|
|
1758
|
+
}
|
|
1759
|
+
/**
|
|
1760
|
+
* API configuration
|
|
1761
|
+
*/
|
|
1762
|
+
interface LocalAPIConfig {
|
|
1763
|
+
/** Port to listen on (default: 31415) */
|
|
1764
|
+
port?: number;
|
|
1765
|
+
/** Host to bind to (default: '127.0.0.1') */
|
|
1766
|
+
host?: string;
|
|
1767
|
+
/** API token for authentication (optional) */
|
|
1768
|
+
token?: string;
|
|
1769
|
+
/**
|
|
1770
|
+
* Allowed CORS origins (default: none).
|
|
1771
|
+
* Set to specific origins like ['http://localhost:3000'] for local dev,
|
|
1772
|
+
* or ['*'] to allow all origins (not recommended for production).
|
|
1773
|
+
* Empty array or undefined disables CORS entirely.
|
|
1774
|
+
*/
|
|
1775
|
+
allowedOrigins?: string[];
|
|
1776
|
+
/** NodeStore instance */
|
|
1777
|
+
store: NodeStoreAPI;
|
|
1778
|
+
/** SchemaRegistry instance */
|
|
1779
|
+
schemas: SchemaRegistryAPI;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* Service Client
|
|
1784
|
+
*
|
|
1785
|
+
* Client API for interacting with services from the renderer process.
|
|
1786
|
+
* Uses IPC to communicate with the ProcessManager in the main process.
|
|
1787
|
+
*/
|
|
1788
|
+
|
|
1789
|
+
declare const SERVICE_IPC_CHANNELS: {
|
|
1790
|
+
readonly START: "xnet:service:start";
|
|
1791
|
+
readonly STOP: "xnet:service:stop";
|
|
1792
|
+
readonly RESTART: "xnet:service:restart";
|
|
1793
|
+
readonly STATUS: "xnet:service:status";
|
|
1794
|
+
readonly LIST_ALL: "xnet:service:list-all";
|
|
1795
|
+
readonly CALL: "xnet:service:call";
|
|
1796
|
+
readonly STATUS_UPDATE: "xnet:service:status-update";
|
|
1797
|
+
readonly OUTPUT: "xnet:service:output";
|
|
1798
|
+
};
|
|
1799
|
+
/**
|
|
1800
|
+
* Create a service client for the renderer process.
|
|
1801
|
+
*
|
|
1802
|
+
* @example
|
|
1803
|
+
* ```typescript
|
|
1804
|
+
* const client = createServiceClient()
|
|
1805
|
+
*
|
|
1806
|
+
* // Start a service
|
|
1807
|
+
* const status = await client.start({
|
|
1808
|
+
* id: 'my-service',
|
|
1809
|
+
* name: 'My Service',
|
|
1810
|
+
* process: { command: 'node', args: ['server.js'] },
|
|
1811
|
+
* lifecycle: { restart: 'on-failure' },
|
|
1812
|
+
* communication: { protocol: 'http', port: 3000 }
|
|
1813
|
+
* })
|
|
1814
|
+
*
|
|
1815
|
+
* // Call the service
|
|
1816
|
+
* const result = await client.call('my-service', 'GET', '/api/data')
|
|
1817
|
+
*
|
|
1818
|
+
* // Listen for status changes
|
|
1819
|
+
* const unsubscribe = client.onStatusChange('my-service', (status) => {
|
|
1820
|
+
* console.log('Status:', status.state)
|
|
1821
|
+
* })
|
|
1822
|
+
* ```
|
|
1823
|
+
*/
|
|
1824
|
+
declare function createServiceClient(): ServiceClient;
|
|
1825
|
+
/**
|
|
1826
|
+
* Check if service client is available
|
|
1827
|
+
*/
|
|
1828
|
+
declare function isServiceClientAvailable(): boolean;
|
|
1829
|
+
|
|
1830
|
+
/**
|
|
1831
|
+
* Webhook Event Emitter
|
|
1832
|
+
*
|
|
1833
|
+
* Sends webhook notifications when nodes change in the store.
|
|
1834
|
+
* Supports filtering by schema, event type, and includes HMAC signing.
|
|
1835
|
+
*/
|
|
1836
|
+
|
|
1837
|
+
/**
|
|
1838
|
+
* Webhook configuration
|
|
1839
|
+
*/
|
|
1840
|
+
interface WebhookConfig {
|
|
1841
|
+
/** Unique identifier for this webhook */
|
|
1842
|
+
id: string;
|
|
1843
|
+
/** URL to send webhooks to */
|
|
1844
|
+
url: string;
|
|
1845
|
+
/** Event types to send */
|
|
1846
|
+
events: ('created' | 'updated' | 'deleted')[];
|
|
1847
|
+
/** Filter by schema IRI (optional) */
|
|
1848
|
+
schema?: string;
|
|
1849
|
+
/** HMAC secret for signing (optional) */
|
|
1850
|
+
secret?: string;
|
|
1851
|
+
/** Maximum retry attempts (default: 3) */
|
|
1852
|
+
retries?: number;
|
|
1853
|
+
/** Enabled flag */
|
|
1854
|
+
enabled?: boolean;
|
|
1855
|
+
}
|
|
1856
|
+
/**
|
|
1857
|
+
* Webhook payload sent to subscribers
|
|
1858
|
+
*/
|
|
1859
|
+
interface WebhookPayload {
|
|
1860
|
+
/** Event type */
|
|
1861
|
+
type: 'created' | 'updated' | 'deleted';
|
|
1862
|
+
/** Timestamp when event occurred */
|
|
1863
|
+
timestamp: number;
|
|
1864
|
+
/** The affected node */
|
|
1865
|
+
node: NodeData | null;
|
|
1866
|
+
/** Schema IRI of the node */
|
|
1867
|
+
schema?: string;
|
|
1868
|
+
}
|
|
1869
|
+
/**
|
|
1870
|
+
* Delivery result
|
|
1871
|
+
*/
|
|
1872
|
+
interface DeliveryResult {
|
|
1873
|
+
webhookId: string;
|
|
1874
|
+
success: boolean;
|
|
1875
|
+
statusCode?: number;
|
|
1876
|
+
error?: string;
|
|
1877
|
+
attempts: number;
|
|
1878
|
+
deliveredAt?: number;
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Disposable interface for cleanup
|
|
1882
|
+
*/
|
|
1883
|
+
interface Disposable {
|
|
1884
|
+
dispose(): void;
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* WebhookEmitter sends HTTP notifications when nodes change.
|
|
1888
|
+
*
|
|
1889
|
+
* @example
|
|
1890
|
+
* ```typescript
|
|
1891
|
+
* const emitter = new WebhookEmitter(store)
|
|
1892
|
+
*
|
|
1893
|
+
* // Register a webhook
|
|
1894
|
+
* const dispose = emitter.register({
|
|
1895
|
+
* id: 'my-webhook',
|
|
1896
|
+
* url: 'https://example.com/webhook',
|
|
1897
|
+
* events: ['created', 'updated'],
|
|
1898
|
+
* schema: 'xnet://xnet.dev/Task',
|
|
1899
|
+
* secret: 'my-secret-key'
|
|
1900
|
+
* })
|
|
1901
|
+
*
|
|
1902
|
+
* // Later: dispose.dispose() to unregister
|
|
1903
|
+
* ```
|
|
1904
|
+
*/
|
|
1905
|
+
declare class WebhookEmitter {
|
|
1906
|
+
private store;
|
|
1907
|
+
private webhooks;
|
|
1908
|
+
private unsubscribe?;
|
|
1909
|
+
private deliveryHistory;
|
|
1910
|
+
private maxHistorySize;
|
|
1911
|
+
constructor(store: NodeStoreAPI);
|
|
1912
|
+
/**
|
|
1913
|
+
* Start listening for store changes.
|
|
1914
|
+
* Must be called before webhooks will be sent.
|
|
1915
|
+
*/
|
|
1916
|
+
start(): void;
|
|
1917
|
+
/**
|
|
1918
|
+
* Stop listening for store changes.
|
|
1919
|
+
*/
|
|
1920
|
+
stop(): void;
|
|
1921
|
+
/**
|
|
1922
|
+
* Register a webhook configuration.
|
|
1923
|
+
* Returns a disposable to unregister.
|
|
1924
|
+
*/
|
|
1925
|
+
register(config: WebhookConfig): Disposable;
|
|
1926
|
+
/**
|
|
1927
|
+
* Unregister a webhook by ID.
|
|
1928
|
+
*/
|
|
1929
|
+
unregister(id: string): boolean;
|
|
1930
|
+
/**
|
|
1931
|
+
* Get all registered webhooks.
|
|
1932
|
+
*/
|
|
1933
|
+
getWebhooks(): WebhookConfig[];
|
|
1934
|
+
/**
|
|
1935
|
+
* Get a webhook by ID.
|
|
1936
|
+
*/
|
|
1937
|
+
getWebhook(id: string): WebhookConfig | undefined;
|
|
1938
|
+
/**
|
|
1939
|
+
* Update a webhook configuration.
|
|
1940
|
+
*/
|
|
1941
|
+
updateWebhook(id: string, updates: Partial<WebhookConfig>): boolean;
|
|
1942
|
+
/**
|
|
1943
|
+
* Get recent delivery history.
|
|
1944
|
+
*/
|
|
1945
|
+
getDeliveryHistory(): DeliveryResult[];
|
|
1946
|
+
/**
|
|
1947
|
+
* Clear delivery history.
|
|
1948
|
+
*/
|
|
1949
|
+
clearDeliveryHistory(): void;
|
|
1950
|
+
private handleEvent;
|
|
1951
|
+
private getEventType;
|
|
1952
|
+
private send;
|
|
1953
|
+
private deliverWebhook;
|
|
1954
|
+
private sign;
|
|
1955
|
+
private recordDelivery;
|
|
1956
|
+
private delay;
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* Create a webhook emitter.
|
|
1960
|
+
*
|
|
1961
|
+
* @example
|
|
1962
|
+
* ```typescript
|
|
1963
|
+
* const emitter = createWebhookEmitter(store)
|
|
1964
|
+
* emitter.start()
|
|
1965
|
+
*
|
|
1966
|
+
* emitter.register({
|
|
1967
|
+
* id: 'n8n',
|
|
1968
|
+
* url: 'http://localhost:5678/webhook/xnet',
|
|
1969
|
+
* events: ['created', 'updated', 'deleted']
|
|
1970
|
+
* })
|
|
1971
|
+
* ```
|
|
1972
|
+
*/
|
|
1973
|
+
declare function createWebhookEmitter(store: NodeStoreAPI): WebhookEmitter;
|
|
1974
|
+
|
|
1975
|
+
/**
|
|
1976
|
+
* MCP Server for xNet
|
|
1977
|
+
*
|
|
1978
|
+
* Exposes xNet data to AI agents via the Model Context Protocol.
|
|
1979
|
+
* Provides tools for querying, creating, and updating nodes.
|
|
1980
|
+
*
|
|
1981
|
+
* This runs as a stdio-based MCP server, typically spawned by an MCP client.
|
|
1982
|
+
*/
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* MCP Tool definition
|
|
1986
|
+
*/
|
|
1987
|
+
interface MCPTool {
|
|
1988
|
+
name: string;
|
|
1989
|
+
description: string;
|
|
1990
|
+
inputSchema: {
|
|
1991
|
+
type: 'object';
|
|
1992
|
+
properties: Record<string, MCPPropertySchema>;
|
|
1993
|
+
required?: string[];
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
/**
|
|
1997
|
+
* MCP property schema
|
|
1998
|
+
*/
|
|
1999
|
+
interface MCPPropertySchema {
|
|
2000
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
2001
|
+
description?: string;
|
|
2002
|
+
items?: MCPPropertySchema;
|
|
2003
|
+
}
|
|
2004
|
+
/**
|
|
2005
|
+
* MCP Resource definition
|
|
2006
|
+
*/
|
|
2007
|
+
interface MCPResource {
|
|
2008
|
+
uri: string;
|
|
2009
|
+
name: string;
|
|
2010
|
+
description?: string;
|
|
2011
|
+
mimeType?: string;
|
|
2012
|
+
}
|
|
2013
|
+
/**
|
|
2014
|
+
* MCP Request from client
|
|
2015
|
+
*/
|
|
2016
|
+
interface MCPRequest {
|
|
2017
|
+
jsonrpc: '2.0';
|
|
2018
|
+
id: number | string;
|
|
2019
|
+
method: string;
|
|
2020
|
+
params?: Record<string, unknown>;
|
|
2021
|
+
}
|
|
2022
|
+
/**
|
|
2023
|
+
* MCP Response to client
|
|
2024
|
+
*/
|
|
2025
|
+
interface MCPResponse {
|
|
2026
|
+
jsonrpc: '2.0';
|
|
2027
|
+
id: number | string;
|
|
2028
|
+
result?: unknown;
|
|
2029
|
+
error?: {
|
|
2030
|
+
code: number;
|
|
2031
|
+
message: string;
|
|
2032
|
+
data?: unknown;
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* MCP Server configuration
|
|
2037
|
+
*/
|
|
2038
|
+
interface MCPServerConfig {
|
|
2039
|
+
store: NodeStoreAPI;
|
|
2040
|
+
schemas: SchemaRegistryAPI;
|
|
2041
|
+
/** Server name (default: 'xnet') */
|
|
2042
|
+
name?: string;
|
|
2043
|
+
/** Server version (default: '1.0.0') */
|
|
2044
|
+
version?: string;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
export { AIGenerationError, type AIProvider, type AIProviderConfig, type AIProviderOptions, type AIProviderType, type AIScriptRequest, type AIScriptResponse, AnthropicProvider, type ArrayHelpers, type BlockContribution, type BlockProps, type CommandContribution, ContributionRegistry, type DeliveryResult, type Disposable$1 as Disposable, type EditorContribution, type ExtensionContext, type ExtensionStorage, type FlatNode, type FormatHelpers, type IProcessManager, type LocalAPIConfig, type MCPPropertySchema, type MCPRequest, type MCPResource, type MCPResponse, type MCPServerConfig, type MCPTool, type MathHelpers, MiddlewareChain, type NodeChangeEvent, type NodeChangeEventData, type NodeData, type NodeStoreAPI, type NodeStoreMiddleware, OllamaProvider, OpenAIProvider, type PendingChange, type Platform, type PlatformCapabilities, type PluginContributions, PluginError, type PluginNode, type PluginNodeChangeEvent, type PluginNodeChangeListener, type PluginPermissions, PluginRegistry, PluginSchema, type PluginStatus, PluginValidationError, type ProcessManagerEvents, type PropertyCellProps, type PropertyEditorProps, type PropertyHandler, type PropertyHandlerContribution, type QueryFilter, type RegisteredPlugin, SERVICE_IPC_CHANNELS, type SandboxOptions, type SchemaContribution, type SchemaData, type SchemaDefinition, type SchemaProperty, type SchemaRegistryAPI, type ScriptContext, ScriptError, type ScriptExecutionResult, ScriptGenerationError, ScriptGenerator, type ScriptGeneratorOptions, type ScriptNode, type ScriptNodeChangeEvent, type ScriptOutputType, ScriptRunner, type ScriptRunnerOptions, ScriptSandbox, ScriptSchema, type ScriptStore, ScriptTimeoutError, type ScriptTriggerType, ScriptValidationError, type ServiceClient, type ServiceCommunication, type ServiceDefinition, type ServiceHealthCheck, type ServiceLifecycle, type ServiceOutputEvent, type ServiceProcessConfig, type ServiceProvides, type ServiceState, type ServiceStatus, type ServiceStatusEvent, type SettingContribution, type SettingsPanelProps, ShortcutManager, type SidebarContribution, type SlashCommandContext, type SlashCommandContribution, type TelemetryReporter, type TextHelpers, type ToolbarContribution, TypedRegistry, type ValidationResult, type ViewContribution, type ViewProps, type WebhookConfig, WebhookEmitter, type WebhookPayload, type XNetExtension, buildRetryPrompt, buildScriptPrompt, createAIProvider, createExtensionContext, createExtensionStorage, createScriptContext, createServiceClient, createWebhookEmitter, defineExtension, executeScript, generateScript, getPlatformCapabilities, getShortcutManager, installShortcutHandler, isOllamaAvailable, isScriptNode, isServiceClientAvailable, listOllamaModels, quickSafetyCheck, validateManifest, validateScript, validateScriptAST };
|