@graphrefly/graphrefly 0.1.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +234 -0
  3. package/dist/chunk-5X3LAO3B.js +1571 -0
  4. package/dist/chunk-5X3LAO3B.js.map +1 -0
  5. package/dist/chunk-6W5SGIGB.js +1793 -0
  6. package/dist/chunk-6W5SGIGB.js.map +1 -0
  7. package/dist/chunk-CP6MNKAA.js +97 -0
  8. package/dist/chunk-CP6MNKAA.js.map +1 -0
  9. package/dist/chunk-HP7OKEOE.js +107 -0
  10. package/dist/chunk-HP7OKEOE.js.map +1 -0
  11. package/dist/chunk-KWXPDASV.js +781 -0
  12. package/dist/chunk-KWXPDASV.js.map +1 -0
  13. package/dist/chunk-O3PI7W45.js +68 -0
  14. package/dist/chunk-O3PI7W45.js.map +1 -0
  15. package/dist/chunk-QW7H3ICI.js +1372 -0
  16. package/dist/chunk-QW7H3ICI.js.map +1 -0
  17. package/dist/chunk-VPS7L64N.js +4785 -0
  18. package/dist/chunk-VPS7L64N.js.map +1 -0
  19. package/dist/chunk-Z4Y4FMQN.js +1097 -0
  20. package/dist/chunk-Z4Y4FMQN.js.map +1 -0
  21. package/dist/compat/nestjs/index.cjs +4883 -0
  22. package/dist/compat/nestjs/index.cjs.map +1 -0
  23. package/dist/compat/nestjs/index.d.cts +7 -0
  24. package/dist/compat/nestjs/index.d.ts +7 -0
  25. package/dist/compat/nestjs/index.js +84 -0
  26. package/dist/compat/nestjs/index.js.map +1 -0
  27. package/dist/core/index.cjs +1632 -0
  28. package/dist/core/index.cjs.map +1 -0
  29. package/dist/core/index.d.cts +2 -0
  30. package/dist/core/index.d.ts +2 -0
  31. package/dist/core/index.js +90 -0
  32. package/dist/core/index.js.map +1 -0
  33. package/dist/extra/index.cjs +6885 -0
  34. package/dist/extra/index.cjs.map +1 -0
  35. package/dist/extra/index.d.cts +5 -0
  36. package/dist/extra/index.d.ts +5 -0
  37. package/dist/extra/index.js +290 -0
  38. package/dist/extra/index.js.map +1 -0
  39. package/dist/graph/index.cjs +3225 -0
  40. package/dist/graph/index.cjs.map +1 -0
  41. package/dist/graph/index.d.cts +3 -0
  42. package/dist/graph/index.d.ts +3 -0
  43. package/dist/graph/index.js +25 -0
  44. package/dist/graph/index.js.map +1 -0
  45. package/dist/graph-CL_ZDAj9.d.cts +605 -0
  46. package/dist/graph-D18qmsNm.d.ts +605 -0
  47. package/dist/index-B6SsZs2h.d.cts +3463 -0
  48. package/dist/index-B7eOdgEx.d.ts +449 -0
  49. package/dist/index-BHUvlQ3v.d.ts +3463 -0
  50. package/dist/index-BtK55IE2.d.ts +231 -0
  51. package/dist/index-BvhgZRHK.d.cts +231 -0
  52. package/dist/index-Bvy_6CaN.d.ts +452 -0
  53. package/dist/index-C3BMRmmp.d.cts +449 -0
  54. package/dist/index-C5mqLhMX.d.cts +452 -0
  55. package/dist/index-CP_QvbWu.d.ts +940 -0
  56. package/dist/index-D_geH2Bm.d.cts +940 -0
  57. package/dist/index.cjs +14843 -0
  58. package/dist/index.cjs.map +1 -0
  59. package/dist/index.d.cts +1517 -0
  60. package/dist/index.d.ts +1517 -0
  61. package/dist/index.js +3649 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/meta-BsF6Sag9.d.cts +607 -0
  64. package/dist/meta-BsF6Sag9.d.ts +607 -0
  65. package/dist/patterns/reactive-layout/index.cjs +4143 -0
  66. package/dist/patterns/reactive-layout/index.cjs.map +1 -0
  67. package/dist/patterns/reactive-layout/index.d.cts +3 -0
  68. package/dist/patterns/reactive-layout/index.d.ts +3 -0
  69. package/dist/patterns/reactive-layout/index.js +38 -0
  70. package/dist/patterns/reactive-layout/index.js.map +1 -0
  71. package/dist/reactive-log-BfvfNWQh.d.cts +137 -0
  72. package/dist/reactive-log-ohLmTXoZ.d.ts +137 -0
  73. package/package.json +256 -0
