skeleton-crew-runtime 0.1.1
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 +726 -0
- package/dist/action-engine.d.ts +90 -0
- package/dist/action-engine.d.ts.map +1 -0
- package/dist/action-engine.js +166 -0
- package/dist/action-engine.js.map +1 -0
- package/dist/event-bus.d.ts +55 -0
- package/dist/event-bus.d.ts.map +1 -0
- package/dist/event-bus.js +110 -0
- package/dist/event-bus.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin-registry.d.ts +23 -0
- package/dist/plugin-registry.d.ts.map +1 -0
- package/dist/plugin-registry.js +108 -0
- package/dist/plugin-registry.js.map +1 -0
- package/dist/runtime-context.d.ts +127 -0
- package/dist/runtime-context.d.ts.map +1 -0
- package/dist/runtime-context.js +227 -0
- package/dist/runtime-context.js.map +1 -0
- package/dist/runtime.d.ts +125 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +257 -0
- package/dist/runtime.js.map +1 -0
- package/dist/screen-registry.d.ts +51 -0
- package/dist/screen-registry.d.ts.map +1 -0
- package/dist/screen-registry.js +82 -0
- package/dist/screen-registry.js.map +1 -0
- package/dist/types.d.ts +189 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +93 -0
- package/dist/types.js.map +1 -0
- package/dist/ui-bridge.d.ts +39 -0
- package/dist/ui-bridge.d.ts.map +1 -0
- package/dist/ui-bridge.js +74 -0
- package/dist/ui-bridge.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ActionDefinition, RuntimeContext, Logger } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* ActionEngine subsystem for storing and executing actions.
|
|
4
|
+
* Provides O(1) lookup performance using Map-based storage.
|
|
5
|
+
*
|
|
6
|
+
* Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 4.1, 4.2, 4.3, 4.4, 4.5, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 10.1, 10.2, 10.3, 10.4, 10.5, 11.1, 11.2, 11.3, 11.4, 11.5, 13.2, 13.5, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 15.1, 15.2, 15.3, 15.4, 15.5, 16.2, 16.4, 19.1, 19.2, 19.3, 19.4, 19.5
|
|
7
|
+
*/
|
|
8
|
+
export declare class ActionEngine {
|
|
9
|
+
private actions;
|
|
10
|
+
private context;
|
|
11
|
+
private logger;
|
|
12
|
+
constructor(logger: Logger);
|
|
13
|
+
/**
|
|
14
|
+
* Sets the RuntimeContext for this ActionEngine.
|
|
15
|
+
* This must be called after the RuntimeContext is created during initialization.
|
|
16
|
+
*
|
|
17
|
+
* @param context - The RuntimeContext to pass to action handlers
|
|
18
|
+
*
|
|
19
|
+
* Requirement: 6.6
|
|
20
|
+
*/
|
|
21
|
+
setContext(context: RuntimeContext): void;
|
|
22
|
+
/**
|
|
23
|
+
* Registers an action definition.
|
|
24
|
+
* Rejects duplicate action IDs.
|
|
25
|
+
* Returns an unregister function that removes the action when called.
|
|
26
|
+
*
|
|
27
|
+
* @param action - The action definition to register
|
|
28
|
+
* @returns A function that unregisters the action when called
|
|
29
|
+
* @throws ValidationError if required fields are missing or invalid
|
|
30
|
+
* @throws DuplicateRegistrationError if an action with the same ID is already registered
|
|
31
|
+
*
|
|
32
|
+
* Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 6.2, 6.4, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 15.1, 15.2, 15.3, 15.4, 15.5, 16.2, 19.1, 19.2, 19.3, 19.4, 19.5
|
|
33
|
+
*/
|
|
34
|
+
registerAction<P = unknown, R = unknown>(action: ActionDefinition<P, R>): () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Executes an action by ID with optional parameters.
|
|
37
|
+
* Passes the RuntimeContext to the action handler.
|
|
38
|
+
* Handles both synchronous and asynchronous handlers.
|
|
39
|
+
* Wraps handler errors in ActionExecutionError with context.
|
|
40
|
+
* Enforces timeout if specified in action definition.
|
|
41
|
+
*
|
|
42
|
+
* @param id - The action identifier
|
|
43
|
+
* @param params - Optional parameters to pass to the action handler
|
|
44
|
+
* @returns The result from the action handler
|
|
45
|
+
* @throws Error if the action ID does not exist
|
|
46
|
+
* @throws ActionExecutionError if the handler throws an error
|
|
47
|
+
* @throws ActionTimeoutError if the action exceeds its timeout
|
|
48
|
+
*
|
|
49
|
+
* Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 6.3, 6.5, 6.6, 6.7, 6.8, 11.1, 11.2, 11.3, 11.4, 11.5, 16.4
|
|
50
|
+
*/
|
|
51
|
+
runAction<P = unknown, R = unknown>(id: string, params?: P): Promise<R>;
|
|
52
|
+
/**
|
|
53
|
+
* Runs an action handler with a timeout.
|
|
54
|
+
*
|
|
55
|
+
* @param action - The action definition with timeout
|
|
56
|
+
* @param params - Parameters to pass to the handler
|
|
57
|
+
* @returns The result from the action handler
|
|
58
|
+
* @throws ActionTimeoutError if execution exceeds the timeout
|
|
59
|
+
*
|
|
60
|
+
* Requirements: 11.1, 11.2, 11.3, 11.4, 11.5
|
|
61
|
+
*/
|
|
62
|
+
private runWithTimeout;
|
|
63
|
+
/**
|
|
64
|
+
* Retrieves an action definition by ID.
|
|
65
|
+
* For internal use.
|
|
66
|
+
*
|
|
67
|
+
* @param id - The action identifier
|
|
68
|
+
* @returns The action definition or null if not found
|
|
69
|
+
*
|
|
70
|
+
* Requirement: 13.2
|
|
71
|
+
*/
|
|
72
|
+
getAction(id: string): ActionDefinition | null;
|
|
73
|
+
/**
|
|
74
|
+
* Retrieves all registered action definitions.
|
|
75
|
+
* Returns a copy to prevent external mutation of internal state.
|
|
76
|
+
*
|
|
77
|
+
* @returns Array of all registered action definitions
|
|
78
|
+
*
|
|
79
|
+
* Requirements: 10.1, 10.2, 10.3, 10.4, 10.5, 13.2
|
|
80
|
+
*/
|
|
81
|
+
getAllActions(): ActionDefinition[];
|
|
82
|
+
/**
|
|
83
|
+
* Clears all registered actions.
|
|
84
|
+
* Used during shutdown to release resources.
|
|
85
|
+
*
|
|
86
|
+
* Requirement: 13.5
|
|
87
|
+
*/
|
|
88
|
+
clear(): void;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=action-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-engine.d.ts","sourceRoot":"","sources":["../src/action-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAG3E;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAM1B;;;;;;;OAOG;IACH,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIzC;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,IAAI;IAwBpF;;;;;;;;;;;;;;;OAeG;IACG,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAkC7E;;;;;;;;;OASG;YACW,cAAc;IAqB5B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAI9C;;;;;;;OAOG;IACH,aAAa,IAAI,gBAAgB,EAAE;IAInC;;;;;OAKG;IACH,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { ValidationError, DuplicateRegistrationError, ActionTimeoutError, ActionExecutionError } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* ActionEngine subsystem for storing and executing actions.
|
|
4
|
+
* Provides O(1) lookup performance using Map-based storage.
|
|
5
|
+
*
|
|
6
|
+
* Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 4.1, 4.2, 4.3, 4.4, 4.5, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 10.1, 10.2, 10.3, 10.4, 10.5, 11.1, 11.2, 11.3, 11.4, 11.5, 13.2, 13.5, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 15.1, 15.2, 15.3, 15.4, 15.5, 16.2, 16.4, 19.1, 19.2, 19.3, 19.4, 19.5
|
|
7
|
+
*/
|
|
8
|
+
export class ActionEngine {
|
|
9
|
+
actions;
|
|
10
|
+
context;
|
|
11
|
+
logger;
|
|
12
|
+
constructor(logger) {
|
|
13
|
+
this.actions = new Map();
|
|
14
|
+
this.context = null;
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Sets the RuntimeContext for this ActionEngine.
|
|
19
|
+
* This must be called after the RuntimeContext is created during initialization.
|
|
20
|
+
*
|
|
21
|
+
* @param context - The RuntimeContext to pass to action handlers
|
|
22
|
+
*
|
|
23
|
+
* Requirement: 6.6
|
|
24
|
+
*/
|
|
25
|
+
setContext(context) {
|
|
26
|
+
this.context = context;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Registers an action definition.
|
|
30
|
+
* Rejects duplicate action IDs.
|
|
31
|
+
* Returns an unregister function that removes the action when called.
|
|
32
|
+
*
|
|
33
|
+
* @param action - The action definition to register
|
|
34
|
+
* @returns A function that unregisters the action when called
|
|
35
|
+
* @throws ValidationError if required fields are missing or invalid
|
|
36
|
+
* @throws DuplicateRegistrationError if an action with the same ID is already registered
|
|
37
|
+
*
|
|
38
|
+
* Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 6.2, 6.4, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 15.1, 15.2, 15.3, 15.4, 15.5, 16.2, 19.1, 19.2, 19.3, 19.4, 19.5
|
|
39
|
+
*/
|
|
40
|
+
registerAction(action) {
|
|
41
|
+
// Validate required fields (Requirements 19.1, 19.2, 19.3, 19.5)
|
|
42
|
+
if (!action.id || typeof action.id !== 'string') {
|
|
43
|
+
throw new ValidationError('Action', 'id');
|
|
44
|
+
}
|
|
45
|
+
if (!action.handler || typeof action.handler !== 'function') {
|
|
46
|
+
throw new ValidationError('Action', 'handler', action.id);
|
|
47
|
+
}
|
|
48
|
+
// Check for duplicate ID (Requirements 6.4, 15.1, 15.2, 15.4, 15.5, 16.2)
|
|
49
|
+
if (this.actions.has(action.id)) {
|
|
50
|
+
throw new DuplicateRegistrationError('Action', action.id);
|
|
51
|
+
}
|
|
52
|
+
// Register the action
|
|
53
|
+
this.actions.set(action.id, action);
|
|
54
|
+
this.logger.debug(`Action "${action.id}" registered successfully`);
|
|
55
|
+
// Return unregister function (Requirements 4.1, 4.2, 4.4, 4.5)
|
|
56
|
+
return () => {
|
|
57
|
+
this.actions.delete(action.id);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Executes an action by ID with optional parameters.
|
|
62
|
+
* Passes the RuntimeContext to the action handler.
|
|
63
|
+
* Handles both synchronous and asynchronous handlers.
|
|
64
|
+
* Wraps handler errors in ActionExecutionError with context.
|
|
65
|
+
* Enforces timeout if specified in action definition.
|
|
66
|
+
*
|
|
67
|
+
* @param id - The action identifier
|
|
68
|
+
* @param params - Optional parameters to pass to the action handler
|
|
69
|
+
* @returns The result from the action handler
|
|
70
|
+
* @throws Error if the action ID does not exist
|
|
71
|
+
* @throws ActionExecutionError if the handler throws an error
|
|
72
|
+
* @throws ActionTimeoutError if the action exceeds its timeout
|
|
73
|
+
*
|
|
74
|
+
* Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 6.3, 6.5, 6.6, 6.7, 6.8, 11.1, 11.2, 11.3, 11.4, 11.5, 16.4
|
|
75
|
+
*/
|
|
76
|
+
async runAction(id, params) {
|
|
77
|
+
// Check if action exists (Requirements 6.5, 16.4)
|
|
78
|
+
const action = this.actions.get(id);
|
|
79
|
+
if (!action) {
|
|
80
|
+
throw new Error(`Action with id "${id}" not found`);
|
|
81
|
+
}
|
|
82
|
+
// Ensure context is available (Requirement 6.6)
|
|
83
|
+
if (!this.context) {
|
|
84
|
+
throw new Error('RuntimeContext not set in ActionEngine');
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
// Handle timeout if specified (Requirements 11.1, 11.2, 11.3, 11.4, 11.5)
|
|
88
|
+
if (action.timeout) {
|
|
89
|
+
const result = await this.runWithTimeout(action, params);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
// Execute without timeout (Requirements 6.6, 6.7, 6.8)
|
|
93
|
+
const result = await Promise.resolve(action.handler(params, this.context));
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
// Don't wrap timeout errors (Requirements 11.3, 11.5)
|
|
98
|
+
if (error instanceof ActionTimeoutError) {
|
|
99
|
+
this.logger.error(`Action "${id}" timed out`, error);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
// Wrap other errors with contextual information (Requirements 3.1, 3.2, 3.3, 3.4, 3.5)
|
|
103
|
+
this.logger.error(`Action "${id}" execution failed`, error);
|
|
104
|
+
throw new ActionExecutionError(id, error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Runs an action handler with a timeout.
|
|
109
|
+
*
|
|
110
|
+
* @param action - The action definition with timeout
|
|
111
|
+
* @param params - Parameters to pass to the handler
|
|
112
|
+
* @returns The result from the action handler
|
|
113
|
+
* @throws ActionTimeoutError if execution exceeds the timeout
|
|
114
|
+
*
|
|
115
|
+
* Requirements: 11.1, 11.2, 11.3, 11.4, 11.5
|
|
116
|
+
*/
|
|
117
|
+
async runWithTimeout(action, params) {
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
const timeoutId = setTimeout(() => {
|
|
120
|
+
reject(new ActionTimeoutError(action.id, action.timeout));
|
|
121
|
+
}, action.timeout);
|
|
122
|
+
Promise.resolve(action.handler(params, this.context))
|
|
123
|
+
.then(result => {
|
|
124
|
+
clearTimeout(timeoutId);
|
|
125
|
+
resolve(result);
|
|
126
|
+
})
|
|
127
|
+
.catch(error => {
|
|
128
|
+
clearTimeout(timeoutId);
|
|
129
|
+
reject(error);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Retrieves an action definition by ID.
|
|
135
|
+
* For internal use.
|
|
136
|
+
*
|
|
137
|
+
* @param id - The action identifier
|
|
138
|
+
* @returns The action definition or null if not found
|
|
139
|
+
*
|
|
140
|
+
* Requirement: 13.2
|
|
141
|
+
*/
|
|
142
|
+
getAction(id) {
|
|
143
|
+
return this.actions.get(id) ?? null;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Retrieves all registered action definitions.
|
|
147
|
+
* Returns a copy to prevent external mutation of internal state.
|
|
148
|
+
*
|
|
149
|
+
* @returns Array of all registered action definitions
|
|
150
|
+
*
|
|
151
|
+
* Requirements: 10.1, 10.2, 10.3, 10.4, 10.5, 13.2
|
|
152
|
+
*/
|
|
153
|
+
getAllActions() {
|
|
154
|
+
return Array.from(this.actions.values());
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Clears all registered actions.
|
|
158
|
+
* Used during shutdown to release resources.
|
|
159
|
+
*
|
|
160
|
+
* Requirement: 13.5
|
|
161
|
+
*/
|
|
162
|
+
clear() {
|
|
163
|
+
this.actions.clear();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=action-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-engine.js","sourceRoot":"","sources":["../src/action-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Logger } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* EventBus subsystem for publish-subscribe event communication.
|
|
4
|
+
* Provides O(1) lookup performance using Map-based storage.
|
|
5
|
+
* Events are scoped to a Runtime Instance and handlers are invoked synchronously.
|
|
6
|
+
*
|
|
7
|
+
* Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 13.4, 13.5, 2.1, 2.2, 2.3, 2.4, 2.5
|
|
8
|
+
*/
|
|
9
|
+
export declare class EventBus {
|
|
10
|
+
private handlers;
|
|
11
|
+
private logger;
|
|
12
|
+
constructor(logger: Logger);
|
|
13
|
+
/**
|
|
14
|
+
* Emits an event to all registered handlers synchronously.
|
|
15
|
+
* Handlers are invoked in registration order.
|
|
16
|
+
* Handler errors are caught, logged, and do not prevent other handlers from executing.
|
|
17
|
+
*
|
|
18
|
+
* @param event - The event name
|
|
19
|
+
* @param data - Optional data to pass to handlers
|
|
20
|
+
*
|
|
21
|
+
* Requirements: 8.2, 8.6, 8.7, 2.1, 2.2, 2.3, 2.4, 2.5
|
|
22
|
+
*/
|
|
23
|
+
emit(event: string, data?: unknown): void;
|
|
24
|
+
/**
|
|
25
|
+
* Emits an event to all registered handlers asynchronously.
|
|
26
|
+
* Returns a Promise that resolves when all handlers complete or fail.
|
|
27
|
+
* Uses Promise.allSettled to ensure all handlers are invoked even if some fail.
|
|
28
|
+
*
|
|
29
|
+
* @param event - The event name
|
|
30
|
+
* @param data - Optional data to pass to handlers
|
|
31
|
+
* @returns Promise that resolves when all handlers complete
|
|
32
|
+
*
|
|
33
|
+
* Requirements: 12.1, 12.2, 12.3, 12.4, 12.5
|
|
34
|
+
*/
|
|
35
|
+
emitAsync(event: string, data?: unknown): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Registers an event handler for a specific event.
|
|
38
|
+
* Returns an unsubscribe function that removes the handler when called.
|
|
39
|
+
*
|
|
40
|
+
* @param event - The event name
|
|
41
|
+
* @param handler - The handler function to invoke when the event is emitted
|
|
42
|
+
* @returns A function that unsubscribes the handler when called
|
|
43
|
+
*
|
|
44
|
+
* Requirements: 8.3, 8.4, 8.5, 13.4
|
|
45
|
+
*/
|
|
46
|
+
on(event: string, handler: (data: unknown) => void): () => void;
|
|
47
|
+
/**
|
|
48
|
+
* Clears all registered event handlers.
|
|
49
|
+
* Used during shutdown to release resources.
|
|
50
|
+
*
|
|
51
|
+
* Requirement: 13.5
|
|
52
|
+
*/
|
|
53
|
+
clear(): void;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=event-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;;GAMG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAK1B;;;;;;;;;OASG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAsBzC;;;;;;;;;;OAUG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB7D;;;;;;;;;OASG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAsB/D;;;;;OAKG;IACH,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventBus subsystem for publish-subscribe event communication.
|
|
3
|
+
* Provides O(1) lookup performance using Map-based storage.
|
|
4
|
+
* Events are scoped to a Runtime Instance and handlers are invoked synchronously.
|
|
5
|
+
*
|
|
6
|
+
* Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 13.4, 13.5, 2.1, 2.2, 2.3, 2.4, 2.5
|
|
7
|
+
*/
|
|
8
|
+
export class EventBus {
|
|
9
|
+
handlers;
|
|
10
|
+
logger;
|
|
11
|
+
constructor(logger) {
|
|
12
|
+
this.handlers = new Map();
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Emits an event to all registered handlers synchronously.
|
|
17
|
+
* Handlers are invoked in registration order.
|
|
18
|
+
* Handler errors are caught, logged, and do not prevent other handlers from executing.
|
|
19
|
+
*
|
|
20
|
+
* @param event - The event name
|
|
21
|
+
* @param data - Optional data to pass to handlers
|
|
22
|
+
*
|
|
23
|
+
* Requirements: 8.2, 8.6, 8.7, 2.1, 2.2, 2.3, 2.4, 2.5
|
|
24
|
+
*/
|
|
25
|
+
emit(event, data) {
|
|
26
|
+
const eventHandlers = this.handlers.get(event);
|
|
27
|
+
// If no handlers registered for this event, do nothing
|
|
28
|
+
if (!eventHandlers) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Invoke all handlers synchronously in registration order (Requirements 8.6, 8.7)
|
|
32
|
+
// Set maintains insertion order, so iteration is in registration order
|
|
33
|
+
// Wrap each handler in try-catch to ensure all handlers are invoked (Requirements 2.1, 2.2, 2.4, 2.5)
|
|
34
|
+
for (const handler of eventHandlers) {
|
|
35
|
+
try {
|
|
36
|
+
handler(data);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
// Log error with event name and error details (Requirements 2.1, 2.3)
|
|
40
|
+
this.logger.error(`Event handler for "${event}" threw error`, error);
|
|
41
|
+
// Continue invoking remaining handlers (Requirement 2.2)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Emits an event to all registered handlers asynchronously.
|
|
47
|
+
* Returns a Promise that resolves when all handlers complete or fail.
|
|
48
|
+
* Uses Promise.allSettled to ensure all handlers are invoked even if some fail.
|
|
49
|
+
*
|
|
50
|
+
* @param event - The event name
|
|
51
|
+
* @param data - Optional data to pass to handlers
|
|
52
|
+
* @returns Promise that resolves when all handlers complete
|
|
53
|
+
*
|
|
54
|
+
* Requirements: 12.1, 12.2, 12.3, 12.4, 12.5
|
|
55
|
+
*/
|
|
56
|
+
async emitAsync(event, data) {
|
|
57
|
+
const eventHandlers = this.handlers.get(event);
|
|
58
|
+
// If no handlers registered for this event, do nothing
|
|
59
|
+
if (!eventHandlers) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Invoke all handlers asynchronously using Promise.allSettled (Requirements 12.3, 12.4)
|
|
63
|
+
const promises = Array.from(eventHandlers).map(handler => Promise.resolve()
|
|
64
|
+
.then(() => handler(data))
|
|
65
|
+
.catch(error => {
|
|
66
|
+
// Log errors from failed handlers (Requirement 12.5)
|
|
67
|
+
this.logger.error(`Async event handler for "${event}" threw error`, error);
|
|
68
|
+
}));
|
|
69
|
+
// Wait for all handlers to complete or fail (Requirement 12.4)
|
|
70
|
+
await Promise.allSettled(promises);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Registers an event handler for a specific event.
|
|
74
|
+
* Returns an unsubscribe function that removes the handler when called.
|
|
75
|
+
*
|
|
76
|
+
* @param event - The event name
|
|
77
|
+
* @param handler - The handler function to invoke when the event is emitted
|
|
78
|
+
* @returns A function that unsubscribes the handler when called
|
|
79
|
+
*
|
|
80
|
+
* Requirements: 8.3, 8.4, 8.5, 13.4
|
|
81
|
+
*/
|
|
82
|
+
on(event, handler) {
|
|
83
|
+
// Get or create the Set of handlers for this event (Requirement 13.4)
|
|
84
|
+
let eventHandlers = this.handlers.get(event);
|
|
85
|
+
if (!eventHandlers) {
|
|
86
|
+
eventHandlers = new Set();
|
|
87
|
+
this.handlers.set(event, eventHandlers);
|
|
88
|
+
}
|
|
89
|
+
// Add the handler to the Set (maintains insertion order)
|
|
90
|
+
eventHandlers.add(handler);
|
|
91
|
+
// Return unsubscribe function (Requirement 8.4)
|
|
92
|
+
return () => {
|
|
93
|
+
eventHandlers?.delete(handler);
|
|
94
|
+
// Clean up empty Sets to avoid memory leaks
|
|
95
|
+
if (eventHandlers?.size === 0) {
|
|
96
|
+
this.handlers.delete(event);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Clears all registered event handlers.
|
|
102
|
+
* Used during shutdown to release resources.
|
|
103
|
+
*
|
|
104
|
+
* Requirement: 13.5
|
|
105
|
+
*/
|
|
106
|
+
clear() {
|
|
107
|
+
this.handlers.clear();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=event-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,QAAQ;IACX,QAAQ,CAA4C;IACpD,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;;;;;;OASG;IACH,IAAI,CAAC,KAAa,EAAE,IAAc;QAChC,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE/C,uDAAuD;QACvD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QAED,kFAAkF;QAClF,uEAAuE;QACvE,sGAAsG;QACtG,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,sEAAsE;gBACtE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,KAAK,eAAe,EAAE,KAAK,CAAC,CAAC;gBACrE,yDAAyD;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,SAAS,CAAC,KAAa,EAAE,IAAc;QAC3C,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE/C,uDAAuD;QACvD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QAED,wFAAwF;QACxF,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CACvD,OAAO,CAAC,OAAO,EAAE;aACd,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;aACzB,KAAK,CAAC,KAAK,CAAC,EAAE;YACb,qDAAqD;YACrD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,KAAK,eAAe,EAAE,KAAK,CAAC,CAAC;QAC7E,CAAC,CAAC,CACL,CAAC;QAEF,+DAA+D;QAC/D,MAAM,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;;;OASG;IACH,EAAE,CAAC,KAAa,EAAE,OAAgC;QAChD,sEAAsE;QACtE,IAAI,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,aAAa,GAAG,IAAI,GAAG,EAAE,CAAC;YAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QAC1C,CAAC;QAED,yDAAyD;QACzD,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAE3B,gDAAgD;QAChD,OAAO,GAAG,EAAE;YACV,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAE/B,4CAA4C;YAC5C,IAAI,aAAa,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Runtime } from './runtime.js';
|
|
2
|
+
export { ScreenRegistry } from './screen-registry.js';
|
|
3
|
+
export { ActionEngine } from './action-engine.js';
|
|
4
|
+
export { EventBus } from './event-bus.js';
|
|
5
|
+
export { PluginRegistry } from './plugin-registry.js';
|
|
6
|
+
export { UIBridge } from './ui-bridge.js';
|
|
7
|
+
export { RuntimeContextImpl } from './runtime-context.js';
|
|
8
|
+
export type { PluginDefinition, ScreenDefinition, ActionDefinition, UIProvider, RuntimeContext, Logger, RuntimeOptions, ActionMetadata, PluginMetadata, IntrospectionMetadata, IntrospectionAPI } from './types.js';
|
|
9
|
+
export { ConsoleLogger, ValidationError, DuplicateRegistrationError, ActionTimeoutError, ActionExecutionError, RuntimeState } from './types.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,MAAM,EACN,cAAc,EACd,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,aAAa,EACb,eAAe,EACf,0BAA0B,EAC1B,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACb,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Core Runtime entry point
|
|
2
|
+
// This file will export the main Runtime class and public types
|
|
3
|
+
export { Runtime } from './runtime.js';
|
|
4
|
+
export { ScreenRegistry } from './screen-registry.js';
|
|
5
|
+
export { ActionEngine } from './action-engine.js';
|
|
6
|
+
export { EventBus } from './event-bus.js';
|
|
7
|
+
export { PluginRegistry } from './plugin-registry.js';
|
|
8
|
+
export { UIBridge } from './ui-bridge.js';
|
|
9
|
+
export { RuntimeContextImpl } from './runtime-context.js';
|
|
10
|
+
export { ConsoleLogger, ValidationError, DuplicateRegistrationError, ActionTimeoutError, ActionExecutionError, RuntimeState } from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,gEAAgE;AAEhE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAe1D,OAAO,EACL,aAAa,EACb,eAAe,EACf,0BAA0B,EAC1B,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACb,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PluginDefinition, RuntimeContext, Logger } from './types.js';
|
|
2
|
+
export declare class PluginRegistry {
|
|
3
|
+
private plugins;
|
|
4
|
+
private initializedPlugins;
|
|
5
|
+
private logger;
|
|
6
|
+
constructor(logger: Logger);
|
|
7
|
+
registerPlugin(plugin: PluginDefinition): void;
|
|
8
|
+
getPlugin(name: string): PluginDefinition | null;
|
|
9
|
+
getAllPlugins(): PluginDefinition[];
|
|
10
|
+
/**
|
|
11
|
+
* Returns the names of all successfully initialized plugins.
|
|
12
|
+
* Returns an array copy to prevent external mutation.
|
|
13
|
+
*
|
|
14
|
+
* @returns Array of initialized plugin names in initialization order
|
|
15
|
+
*
|
|
16
|
+
* Requirements: 13.1, 13.2, 13.3, 13.4, 13.5
|
|
17
|
+
*/
|
|
18
|
+
getInitializedPlugins(): string[];
|
|
19
|
+
executeSetup(context: RuntimeContext): Promise<void>;
|
|
20
|
+
executeDispose(context: RuntimeContext): Promise<void>;
|
|
21
|
+
clear(): void;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=plugin-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,EAA+C,MAAM,YAAY,CAAC;AAEnH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,kBAAkB,CAAW;IACrC,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAM1B,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAoB9C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAIhD,aAAa,IAAI,gBAAgB,EAAE;IAKnC;;;;;;;OAOG;IACH,qBAAqB,IAAI,MAAM,EAAE;IAK3B,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CpD,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB5D,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ValidationError, DuplicateRegistrationError } from './types.js';
|
|
2
|
+
export class PluginRegistry {
|
|
3
|
+
plugins;
|
|
4
|
+
initializedPlugins; // Changed from Set to Array to preserve order
|
|
5
|
+
logger;
|
|
6
|
+
constructor(logger) {
|
|
7
|
+
this.plugins = new Map();
|
|
8
|
+
this.initializedPlugins = [];
|
|
9
|
+
this.logger = logger;
|
|
10
|
+
}
|
|
11
|
+
registerPlugin(plugin) {
|
|
12
|
+
// Validate required fields with ValidationError
|
|
13
|
+
if (!plugin.name || typeof plugin.name !== 'string') {
|
|
14
|
+
throw new ValidationError('Plugin', 'name');
|
|
15
|
+
}
|
|
16
|
+
if (!plugin.version || typeof plugin.version !== 'string') {
|
|
17
|
+
throw new ValidationError('Plugin', 'version', plugin.name);
|
|
18
|
+
}
|
|
19
|
+
if (!plugin.setup || typeof plugin.setup !== 'function') {
|
|
20
|
+
throw new ValidationError('Plugin', 'setup', plugin.name);
|
|
21
|
+
}
|
|
22
|
+
// Check for duplicate plugin name with DuplicateRegistrationError
|
|
23
|
+
if (this.plugins.has(plugin.name)) {
|
|
24
|
+
throw new DuplicateRegistrationError('Plugin', plugin.name);
|
|
25
|
+
}
|
|
26
|
+
this.plugins.set(plugin.name, plugin);
|
|
27
|
+
}
|
|
28
|
+
getPlugin(name) {
|
|
29
|
+
return this.plugins.get(name) ?? null;
|
|
30
|
+
}
|
|
31
|
+
getAllPlugins() {
|
|
32
|
+
// Return array copy to prevent external mutation
|
|
33
|
+
return Array.from(this.plugins.values());
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Returns the names of all successfully initialized plugins.
|
|
37
|
+
* Returns an array copy to prevent external mutation.
|
|
38
|
+
*
|
|
39
|
+
* @returns Array of initialized plugin names in initialization order
|
|
40
|
+
*
|
|
41
|
+
* Requirements: 13.1, 13.2, 13.3, 13.4, 13.5
|
|
42
|
+
*/
|
|
43
|
+
getInitializedPlugins() {
|
|
44
|
+
// Return array copy to prevent external mutation
|
|
45
|
+
return [...this.initializedPlugins];
|
|
46
|
+
}
|
|
47
|
+
async executeSetup(context) {
|
|
48
|
+
const initialized = [];
|
|
49
|
+
let failingPluginName;
|
|
50
|
+
try {
|
|
51
|
+
// Execute plugin setup callbacks sequentially in registration order
|
|
52
|
+
for (const plugin of this.plugins.values()) {
|
|
53
|
+
failingPluginName = plugin.name; // Track current plugin in case it fails
|
|
54
|
+
// Support both sync and async setup callbacks
|
|
55
|
+
await plugin.setup(context);
|
|
56
|
+
// Track successfully initialized plugins
|
|
57
|
+
initialized.push(plugin.name);
|
|
58
|
+
this.initializedPlugins.push(plugin.name);
|
|
59
|
+
this.logger.debug(`Plugin "${plugin.name}" initialized successfully`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// Rollback: dispose already-initialized plugins in reverse order
|
|
64
|
+
this.logger.error('Plugin setup failed, rolling back initialized plugins');
|
|
65
|
+
for (let i = initialized.length - 1; i >= 0; i--) {
|
|
66
|
+
const pluginName = initialized[i];
|
|
67
|
+
const plugin = this.plugins.get(pluginName);
|
|
68
|
+
if (plugin?.dispose) {
|
|
69
|
+
try {
|
|
70
|
+
await plugin.dispose(context);
|
|
71
|
+
this.logger.debug(`Rolled back plugin: ${pluginName}`);
|
|
72
|
+
}
|
|
73
|
+
catch (disposeError) {
|
|
74
|
+
this.logger.error(`Rollback dispose failed for plugin "${pluginName}"`, disposeError);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Clear initializedPlugins after rollback
|
|
79
|
+
this.initializedPlugins = [];
|
|
80
|
+
// Re-throw with context including plugin name
|
|
81
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
82
|
+
throw new Error(`Plugin "${failingPluginName}" setup failed: ${errorMessage}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async executeDispose(context) {
|
|
86
|
+
// Dispose in reverse order of initialization
|
|
87
|
+
for (let i = this.initializedPlugins.length - 1; i >= 0; i--) {
|
|
88
|
+
const pluginName = this.initializedPlugins[i];
|
|
89
|
+
const plugin = this.plugins.get(pluginName);
|
|
90
|
+
if (plugin?.dispose) {
|
|
91
|
+
try {
|
|
92
|
+
// Support both sync and async dispose callbacks
|
|
93
|
+
await plugin.dispose(context);
|
|
94
|
+
this.logger.debug(`Disposed plugin: ${pluginName}`);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
// Log dispose errors but continue cleanup
|
|
98
|
+
this.logger.error(`Plugin "${pluginName}" dispose failed`, error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
clear() {
|
|
104
|
+
this.plugins.clear();
|
|
105
|
+
this.initializedPlugins = [];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=plugin-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-registry.js","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"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"}
|