@nwire/forge 0.7.0
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 +77 -0
- package/dist/__tests__/actor-methods.test.d.ts +9 -0
- package/dist/__tests__/actor-methods.test.d.ts.map +1 -0
- package/dist/__tests__/actor-methods.test.js +210 -0
- package/dist/__tests__/actor-methods.test.js.map +1 -0
- package/dist/__tests__/actor-schema-bound.test.d.ts +6 -0
- package/dist/__tests__/actor-schema-bound.test.d.ts.map +1 -0
- package/dist/__tests__/actor-schema-bound.test.js +112 -0
- package/dist/__tests__/actor-schema-bound.test.js.map +1 -0
- package/dist/__tests__/app-capabilities.test.d.ts +19 -0
- package/dist/__tests__/app-capabilities.test.d.ts.map +1 -0
- package/dist/__tests__/app-capabilities.test.js +57 -0
- package/dist/__tests__/app-capabilities.test.js.map +1 -0
- package/dist/__tests__/cli-runner.test.d.ts +6 -0
- package/dist/__tests__/cli-runner.test.d.ts.map +1 -0
- package/dist/__tests__/cli-runner.test.js +158 -0
- package/dist/__tests__/cli-runner.test.js.map +1 -0
- package/dist/__tests__/create-app.test.d.ts +18 -0
- package/dist/__tests__/create-app.test.d.ts.map +1 -0
- package/dist/__tests__/create-app.test.js +189 -0
- package/dist/__tests__/create-app.test.js.map +1 -0
- package/dist/__tests__/cross-service-bus.test.d.ts +8 -0
- package/dist/__tests__/cross-service-bus.test.d.ts.map +1 -0
- package/dist/__tests__/cross-service-bus.test.js +139 -0
- package/dist/__tests__/cross-service-bus.test.js.map +1 -0
- package/dist/__tests__/define-schema.test.d.ts +5 -0
- package/dist/__tests__/define-schema.test.d.ts.map +1 -0
- package/dist/__tests__/define-schema.test.js +83 -0
- package/dist/__tests__/define-schema.test.js.map +1 -0
- package/dist/__tests__/dev-logger.test.d.ts +9 -0
- package/dist/__tests__/dev-logger.test.d.ts.map +1 -0
- package/dist/__tests__/dev-logger.test.js +126 -0
- package/dist/__tests__/dev-logger.test.js.map +1 -0
- package/dist/__tests__/external-call.test.d.ts +14 -0
- package/dist/__tests__/external-call.test.d.ts.map +1 -0
- package/dist/__tests__/external-call.test.js +99 -0
- package/dist/__tests__/external-call.test.js.map +1 -0
- package/dist/__tests__/framework-events.test.d.ts +13 -0
- package/dist/__tests__/framework-events.test.d.ts.map +1 -0
- package/dist/__tests__/framework-events.test.js +204 -0
- package/dist/__tests__/framework-events.test.js.map +1 -0
- package/dist/__tests__/inline-handler.test.d.ts +8 -0
- package/dist/__tests__/inline-handler.test.d.ts.map +1 -0
- package/dist/__tests__/inline-handler.test.js +101 -0
- package/dist/__tests__/inline-handler.test.js.map +1 -0
- package/dist/__tests__/lifecycle-logging.test.d.ts +12 -0
- package/dist/__tests__/lifecycle-logging.test.d.ts.map +1 -0
- package/dist/__tests__/lifecycle-logging.test.js +112 -0
- package/dist/__tests__/lifecycle-logging.test.js.map +1 -0
- package/dist/__tests__/middleware.test.d.ts +7 -0
- package/dist/__tests__/middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware.test.js +109 -0
- package/dist/__tests__/middleware.test.js.map +1 -0
- package/dist/__tests__/module-needs.test.d.ts +10 -0
- package/dist/__tests__/module-needs.test.d.ts.map +1 -0
- package/dist/__tests__/module-needs.test.js +77 -0
- package/dist/__tests__/module-needs.test.js.map +1 -0
- package/dist/__tests__/module-topo-sort.test.d.ts +15 -0
- package/dist/__tests__/module-topo-sort.test.d.ts.map +1 -0
- package/dist/__tests__/module-topo-sort.test.js +105 -0
- package/dist/__tests__/module-topo-sort.test.js.map +1 -0
- package/dist/__tests__/multi-tenancy.test.d.ts +10 -0
- package/dist/__tests__/multi-tenancy.test.d.ts.map +1 -0
- package/dist/__tests__/multi-tenancy.test.js +122 -0
- package/dist/__tests__/multi-tenancy.test.js.map +1 -0
- package/dist/__tests__/needs-topology.test.d.ts +11 -0
- package/dist/__tests__/needs-topology.test.d.ts.map +1 -0
- package/dist/__tests__/needs-topology.test.js +82 -0
- package/dist/__tests__/needs-topology.test.js.map +1 -0
- package/dist/__tests__/plugin-closure.test.d.ts +15 -0
- package/dist/__tests__/plugin-closure.test.d.ts.map +1 -0
- package/dist/__tests__/plugin-closure.test.js +140 -0
- package/dist/__tests__/plugin-closure.test.js.map +1 -0
- package/dist/__tests__/plugin.test.d.ts +10 -0
- package/dist/__tests__/plugin.test.d.ts.map +1 -0
- package/dist/__tests__/plugin.test.js +225 -0
- package/dist/__tests__/plugin.test.js.map +1 -0
- package/dist/__tests__/primitives.test.d.ts +9 -0
- package/dist/__tests__/primitives.test.d.ts.map +1 -0
- package/dist/__tests__/primitives.test.js +434 -0
- package/dist/__tests__/primitives.test.js.map +1 -0
- package/dist/__tests__/production-readiness.test.d.ts +22 -0
- package/dist/__tests__/production-readiness.test.d.ts.map +1 -0
- package/dist/__tests__/production-readiness.test.js +196 -0
- package/dist/__tests__/production-readiness.test.js.map +1 -0
- package/dist/__tests__/provider.test.d.ts +6 -0
- package/dist/__tests__/provider.test.d.ts.map +1 -0
- package/dist/__tests__/provider.test.js +122 -0
- package/dist/__tests__/provider.test.js.map +1 -0
- package/dist/__tests__/public-marker.test.d.ts +7 -0
- package/dist/__tests__/public-marker.test.d.ts.map +1 -0
- package/dist/__tests__/public-marker.test.js +54 -0
- package/dist/__tests__/public-marker.test.js.map +1 -0
- package/dist/__tests__/retry-dlq.test.d.ts +6 -0
- package/dist/__tests__/retry-dlq.test.d.ts.map +1 -0
- package/dist/__tests__/retry-dlq.test.js +68 -0
- package/dist/__tests__/retry-dlq.test.js.map +1 -0
- package/dist/__tests__/validate.test.d.ts +5 -0
- package/dist/__tests__/validate.test.d.ts.map +1 -0
- package/dist/__tests__/validate.test.js +53 -0
- package/dist/__tests__/validate.test.js.map +1 -0
- package/dist/__tests__/workflow-saga.test.d.ts +7 -0
- package/dist/__tests__/workflow-saga.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-saga.test.js +239 -0
- package/dist/__tests__/workflow-saga.test.js.map +1 -0
- package/dist/actor-store.d.ts +83 -0
- package/dist/actor-store.d.ts.map +1 -0
- package/dist/actor-store.js +85 -0
- package/dist/actor-store.js.map +1 -0
- package/dist/cli-runner.d.ts +46 -0
- package/dist/cli-runner.d.ts.map +1 -0
- package/dist/cli-runner.js +164 -0
- package/dist/cli-runner.js.map +1 -0
- package/dist/create-app.d.ts +131 -0
- package/dist/create-app.d.ts.map +1 -0
- package/dist/create-app.js +593 -0
- package/dist/create-app.js.map +1 -0
- package/dist/define-action.d.ts +148 -0
- package/dist/define-action.d.ts.map +1 -0
- package/dist/define-action.js +52 -0
- package/dist/define-action.js.map +1 -0
- package/dist/define-actor.d.ts +302 -0
- package/dist/define-actor.d.ts.map +1 -0
- package/dist/define-actor.js +294 -0
- package/dist/define-actor.js.map +1 -0
- package/dist/define-app.d.ts +104 -0
- package/dist/define-app.d.ts.map +1 -0
- package/dist/define-app.js +49 -0
- package/dist/define-app.js.map +1 -0
- package/dist/define-cron.d.ts +50 -0
- package/dist/define-cron.d.ts.map +1 -0
- package/dist/define-cron.js +34 -0
- package/dist/define-cron.js.map +1 -0
- package/dist/define-error.d.ts +10 -0
- package/dist/define-error.d.ts.map +1 -0
- package/dist/define-error.js +10 -0
- package/dist/define-error.js.map +1 -0
- package/dist/define-external-call.d.ts +85 -0
- package/dist/define-external-call.d.ts.map +1 -0
- package/dist/define-external-call.js +38 -0
- package/dist/define-external-call.js.map +1 -0
- package/dist/define-handler.d.ts +98 -0
- package/dist/define-handler.d.ts.map +1 -0
- package/dist/define-handler.js +29 -0
- package/dist/define-handler.js.map +1 -0
- package/dist/define-inbound-webhook.d.ts +82 -0
- package/dist/define-inbound-webhook.d.ts.map +1 -0
- package/dist/define-inbound-webhook.js +42 -0
- package/dist/define-inbound-webhook.js.map +1 -0
- package/dist/define-inbox.d.ts +40 -0
- package/dist/define-inbox.d.ts.map +1 -0
- package/dist/define-inbox.js +31 -0
- package/dist/define-inbox.js.map +1 -0
- package/dist/define-initializer.d.ts +54 -0
- package/dist/define-initializer.d.ts.map +1 -0
- package/dist/define-initializer.js +38 -0
- package/dist/define-initializer.js.map +1 -0
- package/dist/define-middleware.d.ts +8 -0
- package/dist/define-middleware.d.ts.map +1 -0
- package/dist/define-middleware.js +8 -0
- package/dist/define-middleware.js.map +1 -0
- package/dist/define-model.d.ts +10 -0
- package/dist/define-model.d.ts.map +1 -0
- package/dist/define-model.js +13 -0
- package/dist/define-model.js.map +1 -0
- package/dist/define-module.d.ts +157 -0
- package/dist/define-module.d.ts.map +1 -0
- package/dist/define-module.js +60 -0
- package/dist/define-module.js.map +1 -0
- package/dist/define-outbox.d.ts +47 -0
- package/dist/define-outbox.d.ts.map +1 -0
- package/dist/define-outbox.js +36 -0
- package/dist/define-outbox.js.map +1 -0
- package/dist/define-plugin.d.ts +171 -0
- package/dist/define-plugin.d.ts.map +1 -0
- package/dist/define-plugin.js +134 -0
- package/dist/define-plugin.js.map +1 -0
- package/dist/define-projection.d.ts +56 -0
- package/dist/define-projection.d.ts.map +1 -0
- package/dist/define-projection.js +44 -0
- package/dist/define-projection.js.map +1 -0
- package/dist/define-provider.d.ts +49 -0
- package/dist/define-provider.d.ts.map +1 -0
- package/dist/define-provider.js +45 -0
- package/dist/define-provider.js.map +1 -0
- package/dist/define-query.d.ts +50 -0
- package/dist/define-query.d.ts.map +1 -0
- package/dist/define-query.js +33 -0
- package/dist/define-query.js.map +1 -0
- package/dist/define-resolver.d.ts +111 -0
- package/dist/define-resolver.d.ts.map +1 -0
- package/dist/define-resolver.js +146 -0
- package/dist/define-resolver.js.map +1 -0
- package/dist/define-schema.d.ts +88 -0
- package/dist/define-schema.d.ts.map +1 -0
- package/dist/define-schema.js +72 -0
- package/dist/define-schema.js.map +1 -0
- package/dist/define-workflow.d.ts +193 -0
- package/dist/define-workflow.d.ts.map +1 -0
- package/dist/define-workflow.js +345 -0
- package/dist/define-workflow.js.map +1 -0
- package/dist/dev-logger.d.ts +41 -0
- package/dist/dev-logger.d.ts.map +1 -0
- package/dist/dev-logger.js +135 -0
- package/dist/dev-logger.js.map +1 -0
- package/dist/event-message.d.ts +37 -0
- package/dist/event-message.d.ts.map +1 -0
- package/dist/event-message.js +51 -0
- package/dist/event-message.js.map +1 -0
- package/dist/foundation.d.ts +14 -0
- package/dist/foundation.d.ts.map +1 -0
- package/dist/foundation.js +14 -0
- package/dist/foundation.js.map +1 -0
- package/dist/framework-event-bus.d.ts +13 -0
- package/dist/framework-event-bus.d.ts.map +1 -0
- package/dist/framework-event-bus.js +13 -0
- package/dist/framework-event-bus.js.map +1 -0
- package/dist/framework-events.d.ts +121 -0
- package/dist/framework-events.d.ts.map +1 -0
- package/dist/framework-events.js +67 -0
- package/dist/framework-events.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/module-surface.d.ts +47 -0
- package/dist/module-surface.d.ts.map +1 -0
- package/dist/module-surface.js +65 -0
- package/dist/module-surface.js.map +1 -0
- package/dist/projection-store.d.ts +26 -0
- package/dist/projection-store.d.ts.map +1 -0
- package/dist/projection-store.js +28 -0
- package/dist/projection-store.js.map +1 -0
- package/dist/public-marker.d.ts +35 -0
- package/dist/public-marker.d.ts.map +1 -0
- package/dist/public-marker.js +45 -0
- package/dist/public-marker.js.map +1 -0
- package/dist/response.d.ts +8 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +8 -0
- package/dist/response.js.map +1 -0
- package/dist/runtime.d.ts +497 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1083 -0
- package/dist/runtime.js.map +1 -0
- package/dist/validate.d.ts +33 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +48 -0
- package/dist/validate.js.map +1 -0
- package/dist/when.d.ts +101 -0
- package/dist/when.d.ts.map +1 -0
- package/dist/when.js +57 -0
- package/dist/when.js.map +1 -0
- package/dist/workflow-timer-store.d.ts +78 -0
- package/dist/workflow-timer-store.d.ts.map +1 -0
- package/dist/workflow-timer-store.js +56 -0
- package/dist/workflow-timer-store.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `defineWorkflow` — the unified primitive for everything event-driven that
|
|
3
|
+
* isn't an actor. Reactions, translators, and sagas all use this same call.
|
|
4
|
+
*
|
|
5
|
+
* Three sophistication levels live in one closure:
|
|
6
|
+
*
|
|
7
|
+
* • Observer / translator — one event in → side effects out.
|
|
8
|
+
* • Reaction — one event in → dispatch an action.
|
|
9
|
+
* • Saga — multi-event correlated state machine.
|
|
10
|
+
*
|
|
11
|
+
* The framework picks the runtime path:
|
|
12
|
+
* • No `data` and no `states` → plain async dispatch (zero overhead).
|
|
13
|
+
* • `data` or `states` declared → per-correlation instance state, transitions
|
|
14
|
+
* via handler return values, XState-equivalent overlap semantics
|
|
15
|
+
* (state-scoped handlers shadow root-level ones for the current state).
|
|
16
|
+
*
|
|
17
|
+
* Example shapes appear in `packages/nwire-docs/concepts/workflow.md`.
|
|
18
|
+
*/
|
|
19
|
+
import { markable } from "./public-marker.js";
|
|
20
|
+
import { timerEventName } from "./workflow-timer-store.js";
|
|
21
|
+
/**
|
|
22
|
+
* `complete` — framework-emitted pseudo-event that fires when a stateful
|
|
23
|
+
* workflow enters any state marked `final: true`. Exposed on the closure
|
|
24
|
+
* context so `on(complete, …)` can register a finalization hook.
|
|
25
|
+
*/
|
|
26
|
+
export const COMPLETE_EVENT_NAME = "__nwire/workflow.complete";
|
|
27
|
+
function isStateful(opts) {
|
|
28
|
+
if (!opts)
|
|
29
|
+
return false;
|
|
30
|
+
return "data" in opts || "states" in opts;
|
|
31
|
+
}
|
|
32
|
+
// Implementation signature — internal, accepts the union.
|
|
33
|
+
export function defineWorkflow(name,
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
+
closure, options) {
|
|
36
|
+
const stateful = isStateful(options);
|
|
37
|
+
const stateSpecs = stateful ? (options.states ?? {}) : {};
|
|
38
|
+
const finalStates = new Set();
|
|
39
|
+
for (const [n, spec] of Object.entries(stateSpecs)) {
|
|
40
|
+
if (spec.final)
|
|
41
|
+
finalStates.add(n);
|
|
42
|
+
}
|
|
43
|
+
const initialState = stateful
|
|
44
|
+
? Object.keys(stateSpecs).find((n) => !finalStates.has(n))
|
|
45
|
+
: undefined;
|
|
46
|
+
// ── Probe pass: subscribed events, declared dispatches, correlations. ──
|
|
47
|
+
const subscribed = new Set();
|
|
48
|
+
const dispatched = new Set();
|
|
49
|
+
const correlateTable = new Map();
|
|
50
|
+
const completeMarker = {
|
|
51
|
+
$kind: "workflow.complete",
|
|
52
|
+
name: COMPLETE_EVENT_NAME,
|
|
53
|
+
};
|
|
54
|
+
const probeOn = (event, _handler, opts) => {
|
|
55
|
+
const eventName = event.name;
|
|
56
|
+
// Timer subscriptions use a canonical synthesized name so the runtime
|
|
57
|
+
// can route fires by name alone.
|
|
58
|
+
const subscribedName = event.$kind === "workflow-timer"
|
|
59
|
+
? timerEventName(name, eventName)
|
|
60
|
+
: eventName;
|
|
61
|
+
subscribed.add(subscribedName);
|
|
62
|
+
for (const a of opts?.dispatches ?? [])
|
|
63
|
+
dispatched.add(a.name);
|
|
64
|
+
};
|
|
65
|
+
const probeStates = stateful ? buildProbeStateCallables(stateSpecs) : {};
|
|
66
|
+
const probeCtx = stateful
|
|
67
|
+
? {
|
|
68
|
+
on: probeOn,
|
|
69
|
+
send: async () => undefined,
|
|
70
|
+
enqueue: async () => undefined,
|
|
71
|
+
publish: async () => undefined,
|
|
72
|
+
data: {},
|
|
73
|
+
states: probeStates,
|
|
74
|
+
complete: completeMarker,
|
|
75
|
+
assign: async () => undefined,
|
|
76
|
+
timeout: (timerName, delay) => ({ $kind: "workflow-timer", name: timerName, delay }),
|
|
77
|
+
schedule: async () => undefined,
|
|
78
|
+
}
|
|
79
|
+
: {
|
|
80
|
+
on: probeOn,
|
|
81
|
+
send: async () => undefined,
|
|
82
|
+
enqueue: async () => undefined,
|
|
83
|
+
publish: async () => undefined,
|
|
84
|
+
};
|
|
85
|
+
closure(probeCtx);
|
|
86
|
+
if (stateful && options?.correlate) {
|
|
87
|
+
const map = (event, picker) => {
|
|
88
|
+
correlateTable.set(event.name, picker);
|
|
89
|
+
};
|
|
90
|
+
options.correlate(map);
|
|
91
|
+
}
|
|
92
|
+
const correlate = stateful
|
|
93
|
+
? (event) => {
|
|
94
|
+
const picker = correlateTable.get(event.eventName);
|
|
95
|
+
return picker ? picker(event.payload) : undefined;
|
|
96
|
+
}
|
|
97
|
+
: undefined;
|
|
98
|
+
const built = {
|
|
99
|
+
$kind: "workflow",
|
|
100
|
+
name,
|
|
101
|
+
description: options?.description,
|
|
102
|
+
subscribedEvents: subscribed,
|
|
103
|
+
dispatchedActions: dispatched,
|
|
104
|
+
stateful,
|
|
105
|
+
finalStates,
|
|
106
|
+
initialState,
|
|
107
|
+
correlate,
|
|
108
|
+
async _fire(event, fireCtx) {
|
|
109
|
+
if (!stateful) {
|
|
110
|
+
await fireStateless({ closure, event, fireCtx, completeMarker });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
await fireStateful({
|
|
114
|
+
name,
|
|
115
|
+
closure,
|
|
116
|
+
event,
|
|
117
|
+
fireCtx,
|
|
118
|
+
stateSpecs,
|
|
119
|
+
finalStates,
|
|
120
|
+
initialState: initialState ?? "",
|
|
121
|
+
completeMarker,
|
|
122
|
+
correlate,
|
|
123
|
+
// Pass the data schema so fresh instances seed with Zod defaults.
|
|
124
|
+
dataSchema: stateful ? options.data : undefined,
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
return markable(built);
|
|
129
|
+
}
|
|
130
|
+
async function fireStateless({ closure, event, fireCtx, completeMarker, }) {
|
|
131
|
+
const matched = [];
|
|
132
|
+
const completeHandlers = [];
|
|
133
|
+
const ctx = {
|
|
134
|
+
on: ((subscribedEvent, handler) => {
|
|
135
|
+
const eventName = subscribedEvent.name;
|
|
136
|
+
if (eventName === completeMarker.name) {
|
|
137
|
+
completeHandlers.push(handler);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (eventName === event.eventName) {
|
|
141
|
+
matched.push(handler);
|
|
142
|
+
}
|
|
143
|
+
}),
|
|
144
|
+
send: fireCtx.send,
|
|
145
|
+
enqueue: fireCtx.enqueue,
|
|
146
|
+
publish: fireCtx.publish,
|
|
147
|
+
};
|
|
148
|
+
closure(ctx);
|
|
149
|
+
for (const h of matched) {
|
|
150
|
+
await h(event.payload);
|
|
151
|
+
}
|
|
152
|
+
// `complete` for a stateless workflow fires after each successful event.
|
|
153
|
+
if (matched.length > 0) {
|
|
154
|
+
for (const c of completeHandlers)
|
|
155
|
+
await c();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function fireStateful(args) {
|
|
159
|
+
const { name, closure, event, fireCtx, stateSpecs, finalStates, initialState, completeMarker, correlate, dataSchema, } = args;
|
|
160
|
+
// Correlation: which instance owns this event?
|
|
161
|
+
// • If the workflow declared `correlate(map)` and registered a picker
|
|
162
|
+
// for this event, use the picker's output as the key.
|
|
163
|
+
// • Otherwise (singleton workflow / no correlation), use `__default__`.
|
|
164
|
+
// Prefer an explicit override (timer fires hand the stored key down);
|
|
165
|
+
// otherwise derive from the user's correlate map; finally fall back to
|
|
166
|
+
// a singleton default for workflows that don't declare correlation.
|
|
167
|
+
const key = fireCtx.correlationKey ?? correlate?.(event) ?? "__default__";
|
|
168
|
+
let instance = fireCtx.load(key);
|
|
169
|
+
if (!instance) {
|
|
170
|
+
// Seed with Zod-declared defaults so handlers see typed initial values
|
|
171
|
+
// (e.g. `attempts: 0`) instead of `undefined`. If parsing the empty
|
|
172
|
+
// object fails (schema has required fields without defaults), fall
|
|
173
|
+
// back to `{}` so the handler can choose how to populate via assign().
|
|
174
|
+
let seed = {};
|
|
175
|
+
if (dataSchema) {
|
|
176
|
+
const parsed = dataSchema.safeParse({});
|
|
177
|
+
if (parsed.success)
|
|
178
|
+
seed = parsed.data;
|
|
179
|
+
}
|
|
180
|
+
instance = { state: initialState, data: seed, scopedEvents: [] };
|
|
181
|
+
}
|
|
182
|
+
const stateRegistrations = new Map();
|
|
183
|
+
const globalHandlers = [];
|
|
184
|
+
const completeHandlers = [];
|
|
185
|
+
let scope = { kind: "global" };
|
|
186
|
+
const states = buildFireStateCallables(stateSpecs, stateRegistrations);
|
|
187
|
+
const dataView = new Proxy({}, {
|
|
188
|
+
get: (_, prop) => instance.data[prop],
|
|
189
|
+
});
|
|
190
|
+
const onImpl = (subscribedEvent, handler, opts) => {
|
|
191
|
+
const rawName = subscribedEvent.name;
|
|
192
|
+
if (rawName === completeMarker.name) {
|
|
193
|
+
if (scope.kind === "global") {
|
|
194
|
+
completeHandlers.push(handler);
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// Timer subscriptions use the canonical synthesized event name so the
|
|
199
|
+
// runtime's fire path matches by name alone.
|
|
200
|
+
const isTimer = subscribedEvent.$kind === "workflow-timer";
|
|
201
|
+
const eventName = isTimer ? timerEventName(name, rawName) : rawName;
|
|
202
|
+
const entry = {
|
|
203
|
+
eventName,
|
|
204
|
+
handler: handler,
|
|
205
|
+
opts,
|
|
206
|
+
stateFilter: opts?.in ?? [],
|
|
207
|
+
};
|
|
208
|
+
if (scope.kind === "collect") {
|
|
209
|
+
scope.into.push(entry);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
globalHandlers.push(entry);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const ctx = {
|
|
216
|
+
on: onImpl,
|
|
217
|
+
async send(action, input) {
|
|
218
|
+
if (scope.kind === "collect")
|
|
219
|
+
return undefined;
|
|
220
|
+
return fireCtx.send(action, input);
|
|
221
|
+
},
|
|
222
|
+
async enqueue(action, input) {
|
|
223
|
+
if (scope.kind === "collect")
|
|
224
|
+
return;
|
|
225
|
+
await fireCtx.enqueue(action, input);
|
|
226
|
+
},
|
|
227
|
+
async publish(eventMsg) {
|
|
228
|
+
if (scope.kind === "collect")
|
|
229
|
+
return;
|
|
230
|
+
await fireCtx.publish(eventMsg);
|
|
231
|
+
},
|
|
232
|
+
data: dataView,
|
|
233
|
+
states,
|
|
234
|
+
complete: completeMarker,
|
|
235
|
+
async assign(patch) {
|
|
236
|
+
if (scope.kind === "collect")
|
|
237
|
+
return;
|
|
238
|
+
instance.data = { ...instance.data, ...patch };
|
|
239
|
+
// Write-through to the store so recursive workflow fires triggered by
|
|
240
|
+
// `send()` from the same handler see the updated state. Without this,
|
|
241
|
+
// a saga that retries via `send(action)` re-enters fireStateful, calls
|
|
242
|
+
// `fireCtx.load(key)`, gets back undefined (no save yet), re-runs with
|
|
243
|
+
// defaults — and recurses infinitely. Discovered debugging the
|
|
244
|
+
// payment-renewal saga's retry path.
|
|
245
|
+
fireCtx.save(key, instance);
|
|
246
|
+
},
|
|
247
|
+
timeout(timerName, delay) {
|
|
248
|
+
return { $kind: "workflow-timer", name: timerName, delay };
|
|
249
|
+
},
|
|
250
|
+
async schedule(timer, payload) {
|
|
251
|
+
if (scope.kind === "collect")
|
|
252
|
+
return;
|
|
253
|
+
await fireCtx.scheduleTimer(timer.name, timer.delay, payload);
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
closure(ctx);
|
|
257
|
+
// Find the winning handler for this event in the current state.
|
|
258
|
+
// 1. Re-run the current state's entry body in `collect` mode so any
|
|
259
|
+
// nested `on(...)` inside `state(() => {...})` lands in a
|
|
260
|
+
// state-local list. These shadow root-level handlers.
|
|
261
|
+
// 2. Else, among globalHandlers with `in:[…]` constraints that include
|
|
262
|
+
// current state, pick the first match (state-scoped via opts.in).
|
|
263
|
+
// 3. Else, among globalHandlers with no constraint, pick the first match.
|
|
264
|
+
const stateScopedHandlers = [];
|
|
265
|
+
const stateReg = stateRegistrations.get(instance.state);
|
|
266
|
+
if (stateReg) {
|
|
267
|
+
const prev = scope;
|
|
268
|
+
scope = { kind: "collect", into: stateScopedHandlers };
|
|
269
|
+
try {
|
|
270
|
+
await stateReg.body();
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
scope = prev;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const matches = (h) => {
|
|
277
|
+
if (h.eventName !== event.eventName)
|
|
278
|
+
return false;
|
|
279
|
+
if (h.stateFilter.length === 0)
|
|
280
|
+
return true;
|
|
281
|
+
return h.stateFilter.includes(instance.state);
|
|
282
|
+
};
|
|
283
|
+
// XState semantics: state-scoped wins over root.
|
|
284
|
+
const chosen = stateScopedHandlers.find((h) => h.eventName === event.eventName) ??
|
|
285
|
+
globalHandlers.find((h) => matches(h) && h.stateFilter.length > 0) ??
|
|
286
|
+
globalHandlers.find((h) => matches(h) && h.stateFilter.length === 0);
|
|
287
|
+
if (!chosen) {
|
|
288
|
+
fireCtx.save(key, instance);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const next = await chosen.handler(event.payload);
|
|
292
|
+
// Persist any assign() effects before the transition.
|
|
293
|
+
fireCtx.save(key, instance);
|
|
294
|
+
if (next && typeof next === "string" && stateSpecs[next]) {
|
|
295
|
+
instance.state = next;
|
|
296
|
+
// Run the new state's entry body so its effects fire and state-scoped
|
|
297
|
+
// subscriptions populate for the next event.
|
|
298
|
+
const newReg = stateRegistrations.get(next);
|
|
299
|
+
if (newReg) {
|
|
300
|
+
const innerTransition = await newReg.body();
|
|
301
|
+
// The entry body itself may return a state to transition into
|
|
302
|
+
// (early-exit pattern from the docs).
|
|
303
|
+
if (innerTransition && typeof innerTransition === "string" && stateSpecs[innerTransition]) {
|
|
304
|
+
instance.state = innerTransition;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
fireCtx.save(key, instance);
|
|
308
|
+
if (finalStates.has(instance.state)) {
|
|
309
|
+
for (const c of completeHandlers)
|
|
310
|
+
await c();
|
|
311
|
+
fireCtx.drop(key);
|
|
312
|
+
void name; // reserved for richer instance keying (multi-workflow same correlation)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// ─── State callable factories ───────────────────────────────────────
|
|
317
|
+
function buildProbeStateCallables(specs) {
|
|
318
|
+
const out = {};
|
|
319
|
+
for (const [name, spec] of Object.entries(specs)) {
|
|
320
|
+
const callable = ((_body) => {
|
|
321
|
+
// probe pass: ignore body — we only want to count states + flag final
|
|
322
|
+
});
|
|
323
|
+
Object.defineProperties(callable, {
|
|
324
|
+
$name: { value: name, enumerable: true },
|
|
325
|
+
$final: { value: !!spec.final, enumerable: true },
|
|
326
|
+
});
|
|
327
|
+
out[name] = callable;
|
|
328
|
+
}
|
|
329
|
+
return out;
|
|
330
|
+
}
|
|
331
|
+
function buildFireStateCallables(specs, registrations) {
|
|
332
|
+
const out = {};
|
|
333
|
+
for (const [name, spec] of Object.entries(specs)) {
|
|
334
|
+
const callable = ((body) => {
|
|
335
|
+
registrations.set(name, { body });
|
|
336
|
+
});
|
|
337
|
+
Object.defineProperties(callable, {
|
|
338
|
+
$name: { value: name, enumerable: true },
|
|
339
|
+
$final: { value: !!spec.final, enumerable: true },
|
|
340
|
+
});
|
|
341
|
+
out[name] = callable;
|
|
342
|
+
}
|
|
343
|
+
return out;
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=define-workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-workflow.js","sourceRoot":"","sources":["../src/define-workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev console telemetry logger.
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to `runtime.onTelemetry` and prints a single colored line
|
|
5
|
+
* per interesting record. Wired by `createApp` by default so a fresh
|
|
6
|
+
* `pnpm dev` shows something useful in the terminal instead of just the
|
|
7
|
+
* boot banner.
|
|
8
|
+
*
|
|
9
|
+
* Production wires that ship a structured `Logger` (pino, winston) should
|
|
10
|
+
* pass `devLogs: false` to `createApp` — the structured pipeline takes
|
|
11
|
+
* over and dev console noise gets out of the way.
|
|
12
|
+
*
|
|
13
|
+
* The selection of "interesting" records is conservative: domain dispatch
|
|
14
|
+
* + event publish + actor transitions + reaction failures + DLQ.
|
|
15
|
+
* Orchestrator + queue/cron records are suppressed by default to keep
|
|
16
|
+
* the firehose readable.
|
|
17
|
+
*/
|
|
18
|
+
import type { Runtime, Telemetry } from "./runtime.js";
|
|
19
|
+
export interface DevLoggerOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Filter — only records whose `kind` matches one of these is printed.
|
|
22
|
+
* Default: ["action.dispatched","action.completed","action.failed",
|
|
23
|
+
* "event.published","actor.transitioned","reaction.failed","dlq.recorded"].
|
|
24
|
+
*/
|
|
25
|
+
readonly kinds?: readonly Telemetry["kind"][];
|
|
26
|
+
/**
|
|
27
|
+
* Custom sink. Default: stdout via `process.stdout.write`. Tests pass
|
|
28
|
+
* a buffer to assert without touching the real stream.
|
|
29
|
+
*/
|
|
30
|
+
readonly write?: (line: string) => void;
|
|
31
|
+
}
|
|
32
|
+
/** Format a single telemetry record as a one-liner. */
|
|
33
|
+
export declare function formatTelemetry(rec: Telemetry): string;
|
|
34
|
+
/**
|
|
35
|
+
* Attach the dev logger to a runtime. Returns an unsubscribe.
|
|
36
|
+
*
|
|
37
|
+
* Idempotent at the caller's level — call once per runtime. createApp
|
|
38
|
+
* stores the unsubscribe and calls it in stop().
|
|
39
|
+
*/
|
|
40
|
+
export declare function attachDevLogger(runtime: Runtime, options?: DevLoggerOptions): () => void;
|
|
41
|
+
//# sourceMappingURL=dev-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-logger.d.ts","sourceRoot":"","sources":["../src/dev-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;IAC9C;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAsDD,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CA+CtD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAOxF"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev console telemetry logger.
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to `runtime.onTelemetry` and prints a single colored line
|
|
5
|
+
* per interesting record. Wired by `createApp` by default so a fresh
|
|
6
|
+
* `pnpm dev` shows something useful in the terminal instead of just the
|
|
7
|
+
* boot banner.
|
|
8
|
+
*
|
|
9
|
+
* Production wires that ship a structured `Logger` (pino, winston) should
|
|
10
|
+
* pass `devLogs: false` to `createApp` — the structured pipeline takes
|
|
11
|
+
* over and dev console noise gets out of the way.
|
|
12
|
+
*
|
|
13
|
+
* The selection of "interesting" records is conservative: domain dispatch
|
|
14
|
+
* + event publish + actor transitions + reaction failures + DLQ.
|
|
15
|
+
* Orchestrator + queue/cron records are suppressed by default to keep
|
|
16
|
+
* the firehose readable.
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_KINDS = [
|
|
19
|
+
"action.dispatched",
|
|
20
|
+
"action.completed",
|
|
21
|
+
"action.failed",
|
|
22
|
+
"event.published",
|
|
23
|
+
"actor.transitioned",
|
|
24
|
+
"reaction.failed",
|
|
25
|
+
"dlq.recorded",
|
|
26
|
+
"query.executed",
|
|
27
|
+
"lifecycle",
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Render a `nwire:<ns>` tag colored by phase. A single glance distinguishes
|
|
31
|
+
* app boot from plugin lifecycle from wire mounts. The mapping is
|
|
32
|
+
* conservative — anything we don't know prints uncolored.
|
|
33
|
+
*/
|
|
34
|
+
function namespaceTag(ns) {
|
|
35
|
+
const text = `nwire:${ns}`;
|
|
36
|
+
switch (ns) {
|
|
37
|
+
case "app":
|
|
38
|
+
return color(text, BLU);
|
|
39
|
+
case "plugin":
|
|
40
|
+
return color(text, MAG);
|
|
41
|
+
case "wire":
|
|
42
|
+
return color(text, CYAN);
|
|
43
|
+
case "hook":
|
|
44
|
+
return color(text, YEL);
|
|
45
|
+
case "action":
|
|
46
|
+
return color(text, GREEN);
|
|
47
|
+
case "event":
|
|
48
|
+
return color(text, MAG);
|
|
49
|
+
default:
|
|
50
|
+
return color(text, DIM);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Minimal color helpers — no picocolors dep so forge stays leaf-clean.
|
|
54
|
+
const RESET = "\x1b[0m";
|
|
55
|
+
const DIM = "\x1b[2m";
|
|
56
|
+
const CYAN = "\x1b[36m";
|
|
57
|
+
const GREEN = "\x1b[32m";
|
|
58
|
+
const RED = "\x1b[31m";
|
|
59
|
+
const YEL = "\x1b[33m";
|
|
60
|
+
const MAG = "\x1b[35m";
|
|
61
|
+
const BLU = "\x1b[34m";
|
|
62
|
+
function color(text, code) {
|
|
63
|
+
if (!process.stdout.isTTY)
|
|
64
|
+
return text;
|
|
65
|
+
return `${code}${text}${RESET}`;
|
|
66
|
+
}
|
|
67
|
+
/** Format a single telemetry record as a one-liner. */
|
|
68
|
+
export function formatTelemetry(rec) {
|
|
69
|
+
const t = rec.ts.slice(11, 23); // HH:MM:SS.mmm
|
|
70
|
+
const dim = (s) => color(s, DIM);
|
|
71
|
+
switch (rec.kind) {
|
|
72
|
+
case "action.dispatched":
|
|
73
|
+
return `${dim(t)} ${color("→ action", CYAN)} ${rec.action}`;
|
|
74
|
+
case "action.completed":
|
|
75
|
+
return `${dim(t)} ${color("✓ action", GREEN)} ${rec.action} ${dim(`(${rec.durationMs}ms` + (rec.emittedEvents.length ? `, +${rec.emittedEvents.length} event${rec.emittedEvents.length === 1 ? "" : "s"}` : "") + ")")}`;
|
|
76
|
+
case "action.failed":
|
|
77
|
+
return `${dim(t)} ${color("✗ action", RED)} ${rec.action} ${dim(`(attempt ${rec.attempt}/${rec.maxAttempts}` + (rec.willRetry ? ", retrying" : "") + ")")} ${rec.error.message}`;
|
|
78
|
+
case "event.published":
|
|
79
|
+
return `${dim(t)} ${color("● event ", MAG)} ${rec.event.eventName} ${dim(rec.source === "external" ? "(bus)" : "")}`;
|
|
80
|
+
case "actor.transitioned":
|
|
81
|
+
return `${dim(t)} ${color("↻ actor ", YEL)} ${rec.actor}/${rec.key} ${dim(`${rec.from} → ${rec.to}`)} via ${rec.triggeringEvent}`;
|
|
82
|
+
case "reaction.failed":
|
|
83
|
+
return `${dim(t)} ${color("✗ react ", RED)} on ${rec.sourceEvent}: ${rec.error.message}`;
|
|
84
|
+
case "dlq.recorded":
|
|
85
|
+
return `${dim(t)} ${color("☠ dlq ", RED)} ${rec.action} ${dim(`(${rec.attempts} attempts)`)} ${rec.error.message}`;
|
|
86
|
+
case "query.executed":
|
|
87
|
+
return `${dim(t)} ${color("? query ", CYAN)} ${rec.query} ${dim(`(${rec.durationMs.toFixed(1)}ms)`)}`;
|
|
88
|
+
case "lifecycle": {
|
|
89
|
+
// Namespaced lifecycle log: render `nwire:<ns>` colored by phase
|
|
90
|
+
// (app / plugin / wire / hook) so the eye groups events by axis.
|
|
91
|
+
// Pad the visible tag width to 14 chars so subsequent columns
|
|
92
|
+
// line up regardless of which namespace.
|
|
93
|
+
const visibleTag = `nwire:${rec.namespace}`;
|
|
94
|
+
const padded = visibleTag.padEnd(14, " ");
|
|
95
|
+
const tag = namespaceTag(rec.namespace) + padded.slice(visibleTag.length);
|
|
96
|
+
const marker = rec.phase === "prevented" ? color("✗", RED) : color("•", DIM);
|
|
97
|
+
// Strip the leading `nwire.` from the event name — every event has
|
|
98
|
+
// it; printing it once via the colored tag is enough.
|
|
99
|
+
const shortName = rec.event.replace(/^nwire\./, "");
|
|
100
|
+
// Pull the most useful 1-2 fields out of the payload for context.
|
|
101
|
+
const p = rec.payload;
|
|
102
|
+
const ctx = [];
|
|
103
|
+
if (p) {
|
|
104
|
+
if (typeof p["pluginName"] === "string")
|
|
105
|
+
ctx.push(p["pluginName"]);
|
|
106
|
+
if (typeof p["transport"] === "string")
|
|
107
|
+
ctx.push(p["transport"]);
|
|
108
|
+
if (typeof p["reason"] === "string")
|
|
109
|
+
ctx.push(p["reason"]);
|
|
110
|
+
if (typeof p["durationMs"] === "number")
|
|
111
|
+
ctx.push(`${p["durationMs"]}ms`);
|
|
112
|
+
}
|
|
113
|
+
const ctxLine = ctx.length > 0 ? ` ${dim(ctx.join(" · "))}` : "";
|
|
114
|
+
return `${dim(t)} ${marker} ${tag} ${shortName}${ctxLine}`;
|
|
115
|
+
}
|
|
116
|
+
default:
|
|
117
|
+
return `${dim(t)} ${rec.kind}`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Attach the dev logger to a runtime. Returns an unsubscribe.
|
|
122
|
+
*
|
|
123
|
+
* Idempotent at the caller's level — call once per runtime. createApp
|
|
124
|
+
* stores the unsubscribe and calls it in stop().
|
|
125
|
+
*/
|
|
126
|
+
export function attachDevLogger(runtime, options) {
|
|
127
|
+
const kinds = new Set(options?.kinds ?? DEFAULT_KINDS);
|
|
128
|
+
const write = options?.write ?? ((line) => process.stdout.write(line + "\n"));
|
|
129
|
+
return runtime.onTelemetry((rec) => {
|
|
130
|
+
if (!kinds.has(rec.kind))
|
|
131
|
+
return;
|
|
132
|
+
write(formatTelemetry(rec));
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=dev-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-logger.js","sourceRoot":"","sources":["../src/dev-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventMessage — what the framework dispatches and actors react to.
|
|
3
|
+
*
|
|
4
|
+
* Events flow through the runtime as `{ eventName, payload, envelope }`.
|
|
5
|
+
* Domain code authors them via the callable factory returned by
|
|
6
|
+
* `eventFactory(EventDef)` — given an EventDefinition (from @nwire/messages),
|
|
7
|
+
* produces a callable that validates payload and returns an EventMessage:
|
|
8
|
+
*
|
|
9
|
+
* const flagged = AnswerFlaggedEvent({ submissionId, studentId, ... })
|
|
10
|
+
* // ^ EventMessage<typeof AnswerFlaggedEvent>
|
|
11
|
+
*
|
|
12
|
+
* Handlers return EventMessages (or arrays of them). The runtime atomically
|
|
13
|
+
* publishes them, looks up actors by their `key` field, and runs reactions.
|
|
14
|
+
*/
|
|
15
|
+
import type { EventDefinition, EventPayload } from "@nwire/messages";
|
|
16
|
+
export interface EventMessage<E extends EventDefinition = EventDefinition> {
|
|
17
|
+
readonly eventName: string;
|
|
18
|
+
readonly payload: EventPayload<E>;
|
|
19
|
+
}
|
|
20
|
+
export type EventFactory<E extends EventDefinition> = ((payload: EventPayload<E>) => EventMessage<E>) & {
|
|
21
|
+
readonly definition: E;
|
|
22
|
+
readonly name: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Wrap an `EventDefinition` into a callable factory. The factory validates
|
|
26
|
+
* the payload against the event's schema (parse, not safeParse — invalid
|
|
27
|
+
* payloads throw, surfacing programmer errors immediately).
|
|
28
|
+
*
|
|
29
|
+
* The factory carries `.definition` (the original EventDefinition) and `.name`
|
|
30
|
+
* (the event's routing name) so handlers and the runtime can introspect.
|
|
31
|
+
*/
|
|
32
|
+
export declare function eventFactory<E extends EventDefinition>(definition: E): EventFactory<E>;
|
|
33
|
+
/** Type-narrowing predicate. */
|
|
34
|
+
export declare function isEventMessage(value: unknown): value is EventMessage;
|
|
35
|
+
/** Normalize a handler's return value to an EventMessage[]. */
|
|
36
|
+
export declare function normalizeEventReturn(value: void | EventMessage | EventMessage[] | null | undefined): EventMessage[];
|
|
37
|
+
//# sourceMappingURL=event-message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-message.d.ts","sourceRoot":"","sources":["../src/event-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAErE,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe;IACvE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;CACnC;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,eAAe,IAAI,CAAC,CACrD,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,KACrB,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG;IACtB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,eAAe,EAAE,UAAU,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAYtF;AAED,gCAAgC;AAChC,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAOpE;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,EAAE,GAAG,IAAI,GAAG,SAAS,GAC7D,YAAY,EAAE,CAIhB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventMessage — what the framework dispatches and actors react to.
|
|
3
|
+
*
|
|
4
|
+
* Events flow through the runtime as `{ eventName, payload, envelope }`.
|
|
5
|
+
* Domain code authors them via the callable factory returned by
|
|
6
|
+
* `eventFactory(EventDef)` — given an EventDefinition (from @nwire/messages),
|
|
7
|
+
* produces a callable that validates payload and returns an EventMessage:
|
|
8
|
+
*
|
|
9
|
+
* const flagged = AnswerFlaggedEvent({ submissionId, studentId, ... })
|
|
10
|
+
* // ^ EventMessage<typeof AnswerFlaggedEvent>
|
|
11
|
+
*
|
|
12
|
+
* Handlers return EventMessages (or arrays of them). The runtime atomically
|
|
13
|
+
* publishes them, looks up actors by their `key` field, and runs reactions.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Wrap an `EventDefinition` into a callable factory. The factory validates
|
|
17
|
+
* the payload against the event's schema (parse, not safeParse — invalid
|
|
18
|
+
* payloads throw, surfacing programmer errors immediately).
|
|
19
|
+
*
|
|
20
|
+
* The factory carries `.definition` (the original EventDefinition) and `.name`
|
|
21
|
+
* (the event's routing name) so handlers and the runtime can introspect.
|
|
22
|
+
*/
|
|
23
|
+
export function eventFactory(definition) {
|
|
24
|
+
const factory = (payload) => ({
|
|
25
|
+
eventName: definition.name,
|
|
26
|
+
payload: definition.schema.parse(payload),
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(factory, "definition", { value: definition, enumerable: true });
|
|
29
|
+
Object.defineProperty(factory, "name", { value: definition.name, enumerable: true });
|
|
30
|
+
Object.defineProperty(factory, "toString", {
|
|
31
|
+
value: () => definition.name,
|
|
32
|
+
enumerable: false,
|
|
33
|
+
});
|
|
34
|
+
return factory;
|
|
35
|
+
}
|
|
36
|
+
/** Type-narrowing predicate. */
|
|
37
|
+
export function isEventMessage(value) {
|
|
38
|
+
return (typeof value === "object" &&
|
|
39
|
+
value !== null &&
|
|
40
|
+
typeof value.eventName === "string" &&
|
|
41
|
+
"payload" in value);
|
|
42
|
+
}
|
|
43
|
+
/** Normalize a handler's return value to an EventMessage[]. */
|
|
44
|
+
export function normalizeEventReturn(value) {
|
|
45
|
+
if (value == null)
|
|
46
|
+
return [];
|
|
47
|
+
if (Array.isArray(value))
|
|
48
|
+
return value;
|
|
49
|
+
return [value];
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=event-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-message.js","sourceRoot":"","sources":["../src/event-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAkBH;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAA4B,UAAa;IACnE,MAAM,OAAO,GAAG,CAAC,OAAwB,EAAmB,EAAE,CAAC,CAAC;QAC9D,SAAS,EAAE,UAAU,CAAC,IAAI;QAC1B,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAoB;KAC7D,CAAC,CAAC;IACH,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE;QACzC,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI;QAC5B,UAAU,EAAE,KAAK;KAClB,CAAC,CAAC;IACH,OAAO,OAA0B,CAAC;AACpC,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAQ,KAAiC,CAAC,SAAS,KAAK,QAAQ;QAChE,SAAS,IAAI,KAAK,CACnB,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAClC,KAA8D;IAE9D,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC"}
|