@@ -0,0 +1,1372 @@
1
+ import {
2
+ createWatermarkController,
3
+ fromCron,
4
+ fromTimer,
5
+ observeGraph$,
6
+ observeNode$,
7
+ reactiveLog,
8
+ toMessages$,
9
+ toObservable
10
+ } from "./chunk-KWXPDASV.js";
11
+ import {
12
+ Graph
13
+ } from "./chunk-6W5SGIGB.js";
14
+ import {
15
+ COMPLETE,
16
+ DATA,
17
+ DEFAULT_ACTOR,
18
+ ERROR,
19
+ TEARDOWN,
20
+ __decorateElement,
21
+ __decoratorStart,
22
+ __export,
23
+ __runInitializers,
24
+ batch,
25
+ derived,
26
+ node,
27
+ normalizeActor,
28
+ policy,
29
+ state,
30
+ wallClockNs
31
+ } from "./chunk-5X3LAO3B.js";
32
+
33
+ // src/compat/nestjs/index.ts
34
+ var nestjs_exports = {};
35
+ __export(nestjs_exports, {
36
+ ACTOR_KEY: () => ACTOR_KEY,
37
+ COMMAND_HANDLERS: () => COMMAND_HANDLERS,
38
+ CQRS_EVENT_HANDLERS: () => CQRS_EVENT_HANDLERS,
39
+ CRON_HANDLERS: () => CRON_HANDLERS,
40
+ CommandHandler: () => CommandHandler,
41
+ EVENT_HANDLERS: () => EVENT_HANDLERS,
42
+ EventHandler: () => EventHandler,
43
+ GRAPHREFLY_REQUEST_GRAPH: () => GRAPHREFLY_REQUEST_GRAPH,
44
+ GRAPHREFLY_ROOT_GRAPH: () => GRAPHREFLY_ROOT_GRAPH,
45
+ GraphCron: () => GraphCron,
46
+ GraphInterval: () => GraphInterval,
47
+ GraphReflyEventExplorer: () => GraphReflyEventExplorer,
48
+ GraphReflyGuard: () => GraphReflyGuard,
49
+ GraphReflyGuardImpl: () => GraphReflyGuardImpl,
50
+ GraphReflyModule: () => GraphReflyModule,
51
+ INTERVAL_HANDLERS: () => INTERVAL_HANDLERS,
52
+ InjectCqrsGraph: () => InjectCqrsGraph,
53
+ InjectGraph: () => InjectGraph,
54
+ InjectNode: () => InjectNode,
55
+ ObserveGateway: () => ObserveGateway,
56
+ OnGraphEvent: () => OnGraphEvent,
57
+ QUERY_HANDLERS: () => QUERY_HANDLERS,
58
+ QueryHandler: () => QueryHandler,
59
+ SAGA_HANDLERS: () => SAGA_HANDLERS,
60
+ SagaHandler: () => SagaHandler,
61
+ fromHeader: () => fromHeader,
62
+ fromJwtPayload: () => fromJwtPayload,
63
+ getActor: () => getActor,
64
+ getGraphToken: () => getGraphToken,
65
+ getNodeToken: () => getNodeToken,
66
+ observeGraph$: () => observeGraph$,
67
+ observeNode$: () => observeNode$,
68
+ observeSSE: () => observeSSE,
69
+ observeSubscription: () => observeSubscription,
70
+ toMessages$: () => toMessages$,
71
+ toObservable: () => toObservable
72
+ });
73
+
74
+ // src/compat/nestjs/decorators.ts
75
+ import { Inject } from "@nestjs/common";
76
+
77
+ // src/compat/nestjs/tokens.ts
78
+ var GRAPHREFLY_ROOT_GRAPH = /* @__PURE__ */ Symbol.for("graphrefly:root-graph");
79
+ var GRAPHREFLY_REQUEST_GRAPH = /* @__PURE__ */ Symbol.for("graphrefly:request-graph");
80
+ function getGraphToken(name) {
81
+ return /* @__PURE__ */ Symbol.for(`graphrefly:graph:${name}`);
82
+ }
83
+ function getNodeToken(path) {
84
+ return /* @__PURE__ */ Symbol.for(`graphrefly:node:${path}`);
85
+ }
86
+
87
+ // src/compat/nestjs/decorators.ts
88
+ var EVENT_HANDLERS = /* @__PURE__ */ new Map();
89
+ var INTERVAL_HANDLERS = /* @__PURE__ */ new Map();
90
+ var CRON_HANDLERS = /* @__PURE__ */ new Map();
91
+ var COMMAND_HANDLERS = /* @__PURE__ */ new Map();
92
+ var CQRS_EVENT_HANDLERS = /* @__PURE__ */ new Map();
93
+ var QUERY_HANDLERS = /* @__PURE__ */ new Map();
94
+ var SAGA_HANDLERS = /* @__PURE__ */ new Map();
95
+ function InjectGraph(name) {
96
+ if (name === "request") return Inject(GRAPHREFLY_REQUEST_GRAPH);
97
+ return Inject(name ? getGraphToken(name) : GRAPHREFLY_ROOT_GRAPH);
98
+ }
99
+ function InjectCqrsGraph(name) {
100
+ return Inject(getGraphToken(name));
101
+ }
102
+ function InjectNode(path) {
103
+ return Inject(getNodeToken(path));
104
+ }
105
+ function OnGraphEvent(nodeName) {
106
+ return (_value, context) => {
107
+ const methodKey = context.name;
108
+ context.addInitializer(function() {
109
+ const ctor = this.constructor;
110
+ const existing = EVENT_HANDLERS.get(ctor) ?? [];
111
+ existing.push({ nodeName, methodKey });
112
+ EVENT_HANDLERS.set(ctor, existing);
113
+ });
114
+ };
115
+ }
116
+ function GraphInterval(ms) {
117
+ return (_value, context) => {
118
+ const methodKey = context.name;
119
+ context.addInitializer(function() {
120
+ const ctor = this.constructor;
121
+ const existing = INTERVAL_HANDLERS.get(ctor) ?? [];
122
+ existing.push({ ms, methodKey });
123
+ INTERVAL_HANDLERS.set(ctor, existing);
124
+ });
125
+ };
126
+ }
127
+ function GraphCron(expr) {
128
+ return (_value, context) => {
129
+ const methodKey = context.name;
130
+ context.addInitializer(function() {
131
+ const ctor = this.constructor;
132
+ const existing = CRON_HANDLERS.get(ctor) ?? [];
133
+ existing.push({ expr, methodKey });
134
+ CRON_HANDLERS.set(ctor, existing);
135
+ });
136
+ };
137
+ }
138
+ function CommandHandler(cqrsName, commandName) {
139
+ return (_value, context) => {
140
+ const methodKey = context.name;
141
+ context.addInitializer(function() {
142
+ const ctor = this.constructor;
143
+ const existing = COMMAND_HANDLERS.get(ctor) ?? [];
144
+ existing.push({ cqrsName, commandName, methodKey });
145
+ COMMAND_HANDLERS.set(ctor, existing);
146
+ });
147
+ };
148
+ }
149
+ function EventHandler(cqrsName, eventName) {
150
+ return (_value, context) => {
151
+ const methodKey = context.name;
152
+ context.addInitializer(function() {
153
+ const ctor = this.constructor;
154
+ const existing = CQRS_EVENT_HANDLERS.get(ctor) ?? [];
155
+ existing.push({ cqrsName, eventName, methodKey });
156
+ CQRS_EVENT_HANDLERS.set(ctor, existing);
157
+ });
158
+ };
159
+ }
160
+ function QueryHandler(cqrsName, projectionName) {
161
+ return (_value, context) => {
162
+ const methodKey = context.name;
163
+ context.addInitializer(function() {
164
+ const ctor = this.constructor;
165
+ const existing = QUERY_HANDLERS.get(ctor) ?? [];
166
+ existing.push({ cqrsName, projectionName, methodKey });
167
+ QUERY_HANDLERS.set(ctor, existing);
168
+ });
169
+ };
170
+ }
171
+ function SagaHandler(cqrsName, sagaName, eventNames) {
172
+ return (_value, context) => {
173
+ const methodKey = context.name;
174
+ context.addInitializer(function() {
175
+ const ctor = this.constructor;
176
+ const existing = SAGA_HANDLERS.get(ctor) ?? [];
177
+ existing.push({ cqrsName, eventNames, sagaName, methodKey });
178
+ SAGA_HANDLERS.set(ctor, existing);
179
+ });
180
+ };
181
+ }
182
+
183
+ // src/compat/nestjs/explorer.ts
184
+ var scheduleSeq = 0;
185
+ var GraphReflyEventExplorer = class {
186
+ constructor(graph, moduleRef) {
187
+ this.graph = graph;
188
+ this.moduleRef = moduleRef;
189
+ }
190
+ disposers = [];
191
+ scheduleNodeNames = [];
192
+ onModuleInit() {
193
+ this.wireEvents();
194
+ this.wireIntervals();
195
+ this.wireCrons();
196
+ this.wireCqrsCommands();
197
+ this.wireCqrsEvents();
198
+ this.wireCqrsQueries();
199
+ this.wireCqrsSagas();
200
+ }
201
+ onModuleDestroy() {
202
+ for (const dispose of this.disposers) dispose();
203
+ this.disposers.length = 0;
204
+ for (const name of this.scheduleNodeNames) {
205
+ try {
206
+ this.graph.remove(name);
207
+ } catch {
208
+ }
209
+ }
210
+ this.scheduleNodeNames.length = 0;
211
+ }
212
+ // -----------------------------------------------------------------------
213
+ // @OnGraphEvent — reactive subscription via graph.observe()
214
+ // -----------------------------------------------------------------------
215
+ wireEvents() {
216
+ for (const [ctor, metas] of EVENT_HANDLERS) {
217
+ const instance = this.resolveInstance(ctor);
218
+ if (!instance) continue;
219
+ for (const meta of metas) {
220
+ this.wireEventHandler(instance, meta);
221
+ }
222
+ }
223
+ }
224
+ wireEventHandler(instance, meta) {
225
+ const method = instance[meta.methodKey];
226
+ if (typeof method !== "function") return;
227
+ const bound = method.bind(instance);
228
+ const handle = this.observeNode(meta.nodeName);
229
+ const unsub = handle.subscribe((msgs) => {
230
+ for (const m of msgs) {
231
+ if (m[0] === DATA) {
232
+ bound(m[1]);
233
+ }
234
+ }
235
+ });
236
+ this.disposers.push(unsub);
237
+ }
238
+ // -----------------------------------------------------------------------
239
+ // @GraphInterval — reactive via fromTimer central timer primitive
240
+ // -----------------------------------------------------------------------
241
+ wireIntervals() {
242
+ for (const [ctor, metas] of INTERVAL_HANDLERS) {
243
+ const instance = this.resolveInstance(ctor);
244
+ if (!instance) continue;
245
+ for (const meta of metas) {
246
+ this.wireIntervalHandler(instance, ctor, meta);
247
+ }
248
+ }
249
+ }
250
+ wireIntervalHandler(instance, ctor, meta) {
251
+ const method = instance[meta.methodKey];
252
+ if (typeof method !== "function") return;
253
+ const bound = method.bind(instance);
254
+ const className = ctor.name ?? "anonymous";
255
+ const nodeName = `__schedule__.${className}.${String(meta.methodKey)}.${scheduleSeq++}`;
256
+ const timerNode = fromTimer(meta.ms, { period: meta.ms, name: nodeName });
257
+ this.graph.add(nodeName, timerNode);
258
+ this.scheduleNodeNames.push(nodeName);
259
+ const handle = this.observeNode(nodeName);
260
+ const unsub = handle.subscribe((msgs) => {
261
+ for (const m of msgs) {
262
+ if (m[0] === DATA) bound(m[1]);
263
+ }
264
+ });
265
+ this.disposers.push(unsub);
266
+ }
267
+ // -----------------------------------------------------------------------
268
+ // @GraphCron — reactive via fromCron central timer primitive
269
+ // -----------------------------------------------------------------------
270
+ wireCrons() {
271
+ for (const [ctor, metas] of CRON_HANDLERS) {
272
+ const instance = this.resolveInstance(ctor);
273
+ if (!instance) continue;
274
+ for (const meta of metas) {
275
+ this.wireCronHandler(instance, ctor, meta);
276
+ }
277
+ }
278
+ }
279
+ wireCronHandler(instance, ctor, meta) {
280
+ const method = instance[meta.methodKey];
281
+ if (typeof method !== "function") return;
282
+ const bound = method.bind(instance);
283
+ const className = ctor.name ?? "anonymous";
284
+ const nodeName = `__schedule__.${className}.${String(meta.methodKey)}.${scheduleSeq++}`;
285
+ const cronNode = fromCron(meta.expr, { name: nodeName });
286
+ this.graph.add(nodeName, cronNode);
287
+ this.scheduleNodeNames.push(nodeName);
288
+ const handle = this.observeNode(nodeName);
289
+ const unsub = handle.subscribe((msgs) => {
290
+ for (const m of msgs) {
291
+ if (m[0] === DATA) bound(m[1]);
292
+ }
293
+ });
294
+ this.disposers.push(unsub);
295
+ }
296
+ // -----------------------------------------------------------------------
297
+ // @CommandHandler — register method as CqrsGraph command handler
298
+ // -----------------------------------------------------------------------
299
+ wireCqrsCommands() {
300
+ for (const [ctor, metas] of COMMAND_HANDLERS) {
301
+ const instance = this.resolveInstance(ctor);
302
+ if (!instance) continue;
303
+ for (const meta of metas) {
304
+ this.wireCqrsCommand(instance, meta);
305
+ }
306
+ }
307
+ }
308
+ wireCqrsCommand(instance, meta) {
309
+ const method = instance[meta.methodKey];
310
+ if (typeof method !== "function") return;
311
+ const bound = method.bind(instance);
312
+ const cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);
313
+ if (!cqrsGraph) return;
314
+ cqrsGraph.command(meta.commandName, bound);
315
+ }
316
+ // -----------------------------------------------------------------------
317
+ // @EventHandler — subscribe method to CQRS event stream
318
+ // -----------------------------------------------------------------------
319
+ wireCqrsEvents() {
320
+ for (const [ctor, metas] of CQRS_EVENT_HANDLERS) {
321
+ const instance = this.resolveInstance(ctor);
322
+ if (!instance) continue;
323
+ for (const meta of metas) {
324
+ this.wireCqrsEventHandler(instance, meta);
325
+ }
326
+ }
327
+ }
328
+ wireCqrsEventHandler(instance, meta) {
329
+ const method = instance[meta.methodKey];
330
+ if (typeof method !== "function") return;
331
+ const bound = method.bind(instance);
332
+ const cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);
333
+ if (!cqrsGraph) return;
334
+ cqrsGraph.event(meta.eventName);
335
+ const eventNode = cqrsGraph.resolve(meta.eventName);
336
+ const currentSnap = eventNode.get();
337
+ const existingEntries = currentSnap?.value?.entries;
338
+ let lastSeq = existingEntries && existingEntries.length > 0 ? existingEntries[existingEntries.length - 1].seq : 0;
339
+ const handle = this.observeNodeOn(cqrsGraph, meta.eventName);
340
+ const unsub = handle.subscribe((msgs) => {
341
+ for (const m of msgs) {
342
+ if (m[0] === DATA) {
343
+ const snap = m[1];
344
+ for (const entry of snap.value.entries) {
345
+ if (entry.seq > lastSeq) {
346
+ bound(entry);
347
+ lastSeq = entry.seq;
348
+ }
349
+ }
350
+ }
351
+ }
352
+ });
353
+ this.disposers.push(unsub);
354
+ }
355
+ // -----------------------------------------------------------------------
356
+ // @QueryHandler — subscribe method to CQRS projection changes
357
+ // -----------------------------------------------------------------------
358
+ wireCqrsQueries() {
359
+ for (const [ctor, metas] of QUERY_HANDLERS) {
360
+ const instance = this.resolveInstance(ctor);
361
+ if (!instance) continue;
362
+ for (const meta of metas) {
363
+ this.wireCqrsQuery(instance, meta);
364
+ }
365
+ }
366
+ }
367
+ wireCqrsQuery(instance, meta) {
368
+ const method = instance[meta.methodKey];
369
+ if (typeof method !== "function") return;
370
+ const bound = method.bind(instance);
371
+ const cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);
372
+ if (!cqrsGraph) return;
373
+ const handle = this.observeNodeOn(cqrsGraph, meta.projectionName);
374
+ const unsub = handle.subscribe((msgs) => {
375
+ for (const m of msgs) {
376
+ if (m[0] === DATA) {
377
+ bound(m[1]);
378
+ }
379
+ }
380
+ });
381
+ this.disposers.push(unsub);
382
+ }
383
+ // -----------------------------------------------------------------------
384
+ // @SagaHandler — register method as CqrsGraph saga (subgraph side effect)
385
+ // -----------------------------------------------------------------------
386
+ wireCqrsSagas() {
387
+ for (const [ctor, metas] of SAGA_HANDLERS) {
388
+ const instance = this.resolveInstance(ctor);
389
+ if (!instance) continue;
390
+ for (const meta of metas) {
391
+ this.wireCqrsSaga(instance, meta);
392
+ }
393
+ }
394
+ }
395
+ wireCqrsSaga(instance, meta) {
396
+ const method = instance[meta.methodKey];
397
+ if (typeof method !== "function") return;
398
+ const bound = method.bind(instance);
399
+ const cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);
400
+ if (!cqrsGraph) return;
401
+ cqrsGraph.saga(meta.sagaName, meta.eventNames, bound);
402
+ }
403
+ // -----------------------------------------------------------------------
404
+ // Helpers
405
+ // -----------------------------------------------------------------------
406
+ observeNode(name) {
407
+ return this.graph.observe(name);
408
+ }
409
+ observeNodeOn(graph, name) {
410
+ return graph.observe(name);
411
+ }
412
+ resolveCqrsGraph(name) {
413
+ try {
414
+ return this.moduleRef.get(getGraphToken(name), { strict: false });
415
+ } catch {
416
+ console.warn(
417
+ `[GraphReFly] CqrsGraph "${name}" not found in DI \u2014 did you import GraphReflyModule.forCqrs({ name: "${name}" })?`
418
+ );
419
+ return null;
420
+ }
421
+ }
422
+ resolveInstance(ctor) {
423
+ try {
424
+ return this.moduleRef.get(ctor, { strict: false });
425
+ } catch {
426
+ return null;
427
+ }
428
+ }
429
+ };
430
+
431
+ // src/compat/nestjs/gateway.ts
432
+ function observeSSE(graph, path, opts) {
433
+ const { actor, serialize = defaultSerialize, keepAliveMs, signal } = opts ?? {};
434
+ const encoder = new TextEncoder();
435
+ let stop;
436
+ const useBackpressure = opts?.highWaterMark != null;
437
+ let wm;
438
+ let pullResolve;
439
+ const taggedBuf = [];
440
+ let closed = false;
441
+ return new ReadableStream({
442
+ start(controller) {
443
+ let keepAlive;
444
+ let unsub = () => {
445
+ };
446
+ const close = () => {
447
+ if (closed) return;
448
+ closed = true;
449
+ if (keepAlive !== void 0) clearInterval(keepAlive);
450
+ signal?.removeEventListener("abort", onAbort);
451
+ unsub();
452
+ wm?.dispose();
453
+ pullResolve?.();
454
+ pullResolve = void 0;
455
+ for (const entry of taggedBuf) controller.enqueue(entry.frame);
456
+ taggedBuf.length = 0;
457
+ controller.close();
458
+ };
459
+ stop = close;
460
+ const onAbort = () => close();
461
+ const handle = graph.observe(path, { actor });
462
+ if (useBackpressure) {
463
+ wm = createWatermarkController((msgs) => handle.up(msgs), {
464
+ highWaterMark: opts.highWaterMark,
465
+ lowWaterMark: opts.lowWaterMark ?? Math.floor(opts.highWaterMark / 2)
466
+ });
467
+ }
468
+ unsub = handle.subscribe((msgs) => {
469
+ for (const msg of msgs) {
470
+ if (closed) return;
471
+ const t = msg[0];
472
+ if (t === DATA) {
473
+ const frame = encoder.encode(sseFrame("data", serialize(msg[1])));
474
+ if (useBackpressure) {
475
+ taggedBuf.push({ frame, counted: true });
476
+ wm.onEnqueue();
477
+ pullResolve?.();
478
+ pullResolve = void 0;
479
+ } else {
480
+ controller.enqueue(frame);
481
+ }
482
+ } else if (t === ERROR) {
483
+ const frame = encoder.encode(sseFrame("error", serialize(msg[1])));
484
+ if (useBackpressure) {
485
+ taggedBuf.push({ frame, counted: false });
486
+ pullResolve?.();
487
+ pullResolve = void 0;
488
+ } else {
489
+ controller.enqueue(frame);
490
+ }
491
+ close();
492
+ return;
493
+ } else if (t === COMPLETE || t === TEARDOWN) {
494
+ if (t === COMPLETE) {
495
+ const frame = encoder.encode(sseFrame("complete"));
496
+ if (useBackpressure) {
497
+ taggedBuf.push({ frame, counted: false });
498
+ pullResolve?.();
499
+ pullResolve = void 0;
500
+ } else {
501
+ controller.enqueue(frame);
502
+ }
503
+ }
504
+ close();
505
+ return;
506
+ }
507
+ }
508
+ });
509
+ if (keepAliveMs !== void 0 && keepAliveMs > 0) {
510
+ keepAlive = setInterval(() => {
511
+ if (closed) return;
512
+ if (useBackpressure) {
513
+ taggedBuf.push({ frame: encoder.encode(": keepalive\n\n"), counted: false });
514
+ pullResolve?.();
515
+ pullResolve = void 0;
516
+ } else {
517
+ controller.enqueue(encoder.encode(": keepalive\n\n"));
518
+ }
519
+ }, keepAliveMs);
520
+ }
521
+ if (signal?.aborted) onAbort();
522
+ else signal?.addEventListener("abort", onAbort, { once: true });
523
+ },
524
+ pull(controller) {
525
+ if (!useBackpressure) return;
526
+ if (closed) return;
527
+ if (taggedBuf.length > 0) {
528
+ const entry = taggedBuf.shift();
529
+ controller.enqueue(entry.frame);
530
+ if (entry.counted) wm.onDequeue();
531
+ return;
532
+ }
533
+ return new Promise((resolve) => {
534
+ pullResolve = resolve;
535
+ });
536
+ },
537
+ cancel() {
538
+ try {
539
+ stop?.();
540
+ } catch {
541
+ }
542
+ }
543
+ });
544
+ }
545
+ function observeSubscription(graph, path, opts) {
546
+ const { actor, filter } = opts ?? {};
547
+ const queue = [];
548
+ const waiters = [];
549
+ let disposed = false;
550
+ const handle = graph.observe(path, { actor });
551
+ const wm = opts?.highWaterMark != null ? createWatermarkController((msgs) => handle.up(msgs), {
552
+ highWaterMark: opts.highWaterMark,
553
+ lowWaterMark: opts.lowWaterMark ?? Math.floor(opts.highWaterMark / 2)
554
+ }) : void 0;
555
+ const dispose = () => {
556
+ if (disposed) return;
557
+ disposed = true;
558
+ wm?.dispose();
559
+ unsub();
560
+ };
561
+ const push = (item) => {
562
+ if (disposed) return;
563
+ if (waiters.length > 0) {
564
+ const w = waiters.shift();
565
+ if (item.done && item.error) w.reject(item.error);
566
+ else if (item.done) w.resolve({ done: true, value: void 0 });
567
+ else w.resolve({ done: false, value: item.value });
568
+ } else {
569
+ queue.push(item);
570
+ if (!item.done) wm?.onEnqueue();
571
+ }
572
+ };
573
+ const unsub = handle.subscribe((msgs) => {
574
+ for (const msg of msgs) {
575
+ const t = msg[0];
576
+ if (t === DATA) {
577
+ const value = msg[1];
578
+ if (filter && !filter(value)) continue;
579
+ push({ done: false, value });
580
+ } else if (t === ERROR) {
581
+ const err = msg[1] instanceof Error ? msg[1] : new Error(String(msg[1]));
582
+ push({ done: true, error: err });
583
+ dispose();
584
+ return;
585
+ } else if (t === COMPLETE || t === TEARDOWN) {
586
+ push({ done: true });
587
+ dispose();
588
+ return;
589
+ }
590
+ }
591
+ });
592
+ const iterator = {
593
+ next() {
594
+ if (queue.length > 0) {
595
+ const item = queue.shift();
596
+ if (!item.done) wm?.onDequeue();
597
+ if (item.done && item.error) return Promise.reject(item.error);
598
+ return Promise.resolve(
599
+ item.done ? { done: true, value: void 0 } : { done: false, value: item.value }
600
+ );
601
+ }
602
+ if (disposed) return Promise.resolve({ done: true, value: void 0 });
603
+ return new Promise((resolve, reject) => {
604
+ waiters.push({ resolve, reject });
605
+ });
606
+ },
607
+ return() {
608
+ dispose();
609
+ for (const w of waiters) w.resolve({ done: true, value: void 0 });
610
+ waiters.length = 0;
611
+ return Promise.resolve({ done: true, value: void 0 });
612
+ },
613
+ throw(err) {
614
+ dispose();
615
+ return Promise.reject(err);
616
+ },
617
+ [Symbol.asyncIterator]() {
618
+ return this;
619
+ }
620
+ };
621
+ return iterator;
622
+ }
623
+ var ObserveGateway = class {
624
+ constructor(graph, opts) {
625
+ this.graph = graph;
626
+ this.extractActor = opts?.extractActor ?? (() => void 0);
627
+ this.parse = opts?.parse ?? defaultParseCommand;
628
+ this.highWaterMark = opts?.highWaterMark;
629
+ this.lowWaterMark = opts?.lowWaterMark;
630
+ }
631
+ clients = /* @__PURE__ */ new Map();
632
+ extractActor;
633
+ parse;
634
+ highWaterMark;
635
+ lowWaterMark;
636
+ /**
637
+ * Register a new client. Call from `handleConnection`.
638
+ */
639
+ handleConnection(client) {
640
+ if (!this.clients.has(client)) {
641
+ this.clients.set(client, /* @__PURE__ */ new Map());
642
+ }
643
+ }
644
+ /**
645
+ * Unregister a client and dispose all its subscriptions. Call from `handleDisconnect`.
646
+ */
647
+ handleDisconnect(client) {
648
+ const subs = this.clients.get(client);
649
+ if (!subs) return;
650
+ for (const entry of subs.values()) {
651
+ entry.wm?.dispose();
652
+ entry.unsub();
653
+ }
654
+ this.clients.delete(client);
655
+ }
656
+ /**
657
+ * Handle an incoming client message (subscribe/unsubscribe/ack command).
658
+ *
659
+ * @param client - The WebSocket client reference.
660
+ * @param raw - Raw message data (string or parsed object).
661
+ * @param send - Function to send a message back to the client.
662
+ * Defaults to `client.send(JSON.stringify(msg))`.
663
+ */
664
+ handleMessage(client, raw, send) {
665
+ const sender = send ?? defaultSend.bind(null, client);
666
+ let cmd;
667
+ try {
668
+ cmd = typeof raw === "string" ? this.parse(raw) : raw;
669
+ } catch {
670
+ sender({ type: "err", message: "invalid command" });
671
+ return;
672
+ }
673
+ if (cmd.type === "subscribe") {
674
+ this.subscribe(client, cmd.path, sender);
675
+ } else if (cmd.type === "unsubscribe") {
676
+ this.unsubscribe(client, cmd.path, sender);
677
+ } else if (cmd.type === "ack") {
678
+ this.ack(client, cmd.path, cmd.count ?? 1);
679
+ } else {
680
+ sender({ type: "err", message: `unknown command type: ${cmd.type}` });
681
+ }
682
+ }
683
+ /**
684
+ * Number of active subscriptions for a client. Useful for tests.
685
+ */
686
+ subscriptionCount(client) {
687
+ return this.clients.get(client)?.size ?? 0;
688
+ }
689
+ /**
690
+ * Dispose all clients and subscriptions.
691
+ */
692
+ destroy() {
693
+ for (const [client] of this.clients) {
694
+ this.handleDisconnect(client);
695
+ }
696
+ }
697
+ // -----------------------------------------------------------------------
698
+ // Internal
699
+ // -----------------------------------------------------------------------
700
+ subscribe(client, path, send) {
701
+ let subs = this.clients.get(client);
702
+ if (!subs) {
703
+ subs = /* @__PURE__ */ new Map();
704
+ this.clients.set(client, subs);
705
+ }
706
+ if (subs.has(path)) {
707
+ send({ type: "subscribed", path });
708
+ return;
709
+ }
710
+ const actor = this.extractActor(client);
711
+ let handle;
712
+ try {
713
+ handle = this.graph.observe(path, { actor });
714
+ } catch (err) {
715
+ const message = err instanceof Error ? err.message : String(err);
716
+ send({ type: "err", message });
717
+ return;
718
+ }
719
+ const wm = this.highWaterMark != null ? createWatermarkController((msgs) => handle.up(msgs), {
720
+ highWaterMark: this.highWaterMark,
721
+ lowWaterMark: this.lowWaterMark ?? Math.floor(this.highWaterMark / 2)
722
+ }) : void 0;
723
+ const cleanup = () => {
724
+ wm?.dispose();
725
+ unsub();
726
+ subs.delete(path);
727
+ };
728
+ const unsub = handle.subscribe((msgs) => {
729
+ for (const msg of msgs) {
730
+ const t = msg[0];
731
+ if (t === DATA) {
732
+ wm?.onEnqueue();
733
+ trySend(send, { type: "data", path, value: msg[1] });
734
+ } else if (t === ERROR) {
735
+ const errMsg = msg[1] instanceof Error ? msg[1].message : String(msg[1]);
736
+ trySend(send, { type: "error", path, error: errMsg });
737
+ cleanup();
738
+ return;
739
+ } else if (t === COMPLETE || t === TEARDOWN) {
740
+ trySend(send, { type: "complete", path });
741
+ cleanup();
742
+ return;
743
+ }
744
+ }
745
+ });
746
+ subs.set(path, { unsub, wm });
747
+ send({ type: "subscribed", path });
748
+ }
749
+ unsubscribe(client, path, send) {
750
+ const subs = this.clients.get(client);
751
+ const entry = subs?.get(path);
752
+ if (entry) {
753
+ entry.wm?.dispose();
754
+ entry.unsub();
755
+ subs.delete(path);
756
+ }
757
+ send({ type: "unsubscribed", path });
758
+ }
759
+ ack(client, path, count) {
760
+ const entry = this.clients.get(client)?.get(path);
761
+ if (!entry?.wm) return;
762
+ const n = Math.min(Math.max(0, Math.floor(count)), 1024);
763
+ for (let i = 0; i < n; i++) entry.wm.onDequeue();
764
+ }
765
+ };
766
+ function defaultSerialize(value) {
767
+ if (value instanceof Error) return value.message;
768
+ try {
769
+ return JSON.stringify(value);
770
+ } catch {
771
+ return String(value);
772
+ }
773
+ }
774
+ function sseFrame(event, data) {
775
+ let frame = `event: ${event}
776
+ `;
777
+ if (data !== void 0) {
778
+ for (const line of data.split("\n")) {
779
+ frame += `data: ${line}
780
+ `;
781
+ }
782
+ }
783
+ frame += "\n";
784
+ return frame;
785
+ }
786
+ function defaultParseCommand(data) {
787
+ return JSON.parse(data);
788
+ }
789
+ function defaultSend(client, msg) {
790
+ try {
791
+ client.send(JSON.stringify(msg));
792
+ } catch {
793
+ }
794
+ }
795
+ function trySend(send, msg) {
796
+ try {
797
+ send(msg);
798
+ } catch {
799
+ }
800
+ }
801
+
802
+ // src/compat/nestjs/guard.ts
803
+ var ACTOR_KEY = "graphReflyActor";
804
+ function fromJwtPayload(mapping) {
805
+ return (context) => {
806
+ const req = context.switchToHttp().getRequest();
807
+ const user = req?.user;
808
+ if (user == null) return void 0;
809
+ if (mapping) return mapping(user);
810
+ return user;
811
+ };
812
+ }
813
+ function fromHeader(headerName = "x-graphrefly-actor") {
814
+ return (context) => {
815
+ const req = context.switchToHttp().getRequest();
816
+ const raw = req?.headers?.[headerName.toLowerCase()];
817
+ if (typeof raw !== "string" || raw.length === 0) return void 0;
818
+ try {
819
+ return JSON.parse(raw);
820
+ } catch {
821
+ return void 0;
822
+ }
823
+ };
824
+ }
825
+ function getActor(req) {
826
+ const actor = req?.[ACTOR_KEY];
827
+ return actor != null ? normalizeActor(actor) : DEFAULT_ACTOR;
828
+ }
829
+ var GraphReflyGuardImpl = class {
830
+ constructor(extractor) {
831
+ this.extractor = extractor;
832
+ }
833
+ canActivate(context) {
834
+ const actor = normalizeActor(this.extractor(context));
835
+ const req = context.switchToHttp().getRequest();
836
+ if (req != null) {
837
+ req[ACTOR_KEY] = actor;
838
+ }
839
+ return true;
840
+ }
841
+ };
842
+ function GraphReflyGuard(extractor) {
843
+ return new GraphReflyGuardImpl(extractor ?? fromJwtPayload());
844
+ }
845
+
846
+ // src/compat/nestjs/module.ts
847
+ import {
848
+ Module,
849
+ Scope
850
+ } from "@nestjs/common";
851
+ import { ModuleRef } from "@nestjs/core";
852
+
853
+ // src/patterns/cqrs.ts
854
+ var cqrs_exports = {};
855
+ __export(cqrs_exports, {
856
+ CqrsGraph: () => CqrsGraph,
857
+ MemoryEventStore: () => MemoryEventStore,
858
+ cqrs: () => cqrs
859
+ });
860
+ var COMMAND_GUARD = policy((allow, deny) => {
861
+ allow("write");
862
+ allow("signal");
863
+ deny("observe");
864
+ });
865
+ var PROJECTION_GUARD = policy((allow, deny) => {
866
+ allow("observe");
867
+ allow("signal");
868
+ deny("write");
869
+ });
870
+ var EVENT_GUARD = policy((allow, deny) => {
871
+ allow("observe");
872
+ allow("signal");
873
+ deny("write");
874
+ });
875
+ function cqrsMeta(kind, extra) {
876
+ return { cqrs: true, cqrs_type: kind, ...extra ?? {} };
877
+ }
878
+ function keepalive(n) {
879
+ return n.subscribe(() => {
880
+ });
881
+ }
882
+ var MemoryEventStore = class {
883
+ _store = /* @__PURE__ */ new Map();
884
+ persist(event) {
885
+ let list = this._store.get(event.type);
886
+ if (!list) {
887
+ list = [];
888
+ this._store.set(event.type, list);
889
+ }
890
+ list.push(event);
891
+ }
892
+ loadEvents(eventType, cursor) {
893
+ const list = this._store.get(eventType) ?? [];
894
+ const sinceTs = cursor?.timestampNs;
895
+ const sinceSeq = cursor?.seq;
896
+ const events = sinceTs == null ? [...list] : list.filter(
897
+ (e) => e.timestampNs > sinceTs || e.timestampNs === sinceTs && e.seq > (sinceSeq ?? -1)
898
+ );
899
+ const lastEvent = events.length > 0 ? events[events.length - 1] : void 0;
900
+ return {
901
+ events,
902
+ cursor: lastEvent ? { timestampNs: lastEvent.timestampNs, seq: lastEvent.seq } : cursor
903
+ };
904
+ }
905
+ clear() {
906
+ this._store.clear();
907
+ }
908
+ };
909
+ var CqrsGraph = class extends Graph {
910
+ _eventLogs = /* @__PURE__ */ new Map();
911
+ _commandHandlers = /* @__PURE__ */ new Map();
912
+ _projections = /* @__PURE__ */ new Set();
913
+ _sagas = /* @__PURE__ */ new Set();
914
+ _keepaliveDisposers = [];
915
+ _eventStore;
916
+ _seq = 0;
917
+ constructor(name, opts = {}) {
918
+ super(name, opts.graph);
919
+ }
920
+ destroy() {
921
+ for (const dispose of this._keepaliveDisposers) dispose();
922
+ this._keepaliveDisposers.length = 0;
923
+ super.destroy();
924
+ }
925
+ // -- Events ---------------------------------------------------------------
926
+ /**
927
+ * Register a named event stream backed by `reactiveLog`.
928
+ * Guard denies external `write` — only commands append internally.
929
+ */
930
+ event(name) {
931
+ const existing = this._eventLogs.get(name);
932
+ if (existing) return existing.node;
933
+ const log = reactiveLog([], { name });
934
+ const entries = log.entries;
935
+ const guarded = derived(
936
+ [entries],
937
+ ([snapshot]) => snapshot,
938
+ {
939
+ name,
940
+ describeKind: "state",
941
+ meta: cqrsMeta("event", { event_name: name }),
942
+ guard: EVENT_GUARD,
943
+ initial: entries.get()
944
+ }
945
+ );
946
+ this.add(name, guarded);
947
+ this._keepaliveDisposers.push(keepalive(guarded));
948
+ this._eventLogs.set(name, { log, node: guarded });
949
+ return guarded;
950
+ }
951
+ /** Internal: append to an event log, auto-registering if needed. */
952
+ _appendEvent(eventName, payload) {
953
+ let entry = this._eventLogs.get(eventName);
954
+ if (!entry) {
955
+ this.event(eventName);
956
+ entry = this._eventLogs.get(eventName);
957
+ }
958
+ if (entry.node.status === "completed" || entry.node.status === "errored") {
959
+ throw new Error(
960
+ `Cannot dispatch to terminated event stream "${eventName}" (status: ${entry.node.status}).`
961
+ );
962
+ }
963
+ const nv = entry.log.entries.v;
964
+ const evt = {
965
+ type: eventName,
966
+ payload,
967
+ timestampNs: wallClockNs(),
968
+ seq: ++this._seq,
969
+ ...nv != null ? { v0: { id: nv.id, version: nv.version } } : {}
970
+ };
971
+ entry.log.append(evt);
972
+ if (this._eventStore) {
973
+ this._eventStore.persist(evt);
974
+ }
975
+ }
976
+ // -- Commands -------------------------------------------------------------
977
+ /**
978
+ * Register a command with its handler. Guard denies `observe` (write-only).
979
+ * Use `dispatch(name, payload)` to execute.
980
+ *
981
+ * The command node carries dynamic `meta.error` — a reactive companion
982
+ * that holds the last handler error (or `null` on success).
983
+ */
984
+ command(name, handler) {
985
+ const cmdNode = state(void 0, {
986
+ name,
987
+ describeKind: "state",
988
+ meta: {
989
+ ...cqrsMeta("command", { command_name: name }),
990
+ error: null
991
+ },
992
+ guard: COMMAND_GUARD
993
+ });
994
+ this.add(name, cmdNode);
995
+ this._commandHandlers.set(name, handler);
996
+ return cmdNode;
997
+ }
998
+ /**
999
+ * Execute a registered command. Wraps the entire dispatch in `batch()` so
1000
+ * the command node DATA and all emitted events settle atomically.
1001
+ *
1002
+ * If the handler throws, `meta.error` on the command node is set to the
1003
+ * error and the exception is re-thrown.
1004
+ */
1005
+ dispatch(commandName, payload) {
1006
+ const handler = this._commandHandlers.get(commandName);
1007
+ if (!handler) {
1008
+ throw new Error(`Unknown command: "${commandName}". Register with .command() first.`);
1009
+ }
1010
+ const cmdNode = this.resolve(commandName);
1011
+ batch(() => {
1012
+ cmdNode.down([[DATA, payload]], { internal: true });
1013
+ try {
1014
+ handler(payload, { emit: (eName, data) => this._appendEvent(eName, data) });
1015
+ cmdNode.meta.error.down([[DATA, null]], { internal: true });
1016
+ } catch (err) {
1017
+ cmdNode.meta.error.down([[DATA, err]], { internal: true });
1018
+ throw err;
1019
+ }
1020
+ });
1021
+ }
1022
+ // -- Projections ----------------------------------------------------------
1023
+ /**
1024
+ * Register a read-only projection derived from event streams.
1025
+ * Guard denies `write` — value is computed from events only.
1026
+ *
1027
+ * **Purity contract:** The `reducer` must be a pure function — it receives
1028
+ * the original `initial` on every invocation (full event-sourcing replay).
1029
+ * Never mutate `initial`; always return a new value.
1030
+ */
1031
+ projection(name, eventNames, reducer, initial) {
1032
+ const eventNodes = eventNames.map((eName) => {
1033
+ if (!this._eventLogs.has(eName)) this.event(eName);
1034
+ return this._eventLogs.get(eName).node;
1035
+ });
1036
+ const projNode = derived(
1037
+ eventNodes,
1038
+ (snapshots) => {
1039
+ const allEvents = [];
1040
+ for (const snapshot of snapshots) {
1041
+ const snap = snapshot;
1042
+ allEvents.push(...snap.value.entries);
1043
+ }
1044
+ allEvents.sort((a, b) => a.timestampNs - b.timestampNs || a.seq - b.seq);
1045
+ return reducer(initial, allEvents);
1046
+ },
1047
+ {
1048
+ name,
1049
+ describeKind: "derived",
1050
+ meta: cqrsMeta("projection", { projection_name: name, source_events: eventNames }),
1051
+ guard: PROJECTION_GUARD,
1052
+ initial
1053
+ }
1054
+ );
1055
+ this.add(name, projNode);
1056
+ for (const eName of eventNames) this.connect(eName, name);
1057
+ this._keepaliveDisposers.push(keepalive(projNode));
1058
+ this._projections.add(name);
1059
+ return projNode;
1060
+ }
1061
+ // -- Sagas ----------------------------------------------------------------
1062
+ /**
1063
+ * Register an event-driven side effect. Runs handler for each **new** event
1064
+ * from the specified streams (tracks last-processed entry count per stream).
1065
+ *
1066
+ * The saga node carries dynamic `meta.error` — a reactive companion that
1067
+ * holds the last handler error (or `null` on success). Handler errors do
1068
+ * not propagate out of the saga run (the event cursor still advances so
1069
+ * the same entry is not delivered twice).
1070
+ */
1071
+ saga(name, eventNames, handler) {
1072
+ const eventNodes = eventNames.map((eName) => {
1073
+ if (!this._eventLogs.has(eName)) this.event(eName);
1074
+ return this._eventLogs.get(eName).node;
1075
+ });
1076
+ const lastCounts = /* @__PURE__ */ new Map();
1077
+ const sagaRef = {};
1078
+ const sagaNode = node(
1079
+ eventNodes,
1080
+ (snapshots) => {
1081
+ const errNode = sagaRef.n.meta.error;
1082
+ for (let i = 0; i < snapshots.length; i++) {
1083
+ const snap = snapshots[i];
1084
+ const eName = eventNames[i];
1085
+ const entries = snap.value.entries;
1086
+ const lastCount = lastCounts.get(eName) ?? 0;
1087
+ if (entries.length > lastCount) {
1088
+ const newEntries = entries.slice(lastCount);
1089
+ for (const entry of newEntries) {
1090
+ try {
1091
+ handler(entry);
1092
+ errNode.down([[DATA, null]], { internal: true });
1093
+ } catch (err) {
1094
+ errNode.down([[DATA, err]], { internal: true });
1095
+ }
1096
+ }
1097
+ lastCounts.set(eName, entries.length);
1098
+ }
1099
+ }
1100
+ },
1101
+ {
1102
+ name,
1103
+ describeKind: "effect",
1104
+ meta: {
1105
+ ...cqrsMeta("saga", { saga_name: name, source_events: eventNames }),
1106
+ error: null
1107
+ }
1108
+ }
1109
+ );
1110
+ sagaRef.n = sagaNode;
1111
+ this.add(name, sagaNode);
1112
+ for (const eName of eventNames) this.connect(eName, name);
1113
+ this._keepaliveDisposers.push(keepalive(sagaNode));
1114
+ this._sagas.add(name);
1115
+ return sagaNode;
1116
+ }
1117
+ // -- Event store ----------------------------------------------------------
1118
+ useEventStore(adapter) {
1119
+ this._eventStore = adapter;
1120
+ }
1121
+ /**
1122
+ * Replay persisted events through a reducer to rebuild a read model.
1123
+ * Requires an event store adapter wired via `useEventStore()`.
1124
+ */
1125
+ async rebuildProjection(eventNames, reducer, initial) {
1126
+ if (!this._eventStore) {
1127
+ throw new Error("No event store wired. Call useEventStore() first.");
1128
+ }
1129
+ const allEvents = [];
1130
+ for (const eName of eventNames) {
1131
+ const result = await this._eventStore.loadEvents(eName);
1132
+ allEvents.push(...result.events);
1133
+ }
1134
+ allEvents.sort((a, b) => a.timestampNs - b.timestampNs || a.seq - b.seq);
1135
+ return reducer(initial, allEvents);
1136
+ }
1137
+ };
1138
+ function cqrs(name, opts) {
1139
+ return new CqrsGraph(name, opts);
1140
+ }
1141
+
1142
+ // src/compat/nestjs/module.ts
1143
+ var GraphReflyRootLifecycle = class {
1144
+ constructor(graph) {
1145
+ this.graph = graph;
1146
+ }
1147
+ onModuleDestroy() {
1148
+ this.graph.destroy();
1149
+ }
1150
+ };
1151
+ var GraphReflyRequestLifecycle = class {
1152
+ graph = new Graph("request");
1153
+ onModuleDestroy() {
1154
+ this.graph.destroy();
1155
+ }
1156
+ };
1157
+ var _GraphReflyModule_decorators, _init;
1158
+ _GraphReflyModule_decorators = [Module({})];
1159
+ var _GraphReflyModule = class _GraphReflyModule {
1160
+ /**
1161
+ * Register the root `Graph` singleton in the NestJS DI container.
1162
+ *
1163
+ * The root graph is `@Global()` — injectable everywhere without importing
1164
+ * the module again. Use `@InjectGraph()` to inject it.
1165
+ *
1166
+ * Lifecycle:
1167
+ * - **init:** Graph created in factory. If `build` is provided, it runs
1168
+ * first (registers nodes/mounts). If `snapshot` is provided, values
1169
+ * are restored via `graph.restore()`.
1170
+ * - **destroy:** Calls `graph.destroy()` — sends `[[TEARDOWN]]` to all
1171
+ * nodes, including mounted feature subgraphs (cascading teardown).
1172
+ */
1173
+ static forRoot(opts) {
1174
+ const options = opts ?? {};
1175
+ const graphName = options.name ?? "root";
1176
+ const providers = [
1177
+ {
1178
+ provide: GRAPHREFLY_ROOT_GRAPH,
1179
+ useFactory: () => {
1180
+ const g = new Graph(graphName);
1181
+ if (options.build) options.build(g);
1182
+ if (options.snapshot) g.restore(options.snapshot);
1183
+ return g;
1184
+ }
1185
+ },
1186
+ {
1187
+ provide: /* @__PURE__ */ Symbol.for("graphrefly:root-lifecycle"),
1188
+ useFactory: (graph) => new GraphReflyRootLifecycle(graph),
1189
+ inject: [GRAPHREFLY_ROOT_GRAPH]
1190
+ },
1191
+ {
1192
+ provide: GraphReflyEventExplorer,
1193
+ useFactory: (graph, moduleRef) => new GraphReflyEventExplorer(graph, moduleRef),
1194
+ inject: [GRAPHREFLY_ROOT_GRAPH, ModuleRef]
1195
+ }
1196
+ ];
1197
+ if (options.nodes) {
1198
+ for (const path of options.nodes) {
1199
+ providers.push({
1200
+ provide: getNodeToken(path),
1201
+ useFactory: (graph) => graph.resolve(path),
1202
+ inject: [GRAPHREFLY_ROOT_GRAPH]
1203
+ });
1204
+ }
1205
+ }
1206
+ if (options.requestScope) {
1207
+ providers.push(
1208
+ {
1209
+ provide: /* @__PURE__ */ Symbol.for("graphrefly:request-lifecycle"),
1210
+ useFactory: () => new GraphReflyRequestLifecycle(),
1211
+ scope: Scope.REQUEST
1212
+ },
1213
+ {
1214
+ provide: GRAPHREFLY_REQUEST_GRAPH,
1215
+ useFactory: (lifecycle) => lifecycle.graph,
1216
+ inject: [/* @__PURE__ */ Symbol.for("graphrefly:request-lifecycle")],
1217
+ scope: Scope.REQUEST
1218
+ }
1219
+ );
1220
+ }
1221
+ return {
1222
+ module: _GraphReflyModule,
1223
+ global: true,
1224
+ providers,
1225
+ exports: [
1226
+ GRAPHREFLY_ROOT_GRAPH,
1227
+ ...(options.nodes ?? []).map(getNodeToken),
1228
+ ...options.requestScope ? [GRAPHREFLY_REQUEST_GRAPH] : []
1229
+ ]
1230
+ };
1231
+ }
1232
+ /**
1233
+ * Register a feature subgraph that auto-mounts into the root graph.
1234
+ *
1235
+ * The feature graph is created in the factory, built/restored, then
1236
+ * mounted into root via `root.mount(name, featureGraph)`. On app
1237
+ * shutdown, root's `graph.destroy()` cascades TEARDOWN through all
1238
+ * mounted subgraphs (no explicit remove needed).
1239
+ *
1240
+ * Node tokens are auto-qualified as `featureName::path` to prevent
1241
+ * collisions between features declaring nodes with the same local name.
1242
+ *
1243
+ * Injectable via `@InjectGraph(name)`.
1244
+ */
1245
+ static forFeature(opts) {
1246
+ const providers = [
1247
+ {
1248
+ provide: getGraphToken(opts.name),
1249
+ useFactory: (rootGraph) => {
1250
+ const g = new Graph(opts.name);
1251
+ if (opts.build) opts.build(g);
1252
+ if (opts.snapshot) g.restore(opts.snapshot);
1253
+ rootGraph.mount(opts.name, g);
1254
+ return g;
1255
+ },
1256
+ inject: [GRAPHREFLY_ROOT_GRAPH]
1257
+ }
1258
+ ];
1259
+ if (opts.nodes) {
1260
+ for (const path of opts.nodes) {
1261
+ providers.push({
1262
+ provide: getNodeToken(`${opts.name}::${path}`),
1263
+ useFactory: (graph) => graph.resolve(path),
1264
+ inject: [getGraphToken(opts.name)]
1265
+ });
1266
+ }
1267
+ }
1268
+ return {
1269
+ module: _GraphReflyModule,
1270
+ providers,
1271
+ exports: [
1272
+ getGraphToken(opts.name),
1273
+ ...(opts.nodes ?? []).map((p) => getNodeToken(`${opts.name}::${p}`))
1274
+ ]
1275
+ };
1276
+ }
1277
+ /**
1278
+ * Register a CQRS subgraph that auto-mounts into the root graph.
1279
+ *
1280
+ * Creates a `CqrsGraph` via the `cqrs()` factory (roadmap §4.5), mounts it
1281
+ * into the root graph, and exposes it for DI via `@InjectGraph(name)`.
1282
+ *
1283
+ * CQRS decorators (`@CommandHandler`, `@EventHandler`, `@QueryHandler`,
1284
+ * `@SagaHandler`) are discovered by the explorer and wired to this graph
1285
+ * on module init.
1286
+ *
1287
+ * @example
1288
+ * ```ts
1289
+ * GraphReflyModule.forCqrs({
1290
+ * name: "orders",
1291
+ * build: (g) => {
1292
+ * g.event("orderPlaced");
1293
+ * g.projection("orderCount", ["orderPlaced"], (_s, evts) => evts.length, 0);
1294
+ * },
1295
+ * })
1296
+ * ```
1297
+ */
1298
+ static forCqrs(opts) {
1299
+ const providers = [
1300
+ {
1301
+ provide: getGraphToken(opts.name),
1302
+ useFactory: (rootGraph) => {
1303
+ const g = cqrs(opts.name, opts.cqrs);
1304
+ if (opts.eventStore) g.useEventStore(opts.eventStore);
1305
+ if (opts.build) opts.build(g);
1306
+ rootGraph.mount(opts.name, g);
1307
+ return g;
1308
+ },
1309
+ inject: [GRAPHREFLY_ROOT_GRAPH]
1310
+ }
1311
+ ];
1312
+ if (opts.nodes) {
1313
+ for (const path of opts.nodes) {
1314
+ providers.push({
1315
+ provide: getNodeToken(`${opts.name}::${path}`),
1316
+ useFactory: (graph) => graph.resolve(path),
1317
+ inject: [getGraphToken(opts.name)]
1318
+ });
1319
+ }
1320
+ }
1321
+ return {
1322
+ module: _GraphReflyModule,
1323
+ providers,
1324
+ exports: [
1325
+ getGraphToken(opts.name),
1326
+ ...(opts.nodes ?? []).map((p) => getNodeToken(`${opts.name}::${p}`))
1327
+ ]
1328
+ };
1329
+ }
1330
+ };
1331
+ _init = __decoratorStart(null);
1332
+ _GraphReflyModule = __decorateElement(_init, 0, "GraphReflyModule", _GraphReflyModule_decorators, _GraphReflyModule);
1333
+ __runInitializers(_init, 1, _GraphReflyModule);
1334
+ var GraphReflyModule = _GraphReflyModule;
1335
+
1336
+ export {
1337
+ GRAPHREFLY_ROOT_GRAPH,
1338
+ GRAPHREFLY_REQUEST_GRAPH,
1339
+ getGraphToken,
1340
+ getNodeToken,
1341
+ EVENT_HANDLERS,
1342
+ INTERVAL_HANDLERS,
1343
+ CRON_HANDLERS,
1344
+ COMMAND_HANDLERS,
1345
+ CQRS_EVENT_HANDLERS,
1346
+ QUERY_HANDLERS,
1347
+ SAGA_HANDLERS,
1348
+ InjectGraph,
1349
+ InjectCqrsGraph,
1350
+ InjectNode,
1351
+ OnGraphEvent,
1352
+ GraphInterval,
1353
+ GraphCron,
1354
+ CommandHandler,
1355
+ EventHandler,
1356
+ QueryHandler,
1357
+ SagaHandler,
1358
+ GraphReflyEventExplorer,
1359
+ observeSSE,
1360
+ observeSubscription,
1361
+ ObserveGateway,
1362
+ ACTOR_KEY,
1363
+ fromJwtPayload,
1364
+ fromHeader,
1365
+ getActor,
1366
+ GraphReflyGuardImpl,
1367
+ GraphReflyGuard,
1368
+ cqrs_exports,
1369
+ GraphReflyModule,
1370
+ nestjs_exports
1371
+ };
1372
+ //# sourceMappingURL=chunk-QW7H3ICI.js.map