@almadar/runtime 2.5.0 → 2.6.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/dist/{OrbitalServerRuntime-Bel-jQ_o.d.ts → OrbitalServerRuntime-B-QeKtKd.d.ts} +186 -14
- package/dist/OrbitalServerRuntime.d.ts +2 -2
- package/dist/OrbitalServerRuntime.js +10 -9
- package/dist/OrbitalServerRuntime.js.map +1 -1
- package/dist/ServerBridge.d.ts +3 -2
- package/dist/ServerBridge.js.map +1 -1
- package/dist/{chunk-ICTFAD3I.js → chunk-ESNML4B4.js} +2 -2
- package/dist/chunk-ESNML4B4.js.map +1 -0
- package/dist/index.d.ts +13 -173
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{types-BrbvZxzX.d.ts → types-DYcUvi4H.d.ts} +38 -20
- package/package.json +3 -3
- package/dist/chunk-ICTFAD3I.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { B as BindingContext,
|
|
2
|
-
export {
|
|
3
|
-
export { E as EntitySharingMap, a as EventBus, b as EventNamespaceMap, O as OrbitalEventRequest, c as OrbitalEventResponse, d as OrbitalServerRuntimeConfig, P as PersistenceAdapter, e as PreprocessOptions, f as PreprocessResult, g as PreprocessedSchema, R as RuntimeOrbital,
|
|
1
|
+
import { B as BindingContext, P as PatternProps, E as EffectHandlers, a as EffectContext, b as ExecutionEnvironment, c as EffectResult, T as TraitDefinition } from './types-DYcUvi4H.js';
|
|
2
|
+
export { d as Effect, e as EventListener, H as HANDLER_MANIFEST, I as IEventBus, R as RuntimeConfig, f as RuntimeEvent, g as TraitState, h as TransitionObserver, i as TransitionResult, U as Unsubscribe } from './types-DYcUvi4H.js';
|
|
3
|
+
export { E as EntitySharingMap, a as EventBus, b as EventNamespaceMap, O as OrbitalEventRequest, c as OrbitalEventResponse, d as OrbitalServerRuntimeConfig, P as PersistenceAdapter, e as PreprocessOptions, f as PreprocessResult, g as PreprocessedSchema, h as ProcessEventOptions, R as RegisteredOrbital, i as RuntimeOrbital, j as RuntimeOrbitalSchema, k as RuntimeTrait, S as StateMachineManager, l as createInitialTraitState, m as findInitialState, n as findTransition, o as getIsolatedCollectionName, p as getNamespacedEvent, q as isNamespacedEvent, r as normalizeEventKey, s as parseNamespacedEvent, t as preprocessSchema, u as processEvent } from './OrbitalServerRuntime-B-QeKtKd.js';
|
|
4
4
|
import { EvaluationContext } from '@almadar/evaluator';
|
|
5
5
|
export { EvaluationContext, createMinimalContext } from '@almadar/evaluator';
|
|
6
|
+
import { EventPayload, EntityRow } from '@almadar/core';
|
|
6
7
|
export { ServerBridgeConfig, ServerBridgeState } from './ServerBridge.js';
|
|
7
8
|
import 'express';
|
|
8
|
-
import '@almadar/core';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* BindingResolver - Platform-Agnostic Binding Resolution
|
|
@@ -36,7 +36,7 @@ import '@almadar/core';
|
|
|
36
36
|
* // { title: 'Project Alpha', total: 52 }
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
|
-
declare function interpolateProps(props:
|
|
39
|
+
declare function interpolateProps(props: PatternProps, ctx: EvaluationContext): PatternProps;
|
|
40
40
|
/**
|
|
41
41
|
* Interpolate a single value.
|
|
42
42
|
*/
|
|
@@ -57,168 +57,6 @@ declare function extractBindings(value: unknown): string[];
|
|
|
57
57
|
*/
|
|
58
58
|
declare function createContextFromBindings(bindings: BindingContext, strictBindings?: boolean): EvaluationContext;
|
|
59
59
|
|
|
60
|
-
/**
|
|
61
|
-
* StateMachineCore - Platform-Agnostic State Machine Logic
|
|
62
|
-
*
|
|
63
|
-
* Pure TypeScript implementation of trait state machine execution.
|
|
64
|
-
* Extracts the core logic from useTraitStateMachine for use on
|
|
65
|
-
* both client and server.
|
|
66
|
-
*
|
|
67
|
-
* @packageDocumentation
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Find the initial state for a trait definition.
|
|
72
|
-
*/
|
|
73
|
-
declare function findInitialState(trait: TraitDefinition): string;
|
|
74
|
-
/**
|
|
75
|
-
* Create initial trait state for a trait definition.
|
|
76
|
-
*/
|
|
77
|
-
declare function createInitialTraitState(trait: TraitDefinition): TraitState;
|
|
78
|
-
/**
|
|
79
|
-
* Find a matching transition from the current state for the given event.
|
|
80
|
-
*/
|
|
81
|
-
declare function findTransition(trait: TraitDefinition, currentState: string, eventKey: string): TraitDefinition['transitions'][0] | undefined;
|
|
82
|
-
/**
|
|
83
|
-
* Normalize event key - strip UI: prefix if present.
|
|
84
|
-
*/
|
|
85
|
-
declare function normalizeEventKey(eventKey: string): string;
|
|
86
|
-
/**
|
|
87
|
-
* Options for processing an event through the state machine.
|
|
88
|
-
*/
|
|
89
|
-
interface ProcessEventOptions {
|
|
90
|
-
/** Current trait state */
|
|
91
|
-
traitState: TraitState;
|
|
92
|
-
/** Trait definition */
|
|
93
|
-
trait: TraitDefinition;
|
|
94
|
-
/** Event key to process */
|
|
95
|
-
eventKey: string;
|
|
96
|
-
/** Event payload */
|
|
97
|
-
payload?: Record<string, unknown>;
|
|
98
|
-
/** Entity data for binding resolution */
|
|
99
|
-
entityData?: Record<string, unknown>;
|
|
100
|
-
/**
|
|
101
|
-
* Guard evaluation error handling mode. (RCG-02)
|
|
102
|
-
* - "permissive": Guard errors allow the transition (default, backwards-compatible)
|
|
103
|
-
* - "strict": Guard errors block the transition
|
|
104
|
-
*/
|
|
105
|
-
guardMode?: "strict" | "permissive";
|
|
106
|
-
/**
|
|
107
|
-
* When true, log warnings when bindings resolve to undefined. (RCG-01)
|
|
108
|
-
*/
|
|
109
|
-
strictBindings?: boolean;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Process an event through a trait's state machine.
|
|
113
|
-
*
|
|
114
|
-
* This is a pure function that:
|
|
115
|
-
* 1. Finds matching transitions
|
|
116
|
-
* 2. Evaluates guards
|
|
117
|
-
* 3. Returns the transition result (but does not execute effects)
|
|
118
|
-
*
|
|
119
|
-
* @returns TransitionResult with effects to execute
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```ts
|
|
123
|
-
* const result = processEvent({
|
|
124
|
-
* traitState: { traitName: 'Cart', currentState: 'empty', ... },
|
|
125
|
-
* trait: cartTraitDefinition,
|
|
126
|
-
* eventKey: 'ADD_ITEM',
|
|
127
|
-
* payload: { productId: '123' },
|
|
128
|
-
* });
|
|
129
|
-
*
|
|
130
|
-
* if (result.executed) {
|
|
131
|
-
* // Execute effects
|
|
132
|
-
* for (const effect of result.effects) {
|
|
133
|
-
* effectExecutor.execute(effect);
|
|
134
|
-
* }
|
|
135
|
-
* // Update state
|
|
136
|
-
* traitState.currentState = result.newState;
|
|
137
|
-
* }
|
|
138
|
-
* ```
|
|
139
|
-
*/
|
|
140
|
-
declare function processEvent(options: ProcessEventOptions): TransitionResult;
|
|
141
|
-
declare class StateMachineManager {
|
|
142
|
-
private traits;
|
|
143
|
-
private states;
|
|
144
|
-
private config;
|
|
145
|
-
private observer?;
|
|
146
|
-
private queues;
|
|
147
|
-
private processing;
|
|
148
|
-
constructor(traits?: TraitDefinition[], config?: RuntimeConfig, observer?: TransitionObserver);
|
|
149
|
-
/**
|
|
150
|
-
* Set the transition observer for runtime verification.
|
|
151
|
-
* Wire this to `verificationRegistry.recordTransition()` to enable
|
|
152
|
-
* automatic verification tracking.
|
|
153
|
-
*/
|
|
154
|
-
setObserver(observer: TransitionObserver): void;
|
|
155
|
-
/**
|
|
156
|
-
* Add a trait to the manager.
|
|
157
|
-
*/
|
|
158
|
-
addTrait(trait: TraitDefinition): void;
|
|
159
|
-
/**
|
|
160
|
-
* Remove a trait from the manager.
|
|
161
|
-
*/
|
|
162
|
-
removeTrait(traitName: string): void;
|
|
163
|
-
/**
|
|
164
|
-
* Get current state for a trait.
|
|
165
|
-
*/
|
|
166
|
-
getState(traitName: string): TraitState | undefined;
|
|
167
|
-
/**
|
|
168
|
-
* Get all current states.
|
|
169
|
-
*/
|
|
170
|
-
getAllStates(): Map<string, TraitState>;
|
|
171
|
-
/**
|
|
172
|
-
* Check if a trait can handle an event from its current state.
|
|
173
|
-
*/
|
|
174
|
-
canHandleEvent(traitName: string, eventKey: string): boolean;
|
|
175
|
-
/**
|
|
176
|
-
* Send an event to all traits.
|
|
177
|
-
*
|
|
178
|
-
* @returns Array of transition results (one per trait that had a matching transition)
|
|
179
|
-
*/
|
|
180
|
-
sendEvent(eventKey: string, payload?: Record<string, unknown>, entityData?: Record<string, unknown>): Array<{
|
|
181
|
-
traitName: string;
|
|
182
|
-
result: TransitionResult;
|
|
183
|
-
}>;
|
|
184
|
-
/**
|
|
185
|
-
* Enqueue an event into every trait's per-trait queue.
|
|
186
|
-
*
|
|
187
|
-
* Events are not processed immediately. Call `drainQueue()` for each
|
|
188
|
-
* trait to process them sequentially (actor-model guarantee: one event
|
|
189
|
-
* at a time per trait, effects fully awaited before the next event).
|
|
190
|
-
*/
|
|
191
|
-
enqueueEvent(eventKey: string, payload?: Record<string, unknown>, entityData?: Record<string, unknown>): void;
|
|
192
|
-
/**
|
|
193
|
-
* Drain a single trait's event queue, processing events sequentially.
|
|
194
|
-
*
|
|
195
|
-
* This is the core actor loop: each event is fully processed (including
|
|
196
|
-
* awaiting all effects) before the next event is dequeued. If the queue
|
|
197
|
-
* is already being drained for this trait, this call is a no-op (the
|
|
198
|
-
* running drain will pick up newly enqueued events).
|
|
199
|
-
*
|
|
200
|
-
* @param traitName - Which trait's queue to drain
|
|
201
|
-
* @param executeEffects - Async callback to run effects for a successful transition
|
|
202
|
-
*/
|
|
203
|
-
drainQueue(traitName: string, executeEffects: (traitName: string, result: TransitionResult, payload?: Record<string, unknown>) => Promise<void>): Promise<void>;
|
|
204
|
-
/**
|
|
205
|
-
* Check whether a trait's queue is currently being drained.
|
|
206
|
-
*/
|
|
207
|
-
isProcessing(traitName: string): boolean;
|
|
208
|
-
/**
|
|
209
|
-
* Get the number of pending events in a trait's queue.
|
|
210
|
-
*/
|
|
211
|
-
getQueueLength(traitName: string): number;
|
|
212
|
-
/**
|
|
213
|
-
* Reset a trait to its initial state.
|
|
214
|
-
*/
|
|
215
|
-
resetTrait(traitName: string): void;
|
|
216
|
-
/**
|
|
217
|
-
* Reset all traits to initial states.
|
|
218
|
-
*/
|
|
219
|
-
resetAll(): void;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
60
|
/**
|
|
223
61
|
* EffectExecutor - Platform-Agnostic Effect Dispatch
|
|
224
62
|
*
|
|
@@ -342,7 +180,7 @@ declare function createTestExecutor(overrides?: Partial<EffectHandlers>): Effect
|
|
|
342
180
|
* Minimal event bus interface required by the factory.
|
|
343
181
|
*/
|
|
344
182
|
interface ClientEventBus {
|
|
345
|
-
emit: (type: string, payload?:
|
|
183
|
+
emit: (type: string, payload?: EventPayload) => void;
|
|
346
184
|
}
|
|
347
185
|
/**
|
|
348
186
|
* Slot setter interface for render-ui effects.
|
|
@@ -350,7 +188,7 @@ interface ClientEventBus {
|
|
|
350
188
|
*/
|
|
351
189
|
interface SlotSetter {
|
|
352
190
|
/** Accumulate a pattern into the pending slot map */
|
|
353
|
-
addPattern: (slot: string, pattern: unknown, props?:
|
|
191
|
+
addPattern: (slot: string, pattern: unknown, props?: PatternProps) => void;
|
|
354
192
|
/** Mark a slot for clearing */
|
|
355
193
|
clearSlot: (slot: string) => void;
|
|
356
194
|
}
|
|
@@ -363,7 +201,9 @@ interface CreateClientEffectHandlersOptions {
|
|
|
363
201
|
/** Slot setter for render-ui effects */
|
|
364
202
|
slotSetter: SlotSetter;
|
|
365
203
|
/** Navigate function for navigate effects */
|
|
366
|
-
navigate?: (path: string, params?:
|
|
204
|
+
navigate?: (path: string, params?: {
|
|
205
|
+
[key: string]: string;
|
|
206
|
+
}) => void;
|
|
367
207
|
/** Notify function for notification effects */
|
|
368
208
|
notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;
|
|
369
209
|
}
|
|
@@ -402,7 +242,7 @@ declare function createClientEffectHandlers(options: CreateClientEffectHandlersO
|
|
|
402
242
|
|
|
403
243
|
interface OsHandlerContext {
|
|
404
244
|
/** Emit an event on the EventBus */
|
|
405
|
-
emitEvent: (type: string, payload:
|
|
245
|
+
emitEvent: (type: string, payload: EventPayload) => void;
|
|
406
246
|
/** Working directory for file watching (defaults to process.cwd()) */
|
|
407
247
|
cwd?: string;
|
|
408
248
|
}
|
|
@@ -431,7 +271,7 @@ interface EntitySchema {
|
|
|
431
271
|
name: string;
|
|
432
272
|
fields: EntityField[];
|
|
433
273
|
/** Pre-authored instance data from the schema (used instead of faker generation) */
|
|
434
|
-
seedData?:
|
|
274
|
+
seedData?: EntityRow[];
|
|
435
275
|
}
|
|
436
276
|
interface MockPersistenceConfig {
|
|
437
277
|
/** Seed for deterministic generation */
|
|
@@ -506,4 +346,4 @@ declare function validatePayloadShapes(traits: TraitDefinition[], emits: Map<str
|
|
|
506
346
|
*/
|
|
507
347
|
declare function buildEmitsFromTraits(traits: TraitDefinition[], explicitEmits?: Map<string, EmitDeclaration[]>): Map<string, EmitDeclaration[]>;
|
|
508
348
|
|
|
509
|
-
export { BindingContext, type ClientEventBus, type CreateClientEffectHandlersOptions, EffectContext, EffectExecutor, type EffectExecutorOptions, EffectHandlers, EffectResult, type EntityField, type EntitySchema, ExecutionEnvironment, type MockPersistenceConfig, type OsHandlerContext, type OsHandlerResult, type PayloadMismatch, type
|
|
349
|
+
export { BindingContext, type ClientEventBus, type CreateClientEffectHandlersOptions, EffectContext, EffectExecutor, type EffectExecutorOptions, EffectHandlers, EffectResult, type EntityField, type EntitySchema, ExecutionEnvironment, type MockPersistenceConfig, type OsHandlerContext, type OsHandlerResult, type PayloadMismatch, type SlotSetter, TraitDefinition, buildEmitsFromTraits, containsBindings, createClientEffectHandlers, createContextFromBindings, createTestExecutor, extractBindings, interpolateProps, interpolateValue, validatePayloadShapes };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { EffectExecutor, EventBus, HANDLER_MANIFEST, StateMachineManager, containsBindings, createContextFromBindings, createInitialTraitState, createMinimalContext, createTestExecutor, extractBindings, findInitialState, findTransition, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isNamespacedEvent, normalizeEventKey, parseNamespacedEvent, preprocessSchema, processEvent } from './chunk-
|
|
1
|
+
export { EffectExecutor, EventBus, HANDLER_MANIFEST, StateMachineManager, containsBindings, createContextFromBindings, createInitialTraitState, createMinimalContext, createTestExecutor, extractBindings, findInitialState, findTransition, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isNamespacedEvent, normalizeEventKey, parseNamespacedEvent, preprocessSchema, processEvent } from './chunk-ESNML4B4.js';
|
|
2
2
|
|
|
3
3
|
// src/ClientEffectHandlers.ts
|
|
4
4
|
function createClientEffectHandlers(options) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ClientEffectHandlers.ts","../src/PayloadValidator.ts"],"names":[],"mappings":";;;AAsEO,SAAS,2BACZ,OAAA,EACc;AACd,EAAA,MAAM,EAAE,QAAA,EAAU,UAAA,EAAY,QAAA,EAAU,QAAO,GAAI,OAAA;AAEnD,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,CAAC,KAAA,EAAe,OAAA,KAAsC;AACxD,MAAA,MAAM,gBAAgB,KAAA,CAAM,UAAA,CAAW,KAAK,CAAA,GAAI,KAAA,GAAQ,MAAM,KAAK,CAAA,CAAA;AACnE,MAAA,QAAA,CAAS,IAAA,CAAK,aAAA,EAAe,EAAE,OAAA,EAAS,CAAA;AAAA,IAC5C,CAAA;AAAA,IAEA,SAAS,YAAY;AACjB,MAAA,OAAA,CAAQ,KAAK,uEAAuE,CAAA;AAAA,IACxF,CAAA;AAAA,IAEA,KAAK,MAAM;AACP,MAAA,OAAA,CAAQ,KAAK,mEAAmE,CAAA;AAAA,IACpF,CAAA;AAAA,IAEA,aAAa,YAAY;AACrB,MAAA,OAAA,CAAQ,KAAK,2EAA2E,CAAA;AACxF,MAAA,OAAO,EAAC;AAAA,IACZ,CAAA;AAAA,IAEA,QAAA,EAAU,CAAC,IAAA,EAAc,OAAA,EAAkB,KAAA,KAAoC;AAC3E,MAAA,IAAI,YAAY,IAAA,EAAM;AAClB,QAAA,UAAA,CAAW,UAAU,IAAI,CAAA;AACzB,QAAA;AAAA,MACJ;AACA,MAAA,UAAA,CAAW,UAAA,CAAW,IAAA,EAAM,OAAA,EAAS,KAAK,CAAA;AAAA,IAC9C,CAAA;AAAA,IAEA,QAAA,EAAU,QAAA,KAAa,CAAC,IAAA,KAAiB;AACrC,MAAA,OAAA,CAAQ,IAAA,CAAK,yDAAyD,IAAI,CAAA;AAAA,IAC9E,CAAA,CAAA;AAAA,IAEA,MAAA,EAAQ,MAAA,KAAW,CAAC,GAAA,EAAa,IAAA,KAAkB;AAC/C,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,+BAAA,EAAkC,IAAI,CAAA,EAAA,CAAA,EAAM,GAAG,CAAA;AAAA,IAC/D,CAAA;AAAA,GACJ;AACJ;;;AC/CO,SAAS,qBAAA,CACZ,QACA,KAAA,EACiB;AACjB,EAAA,MAAM,aAAgC,EAAC;AAGvC,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAqD;AAC3E,EAAA,KAAA,MAAW,CAAC,SAAA,EAAW,YAAY,CAAA,IAAK,KAAA,EAAO;AAC3C,IAAA,KAAA,MAAW,QAAQ,YAAA,EAAc;AAC7B,MAAA,MAAM,MAAA,GAAS,KAAK,OAAA,EAAS,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA,IAAK,EAAC;AACpD,MAAA,SAAA,CAAU,IAAI,IAAA,CAAK,KAAA,EAAO,EAAE,SAAA,EAAW,QAAQ,CAAA;AAAA,IACnD;AAAA,EACJ;AAGA,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AACxB,IAAA,IAAI,CAAC,MAAM,OAAA,EAAS;AAEpB,IAAA,KAAA,MAAW,QAAA,IAAY,MAAM,OAAA,EAAS;AAClC,MAAA,MAAM,OAAA,GAAU,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,KAAK,CAAA;AAC5C,MAAA,IAAI,CAAC,OAAA,EAAS;AAEd,MAAA,IAAI,CAAC,SAAS,cAAA,EAAgB;AAG9B,MAAA,MAAM,WAAA,GAAc,wBAAA,CAAyB,QAAA,CAAS,cAAc,CAAA;AAEpE,MAAA,KAAA,MAAW,OAAO,WAAA,EAAa;AAC3B,QAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAG;AAC/B,UAAA,UAAA,CAAW,IAAA,CAAK;AAAA,YACZ,eAAe,KAAA,CAAM,IAAA;AAAA,YACrB,cAAc,OAAA,CAAQ,SAAA;AAAA,YACtB,OAAO,QAAA,CAAS,KAAA;AAAA,YAChB,eAAA,EAAiB,GAAA;AAAA,YACjB,iBAAiB,OAAA,CAAQ;AAAA,WAC5B,CAAA;AAAA,QACL;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,EAAA,OAAO,UAAA;AACX;AAMA,SAAS,yBAAyB,OAAA,EAA4C;AAC1E,EAAA,MAAM,OAAiB,EAAC;AAExB,EAAA,SAAS,QAAQ,KAAA,EAAsB;AACnC,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,mBAAmB,CAAA;AAC7C,MAAA,IAAI,KAAA,EAAO;AACP,QAAA,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,MACtB;AAAA,IACJ,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,IAAY,UAAU,IAAA,EAAM;AACpD,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,QAAA,KAAA,CAAM,QAAQ,OAAO,CAAA;AAAA,MACzB,CAAA,MAAO;AACH,QAAA,MAAA,CAAO,MAAA,CAAO,KAAgC,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AAAA,MACnE;AAAA,IACJ;AAAA,EACJ;AAEA,EAAA,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AACtC,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,IAAI,CAAC,CAAA;AAC5B;AASO,SAAS,oBAAA,CACZ,QACA,aAAA,EAC8B;AAE9B,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAA+B,aAAA,IAAiB,EAAE,CAAA;AAErE,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AACxB,IAAA,IAAI,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA,EAAG;AAE5B,IAAA,MAAM,YAA+B,EAAC;AACtC,IAAA,KAAA,MAAW,UAAA,IAAc,MAAM,WAAA,EAAa;AACxC,MAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AAEzB,MAAA,KAAA,MAAW,MAAA,IAAU,WAAW,OAAA,EAAS;AACrC,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC5B,QAAA,IAAI,MAAA,CAAO,CAAC,CAAA,KAAM,MAAA,IAAU,OAAO,MAAA,CAAO,CAAC,MAAM,QAAA,EAAU;AACvD,UAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AAEtB,UAAA,MAAM,UAAA,GAAa,OAAO,CAAC,CAAA;AAC3B,UAAA,MAAM,OAAA,GAAU,UAAA,GACV,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,GAAA,CAAI,CAAC,IAAA,MAAU,EAAE,IAAA,EAAK,CAAE,CAAA,GAChD,MAAA;AAGN,UAAA,IAAI,CAAC,UAAU,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,KAAU,KAAK,CAAA,EAAG;AAC3C,YAAA,SAAA,CAAU,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,UACrC;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAEA,IAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG;AACtB,MAAA,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,IAAA,EAAM,SAAS,CAAA;AAAA,IACpC;AAAA,EACJ;AAEA,EAAA,OAAO,MAAA;AACX","file":"index.js","sourcesContent":["/**\n * Client Effect Handlers Factory\n *\n * Creates the standard effect handler set for client-side trait execution.\n * Platform-agnostic — works with any UI framework that provides the required interfaces.\n *\n * @packageDocumentation\n */\n\nimport type { EffectHandlers } from './types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Minimal event bus interface required by the factory.\n */\nexport interface ClientEventBus {\n emit: (type: string, payload?: Record<string, unknown>) => void;\n}\n\n/**\n * Slot setter interface for render-ui effects.\n * The factory doesn't know about React state — it just calls this function.\n */\nexport interface SlotSetter {\n /** Accumulate a pattern into the pending slot map */\n addPattern: (slot: string, pattern: unknown, props?: Record<string, unknown>) => void;\n /** Mark a slot for clearing */\n clearSlot: (slot: string) => void;\n}\n\n/**\n * Options for creating client effect handlers.\n */\nexport interface CreateClientEffectHandlersOptions {\n /** Event bus for emit effects */\n eventBus: ClientEventBus;\n /** Slot setter for render-ui effects */\n slotSetter: SlotSetter;\n /** Navigate function for navigate effects */\n navigate?: (path: string, params?: Record<string, unknown>) => void;\n /** Notify function for notification effects */\n notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create client-side effect handlers for trait state machine execution.\n *\n * Client handles: emit, renderUI, navigate, notify\n * Server handles: persist, set, callService (logged as warnings on client)\n *\n * @example\n * ```ts\n * const handlers = createClientEffectHandlers({\n * eventBus,\n * slotSetter: {\n * addPattern: (slot, pattern, props) => pendingSlots.get(slot)?.push({ pattern, props }),\n * clearSlot: (slot) => pendingSlots.set(slot, []),\n * },\n * navigate: (path) => router.push(path),\n * notify: (msg, type) => toast[type](msg),\n * });\n * ```\n */\nexport function createClientEffectHandlers(\n options: CreateClientEffectHandlersOptions\n): EffectHandlers {\n const { eventBus, slotSetter, navigate, notify } = options;\n\n return {\n emit: (event: string, payload?: Record<string, unknown>) => {\n const prefixedEvent = event.startsWith('UI:') ? event : `UI:${event}`;\n eventBus.emit(prefixedEvent, { payload });\n },\n\n persist: async () => {\n console.warn('[ClientEffectHandlers] persist is server-side only, ignored on client');\n },\n\n set: () => {\n console.warn('[ClientEffectHandlers] set is server-side only, ignored on client');\n },\n\n callService: async () => {\n console.warn('[ClientEffectHandlers] callService is server-side only, ignored on client');\n return {};\n },\n\n renderUI: (slot: string, pattern: unknown, props?: Record<string, unknown>) => {\n if (pattern === null) {\n slotSetter.clearSlot(slot);\n return;\n }\n slotSetter.addPattern(slot, pattern, props);\n },\n\n navigate: navigate ?? ((path: string) => {\n console.warn('[ClientEffectHandlers] No navigate handler, ignoring:', path);\n }),\n\n notify: notify ?? ((msg: string, type?: string) => {\n console.log(`[ClientEffectHandlers] notify (${type}):`, msg);\n }),\n };\n}\n","/**\n * PayloadValidator - Cross-Trait Payload Shape Validation (RCG-10)\n *\n * Validates that listener `payloadMapping` references match the emitter's\n * payload field names. Catches mismatches like `@payload.task_id` when the\n * emitter defines `taskId`.\n *\n * @packageDocumentation\n */\n\nimport type { TraitDefinition } from './types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Emit declaration from a trait.\n */\ninterface EmitDeclaration {\n event: string;\n payload?: Array<{ name: string; type?: string }>;\n}\n\n/**\n * Payload validation error.\n */\nexport interface PayloadMismatch {\n /** Listening trait name */\n listenerTrait: string;\n /** Emitting trait name */\n emitterTrait: string;\n /** Event name */\n event: string;\n /** The payload field referenced in the listener's payloadMapping */\n referencedField: string;\n /** Available fields from the emitter's payload declaration */\n availableFields: string[];\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n/**\n * Validate that all listener payloadMapping references match emitter payload fields.\n *\n * @param traits - All trait definitions in the schema\n * @param emits - Emit declarations per trait (traitName → EmitDeclaration[])\n * @returns Array of payload mismatches (empty if all valid)\n *\n * @example\n * ```ts\n * const mismatches = validatePayloadShapes(traits, emitsMap);\n * for (const m of mismatches) {\n * console.warn(\n * `Trait \"${m.listenerTrait}\" references @payload.${m.referencedField} ` +\n * `for event \"${m.event}\" but emitter \"${m.emitterTrait}\" only declares: ` +\n * `${m.availableFields.join(', ')}`\n * );\n * }\n * ```\n */\nexport function validatePayloadShapes(\n traits: TraitDefinition[],\n emits: Map<string, EmitDeclaration[]>\n): PayloadMismatch[] {\n const mismatches: PayloadMismatch[] = [];\n\n // Build event→emitter lookup: event name → { traitName, payload fields }\n const emitIndex = new Map<string, { traitName: string; fields: string[] }>();\n for (const [traitName, declarations] of emits) {\n for (const decl of declarations) {\n const fields = decl.payload?.map((p) => p.name) ?? [];\n emitIndex.set(decl.event, { traitName, fields });\n }\n }\n\n // Check each listener's payloadMapping references\n for (const trait of traits) {\n if (!trait.listens) continue;\n\n for (const listener of trait.listens) {\n const emitter = emitIndex.get(listener.event);\n if (!emitter) continue; // No emitter found — separate validation concern\n\n if (!listener.payloadMapping) continue;\n\n // Extract @payload.X references from payloadMapping values\n const payloadRefs = extractPayloadReferences(listener.payloadMapping);\n\n for (const ref of payloadRefs) {\n if (!emitter.fields.includes(ref)) {\n mismatches.push({\n listenerTrait: trait.name,\n emitterTrait: emitter.traitName,\n event: listener.event,\n referencedField: ref,\n availableFields: emitter.fields,\n });\n }\n }\n }\n }\n\n return mismatches;\n}\n\n/**\n * Extract payload field references from a payloadMapping object.\n * Finds all `@payload.fieldName` patterns and returns the field names.\n */\nfunction extractPayloadReferences(mapping: Record<string, unknown>): string[] {\n const refs: string[] = [];\n\n function collect(value: unknown): void {\n if (typeof value === 'string') {\n const match = value.match(/^@payload\\.(\\w+)$/);\n if (match) {\n refs.push(match[1]);\n }\n } else if (typeof value === 'object' && value !== null) {\n if (Array.isArray(value)) {\n value.forEach(collect);\n } else {\n Object.values(value as Record<string, unknown>).forEach(collect);\n }\n }\n }\n\n Object.values(mapping).forEach(collect);\n return [...new Set(refs)];\n}\n\n/**\n * Build emit declarations map from trait definitions.\n * Extracts emits from transitions that use the `emit` effect.\n *\n * Note: This is a heuristic — it parses emit effects from transitions.\n * For full accuracy, the schema should include explicit `emits` declarations.\n */\nexport function buildEmitsFromTraits(\n traits: TraitDefinition[],\n explicitEmits?: Map<string, EmitDeclaration[]>\n): Map<string, EmitDeclaration[]> {\n // Start with explicit emits if provided\n const result = new Map<string, EmitDeclaration[]>(explicitEmits ?? []);\n\n for (const trait of traits) {\n if (result.has(trait.name)) continue; // Explicit declarations take precedence\n\n const emitDecls: EmitDeclaration[] = [];\n for (const transition of trait.transitions) {\n if (!transition.effects) continue;\n\n for (const effect of transition.effects) {\n if (!Array.isArray(effect)) continue;\n if (effect[0] === 'emit' && typeof effect[1] === 'string') {\n const event = effect[1] as string;\n // Payload is in effect[2] if present\n const payloadObj = effect[2] as Record<string, unknown> | undefined;\n const payload = payloadObj\n ? Object.keys(payloadObj).map((name) => ({ name }))\n : undefined;\n\n // Avoid duplicates\n if (!emitDecls.some((d) => d.event === event)) {\n emitDecls.push({ event, payload });\n }\n }\n }\n }\n\n if (emitDecls.length > 0) {\n result.set(trait.name, emitDecls);\n }\n }\n\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/ClientEffectHandlers.ts","../src/PayloadValidator.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Client Effect Handlers Factory\n *\n * Creates the standard effect handler set for client-side trait execution.\n * Platform-agnostic — works with any UI framework that provides the required interfaces.\n *\n * @packageDocumentation\n */\n\nimport type { EffectHandlers, EventPayload, PatternProps } from './types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Minimal event bus interface required by the factory.\n */\nexport interface ClientEventBus {\n emit: (type: string, payload?: EventPayload) => void;\n}\n\n/**\n * Slot setter interface for render-ui effects.\n * The factory doesn't know about React state — it just calls this function.\n */\nexport interface SlotSetter {\n /** Accumulate a pattern into the pending slot map */\n addPattern: (slot: string, pattern: unknown, props?: PatternProps) => void;\n /** Mark a slot for clearing */\n clearSlot: (slot: string) => void;\n}\n\n/**\n * Options for creating client effect handlers.\n */\nexport interface CreateClientEffectHandlersOptions {\n /** Event bus for emit effects */\n eventBus: ClientEventBus;\n /** Slot setter for render-ui effects */\n slotSetter: SlotSetter;\n /** Navigate function for navigate effects */\n navigate?: (path: string, params?: { [key: string]: string }) => void;\n /** Notify function for notification effects */\n notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create client-side effect handlers for trait state machine execution.\n *\n * Client handles: emit, renderUI, navigate, notify\n * Server handles: persist, set, callService (logged as warnings on client)\n *\n * @example\n * ```ts\n * const handlers = createClientEffectHandlers({\n * eventBus,\n * slotSetter: {\n * addPattern: (slot, pattern, props) => pendingSlots.get(slot)?.push({ pattern, props }),\n * clearSlot: (slot) => pendingSlots.set(slot, []),\n * },\n * navigate: (path) => router.push(path),\n * notify: (msg, type) => toast[type](msg),\n * });\n * ```\n */\nexport function createClientEffectHandlers(\n options: CreateClientEffectHandlersOptions\n): EffectHandlers {\n const { eventBus, slotSetter, navigate, notify } = options;\n\n return {\n emit: (event: string, payload?: EventPayload) => {\n const prefixedEvent = event.startsWith('UI:') ? event : `UI:${event}`;\n eventBus.emit(prefixedEvent, { payload });\n },\n\n persist: async () => {\n console.warn('[ClientEffectHandlers] persist is server-side only, ignored on client');\n },\n\n set: () => {\n console.warn('[ClientEffectHandlers] set is server-side only, ignored on client');\n },\n\n callService: async () => {\n console.warn('[ClientEffectHandlers] callService is server-side only, ignored on client');\n return {};\n },\n\n renderUI: (slot: string, pattern: unknown, props?: PatternProps) => {\n if (pattern === null) {\n slotSetter.clearSlot(slot);\n return;\n }\n slotSetter.addPattern(slot, pattern, props);\n },\n\n navigate: navigate ?? ((path: string) => {\n console.warn('[ClientEffectHandlers] No navigate handler, ignoring:', path);\n }),\n\n notify: notify ?? ((msg: string, type?: string) => {\n console.log(`[ClientEffectHandlers] notify (${type}):`, msg);\n }),\n };\n}\n","/**\n * PayloadValidator - Cross-Trait Payload Shape Validation (RCG-10)\n *\n * Validates that listener `payloadMapping` references match the emitter's\n * payload field names. Catches mismatches like `@payload.task_id` when the\n * emitter defines `taskId`.\n *\n * @packageDocumentation\n */\n\nimport type { TraitDefinition, EventPayload } from './types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Emit declaration from a trait.\n */\ninterface EmitDeclaration {\n event: string;\n payload?: Array<{ name: string; type?: string }>;\n}\n\n/**\n * Payload validation error.\n */\nexport interface PayloadMismatch {\n /** Listening trait name */\n listenerTrait: string;\n /** Emitting trait name */\n emitterTrait: string;\n /** Event name */\n event: string;\n /** The payload field referenced in the listener's payloadMapping */\n referencedField: string;\n /** Available fields from the emitter's payload declaration */\n availableFields: string[];\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n/**\n * Validate that all listener payloadMapping references match emitter payload fields.\n *\n * @param traits - All trait definitions in the schema\n * @param emits - Emit declarations per trait (traitName → EmitDeclaration[])\n * @returns Array of payload mismatches (empty if all valid)\n *\n * @example\n * ```ts\n * const mismatches = validatePayloadShapes(traits, emitsMap);\n * for (const m of mismatches) {\n * console.warn(\n * `Trait \"${m.listenerTrait}\" references @payload.${m.referencedField} ` +\n * `for event \"${m.event}\" but emitter \"${m.emitterTrait}\" only declares: ` +\n * `${m.availableFields.join(', ')}`\n * );\n * }\n * ```\n */\nexport function validatePayloadShapes(\n traits: TraitDefinition[],\n emits: Map<string, EmitDeclaration[]>\n): PayloadMismatch[] {\n const mismatches: PayloadMismatch[] = [];\n\n // Build event→emitter lookup: event name → { traitName, payload fields }\n const emitIndex = new Map<string, { traitName: string; fields: string[] }>();\n for (const [traitName, declarations] of emits) {\n for (const decl of declarations) {\n const fields = decl.payload?.map((p) => p.name) ?? [];\n emitIndex.set(decl.event, { traitName, fields });\n }\n }\n\n // Check each listener's payloadMapping references\n for (const trait of traits) {\n if (!trait.listens) continue;\n\n for (const listener of trait.listens) {\n const emitter = emitIndex.get(listener.event);\n if (!emitter) continue; // No emitter found — separate validation concern\n\n if (!listener.payloadMapping) continue;\n\n // Extract @payload.X references from payloadMapping values\n const payloadRefs = extractPayloadReferences(listener.payloadMapping);\n\n for (const ref of payloadRefs) {\n if (!emitter.fields.includes(ref)) {\n mismatches.push({\n listenerTrait: trait.name,\n emitterTrait: emitter.traitName,\n event: listener.event,\n referencedField: ref,\n availableFields: emitter.fields,\n });\n }\n }\n }\n }\n\n return mismatches;\n}\n\n/**\n * Extract payload field references from a payloadMapping object.\n * Finds all `@payload.fieldName` patterns and returns the field names.\n */\nfunction extractPayloadReferences(mapping: EventPayload): string[] {\n const refs: string[] = [];\n\n function collect(value: unknown): void {\n if (typeof value === 'string') {\n const match = value.match(/^@payload\\.(\\w+)$/);\n if (match) {\n refs.push(match[1]);\n }\n } else if (typeof value === 'object' && value !== null) {\n if (Array.isArray(value)) {\n value.forEach(collect);\n } else {\n Object.values(value as EventPayload).forEach(collect);\n }\n }\n }\n\n Object.values(mapping).forEach(collect);\n return [...new Set(refs)];\n}\n\n/**\n * Build emit declarations map from trait definitions.\n * Extracts emits from transitions that use the `emit` effect.\n *\n * Note: This is a heuristic — it parses emit effects from transitions.\n * For full accuracy, the schema should include explicit `emits` declarations.\n */\nexport function buildEmitsFromTraits(\n traits: TraitDefinition[],\n explicitEmits?: Map<string, EmitDeclaration[]>\n): Map<string, EmitDeclaration[]> {\n // Start with explicit emits if provided\n const result = new Map<string, EmitDeclaration[]>(explicitEmits ?? []);\n\n for (const trait of traits) {\n if (result.has(trait.name)) continue; // Explicit declarations take precedence\n\n const emitDecls: EmitDeclaration[] = [];\n for (const transition of trait.transitions) {\n if (!transition.effects) continue;\n\n for (const effect of transition.effects) {\n if (!Array.isArray(effect)) continue;\n if (effect[0] === 'emit' && typeof effect[1] === 'string') {\n const event = effect[1] as string;\n // Payload is in effect[2] if present\n const payloadObj = effect[2] as EventPayload | undefined;\n const payload = payloadObj\n ? Object.keys(payloadObj).map((name) => ({ name }))\n : undefined;\n\n // Avoid duplicates\n if (!emitDecls.some((d) => d.event === event)) {\n emitDecls.push({ event, payload });\n }\n }\n }\n }\n\n if (emitDecls.length > 0) {\n result.set(trait.name, emitDecls);\n }\n }\n\n return result;\n}\n"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { EventPayload, EntityRow, ServiceParams, ResolvedPatternProps } from '@almadar/core';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Unified Runtime Types
|
|
3
5
|
*
|
|
@@ -5,6 +7,13 @@
|
|
|
5
7
|
*
|
|
6
8
|
* @packageDocumentation
|
|
7
9
|
*/
|
|
10
|
+
|
|
11
|
+
/** Alias for ResolvedPatternProps to avoid breaking internal consumers */
|
|
12
|
+
type PatternProps = ResolvedPatternProps;
|
|
13
|
+
/** Configuration context */
|
|
14
|
+
type ConfigContext = {
|
|
15
|
+
[key: string]: string | number | boolean | null | undefined;
|
|
16
|
+
};
|
|
8
17
|
/**
|
|
9
18
|
* Event structure for cross-trait communication
|
|
10
19
|
*/
|
|
@@ -12,7 +21,7 @@ interface RuntimeEvent {
|
|
|
12
21
|
/** Event type (e.g., "ORDER_CONFIRMED", "TraitName.EVENT_NAME") */
|
|
13
22
|
type: string;
|
|
14
23
|
/** Event payload data */
|
|
15
|
-
payload?:
|
|
24
|
+
payload?: EventPayload;
|
|
16
25
|
/** Timestamp when event was emitted */
|
|
17
26
|
timestamp: number;
|
|
18
27
|
/** Source information for debugging */
|
|
@@ -30,7 +39,7 @@ type Unsubscribe = () => void;
|
|
|
30
39
|
*/
|
|
31
40
|
interface IEventBus {
|
|
32
41
|
/** Emit an event */
|
|
33
|
-
emit(type: string, payload?:
|
|
42
|
+
emit(type: string, payload?: EventPayload, source?: RuntimeEvent['source']): void;
|
|
34
43
|
/** Subscribe to an event */
|
|
35
44
|
on(type: string, listener: EventListener): Unsubscribe;
|
|
36
45
|
/** Subscribe to ALL events (wildcard listener) */
|
|
@@ -55,7 +64,7 @@ interface TraitState {
|
|
|
55
64
|
/** Last event that caused a transition */
|
|
56
65
|
lastEvent: string | null;
|
|
57
66
|
/** Custom context data */
|
|
58
|
-
context:
|
|
67
|
+
context: ConfigContext;
|
|
59
68
|
}
|
|
60
69
|
/**
|
|
61
70
|
* Result of processing an event through a state machine
|
|
@@ -103,7 +112,7 @@ interface TraitDefinition {
|
|
|
103
112
|
listens?: Array<{
|
|
104
113
|
event: string;
|
|
105
114
|
triggers: string;
|
|
106
|
-
payloadMapping?:
|
|
115
|
+
payloadMapping?: EventPayload;
|
|
107
116
|
}>;
|
|
108
117
|
}
|
|
109
118
|
/**
|
|
@@ -114,13 +123,13 @@ interface TraitDefinition {
|
|
|
114
123
|
*/
|
|
115
124
|
interface EffectHandlers {
|
|
116
125
|
/** Emit an event to the event bus */
|
|
117
|
-
emit: (event: string, payload?:
|
|
126
|
+
emit: (event: string, payload?: EventPayload) => void;
|
|
118
127
|
/** Persist data (create/update/delete/batch) */
|
|
119
|
-
persist: (action: 'create' | 'update' | 'delete' | 'batch', entityType: string, data?:
|
|
128
|
+
persist: (action: 'create' | 'update' | 'delete' | 'batch', entityType: string, data?: EntityRow) => Promise<void>;
|
|
120
129
|
/** Set a field value on an entity */
|
|
121
130
|
set: (entityId: string, field: string, value: unknown) => void;
|
|
122
131
|
/** Call an external service */
|
|
123
|
-
callService: (service: string, action: string, params?:
|
|
132
|
+
callService: (service: string, action: string, params?: ServiceParams) => Promise<unknown>;
|
|
124
133
|
/** Fetch entity data (server only) - returns data for client-side rendering */
|
|
125
134
|
fetch?: (entityType: string, options?: {
|
|
126
135
|
id?: string;
|
|
@@ -129,15 +138,17 @@ interface EffectHandlers {
|
|
|
129
138
|
offset?: number;
|
|
130
139
|
/** Relation fields to include (populate) in the response */
|
|
131
140
|
include?: string[];
|
|
132
|
-
}) => Promise<
|
|
141
|
+
}) => Promise<EntityRow | EntityRow[] | null>;
|
|
133
142
|
/** Spawn a new entity instance */
|
|
134
|
-
spawn?: (entityType: string, props?:
|
|
143
|
+
spawn?: (entityType: string, props?: EntityRow) => void;
|
|
135
144
|
/** Despawn (delete) an entity instance */
|
|
136
145
|
despawn?: (entityId: string) => void;
|
|
137
146
|
/** Render UI to a slot (client only) */
|
|
138
|
-
renderUI?: (slot: string, pattern: unknown, props?:
|
|
147
|
+
renderUI?: (slot: string, pattern: unknown, props?: PatternProps, priority?: number) => void;
|
|
139
148
|
/** Navigate to a route (client only) */
|
|
140
|
-
navigate?: (path: string, params?:
|
|
149
|
+
navigate?: (path: string, params?: {
|
|
150
|
+
[key: string]: string;
|
|
151
|
+
}) => void;
|
|
141
152
|
/** Show a notification (client: toast, server: log) */
|
|
142
153
|
notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;
|
|
143
154
|
/** Log a message */
|
|
@@ -149,20 +160,27 @@ interface EffectHandlers {
|
|
|
149
160
|
limit?: number;
|
|
150
161
|
offset?: number;
|
|
151
162
|
include?: string[];
|
|
152
|
-
}) => Promise<
|
|
163
|
+
}) => Promise<EntityRow | EntityRow[] | null>;
|
|
153
164
|
/** Deref: one-shot data read (server: same as fetch) */
|
|
154
165
|
deref?: (entityType: string, options?: {
|
|
155
166
|
id?: string;
|
|
156
167
|
filter?: unknown;
|
|
157
|
-
}) => Promise<
|
|
168
|
+
}) => Promise<EntityRow | EntityRow[] | null>;
|
|
158
169
|
/** Swap!: atomic read-modify-write on an entity */
|
|
159
|
-
swap?: (entityType: string, entityId: string, transform: unknown) => Promise<
|
|
170
|
+
swap?: (entityType: string, entityId: string, transform: unknown) => Promise<EntityRow | null>;
|
|
160
171
|
/** Watch: client-side reactive subscription (no-op on server) */
|
|
161
|
-
watch?: (entityType: string, options?:
|
|
172
|
+
watch?: (entityType: string, options?: {
|
|
173
|
+
id?: string;
|
|
174
|
+
filter?: unknown;
|
|
175
|
+
limit?: number;
|
|
176
|
+
}) => void;
|
|
162
177
|
/** Atomic: execute inner effects as a transaction */
|
|
163
178
|
atomic?: (effects: unknown[]) => Promise<void>;
|
|
164
179
|
/** Watch file system for changes matching glob pattern */
|
|
165
|
-
osWatchFiles?: (glob: string, options:
|
|
180
|
+
osWatchFiles?: (glob: string, options: {
|
|
181
|
+
recursive?: boolean;
|
|
182
|
+
debounce?: number;
|
|
183
|
+
}) => void;
|
|
166
184
|
/** Monitor a process by name */
|
|
167
185
|
osWatchProcess?: (name: string, subcommand?: string) => void;
|
|
168
186
|
/** Monitor a port for open/close */
|
|
@@ -183,13 +201,13 @@ interface EffectHandlers {
|
|
|
183
201
|
*/
|
|
184
202
|
interface BindingContext {
|
|
185
203
|
/** Current entity data */
|
|
186
|
-
entity?:
|
|
204
|
+
entity?: EntityRow;
|
|
187
205
|
/** Event payload data */
|
|
188
|
-
payload?:
|
|
206
|
+
payload?: EventPayload;
|
|
189
207
|
/** Current state name */
|
|
190
208
|
state?: string;
|
|
191
209
|
/** Trait-level state/config */
|
|
192
|
-
config?:
|
|
210
|
+
config?: ConfigContext;
|
|
193
211
|
/** Additional custom bindings */
|
|
194
212
|
[key: string]: unknown;
|
|
195
213
|
}
|
|
@@ -293,4 +311,4 @@ interface TransitionObserver {
|
|
|
293
311
|
*/
|
|
294
312
|
declare const HANDLER_MANIFEST: Record<ExecutionEnvironment, string[]>;
|
|
295
313
|
|
|
296
|
-
export { type BindingContext as B, type EffectHandlers as E, HANDLER_MANIFEST as H, type IEventBus as I, type RuntimeConfig as R, type
|
|
314
|
+
export { type BindingContext as B, type EffectHandlers as E, HANDLER_MANIFEST as H, type IEventBus as I, type PatternProps as P, type RuntimeConfig as R, type TraitDefinition as T, type Unsubscribe as U, type EffectContext as a, type ExecutionEnvironment as b, type EffectResult as c, type Effect as d, type EventListener as e, type RuntimeEvent as f, type TraitState as g, type TransitionObserver as h, type TransitionResult as i };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almadar/runtime",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "Interpreted runtime for Almadar orbital applications (OrbitalServerRuntime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@almadar/evaluator": ">=2.5.4",
|
|
40
40
|
"@almadar/operators": ">=2.1.3",
|
|
41
|
-
"@almadar/core": ">=2.
|
|
41
|
+
"@almadar/core": ">=2.13.0",
|
|
42
42
|
"@faker-js/faker": "^9.3.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"vitest": "^2.1.0",
|
|
54
54
|
"eslint": "10.0.0",
|
|
55
55
|
"@typescript-eslint/parser": "8.56.0",
|
|
56
|
-
"@almadar/eslint-plugin": ">=2.
|
|
56
|
+
"@almadar/eslint-plugin": ">=2.7.0"
|
|
57
57
|
},
|
|
58
58
|
"repository": {
|
|
59
59
|
"type": "git",
|