@graphrefly/graphrefly 0.21.0 → 0.23.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 (101) hide show
  1. package/README.md +7 -5
  2. package/dist/chunk-263BEJJO.js +115 -0
  3. package/dist/chunk-263BEJJO.js.map +1 -0
  4. package/dist/chunk-2GQLMQVJ.js +47 -0
  5. package/dist/chunk-2GQLMQVJ.js.map +1 -0
  6. package/dist/chunk-32N5A454.js +36 -0
  7. package/dist/chunk-32N5A454.js.map +1 -0
  8. package/dist/chunk-7TAQJHQV.js +103 -0
  9. package/dist/chunk-7TAQJHQV.js.map +1 -0
  10. package/dist/{chunk-VOQFK7YN.js → chunk-CWYPA63G.js} +109 -259
  11. package/dist/chunk-CWYPA63G.js.map +1 -0
  12. package/dist/{chunk-7IGHIFTT.js → chunk-HVBX5KIW.js} +15 -26
  13. package/dist/chunk-HVBX5KIW.js.map +1 -0
  14. package/dist/chunk-JFONSPNF.js +391 -0
  15. package/dist/chunk-JFONSPNF.js.map +1 -0
  16. package/dist/chunk-NZMBRXQV.js +2330 -0
  17. package/dist/chunk-NZMBRXQV.js.map +1 -0
  18. package/dist/{chunk-XWBVAO2R.js → chunk-PNUZM7PC.js} +20 -30
  19. package/dist/chunk-PNUZM7PC.js.map +1 -0
  20. package/dist/{chunk-ZTCDY5NQ.js → chunk-PX6PDUJ5.js} +34 -50
  21. package/dist/chunk-PX6PDUJ5.js.map +1 -0
  22. package/dist/chunk-XRFJJ2IU.js +2417 -0
  23. package/dist/chunk-XRFJJ2IU.js.map +1 -0
  24. package/dist/chunk-XTLYW4FR.js +6829 -0
  25. package/dist/chunk-XTLYW4FR.js.map +1 -0
  26. package/dist/compat/nestjs/index.cjs +3489 -2286
  27. package/dist/compat/nestjs/index.cjs.map +1 -1
  28. package/dist/compat/nestjs/index.d.cts +6 -4
  29. package/dist/compat/nestjs/index.d.ts +6 -4
  30. package/dist/compat/nestjs/index.js +10 -8
  31. package/dist/core/index.cjs +1706 -1217
  32. package/dist/core/index.cjs.map +1 -1
  33. package/dist/core/index.d.cts +3 -2
  34. package/dist/core/index.d.ts +3 -2
  35. package/dist/core/index.js +37 -34
  36. package/dist/extra/index.cjs +7519 -6125
  37. package/dist/extra/index.cjs.map +1 -1
  38. package/dist/extra/index.d.cts +4 -4
  39. package/dist/extra/index.d.ts +4 -4
  40. package/dist/extra/index.js +63 -34
  41. package/dist/graph/index.cjs +3199 -2212
  42. package/dist/graph/index.cjs.map +1 -1
  43. package/dist/graph/index.d.cts +5 -3
  44. package/dist/graph/index.d.ts +5 -3
  45. package/dist/graph/index.js +24 -11
  46. package/dist/graph-BtdSRHUc.d.cts +1128 -0
  47. package/dist/graph-CEO2FkLY.d.ts +1128 -0
  48. package/dist/{index-DuN3bhtm.d.ts → index-B0tfuXwV.d.cts} +1697 -586
  49. package/dist/index-BFGjXbiP.d.cts +315 -0
  50. package/dist/{index-CgSiUouz.d.ts → index-BPlWVAKY.d.cts} +4 -4
  51. package/dist/index-BUj3ASVe.d.cts +406 -0
  52. package/dist/{index-VHA43cGP.d.cts → index-C59uSJAH.d.cts} +2 -2
  53. package/dist/index-CkElcUY6.d.ts +315 -0
  54. package/dist/index-DSPc5rkv.d.ts +406 -0
  55. package/dist/{index-BjtlNirP.d.cts → index-DgscL7v0.d.ts} +4 -4
  56. package/dist/{index-SFzE_KTa.d.cts → index-RXN94sHK.d.ts} +1697 -586
  57. package/dist/{index-8a605sg9.d.ts → index-jEtF4N7L.d.ts} +2 -2
  58. package/dist/index.cjs +9947 -7949
  59. package/dist/index.cjs.map +1 -1
  60. package/dist/index.d.cts +214 -37
  61. package/dist/index.d.ts +214 -37
  62. package/dist/index.js +919 -648
  63. package/dist/index.js.map +1 -1
  64. package/dist/meta-3QjzotRv.d.ts +41 -0
  65. package/dist/meta-B-Lbs4-O.d.cts +41 -0
  66. package/dist/node-C7PD3sn9.d.cts +1188 -0
  67. package/dist/node-C7PD3sn9.d.ts +1188 -0
  68. package/dist/{observable-DcBwQY7t.d.ts → observable-EyO-moQY.d.ts} +1 -1
  69. package/dist/{observable-C8Kx_O6k.d.cts → observable-axpzv1K2.d.cts} +1 -1
  70. package/dist/patterns/reactive-layout/index.cjs +3205 -2138
  71. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  72. package/dist/patterns/reactive-layout/index.d.cts +5 -3
  73. package/dist/patterns/reactive-layout/index.d.ts +5 -3
  74. package/dist/patterns/reactive-layout/index.js +7 -4
  75. package/dist/storage-CHT5WE9m.d.ts +182 -0
  76. package/dist/storage-DIgAr7M_.d.cts +182 -0
  77. package/package.json +2 -1
  78. package/dist/chunk-2UDLYZHT.js +0 -2117
  79. package/dist/chunk-2UDLYZHT.js.map +0 -1
  80. package/dist/chunk-4MQ2J6IG.js +0 -1631
  81. package/dist/chunk-4MQ2J6IG.js.map +0 -1
  82. package/dist/chunk-7IGHIFTT.js.map +0 -1
  83. package/dist/chunk-DOSLSFKL.js +0 -162
  84. package/dist/chunk-DOSLSFKL.js.map +0 -1
  85. package/dist/chunk-ECN37NVS.js +0 -6227
  86. package/dist/chunk-ECN37NVS.js.map +0 -1
  87. package/dist/chunk-G66H6ZRK.js +0 -111
  88. package/dist/chunk-G66H6ZRK.js.map +0 -1
  89. package/dist/chunk-VOQFK7YN.js.map +0 -1
  90. package/dist/chunk-WZ2Z2CRV.js +0 -32
  91. package/dist/chunk-WZ2Z2CRV.js.map +0 -1
  92. package/dist/chunk-XWBVAO2R.js.map +0 -1
  93. package/dist/chunk-ZTCDY5NQ.js.map +0 -1
  94. package/dist/graph-KsTe57nI.d.cts +0 -750
  95. package/dist/graph-mILUUqW8.d.ts +0 -750
  96. package/dist/index-B2SvPEbc.d.ts +0 -257
  97. package/dist/index-BHfg_Ez3.d.ts +0 -629
  98. package/dist/index-Bc_diYYJ.d.cts +0 -629
  99. package/dist/index-UudxGnzc.d.cts +0 -257
  100. package/dist/meta-BnG7XAaE.d.cts +0 -778
  101. package/dist/meta-BnG7XAaE.d.ts +0 -778
package/dist/index.js CHANGED
@@ -1,20 +1,19 @@
1
1
  import {
2
2
  CircuitOpenError,
3
- DictCheckpointAdapter,
4
- FileCheckpointAdapter,
5
- MemoryCheckpointAdapter,
6
3
  NS_PER_MS,
7
4
  NS_PER_SEC,
8
- SqliteCheckpointAdapter,
5
+ NativeIndexBackend,
6
+ NativeListBackend,
7
+ NativeMapBackend,
8
+ NativePubSubBackend,
9
+ RateLimiterOverflowError,
9
10
  TimeoutError,
10
11
  audit,
11
12
  buffer,
12
13
  bufferCount,
13
14
  bufferTime,
14
- cache,
15
15
  cascadingCache,
16
16
  catchError,
17
- checkpointNodeValue,
18
17
  checkpointToRedis,
19
18
  checkpointToS3,
20
19
  circuitBreaker,
@@ -24,19 +23,24 @@ import {
24
23
  concatMap,
25
24
  constant,
26
25
  createTransport,
26
+ csvRows,
27
27
  debounce,
28
28
  debounceTime,
29
29
  decorrelatedJitter,
30
30
  delay,
31
31
  deserializeError,
32
+ dictStorage,
32
33
  distill,
33
34
  distinctUntilChanged,
34
35
  elementAt,
35
36
  exhaustMap,
36
37
  exponential,
38
+ externalBundle,
39
+ externalProducer,
37
40
  extra_exports,
38
41
  fallback,
39
42
  fibonacci,
43
+ fileStorage,
40
44
  filter,
41
45
  find,
42
46
  first,
@@ -46,6 +50,8 @@ import {
46
50
  fromDrizzle,
47
51
  fromGitHook,
48
52
  fromHTTP,
53
+ fromHTTPPoll,
54
+ fromHTTPStream,
49
55
  fromIDBRequest,
50
56
  fromIDBTransaction,
51
57
  fromKafka,
@@ -59,19 +65,25 @@ import {
59
65
  fromPulsar,
60
66
  fromRabbitMQ,
61
67
  fromRedisStream,
68
+ fromSSE,
62
69
  fromSqlite,
70
+ fromSqliteCursor,
63
71
  fromStatsD,
64
72
  fromSyslog,
65
73
  fromWebSocket,
74
+ fromWebSocketReconnect,
66
75
  fromWebhook,
76
+ indexedDbStorage,
67
77
  interval,
68
78
  last,
69
79
  linear,
70
80
  lru,
71
81
  map,
82
+ memoryStorage,
72
83
  merge,
73
84
  mergeMap,
74
85
  nameToSignal,
86
+ ndjsonRows,
75
87
  pairwise,
76
88
  parsePrometheusText,
77
89
  parseStatsD,
@@ -83,20 +95,19 @@ import {
83
95
  reactiveIndex,
84
96
  reactiveList,
85
97
  reactiveMap,
98
+ reactiveSink,
86
99
  reduce,
87
100
  repeat,
88
101
  rescue,
89
102
  resolveBackoffPreset,
90
- restoreGraphCheckpoint,
91
- restoreGraphCheckpointIndexedDb,
92
103
  retry,
104
+ retrySource,
93
105
  sample,
94
- saveGraphCheckpoint,
95
- saveGraphCheckpointIndexedDb,
96
106
  scan,
97
107
  serializeError,
98
108
  signalToName,
99
109
  skip,
110
+ sqliteStorage,
100
111
  switchMap,
101
112
  take,
102
113
  takeUntil,
@@ -104,11 +115,11 @@ import {
104
115
  tap,
105
116
  throttle,
106
117
  throttleTime,
107
- tieredStorage,
108
118
  timeout,
109
119
  toCSV,
110
120
  toClickHouse,
111
121
  toFile,
122
+ toHTTP,
112
123
  toKafka,
113
124
  toLoki,
114
125
  toMongo,
@@ -116,14 +127,15 @@ import {
116
127
  toPostgres,
117
128
  toPulsar,
118
129
  toRabbitMQ,
130
+ toReadableStream,
119
131
  toRedisStream,
120
132
  toS3,
121
133
  toSSE,
134
+ toSSEBytes,
122
135
  toSqlite,
123
136
  toTempo,
124
137
  toWebSocket,
125
138
  tokenBucket,
126
- tokenTracker,
127
139
  valve,
128
140
  verifiable,
129
141
  window,
@@ -136,29 +148,35 @@ import {
136
148
  workerBridge,
137
149
  workerSelf,
138
150
  zip
139
- } from "./chunk-ECN37NVS.js";
151
+ } from "./chunk-XTLYW4FR.js";
140
152
  import {
141
153
  cqrs_exports,
142
- domainMeta,
143
- nestjs_exports,
144
- trackingKey
145
- } from "./chunk-XWBVAO2R.js";
146
- import {
147
- JsonCodec,
148
- createDagCborCodec,
149
- createDagCborZstdCodec,
150
- graph_exports,
151
- negotiateCodec,
152
- replayWAL
153
- } from "./chunk-G66H6ZRK.js";
154
+ nestjs_exports
155
+ } from "./chunk-PNUZM7PC.js";
154
156
  import {
155
- DEFAULT_DOWN,
156
- bridge,
157
157
  core_exports
158
- } from "./chunk-DOSLSFKL.js";
158
+ } from "./chunk-263BEJJO.js";
159
159
  import {
160
- cached,
160
+ NativeLogBackend,
161
161
  createWatermarkController,
162
+ reactiveLog,
163
+ toObservable
164
+ } from "./chunk-JFONSPNF.js";
165
+ import {
166
+ graph_exports
167
+ } from "./chunk-2GQLMQVJ.js";
168
+ import {
169
+ analyzeAndMeasure,
170
+ computeLineBreaks,
171
+ reactive_layout_exports
172
+ } from "./chunk-PX6PDUJ5.js";
173
+ import {
174
+ domainMeta,
175
+ trackingKey,
176
+ tryIncrementBounded
177
+ } from "./chunk-32N5A454.js";
178
+ import {
179
+ cached,
162
180
  empty,
163
181
  escapeRegexChar,
164
182
  firstValueFrom,
@@ -174,86 +192,95 @@ import {
174
192
  fromTimer,
175
193
  globToRegExp,
176
194
  keepalive,
177
- logSlice,
178
195
  matchesAnyPattern,
179
196
  matchesCron,
180
197
  never,
181
198
  of,
182
199
  parseCron,
183
200
  reactiveCounter,
184
- reactiveLog,
185
201
  replay,
186
202
  share,
187
203
  shareReplay,
188
204
  throwError,
189
- toArray,
190
- toObservable
191
- } from "./chunk-VOQFK7YN.js";
192
- import {
193
- ResettableTimer
194
- } from "./chunk-WZ2Z2CRV.js";
195
- import {
196
- analyzeAndMeasure,
197
- computeLineBreaks,
198
- reactive_layout_exports
199
- } from "./chunk-ZTCDY5NQ.js";
205
+ toArray
206
+ } from "./chunk-CWYPA63G.js";
200
207
  import {
201
208
  GRAPH_META_SEGMENT,
202
209
  Graph,
210
+ OVERHEAD,
211
+ SIZEOF_SYMBOL,
212
+ diffForWAL,
203
213
  graphProfile,
204
214
  reachable,
205
215
  sizeof
206
- } from "./chunk-2UDLYZHT.js";
216
+ } from "./chunk-XRFJJ2IU.js";
207
217
  import {
208
218
  describeNode,
209
219
  resolveDescribeFields
210
- } from "./chunk-7IGHIFTT.js";
220
+ } from "./chunk-HVBX5KIW.js";
221
+ import {
222
+ ResettableTimer
223
+ } from "./chunk-7TAQJHQV.js";
211
224
  import {
212
- CLEANUP_RESULT,
213
225
  COMPLETE,
226
+ COMPLETE_MSG,
227
+ COMPLETE_ONLY_BATCH,
214
228
  DATA,
215
229
  DEFAULT_ACTOR,
216
230
  DIRTY,
217
- DynamicNodeImpl,
231
+ DIRTY_MSG,
232
+ DIRTY_ONLY_BATCH,
233
+ ENVELOPE_VERSION,
218
234
  ERROR,
235
+ GraphReFlyConfig,
219
236
  GuardDenied,
220
237
  INVALIDATE,
238
+ INVALIDATE_MSG,
239
+ INVALIDATE_ONLY_BATCH,
240
+ JsonCodec,
241
+ NodeImpl,
221
242
  PAUSE,
222
243
  RESOLVED,
244
+ RESOLVED_MSG,
245
+ RESOLVED_ONLY_BATCH,
223
246
  RESUME,
224
247
  START,
248
+ START_MSG,
225
249
  TEARDOWN,
250
+ TEARDOWN_MSG,
251
+ TEARDOWN_ONLY_BATCH,
226
252
  __export,
227
253
  accessHintForGuard,
228
254
  advanceVersion,
255
+ autoTrackNode,
229
256
  batch,
230
- cleanupResult,
257
+ configure,
258
+ createDagCborCodec,
259
+ createDagCborZstdCodec,
231
260
  createVersioning,
261
+ decodeEnvelope,
262
+ defaultConfig,
232
263
  defaultHash,
233
264
  derived,
234
265
  downWithBatch,
235
266
  dynamicNode,
236
267
  effect,
268
+ encodeEnvelope,
237
269
  isBatching,
238
- isKnownMessageType,
239
- isLocalOnly,
240
- isPhase2Message,
241
- isTerminalMessage,
242
270
  isV1,
243
- knownMessageTypes,
244
- messageTier,
245
271
  monotonicNs,
246
272
  node,
247
273
  normalizeActor,
248
- partitionForBatch,
249
274
  pipe,
250
275
  policy,
251
276
  policyFromRules,
252
277
  producer,
253
- propagatesToMeta,
278
+ registerBuiltinCodecs,
279
+ registerBuiltins,
280
+ replayWAL,
254
281
  state,
255
282
  wallClockNs
256
- } from "./chunk-4MQ2J6IG.js";
283
+ } from "./chunk-NZMBRXQV.js";
257
284
 
258
285
  // src/compat/index.ts
259
286
  var compat_exports = {};
@@ -285,7 +312,7 @@ function atom(initialOrRead, writeOrOptions, options) {
285
312
  return createPrimitiveAtom(initialOrRead, writeOrOptions);
286
313
  }
287
314
  function pull(n) {
288
- let val = n.get();
315
+ let val = n.cache;
289
316
  let err;
290
317
  const unsub = n.subscribe((msgs) => {
291
318
  for (const [t, v] of msgs) {
@@ -305,15 +332,19 @@ function createPrimitiveAtom(initial, options) {
305
332
  });
306
333
  return {
307
334
  get: () => {
308
- if (n.status === "disconnected") {
335
+ if (n.status === "sentinel") {
309
336
  return pull(n);
310
337
  }
311
- return n.get();
338
+ return n.cache;
312
339
  },
313
- set: (value) => n.down([[DATA, value]]),
340
+ // Use `n.emit` (not raw `n.down`) so writes go through the framed
341
+ // emit pipeline: bundle() auto-prefixes DIRTY (diamond-safe wave
342
+ // coordination) and the equals check folds same-value writes to
343
+ // RESOLVED (no spurious subscriber fires).
344
+ set: (value) => n.emit(value),
314
345
  update: (fn) => {
315
- const current = n.status === "disconnected" ? pull(n) : n.get();
316
- n.down([[DATA, fn(current)]]);
346
+ const current = n.status === "sentinel" ? pull(n) : n.cache;
347
+ n.emit(fn(current));
317
348
  },
318
349
  subscribe: (cb) => {
319
350
  let initial2 = true;
@@ -334,13 +365,13 @@ function createPrimitiveAtom(initial, options) {
334
365
  };
335
366
  }
336
367
  function createDerivedAtom(read, write, options) {
337
- const n = dynamicNode(
338
- (get) => read((a) => {
368
+ const n = autoTrackNode(
369
+ (track) => read((a) => {
339
370
  const dn = a._node;
340
- if (dn.status === "disconnected") {
371
+ if (dn.status === "sentinel") {
341
372
  pull(dn);
342
373
  }
343
- return get(dn);
374
+ return track(dn);
344
375
  }),
345
376
  {
346
377
  ...options,
@@ -350,10 +381,10 @@ function createDerivedAtom(read, write, options) {
350
381
  );
351
382
  const result = {
352
383
  get: () => {
353
- if (n.status === "disconnected") {
384
+ if (n.status === "sentinel") {
354
385
  return pull(n);
355
386
  }
356
- return n.get();
387
+ return n.cache;
357
388
  },
358
389
  subscribe: (cb) => {
359
390
  let initial = true;
@@ -378,7 +409,7 @@ function createDerivedAtom(read, write, options) {
378
409
  const writable = result;
379
410
  writable.set = (value) => write(getFn, setFn, value);
380
411
  writable.update = (fn) => {
381
- const current = n.status === "disconnected" ? pull(n) : n.get();
412
+ const current = n.status === "sentinel" ? pull(n) : n.cache;
382
413
  return write(getFn, setFn, fn(current));
383
414
  };
384
415
  return writable;
@@ -451,7 +482,7 @@ function createStore(node2, extra = {}) {
451
482
  return store;
452
483
  }
453
484
  function pull2(n) {
454
- let val = n.get();
485
+ let val = n.cache;
455
486
  let err;
456
487
  const unsub = n.subscribe((msgs) => {
457
488
  for (const [t, v] of msgs) {
@@ -464,10 +495,10 @@ function pull2(n) {
464
495
  return val;
465
496
  }
466
497
  function getVal(n) {
467
- if (n.status === "disconnected") {
498
+ if (n.status === "sentinel") {
468
499
  return pull2(n);
469
500
  }
470
- return n.get();
501
+ return n.cache;
471
502
  }
472
503
  function atom2(initial) {
473
504
  const n = state(initial, {
@@ -475,19 +506,26 @@ function atom2(initial) {
475
506
  resetOnTeardown: true
476
507
  });
477
508
  return createStore(n, {
478
- set: (value) => n.down([[DATA, value]])
509
+ // `n.emit` routes through the framed pipeline: `bundle()` auto-
510
+ // prefixes `[DIRTY]` (diamond-safe wave coordination) and the
511
+ // node's `equals` (default `Object.is`) folds same-value writes
512
+ // into `RESOLVED`. Matches nanostores' documented Object.is
513
+ // dedup semantics without any custom check.
514
+ set: (value) => n.emit(value)
479
515
  });
480
516
  }
481
517
  function computed(stores, fn) {
482
518
  const storeArray = Array.isArray(stores) ? stores : [stores];
519
+ const depNodes = storeArray.map((s) => s._node);
483
520
  const n = dynamicNode(
484
- (get) => {
521
+ depNodes,
522
+ (track) => {
485
523
  const vals = storeArray.map((s) => {
486
524
  const node2 = s._node;
487
- if (node2.status === "disconnected") {
525
+ if (node2.status === "sentinel") {
488
526
  pull2(node2);
489
527
  }
490
- return get(node2);
528
+ return track(node2);
491
529
  });
492
530
  return fn(...vals);
493
531
  },
@@ -506,10 +544,14 @@ function map2(initial) {
506
544
  equals: () => false
507
545
  });
508
546
  return createStore(n, {
509
- set: (value) => n.down([[DATA, value]]),
547
+ // `map`'s state node is configured with `equals: () => false`
548
+ // above, so every `emit` produces DATA (even for same-key same-
549
+ // value sets). The `emit` path is still required for diamond
550
+ // coordination (`[DIRTY]` auto-prefix via `bundle()`).
551
+ set: (value) => n.emit(value),
510
552
  setKey: (key, value) => {
511
553
  const current = getVal(n);
512
- n.down([[DATA, { ...current, [key]: value }]]);
554
+ n.emit({ ...current, [key]: value });
513
555
  }
514
556
  });
515
557
  }
@@ -570,8 +612,8 @@ function useSubscribe(node2) {
570
612
  unsub();
571
613
  };
572
614
  },
573
- () => node2.get(),
574
- () => node2.get()
615
+ () => node2.cache,
616
+ () => node2.cache
575
617
  // Server snapshot
576
618
  );
577
619
  }
@@ -591,12 +633,12 @@ function useSubscribeRecord(keysNode, factory) {
591
633
  const store = useMemo(() => {
592
634
  const computeSnap = () => {
593
635
  const snap = {};
594
- const keys = keysNode.get() ?? [];
636
+ const keys = keysNode.cache ?? [];
595
637
  for (const key of keys) {
596
638
  const nodes = factoryRef.current(key);
597
639
  const values = {};
598
640
  for (const field of Object.keys(nodes)) {
599
- values[field] = nodes[field].get();
641
+ values[field] = nodes[field].cache;
600
642
  }
601
643
  snap[key] = values;
602
644
  }
@@ -627,10 +669,10 @@ function useSubscribeRecord(keysNode, factory) {
627
669
  if (!disposed) onStoreChange();
628
670
  };
629
671
  const keysUnsub = keysNode.subscribe((msgs) => {
630
- const hasSettled = msgs.some((m) => messageTier(m[0]) >= 3);
631
- if (!disposed && hasSettled) sync(keysNode.get() ?? []);
672
+ const hasSettled = msgs.some((m) => m[0] === DATA || m[0] === RESOLVED);
673
+ if (!disposed && hasSettled) sync(keysNode.cache ?? []);
632
674
  });
633
- sync(keysNode.get() ?? []);
675
+ sync(keysNode.cache ?? []);
634
676
  return () => {
635
677
  disposed = true;
636
678
  keysUnsub();
@@ -650,7 +692,7 @@ __export(signals_exports, {
650
692
  });
651
693
  var trackingStack = [];
652
694
  function pull3(n) {
653
- let val = n.get();
695
+ let val = n.cache;
654
696
  const unsub = n.subscribe((msgs) => {
655
697
  for (const [t, v] of msgs) {
656
698
  if (t === DATA) val = v;
@@ -674,15 +716,15 @@ var SignalState = class {
674
716
  get() {
675
717
  const tracker = trackingStack[trackingStack.length - 1];
676
718
  if (tracker) {
677
- if (this._node.status === "disconnected") {
719
+ if (this._node.status === "sentinel") {
678
720
  pull3(this._node);
679
721
  }
680
722
  return tracker(this._node);
681
723
  }
682
- if (this._node.status === "disconnected") {
724
+ if (this._node.status === "sentinel") {
683
725
  return pull3(this._node);
684
726
  }
685
- return this._node.get();
727
+ return this._node.cache;
686
728
  }
687
729
  set(value) {
688
730
  if (this._equals(this.get(), value)) return;
@@ -695,9 +737,9 @@ var SignalComputed = class {
695
737
  /** @internal */
696
738
  _node;
697
739
  constructor(computation, opts) {
698
- this._node = dynamicNode(
699
- (get) => {
700
- trackingStack.push(get);
740
+ this._node = autoTrackNode(
741
+ (track) => {
742
+ trackingStack.push(track);
701
743
  try {
702
744
  return computation();
703
745
  } finally {
@@ -715,15 +757,15 @@ var SignalComputed = class {
715
757
  get() {
716
758
  const tracker = trackingStack[trackingStack.length - 1];
717
759
  if (tracker) {
718
- if (this._node.status === "disconnected") {
760
+ if (this._node.status === "sentinel") {
719
761
  pull3(this._node);
720
762
  }
721
763
  return tracker(this._node);
722
764
  }
723
- if (this._node.status === "disconnected") {
765
+ if (this._node.status === "sentinel") {
724
766
  return pull3(this._node);
725
767
  }
726
- return this._node.get();
768
+ return this._node.cache;
727
769
  }
728
770
  };
729
771
  var Signal = {
@@ -767,9 +809,9 @@ __export(solid_exports, {
767
809
  });
768
810
  import { createSignal, getOwner, onCleanup } from "solid-js";
769
811
  function useSubscribe2(node2) {
770
- const [value, setValue] = createSignal(node2.get(), { equals: false });
812
+ const [value, setValue] = createSignal(node2.cache, { equals: false });
771
813
  const unsub = node2.subscribe(() => {
772
- setValue(() => node2.get());
814
+ setValue(() => node2.cache);
773
815
  });
774
816
  if (getOwner()) {
775
817
  onCleanup(() => unsub());
@@ -796,11 +838,11 @@ function useSubscribeRecord2(keysNode, factory) {
796
838
  };
797
839
  const buildSnapshot = () => {
798
840
  const snap = {};
799
- for (const key of keysNode.get() ?? []) {
841
+ for (const key of keysNode.cache ?? []) {
800
842
  const nodes = factory(key);
801
843
  const values = {};
802
844
  for (const field of Object.keys(nodes)) {
803
- values[field] = nodes[field].get();
845
+ values[field] = nodes[field].cache;
804
846
  }
805
847
  snap[key] = values;
806
848
  }
@@ -820,11 +862,11 @@ function useSubscribeRecord2(keysNode, factory) {
820
862
  setValue(() => buildSnapshot());
821
863
  };
822
864
  const keysUnsub = keysNode.subscribe((msgs) => {
823
- if (msgs.some((m) => messageTier(m[0]) >= 3)) {
824
- sync(keysNode.get() ?? []);
865
+ if (msgs.some((m) => m[0] === DATA || m[0] === RESOLVED)) {
866
+ sync(keysNode.cache ?? []);
825
867
  }
826
868
  });
827
- sync(keysNode.get() ?? []);
869
+ sync(keysNode.cache ?? []);
828
870
  if (getOwner()) {
829
871
  onCleanup(() => {
830
872
  keysUnsub();
@@ -849,9 +891,9 @@ function useSubscribe3(node2) {
849
891
  return {
850
892
  subscribe(run) {
851
893
  const unsub = node2.subscribe(() => {
852
- run(node2.get());
894
+ run(node2.cache);
853
895
  });
854
- run(node2.get());
896
+ run(node2.cache);
855
897
  return unsub;
856
898
  }
857
899
  };
@@ -860,16 +902,16 @@ function useStore3(node2) {
860
902
  return {
861
903
  subscribe(run) {
862
904
  const unsub = node2.subscribe(() => {
863
- run(node2.get());
905
+ run(node2.cache);
864
906
  });
865
- run(node2.get());
907
+ run(node2.cache);
866
908
  return unsub;
867
909
  },
868
910
  set(value) {
869
911
  node2.down([[DIRTY], [DATA, value]]);
870
912
  },
871
913
  update(updater) {
872
- const next = updater(node2.get());
914
+ const next = updater(node2.cache);
873
915
  node2.down([[DIRTY], [DATA, next]]);
874
916
  }
875
917
  };
@@ -884,11 +926,11 @@ function useSubscribeRecord3(keysNode, factory) {
884
926
  };
885
927
  const buildSnapshot = () => {
886
928
  const snap = {};
887
- for (const key of keysNode.get() ?? []) {
929
+ for (const key of keysNode.cache ?? []) {
888
930
  const nodes = factory(key);
889
931
  const values = {};
890
932
  for (const field of Object.keys(nodes)) {
891
- values[field] = nodes[field].get();
933
+ values[field] = nodes[field].cache;
892
934
  }
893
935
  snap[key] = values;
894
936
  }
@@ -908,11 +950,11 @@ function useSubscribeRecord3(keysNode, factory) {
908
950
  run(buildSnapshot());
909
951
  };
910
952
  const keysUnsub = keysNode.subscribe((msgs) => {
911
- if (msgs.some((m) => messageTier(m[0]) >= 3)) {
912
- sync(keysNode.get() ?? []);
953
+ if (msgs.some((m) => m[0] === DATA || m[0] === RESOLVED)) {
954
+ sync(keysNode.cache ?? []);
913
955
  }
914
956
  });
915
- sync(keysNode.get() ?? []);
957
+ sync(keysNode.cache ?? []);
916
958
  return () => {
917
959
  keysUnsub();
918
960
  cleanupEntries();
@@ -938,9 +980,9 @@ import {
938
980
  watch
939
981
  } from "vue";
940
982
  function useSubscribe4(node2) {
941
- const ref = shallowRef(node2.get());
983
+ const ref = shallowRef(node2.cache);
942
984
  const unsub = node2.subscribe(() => {
943
- ref.value = node2.get();
985
+ ref.value = node2.cache;
944
986
  });
945
987
  if (getCurrentScope()) {
946
988
  onScopeDispose(() => unsub());
@@ -952,9 +994,9 @@ function useSubscribe4(node2) {
952
994
  return readonly(ref);
953
995
  }
954
996
  function useStore4(node2) {
955
- const inner = shallowRef(node2.get());
997
+ const inner = shallowRef(node2.cache);
956
998
  const unsub = node2.subscribe(() => {
957
- inner.value = node2.get();
999
+ inner.value = node2.cache;
958
1000
  });
959
1001
  if (getCurrentScope()) {
960
1002
  onScopeDispose(() => unsub());
@@ -1000,9 +1042,9 @@ function useSubscribeRecord4(keys, factory) {
1000
1042
  const subs = [];
1001
1043
  for (const field of fields) {
1002
1044
  const node2 = nodes[field];
1003
- values[field] = node2.get();
1045
+ values[field] = node2.cache;
1004
1046
  const unsub = node2.subscribe(() => {
1005
- values[field] = node2.get();
1047
+ values[field] = node2.cache;
1006
1048
  scheduleBatch();
1007
1049
  });
1008
1050
  subs.push(unsub);
@@ -1041,16 +1083,20 @@ var zustand_exports = {};
1041
1083
  __export(zustand_exports, {
1042
1084
  create: () => create
1043
1085
  });
1086
+ var alwaysDiffer = () => false;
1044
1087
  function create(initializer) {
1045
1088
  const g = new Graph("zustand");
1046
- const s = state(void 0, { name: "state" });
1089
+ const s = state(void 0, {
1090
+ name: "state",
1091
+ equals: alwaysDiffer
1092
+ });
1047
1093
  g.add("state", s);
1048
- const getState = () => s.get();
1094
+ const getState = () => s.cache;
1049
1095
  const setState = (partial, replace) => {
1050
1096
  const prev = getState();
1051
1097
  const next = typeof partial === "function" ? partial(prev) : partial;
1052
1098
  const nextState = replace ? next : { ...prev, ...next };
1053
- s.down([[DATA, nextState]]);
1099
+ s.emit(nextState);
1054
1100
  };
1055
1101
  const api = {
1056
1102
  getState,
@@ -1075,7 +1121,7 @@ function create(initializer) {
1075
1121
  destroy: g.destroy.bind(g)
1076
1122
  };
1077
1123
  const initialValue = initializer(setState, getState, api);
1078
- s.down([[DATA, initialValue]]);
1124
+ s.emit(initialValue);
1079
1125
  return Object.assign(g, api);
1080
1126
  }
1081
1127
 
@@ -1151,10 +1197,10 @@ function copyMap(m) {
1151
1197
  return new Map(m);
1152
1198
  }
1153
1199
  function readMap(node2) {
1154
- return node2.get() ?? /* @__PURE__ */ new Map();
1200
+ return node2.cache ?? /* @__PURE__ */ new Map();
1155
1201
  }
1156
1202
  function readArray(node2) {
1157
- return node2.get() ?? [];
1203
+ return node2.cache ?? [];
1158
1204
  }
1159
1205
  function cosineSimilarity(a, b) {
1160
1206
  const n = Math.max(a.length, b.length);
@@ -1284,8 +1330,6 @@ function collection(name, opts = {}) {
1284
1330
  graph.add("items", items);
1285
1331
  graph.add("ranked", ranked);
1286
1332
  graph.add("size", size);
1287
- graph.connect("items", "ranked");
1288
- graph.connect("items", "size");
1289
1333
  function effective(entry, now) {
1290
1334
  const ageSeconds = (now - entry.lastAccessNs) / 1e9;
1291
1335
  return decay(entry.baseScore, ageSeconds, decayRate, minScore);
@@ -1443,7 +1487,6 @@ function knowledgeGraph(name) {
1443
1487
  graph.add("entities", entities);
1444
1488
  graph.add("edges", edges);
1445
1489
  graph.add("adjacency", adjacency);
1446
- graph.connect("edges", "adjacency");
1447
1490
  function commitEntities(next) {
1448
1491
  entities.down([[DATA, next]]);
1449
1492
  }
@@ -1507,11 +1550,13 @@ var messaging_exports = {};
1507
1550
  __export(messaging_exports, {
1508
1551
  JobFlowGraph: () => JobFlowGraph,
1509
1552
  JobQueueGraph: () => JobQueueGraph,
1553
+ MessagingHubGraph: () => MessagingHubGraph,
1510
1554
  SubscriptionGraph: () => SubscriptionGraph,
1511
1555
  TopicBridgeGraph: () => TopicBridgeGraph,
1512
1556
  TopicGraph: () => TopicGraph,
1513
1557
  jobFlow: () => jobFlow,
1514
1558
  jobQueue: () => jobQueue,
1559
+ messagingHub: () => messagingHub,
1515
1560
  subscription: () => subscription,
1516
1561
  topic: () => topic,
1517
1562
  topicBridge: () => topicBridge
@@ -1529,7 +1574,24 @@ function messagingMeta(kind, extra) {
1529
1574
  var TopicGraph = class extends Graph {
1530
1575
  _log;
1531
1576
  events;
1577
+ /**
1578
+ * Most recently published value, or `null` when the topic has no entries
1579
+ * yet. Spec §5.12 reserves `undefined` as the protocol-internal "never
1580
+ * sent DATA" sentinel — `null` is the idiomatic "empty / no value" signal
1581
+ * for domain nodes. F7.
1582
+ *
1583
+ * **Caveat when `T` itself includes `null`** (e.g., `topic<number | null>`):
1584
+ * `latest === null` is ambiguous — it could mean "no publish yet" OR "a
1585
+ * `null` value was published". Use {@link hasLatest} to disambiguate, or
1586
+ * observe {@link events} directly and track length yourself.
1587
+ */
1532
1588
  latest;
1589
+ /**
1590
+ * Reactive `true` once the topic has at least one published entry.
1591
+ * Disambiguates "`null` never published" from "`null` was published" when
1592
+ * `T` includes `null`.
1593
+ */
1594
+ hasLatest;
1533
1595
  constructor(name, opts = {}) {
1534
1596
  super(name, opts.graph);
1535
1597
  this._log = reactiveLog([], { name: "events", maxSize: opts.retainedLimit });
@@ -1539,40 +1601,62 @@ var TopicGraph = class extends Graph {
1539
1601
  [this.events],
1540
1602
  ([snapshot]) => {
1541
1603
  const entries = snapshot;
1542
- return entries.length === 0 ? void 0 : entries[entries.length - 1];
1604
+ return entries.length === 0 ? null : entries[entries.length - 1];
1543
1605
  },
1544
1606
  {
1545
1607
  name: "latest",
1546
1608
  describeKind: "derived",
1547
- meta: messagingMeta("topic_latest"),
1548
- initial: void 0
1609
+ meta: messagingMeta("topic_latest")
1549
1610
  }
1550
1611
  );
1551
1612
  this.add("latest", this.latest);
1552
- this.connect("events", "latest");
1553
1613
  this.addDisposer(keepalive(this.latest));
1614
+ this.hasLatest = derived(
1615
+ [this.events],
1616
+ ([snapshot]) => snapshot.length > 0,
1617
+ {
1618
+ name: "hasLatest",
1619
+ describeKind: "derived",
1620
+ meta: messagingMeta("topic_has_latest")
1621
+ }
1622
+ );
1623
+ this.add("hasLatest", this.hasLatest);
1624
+ this.addDisposer(keepalive(this.hasLatest));
1625
+ this.addDisposer(() => {
1626
+ this.events.down([[COMPLETE]]);
1627
+ });
1628
+ this.addDisposer(() => this._log.disposeAllViews());
1554
1629
  }
1555
1630
  publish(value) {
1556
1631
  this._log.append(value);
1557
1632
  }
1558
1633
  retained() {
1559
- return this.events.get();
1634
+ return this.events.cache;
1560
1635
  }
1561
1636
  };
1562
1637
  var SubscriptionGraph = class extends Graph {
1563
1638
  source;
1564
1639
  cursor;
1565
1640
  available;
1641
+ /**
1642
+ * Reference to the upstream topic graph. Intentionally NOT mounted
1643
+ * under this subscription: a subscription is a VIEW over an
1644
+ * externally-owned topic. Double-mounting (e.g. hub-owned topic +
1645
+ * sub-mount here) would make either-side teardown leave the other
1646
+ * holding a dead reference. Node-level `derived([topicEvents], …)`
1647
+ * still wires the data dependency across graph boundaries. D1(e).
1648
+ */
1649
+ topic;
1566
1650
  constructor(name, topicGraph, opts = {}) {
1567
1651
  super(name, opts.graph);
1568
1652
  const initialCursor = requireNonNegativeInt(opts.cursor ?? 0, "subscription cursor");
1569
- this.mount("topic", topicGraph);
1653
+ this.topic = topicGraph;
1570
1654
  const topicEvents = topicGraph.events;
1571
1655
  this.source = derived([topicEvents], ([snapshot]) => snapshot, {
1572
1656
  name: "source",
1573
1657
  describeKind: "derived",
1574
1658
  meta: messagingMeta("subscription_source"),
1575
- initial: topicEvents.get()
1659
+ initial: topicEvents.cache
1576
1660
  });
1577
1661
  this.add("source", this.source);
1578
1662
  this.cursor = state(initialCursor, {
@@ -1596,23 +1680,20 @@ var SubscriptionGraph = class extends Graph {
1596
1680
  }
1597
1681
  );
1598
1682
  this.add("available", this.available);
1599
- this.connect("topic::events", "source");
1600
- this.connect("source", "available");
1601
- this.connect("cursor", "available");
1602
1683
  this.addDisposer(keepalive(this.source));
1603
1684
  this.addDisposer(keepalive(this.available));
1604
1685
  }
1605
1686
  ack(count) {
1606
- const available = this.available.get();
1687
+ const available = this.available.cache;
1607
1688
  const requested = count === void 0 ? available.length : requireNonNegativeInt(count, "subscription ack count");
1608
1689
  const step = Math.min(requested, available.length);
1609
- if (step <= 0) return this.cursor.get();
1610
- const next = this.cursor.get() + step;
1611
- this.cursor.down([[DATA, next]]);
1690
+ if (step <= 0) return this.cursor.cache;
1691
+ const next = this.cursor.cache + step;
1692
+ this.cursor.emit(next);
1612
1693
  return next;
1613
1694
  }
1614
1695
  pull(limit, opts = {}) {
1615
- const available = this.available.get();
1696
+ const available = this.available.cache;
1616
1697
  const max = limit === void 0 ? available.length : requireNonNegativeInt(limit, "subscription pull limit");
1617
1698
  const out = available.slice(0, max);
1618
1699
  if (opts.ack && out.length > 0) this.ack(out.length);
@@ -1641,7 +1722,6 @@ var JobQueueGraph = class extends Graph {
1641
1722
  initial: 0
1642
1723
  });
1643
1724
  this.add("depth", this.depth);
1644
- this.connect("pending", "depth");
1645
1725
  this.addDisposer(keepalive(this.depth));
1646
1726
  }
1647
1727
  enqueue(payload, opts = {}) {
@@ -1665,7 +1745,7 @@ var JobQueueGraph = class extends Graph {
1665
1745
  if (max === 0) return [];
1666
1746
  const out = [];
1667
1747
  while (out.length < max) {
1668
- const ids = this.pending.get();
1748
+ const ids = this.pending.cache;
1669
1749
  if (ids.length === 0) break;
1670
1750
  const id = this._pending.pop(0);
1671
1751
  const job = this._jobs.get(id);
@@ -1734,7 +1814,6 @@ var JobFlowGraph = class extends Graph {
1734
1814
  }
1735
1815
  );
1736
1816
  this.add("completedCount", this.completedCount);
1737
- this.connect("completed", "completedCount");
1738
1817
  this.addDisposer(keepalive(this.completedCount));
1739
1818
  const maxPerPump = Math.max(
1740
1819
  1,
@@ -1774,7 +1853,6 @@ var JobFlowGraph = class extends Graph {
1774
1853
  }
1775
1854
  );
1776
1855
  this.add(`pump_${stage}`, pump);
1777
- this.connect(`${stage}::pending`, `pump_${stage}`);
1778
1856
  this.addDisposer(keepalive(pump));
1779
1857
  }
1780
1858
  }
@@ -1790,7 +1868,7 @@ var JobFlowGraph = class extends Graph {
1790
1868
  return this.queue(this._stageNames[0]).enqueue(payload, opts);
1791
1869
  }
1792
1870
  retainedCompleted() {
1793
- return this.completed.get();
1871
+ return this.completed.cache;
1794
1872
  }
1795
1873
  };
1796
1874
  var TopicBridgeGraph = class extends Graph {
@@ -1828,7 +1906,7 @@ var TopicBridgeGraph = class extends Graph {
1828
1906
  bridged += 1;
1829
1907
  }
1830
1908
  if (bridged > 0) {
1831
- const current = this.bridgedCount.get();
1909
+ const current = this.bridgedCount.cache;
1832
1910
  this.bridgedCount.down([[DATA, current + bridged]]);
1833
1911
  }
1834
1912
  },
@@ -1839,13 +1917,112 @@ var TopicBridgeGraph = class extends Graph {
1839
1917
  }
1840
1918
  );
1841
1919
  this.add("pump", pump);
1842
- this.connect("subscription::available", "pump");
1843
1920
  this.addDisposer(keepalive(pump));
1844
1921
  }
1845
1922
  };
1923
+ var MessagingHubGraph = class extends Graph {
1924
+ _topics = /* @__PURE__ */ new Map();
1925
+ _version = 0;
1926
+ _defaultTopicOptions;
1927
+ constructor(name, opts = {}) {
1928
+ super(name, opts.graph);
1929
+ this._defaultTopicOptions = { ...opts.defaultTopicOptions ?? {} };
1930
+ }
1931
+ /** Monotonic counter advancing on topic create/remove. */
1932
+ get version() {
1933
+ return this._version;
1934
+ }
1935
+ /** Number of topics currently in the hub. */
1936
+ get size() {
1937
+ return this._topics.size;
1938
+ }
1939
+ /** Checks topic existence without creating. */
1940
+ has(name) {
1941
+ return this._topics.has(name);
1942
+ }
1943
+ /** Iterator over topic names. */
1944
+ topicNames() {
1945
+ return this._topics.keys();
1946
+ }
1947
+ /**
1948
+ * Returns the {@link TopicGraph} for `name`, creating lazily on first call.
1949
+ * Subsequent calls with the same name return the same instance (options on
1950
+ * repeat calls are ignored — the topic is already configured).
1951
+ */
1952
+ topic(name, opts) {
1953
+ let t = this._topics.get(name);
1954
+ if (t === void 0) {
1955
+ const effective = { ...this._defaultTopicOptions, ...opts ?? {} };
1956
+ t = new TopicGraph(name, effective);
1957
+ this._topics.set(name, t);
1958
+ this.mount(name, t);
1959
+ this._version += 1;
1960
+ }
1961
+ return t;
1962
+ }
1963
+ /**
1964
+ * Publishes a value to the topic, lazily creating it on first publish.
1965
+ *
1966
+ * **Late-subscriber caveat:** the topic is created lazily, so subscribers
1967
+ * that attach AFTER a publish only see the retained window (governed by
1968
+ * `retainedLimit` on `TopicOptions` / `defaultTopicOptions`). If
1969
+ * `retainedLimit === 0` is set explicitly, early publishes are
1970
+ * effectively dropped — prefer an unset `retainedLimit` (unbounded
1971
+ * retention) or subscribe before publishing when late-subscribers matter.
1972
+ */
1973
+ publish(name, value) {
1974
+ this.topic(name).publish(value);
1975
+ }
1976
+ /**
1977
+ * Bulk publish — issues all publishes inside one outer batch. New topics
1978
+ * are created on demand. No-op if `entries` yields nothing.
1979
+ *
1980
+ * **Iterable consumption (F6):** `entries` is consumed once (single-pass)
1981
+ * INSIDE the batch frame. If the iterator throws mid-way, the batch is
1982
+ * discarded and NO publishes are visible to subscribers (all-or-nothing).
1983
+ * Pass an array or `Set` for multi-shot callers.
1984
+ */
1985
+ publishMany(entries) {
1986
+ batch(() => {
1987
+ for (const [name, value] of entries) {
1988
+ this.topic(name).publish(value);
1989
+ }
1990
+ });
1991
+ }
1992
+ /**
1993
+ * Creates a {@link SubscriptionGraph} over a named topic. The topic is
1994
+ * lazily created if missing. Subscription lifecycle is owned by the caller —
1995
+ * the hub does NOT mount the subscription.
1996
+ *
1997
+ * @param subName - Local name for the subscription graph.
1998
+ * @param topicName - Hub topic to subscribe to.
1999
+ * @param opts - `SubscriptionOptions` (initial cursor, etc.).
2000
+ */
2001
+ subscribe(subName, topicName, opts) {
2002
+ const t = this.topic(topicName);
2003
+ return new SubscriptionGraph(subName, t, opts);
2004
+ }
2005
+ /**
2006
+ * Unmounts and tears down the topic's graph. Returns `true` if the topic
2007
+ * existed. Subscribers receive `TEARDOWN` via {@link Graph.remove}.
2008
+ */
2009
+ removeTopic(name) {
2010
+ if (!this._topics.has(name)) return false;
2011
+ try {
2012
+ this.remove(name);
2013
+ } finally {
2014
+ this._topics.delete(name);
2015
+ this._version += 1;
2016
+ }
2017
+ return true;
2018
+ }
2019
+ };
1846
2020
  function topic(name, opts) {
1847
2021
  return new TopicGraph(name, opts);
1848
2022
  }
2023
+ function messagingHub(name, opts) {
2024
+ return new MessagingHubGraph(name, opts);
2025
+ }
1849
2026
  function subscription(name, topicGraph, opts) {
1850
2027
  return new SubscriptionGraph(name, topicGraph, opts);
1851
2028
  }
@@ -1902,9 +2079,7 @@ function findRegisteredNodePath(graph, target) {
1902
2079
  }
1903
2080
  function registerStep(graph, name, step, depPaths) {
1904
2081
  graph.add(name, step);
1905
- for (const path of depPaths) {
1906
- graph.connect(path, name);
1907
- }
2082
+ void depPaths;
1908
2083
  }
1909
2084
  function baseMeta(kind, meta) {
1910
2085
  return domainMeta("orchestration", kind, meta);
@@ -1933,9 +2108,16 @@ function task(graph, name, run, opts) {
1933
2108
  const depRefs = opts?.deps ?? [];
1934
2109
  const deps = depRefs.map((dep) => resolveDep(graph, dep));
1935
2110
  const { deps: _deps, ...nodeOpts } = opts ?? {};
2111
+ const wrapped = (batchData, actions, ctx) => {
2112
+ const data = batchData.map(
2113
+ (batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
2114
+ );
2115
+ actions.emit(run(data, ctx));
2116
+ return void 0;
2117
+ };
1936
2118
  const step = node(
1937
2119
  deps.map((d) => d.node),
1938
- run,
2120
+ wrapped,
1939
2121
  {
1940
2122
  ...nodeOpts,
1941
2123
  name,
@@ -1953,7 +2135,7 @@ function task(graph, name, run, opts) {
1953
2135
  }
1954
2136
  function branch(graph, name, source, predicate, opts) {
1955
2137
  const src = resolveDep(graph, source);
1956
- const step = node(
2138
+ const step = derived(
1957
2139
  [src.node],
1958
2140
  ([value]) => ({
1959
2141
  branch: predicate(value) ? "then" : "else",
@@ -1962,7 +2144,6 @@ function branch(graph, name, source, predicate, opts) {
1962
2144
  {
1963
2145
  ...opts,
1964
2146
  name,
1965
- describeKind: "derived",
1966
2147
  meta: baseMeta("branch", opts?.meta)
1967
2148
  }
1968
2149
  );
@@ -1974,18 +2155,28 @@ function valve2(graph, name, source, control, opts) {
1974
2155
  const ctrl = resolveDep(graph, control);
1975
2156
  const step = node(
1976
2157
  [src.node, ctrl.node],
1977
- (_deps, actions) => {
1978
- const opened = ctrl.node.get();
1979
- if (!opened) {
2158
+ (batchData, actions, ctx) => {
2159
+ const batch0 = batchData[0];
2160
+ const batch1 = batchData[1];
2161
+ const ctrlVal = batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1];
2162
+ if (batch0 == null || batch0.length === 0) {
2163
+ if (batch1 != null && batch1.length > 0 && ctrlVal && ctx.prevData[0] !== void 0) {
2164
+ actions.emit(ctx.prevData[0]);
2165
+ } else {
2166
+ actions.down([[RESOLVED]]);
2167
+ }
2168
+ return;
2169
+ }
2170
+ if (!ctrlVal) {
1980
2171
  actions.down([[RESOLVED]]);
1981
- return void 0;
2172
+ return;
1982
2173
  }
1983
- return src.node.get();
2174
+ for (const v of batch0) actions.emit(v);
1984
2175
  },
1985
2176
  {
1986
2177
  ...opts,
1987
2178
  name,
1988
- describeKind: "operator",
2179
+ describeKind: "derived",
1989
2180
  meta: baseMeta("valve", opts?.meta)
1990
2181
  }
1991
2182
  );
@@ -2003,17 +2194,28 @@ function approval(graph, name, source, approver, opts) {
2003
2194
  const isApproved = opts?.isApproved ?? ((value) => Boolean(value));
2004
2195
  const step = node(
2005
2196
  [src.node, ctrl.node],
2006
- (_deps, actions) => {
2007
- if (!isApproved(ctrl.node.get())) {
2197
+ (batchData, actions, ctx) => {
2198
+ const batch0 = batchData[0];
2199
+ const batch1 = batchData[1];
2200
+ const ctrlVal = batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1];
2201
+ if (ctrlVal === void 0 || !isApproved(ctrlVal)) {
2008
2202
  actions.down([[RESOLVED]]);
2009
- return void 0;
2203
+ return;
2204
+ }
2205
+ if (batch0 == null || batch0.length === 0) {
2206
+ if (batch1 != null && batch1.length > 0 && ctx.prevData[0] !== void 0) {
2207
+ actions.emit(ctx.prevData[0]);
2208
+ } else {
2209
+ actions.down([[RESOLVED]]);
2210
+ }
2211
+ return;
2010
2212
  }
2011
- return src.node.get();
2213
+ for (const v of batch0) actions.emit(v);
2012
2214
  },
2013
2215
  {
2014
2216
  ...opts,
2015
2217
  name,
2016
- describeKind: "operator",
2218
+ describeKind: "derived",
2017
2219
  meta: baseMeta("approval", opts?.meta)
2018
2220
  }
2019
2221
  );
@@ -2034,12 +2236,17 @@ function gate(graph, name, source, opts) {
2034
2236
  const src = resolveDep(graph, source);
2035
2237
  const pendingNode = state([], { name: "pending", equals: () => false });
2036
2238
  const isOpenNode = state(startOpen, { name: "isOpen" });
2037
- const countNode = node([pendingNode], ([arr]) => arr.length, {
2038
- name: "count",
2039
- describeKind: "derived"
2239
+ const countNode = derived([pendingNode], ([arr]) => arr.length, {
2240
+ name: "count"
2040
2241
  });
2041
2242
  let queue = [];
2042
2243
  let torn = false;
2244
+ let latestIsOpen = startOpen;
2245
+ const isOpenUnsub = isOpenNode.subscribe((msgs) => {
2246
+ for (const m of msgs) {
2247
+ if (m[0] === DATA) latestIsOpen = m[1];
2248
+ }
2249
+ });
2043
2250
  function syncPending() {
2044
2251
  pendingNode.down([[DATA, [...queue]]]);
2045
2252
  }
@@ -2056,38 +2263,37 @@ function gate(graph, name, source, opts) {
2056
2263
  function guardTorn(method) {
2057
2264
  if (torn) throw new Error(`gate: ${method}() called after gate was torn down`);
2058
2265
  }
2059
- const output = node([src.node], () => void 0, {
2060
- name,
2061
- describeKind: "operator",
2062
- meta: baseMeta("gate", opts?.meta),
2063
- onMessage(msg, _depIndex, actions) {
2064
- if (msg[0] === DATA) {
2065
- if (isOpenNode.get()) {
2066
- actions.emit(msg[1]);
2067
- } else {
2068
- enqueue(msg[1]);
2069
- actions.down([[RESOLVED]]);
2070
- }
2071
- return true;
2072
- }
2073
- if (msg[0] === TEARDOWN) {
2266
+ const output = node(
2267
+ [src.node],
2268
+ (batchData, actions, ctx) => {
2269
+ const terminal = ctx.terminalDeps[0];
2270
+ if (terminal !== void 0) {
2074
2271
  torn = true;
2075
2272
  queue = [];
2076
2273
  syncPending();
2077
- actions.down([msg]);
2078
- return true;
2274
+ actions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);
2275
+ return;
2079
2276
  }
2080
- if (msg[0] === COMPLETE || msg[0] === ERROR) {
2081
- torn = true;
2082
- queue = [];
2083
- syncPending();
2084
- actions.down([msg]);
2085
- return true;
2277
+ const batch0 = batchData[0];
2278
+ if (batch0 == null || batch0.length === 0) {
2279
+ actions.down([[RESOLVED]]);
2280
+ return;
2086
2281
  }
2087
- actions.down([msg]);
2088
- return true;
2282
+ for (const v of batch0) {
2283
+ if (latestIsOpen) {
2284
+ actions.emit(v);
2285
+ } else {
2286
+ enqueue(v);
2287
+ actions.down([[RESOLVED]]);
2288
+ }
2289
+ }
2290
+ },
2291
+ {
2292
+ name,
2293
+ describeKind: "derived",
2294
+ meta: baseMeta("gate", opts?.meta)
2089
2295
  }
2090
- });
2296
+ );
2091
2297
  const controller = {
2092
2298
  node: output,
2093
2299
  pending: pendingNode,
@@ -2116,12 +2322,14 @@ function gate(graph, name, source, opts) {
2116
2322
  },
2117
2323
  open() {
2118
2324
  guardTorn("open");
2119
- isOpenNode.down([[DATA, true]]);
2120
- const items = dequeue(queue.length);
2121
- for (const item of items) {
2122
- if (torn) break;
2123
- output.down([[DATA, item]]);
2124
- }
2325
+ batch(() => {
2326
+ isOpenNode.down([[DATA, true]]);
2327
+ const items = dequeue(queue.length);
2328
+ for (const item of items) {
2329
+ if (torn) break;
2330
+ output.down([[DATA, item]]);
2331
+ }
2332
+ });
2125
2333
  },
2126
2334
  close() {
2127
2335
  guardTorn("close");
@@ -2129,58 +2337,65 @@ function gate(graph, name, source, opts) {
2129
2337
  }
2130
2338
  };
2131
2339
  graph.addDisposer(countNode.subscribe(() => void 0));
2340
+ graph.addDisposer(isOpenUnsub);
2132
2341
  registerStep(graph, name, output, src.path ? [src.path] : []);
2133
2342
  const internal = new Graph(`${name}_state`);
2134
2343
  internal.add("pending", pendingNode);
2135
2344
  internal.add("isOpen", isOpenNode);
2136
2345
  internal.add("count", countNode);
2137
- internal.connect("pending", "count");
2138
2346
  graph.mount(`${name}_state`, internal);
2139
2347
  return controller;
2140
2348
  }
2141
2349
  function forEach2(graph, name, source, run, opts) {
2142
2350
  const src = resolveDep(graph, source);
2143
2351
  let terminated = false;
2144
- const step = node([src.node], () => void 0, {
2145
- ...opts,
2146
- name,
2147
- describeKind: "effect",
2148
- completeWhenDepsComplete: false,
2149
- meta: baseMeta("forEach", opts?.meta),
2150
- onMessage(msg, depIndex, actions) {
2151
- if (terminated) return true;
2152
- if (depIndex !== 0) {
2153
- actions.down([msg]);
2154
- if (msg[0] === COMPLETE || msg[0] === ERROR) terminated = true;
2155
- return true;
2352
+ const step = node(
2353
+ [src.node],
2354
+ (batchData, actions, ctx) => {
2355
+ if (terminated) {
2356
+ actions.down([[RESOLVED]]);
2357
+ return;
2358
+ }
2359
+ const terminal = ctx.terminalDeps[0];
2360
+ if (terminal !== void 0) {
2361
+ terminated = true;
2362
+ actions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);
2363
+ return;
2364
+ }
2365
+ const batch0 = batchData[0];
2366
+ if (batch0 == null || batch0.length === 0) {
2367
+ actions.down([[RESOLVED]]);
2368
+ return;
2156
2369
  }
2157
- if (msg[0] === DATA) {
2370
+ for (const v of batch0) {
2158
2371
  try {
2159
- run(msg[1], actions);
2160
- actions.down([msg]);
2372
+ run(v, actions);
2161
2373
  } catch (err) {
2162
2374
  terminated = true;
2163
2375
  actions.down([[ERROR, err]]);
2376
+ return;
2164
2377
  }
2165
- return true;
2166
2378
  }
2167
- actions.down([msg]);
2168
- if (msg[0] === COMPLETE || msg[0] === ERROR) terminated = true;
2169
- return true;
2379
+ },
2380
+ {
2381
+ ...opts,
2382
+ name,
2383
+ describeKind: "effect",
2384
+ completeWhenDepsComplete: false,
2385
+ meta: baseMeta("forEach", opts?.meta)
2170
2386
  }
2171
- });
2387
+ );
2172
2388
  registerStep(graph, name, step, src.path ? [src.path] : []);
2173
2389
  return step;
2174
2390
  }
2175
2391
  function join(graph, name, deps, opts) {
2176
2392
  const resolved = deps.map((dep) => resolveDep(graph, dep));
2177
- const step = node(
2393
+ const step = derived(
2178
2394
  resolved.map((d) => d.node),
2179
2395
  (values) => values,
2180
2396
  {
2181
2397
  ...opts,
2182
2398
  name,
2183
- describeKind: "derived",
2184
2399
  meta: baseMeta("join", opts?.meta)
2185
2400
  }
2186
2401
  );
@@ -2199,14 +2414,16 @@ function loop(graph, name, source, iterate, opts) {
2199
2414
  const staticIterations = typeof iterRef === "number" ? iterRef : void 0;
2200
2415
  const step = node(
2201
2416
  iterDep ? [src.node, iterDep.node] : [src.node],
2202
- (_deps, actions) => {
2203
- let current = src.node.get();
2204
- const rawCount = staticIterations ?? iterDep?.node.get() ?? 1;
2417
+ (depValues, actions, ctx) => {
2418
+ const batch0 = depValues[0];
2419
+ let current = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
2420
+ const batch1 = iterDep ? depValues[1] : void 0;
2421
+ const rawCount = staticIterations ?? (iterDep ? batch1 != null && batch1.length > 0 ? batch1.at(-1) : ctx.prevData[1] : 1);
2205
2422
  const count = coerceLoopIterations(rawCount);
2206
2423
  for (let i = 0; i < count; i += 1) {
2207
2424
  current = iterate(current, i, actions);
2208
2425
  }
2209
- return current;
2426
+ actions.emit(current);
2210
2427
  },
2211
2428
  {
2212
2429
  ...opts,
@@ -2262,7 +2479,7 @@ function wait(graph, name, source, ms, opts) {
2262
2479
  for (const id of timers) clearTimeout(id);
2263
2480
  timers.clear();
2264
2481
  }
2265
- const srcVal = src.node.get();
2482
+ const srcVal = src.node.cache;
2266
2483
  const initialOpt = srcVal !== void 0 ? { initial: srcVal } : {};
2267
2484
  const step = node(
2268
2485
  [],
@@ -2307,46 +2524,50 @@ function wait(graph, name, source, ms, opts) {
2307
2524
  ...opts,
2308
2525
  name,
2309
2526
  ...initialOpt,
2310
- describeKind: "operator",
2527
+ describeKind: "derived",
2311
2528
  completeWhenDepsComplete: false,
2312
2529
  meta: baseMeta("wait", opts?.meta)
2313
2530
  }
2314
2531
  );
2315
2532
  graph.add(name, step);
2316
- if (src.path) {
2317
- try {
2318
- graph.connect(src.path, name);
2319
- } catch (e) {
2320
- if (!(e instanceof Error && /dep|edge|connect/i.test(e.message))) throw e;
2321
- }
2322
- }
2323
2533
  return step;
2324
2534
  }
2325
2535
  function onFailure(graph, name, source, recover, opts) {
2326
2536
  const src = resolveDep(graph, source);
2327
2537
  let terminated = false;
2328
- const step = node([src.node], () => void 0, {
2329
- ...opts,
2330
- name,
2331
- describeKind: "operator",
2332
- completeWhenDepsComplete: false,
2333
- meta: baseMeta("onFailure", opts?.meta),
2334
- onMessage(msg, _depIndex, actions) {
2335
- if (terminated) return true;
2336
- if (msg[0] === ERROR) {
2337
- try {
2338
- actions.emit(recover(msg[1], actions));
2339
- } catch (err) {
2340
- terminated = true;
2341
- actions.down([[ERROR, err]]);
2538
+ const step = node(
2539
+ [],
2540
+ (_data, actions) => {
2541
+ const unsub = src.node.subscribe((msgs) => {
2542
+ for (const msg of msgs) {
2543
+ if (terminated) return;
2544
+ if (msg[0] === ERROR) {
2545
+ try {
2546
+ actions.emit(recover(msg[1], actions));
2547
+ } catch (err) {
2548
+ terminated = true;
2549
+ actions.down([[ERROR, err]]);
2550
+ }
2551
+ } else {
2552
+ actions.down([msg]);
2553
+ if (msg[0] === COMPLETE) terminated = true;
2554
+ }
2342
2555
  }
2343
- return true;
2344
- }
2345
- actions.down([msg]);
2346
- if (msg[0] === COMPLETE) terminated = true;
2347
- return true;
2556
+ });
2557
+ return () => unsub();
2558
+ },
2559
+ {
2560
+ ...opts,
2561
+ name,
2562
+ describeKind: "derived",
2563
+ completeWhenDepsComplete: false,
2564
+ // onFailure handles errors via manual subscription (recover callback).
2565
+ // Disable auto-propagation so dep-channel ERROR doesn't terminate this
2566
+ // node before the recover callback has a chance to emit a replacement value.
2567
+ errorWhenDepsError: false,
2568
+ meta: baseMeta("onFailure", opts?.meta)
2348
2569
  }
2349
- });
2570
+ );
2350
2571
  registerStep(graph, name, step, src.path ? [src.path] : []);
2351
2572
  return step;
2352
2573
  }
@@ -2359,7 +2580,7 @@ function isPromiseLike(x) {
2359
2580
  return x != null && typeof x.then === "function";
2360
2581
  }
2361
2582
  function isNodeLike(x) {
2362
- return typeof x === "object" && x !== null && "subscribe" in x && typeof x.subscribe === "function" && "get" in x && typeof x.get === "function";
2583
+ return typeof x === "object" && x !== null && "subscribe" in x && typeof x.subscribe === "function" && "cache" in x;
2363
2584
  }
2364
2585
  function isAsyncIterableLike(x) {
2365
2586
  return x != null && typeof x === "object" && Symbol.asyncIterator in x && typeof x[Symbol.asyncIterator] === "function";
@@ -2367,7 +2588,7 @@ function isAsyncIterableLike(x) {
2367
2588
  var DEFAULT_TIMEOUT_MS = 3e4;
2368
2589
  function firstDataFromNode(resolved, opts) {
2369
2590
  if (resolved.status === "settled") {
2370
- const immediate = resolved.get();
2591
+ const immediate = resolved.cache;
2371
2592
  if (immediate !== void 0) {
2372
2593
  return Promise.resolve(immediate);
2373
2594
  }
@@ -2507,43 +2728,94 @@ function streamExtractor(streamTopic, extractFn, opts) {
2507
2728
  {
2508
2729
  name: opts?.name ?? "extractor",
2509
2730
  describeKind: "derived",
2510
- initial: null
2731
+ initial: null,
2732
+ meta: aiMeta("stream_extractor"),
2733
+ ...opts?.equals ? { equals: opts.equals } : {}
2511
2734
  }
2512
2735
  );
2513
2736
  }
2737
+ var keywordFlagsEqual = (a, b) => {
2738
+ if (a === b) return true;
2739
+ if (a == null || b == null) return a === b;
2740
+ if (a.length !== b.length) return false;
2741
+ for (let i = 0; i < a.length; i++) {
2742
+ const x = a[i];
2743
+ const y = b[i];
2744
+ if (x.label !== y.label || x.pattern !== y.pattern || x.match !== y.match || x.position !== y.position) {
2745
+ return false;
2746
+ }
2747
+ }
2748
+ return true;
2749
+ };
2514
2750
  function keywordFlagExtractor(streamTopic, opts) {
2751
+ const maxPatternLength = opts.maxPatternLength ?? 128;
2515
2752
  return derived(
2516
2753
  [streamTopic.latest],
2517
- ([chunk]) => {
2754
+ ([chunk], ctx) => {
2518
2755
  if (chunk == null) return [];
2519
2756
  const accumulated = chunk.accumulated;
2520
- const flags = [];
2757
+ if (!("flags" in ctx.store)) {
2758
+ ctx.store.flags = [];
2759
+ ctx.store.scannedTo = 0;
2760
+ }
2761
+ const flags = ctx.store.flags;
2762
+ const scannedTo = ctx.store.scannedTo;
2763
+ const startOffset = Math.max(0, scannedTo - maxPatternLength);
2764
+ const region = accumulated.slice(startOffset);
2765
+ let added = false;
2521
2766
  for (const { pattern, label } of opts.patterns) {
2522
2767
  const re = new RegExp(pattern.source, `${pattern.flags.replace("g", "")}g`);
2523
- for (const m of accumulated.matchAll(re)) {
2524
- flags.push({ label, pattern, match: m[0], position: m.index });
2768
+ for (const m of region.matchAll(re)) {
2769
+ const pos = startOffset + m.index;
2770
+ if (pos + m[0].length <= scannedTo) continue;
2771
+ flags.push({ label, pattern, match: m[0], position: pos });
2772
+ added = true;
2525
2773
  }
2526
2774
  }
2527
- return flags;
2775
+ ctx.store.scannedTo = accumulated.length;
2776
+ return added ? [...flags] : flags.slice();
2528
2777
  },
2529
2778
  {
2530
2779
  name: opts.name ?? "keyword-flag-extractor",
2531
2780
  describeKind: "derived",
2532
- initial: []
2781
+ initial: [],
2782
+ meta: aiMeta("keyword_flag_extractor"),
2783
+ equals: keywordFlagsEqual
2533
2784
  }
2534
2785
  );
2535
2786
  }
2787
+ var toolCallsEqual = (a, b) => {
2788
+ if (a === b) return true;
2789
+ if (a == null || b == null) return a === b;
2790
+ if (a.length !== b.length) return false;
2791
+ for (let i = 0; i < a.length; i++) {
2792
+ const x = a[i];
2793
+ const y = b[i];
2794
+ if (x.startIndex !== y.startIndex || x.name !== y.name || x.raw !== y.raw) {
2795
+ return false;
2796
+ }
2797
+ }
2798
+ return true;
2799
+ };
2536
2800
  function toolCallExtractor(streamTopic, opts) {
2537
2801
  return derived(
2538
2802
  [streamTopic.latest],
2539
- ([chunk]) => {
2803
+ ([chunk], ctx) => {
2540
2804
  if (chunk == null) return [];
2541
2805
  const accumulated = chunk.accumulated;
2542
- const calls = [];
2543
- let i = 0;
2806
+ if (!("calls" in ctx.store)) {
2807
+ ctx.store.calls = [];
2808
+ ctx.store.scanFrom = 0;
2809
+ }
2810
+ const calls = ctx.store.calls;
2811
+ let i = ctx.store.scanFrom;
2812
+ let added = false;
2544
2813
  while (i < accumulated.length) {
2545
2814
  const start = accumulated.indexOf("{", i);
2546
- if (start === -1) break;
2815
+ if (start === -1) {
2816
+ ctx.store.scanFrom = accumulated.length;
2817
+ break;
2818
+ }
2547
2819
  let depth = 0;
2548
2820
  let end = -1;
2549
2821
  let inString = false;
@@ -2567,7 +2839,10 @@ function toolCallExtractor(streamTopic, opts) {
2567
2839
  }
2568
2840
  }
2569
2841
  }
2570
- if (end === -1) break;
2842
+ if (end === -1) {
2843
+ ctx.store.scanFrom = start;
2844
+ break;
2845
+ }
2571
2846
  const raw = accumulated.slice(start, end + 1);
2572
2847
  try {
2573
2848
  const parsed = JSON.parse(raw);
@@ -2578,20 +2853,28 @@ function toolCallExtractor(streamTopic, opts) {
2578
2853
  raw,
2579
2854
  startIndex: start
2580
2855
  });
2856
+ added = true;
2581
2857
  }
2582
2858
  } catch {
2583
2859
  }
2584
2860
  i = end + 1;
2861
+ ctx.store.scanFrom = i;
2585
2862
  }
2586
- return calls;
2863
+ return added ? [...calls] : calls.slice();
2587
2864
  },
2588
2865
  {
2589
2866
  name: opts?.name ?? "tool-call-extractor",
2590
2867
  describeKind: "derived",
2591
- initial: []
2868
+ initial: [],
2869
+ meta: aiMeta("tool_call_extractor"),
2870
+ equals: toolCallsEqual
2592
2871
  }
2593
2872
  );
2594
2873
  }
2874
+ var costMeterEqual = (a, b) => {
2875
+ if (a === b) return true;
2876
+ return a.chunkCount === b.chunkCount && a.charCount === b.charCount && a.estimatedTokens === b.estimatedTokens;
2877
+ };
2595
2878
  function costMeterExtractor(streamTopic, opts) {
2596
2879
  const charsPerToken = opts?.charsPerToken ?? 4;
2597
2880
  return derived(
@@ -2609,7 +2892,9 @@ function costMeterExtractor(streamTopic, opts) {
2609
2892
  {
2610
2893
  name: opts?.name ?? "cost-meter",
2611
2894
  describeKind: "derived",
2612
- initial: { chunkCount: 0, charCount: 0, estimatedTokens: 0 }
2895
+ initial: { chunkCount: 0, charCount: 0, estimatedTokens: 0 },
2896
+ meta: aiMeta("cost_meter_extractor"),
2897
+ equals: costMeterEqual
2613
2898
  }
2614
2899
  );
2615
2900
  }
@@ -2761,7 +3046,7 @@ function promptNode(adapter, deps, prompt, opts) {
2761
3046
  const format = opts?.format ?? "text";
2762
3047
  const retries = opts?.retries ?? 0;
2763
3048
  const useCache = opts?.cache ?? false;
2764
- const cache2 = useCache ? /* @__PURE__ */ new Map() : null;
3049
+ const cache = useCache ? /* @__PURE__ */ new Map() : null;
2765
3050
  const messagesNode = derived(
2766
3051
  deps,
2767
3052
  (values) => {
@@ -2784,8 +3069,8 @@ function promptNode(adapter, deps, prompt, opts) {
2784
3069
  return state(null);
2785
3070
  }
2786
3071
  const cacheKey = useCache ? JSON.stringify(msgs.map((m) => [m.role, m.content])) : "";
2787
- if (cache2?.has(cacheKey)) {
2788
- return state(cache2.get(cacheKey));
3072
+ if (cache?.has(cacheKey)) {
3073
+ return state(cache.get(cacheKey));
2789
3074
  }
2790
3075
  async function attempt(remaining) {
2791
3076
  try {
@@ -2798,8 +3083,8 @@ function promptNode(adapter, deps, prompt, opts) {
2798
3083
  });
2799
3084
  if (input && typeof input.then === "function") {
2800
3085
  input.then(resolve, reject);
2801
- } else if (input && typeof input.get === "function") {
2802
- resolve(input.get());
3086
+ } else if (input && typeof input.subscribe === "function") {
3087
+ resolve(input.cache);
2803
3088
  } else {
2804
3089
  resolve(input);
2805
3090
  }
@@ -2811,7 +3096,7 @@ function promptNode(adapter, deps, prompt, opts) {
2811
3096
  } else {
2812
3097
  parsed = content;
2813
3098
  }
2814
- cache2?.set(cacheKey, parsed);
3099
+ cache?.set(cacheKey, parsed);
2815
3100
  return parsed;
2816
3101
  } catch (err) {
2817
3102
  if (remaining > 0) return attempt(remaining - 1);
@@ -2839,17 +3124,15 @@ var ChatStreamGraph = class extends Graph {
2839
3124
  [this.messages],
2840
3125
  ([snapshot]) => {
2841
3126
  const entries = snapshot;
2842
- return entries.length === 0 ? void 0 : entries[entries.length - 1];
3127
+ return entries.length === 0 ? null : entries[entries.length - 1];
2843
3128
  },
2844
3129
  {
2845
3130
  name: "latest",
2846
3131
  describeKind: "derived",
2847
- meta: aiMeta("chat_latest"),
2848
- initial: void 0
3132
+ meta: aiMeta("chat_latest")
2849
3133
  }
2850
3134
  );
2851
3135
  this.add("latest", this.latest);
2852
- this.connect("messages", "latest");
2853
3136
  this.addDisposer(keepalive(this.latest));
2854
3137
  this.messageCount = derived(
2855
3138
  [this.messages],
@@ -2862,7 +3145,6 @@ var ChatStreamGraph = class extends Graph {
2862
3145
  }
2863
3146
  );
2864
3147
  this.add("messageCount", this.messageCount);
2865
- this.connect("messages", "messageCount");
2866
3148
  this.addDisposer(keepalive(this.messageCount));
2867
3149
  }
2868
3150
  append(role, content, extra) {
@@ -2875,7 +3157,7 @@ var ChatStreamGraph = class extends Graph {
2875
3157
  this._log.clear();
2876
3158
  }
2877
3159
  allMessages() {
2878
- return this.messages.get();
3160
+ return this.messages.cache;
2879
3161
  }
2880
3162
  };
2881
3163
  function chatStream(name, opts) {
@@ -2903,31 +3185,30 @@ var ToolRegistryGraph = class extends Graph {
2903
3185
  }
2904
3186
  );
2905
3187
  this.add("schemas", this.schemas);
2906
- this.connect("definitions", "schemas");
2907
3188
  this.addDisposer(keepalive(this.schemas));
2908
3189
  }
2909
3190
  register(tool) {
2910
- const current = this.definitions.get();
3191
+ const current = this.definitions.cache;
2911
3192
  const next = new Map(current);
2912
3193
  next.set(tool.name, tool);
2913
3194
  this.definitions.down([[DATA, next]]);
2914
3195
  }
2915
3196
  unregister(name) {
2916
- const current = this.definitions.get();
3197
+ const current = this.definitions.cache;
2917
3198
  if (!current.has(name)) return;
2918
3199
  const next = new Map(current);
2919
3200
  next.delete(name);
2920
3201
  this.definitions.down([[DATA, next]]);
2921
3202
  }
2922
3203
  async execute(name, args) {
2923
- const defs = this.definitions.get();
3204
+ const defs = this.definitions.cache;
2924
3205
  const tool = defs.get(name);
2925
3206
  if (!tool) throw new Error(`toolRegistry: unknown tool "${name}"`);
2926
3207
  const raw = tool.handler(args);
2927
3208
  return resolveToolHandlerResult(raw);
2928
3209
  }
2929
3210
  getDefinition(name) {
2930
- return this.definitions.get().get(name);
3211
+ return this.definitions.cache?.get(name);
2931
3212
  }
2932
3213
  };
2933
3214
  function toolRegistry(name, opts) {
@@ -2962,7 +3243,7 @@ function llmExtractor(systemPrompt, opts) {
2962
3243
  })
2963
3244
  }
2964
3245
  ];
2965
- return producer((_deps, actions) => {
3246
+ return producer((actions) => {
2966
3247
  let active = true;
2967
3248
  const result = opts.adapter.invoke(messages, {
2968
3249
  model: opts.model,
@@ -3012,7 +3293,7 @@ function llmConsolidator(systemPrompt, opts) {
3012
3293
  { role: "system", content: systemPrompt },
3013
3294
  { role: "user", content: JSON.stringify({ memories: entriesArray }) }
3014
3295
  ];
3015
- return producer((_deps, actions) => {
3296
+ return producer((actions) => {
3016
3297
  let active = true;
3017
3298
  const result = opts.adapter.invoke(messages, {
3018
3299
  model: opts.model,
@@ -3127,8 +3408,6 @@ function agentMemory(name, source, opts) {
3127
3408
  graph.add("store", distillBundle.store.entries);
3128
3409
  graph.add("compact", distillBundle.compact);
3129
3410
  graph.add("size", distillBundle.size);
3130
- graph.connect("store", "compact");
3131
- graph.connect("store", "size");
3132
3411
  let vectors = null;
3133
3412
  if (opts.vectorDimensions && opts.vectorDimensions > 0 && opts.embedFn) {
3134
3413
  vectors = vectorIndex({ dimension: opts.vectorDimensions });
@@ -3151,7 +3430,7 @@ function agentMemory(name, source, opts) {
3151
3430
  const permanentKeys = /* @__PURE__ */ new Set();
3152
3431
  const tierOf = (key) => {
3153
3432
  if (permanentKeys.has(key)) return "permanent";
3154
- const storeMap = extractStoreMap(distillBundle.store.entries.get());
3433
+ const storeMap = extractStoreMap(distillBundle.store.entries.cache);
3155
3434
  if (storeMap.has(key)) return "active";
3156
3435
  return "archived";
3157
3436
  };
@@ -3210,10 +3489,10 @@ function agentMemory(name, source, opts) {
3210
3489
  });
3211
3490
  keepaliveSubs.push(tierClassifier.subscribe(() => void 0));
3212
3491
  let archiveHandle = null;
3213
- if (tiersOpts.archiveAdapter) {
3214
- archiveHandle = graph.autoCheckpoint(
3215
- tiersOpts.archiveAdapter,
3216
- tiersOpts.archiveCheckpointOptions
3492
+ if (tiersOpts.archiveTier) {
3493
+ archiveHandle = graph.attachStorage(
3494
+ [tiersOpts.archiveTier],
3495
+ tiersOpts.archiveStorageOptions ?? {}
3217
3496
  );
3218
3497
  }
3219
3498
  memoryTiersBundle = {
@@ -3259,12 +3538,14 @@ function agentMemory(name, source, opts) {
3259
3538
  const budget = opts.budget ?? 2e3;
3260
3539
  const costFn = opts.cost;
3261
3540
  const scoreFn = opts.score;
3262
- const queryInput = state(null, {
3263
- name: "retrievalQuery",
3264
- describeKind: "state"
3265
- });
3266
- graph.add("retrievalQuery", queryInput);
3267
3541
  const contextNode = opts.context ? fromAny(opts.context) : state(null);
3542
+ const retrievalOutput = state([], {
3543
+ name: "retrieval",
3544
+ describeKind: "state",
3545
+ meta: aiMeta("retrieval_pipeline")
3546
+ });
3547
+ graph.add("retrieval", retrievalOutput);
3548
+ retrievalNode = retrievalOutput;
3268
3549
  const traceState = state(null, {
3269
3550
  name: "retrievalTrace",
3270
3551
  describeKind: "state",
@@ -3272,97 +3553,81 @@ function agentMemory(name, source, opts) {
3272
3553
  });
3273
3554
  graph.add("retrievalTrace", traceState);
3274
3555
  retrievalTraceNode = traceState;
3275
- const storeNode = distillBundle.store.entries;
3276
- let lastTrace = null;
3277
- const retrievalDerived = derived(
3278
- [queryInput, storeNode, contextNode],
3279
- ([query, snapshot, ctx]) => {
3280
- if (!query) return [];
3281
- const q = query;
3282
- const storeMap = extractStoreMap(snapshot);
3283
- const candidateMap = /* @__PURE__ */ new Map();
3284
- let vectorCandidates = [];
3285
- if (vectors && q.vector) {
3286
- vectorCandidates = vectors.search(q.vector, topK);
3287
- for (const vc of vectorCandidates) {
3288
- const mem = storeMap.get(vc.id);
3289
- if (mem) {
3290
- candidateMap.set(vc.id, { value: mem, sources: /* @__PURE__ */ new Set(["vector"]) });
3291
- }
3556
+ retrieveFn = (query) => {
3557
+ const storeMap = extractStoreMap(distillBundle.store.entries.cache);
3558
+ const ctx = contextNode.cache;
3559
+ const candidateMap = /* @__PURE__ */ new Map();
3560
+ let vectorCandidates = [];
3561
+ if (vectors && query.vector) {
3562
+ vectorCandidates = vectors.search(query.vector, topK);
3563
+ for (const vc of vectorCandidates) {
3564
+ const mem = storeMap.get(vc.id);
3565
+ if (mem) {
3566
+ candidateMap.set(vc.id, { value: mem, sources: /* @__PURE__ */ new Set(["vector"]) });
3292
3567
  }
3293
3568
  }
3294
- const graphExpanded = [];
3295
- if (kg) {
3296
- const seedIds = [...q.entityIds ?? [], ...[...candidateMap.keys()]];
3297
- const visited = /* @__PURE__ */ new Set();
3298
- let frontier = seedIds;
3299
- for (let depth = 0; depth < graphDepth; depth++) {
3300
- const nextFrontier = [];
3301
- for (const id of frontier) {
3302
- if (visited.has(id)) continue;
3303
- visited.add(id);
3304
- const related = kg.related(id);
3305
- for (const edge of related) {
3306
- const targetId = edge.to;
3307
- if (!visited.has(targetId)) {
3308
- nextFrontier.push(targetId);
3309
- const mem = storeMap.get(targetId);
3310
- if (mem) {
3311
- const existing = candidateMap.get(targetId);
3312
- if (existing) {
3313
- existing.sources.add("graph");
3314
- } else {
3315
- candidateMap.set(targetId, { value: mem, sources: /* @__PURE__ */ new Set(["graph"]) });
3316
- }
3317
- graphExpanded.push(targetId);
3569
+ }
3570
+ const graphExpanded = [];
3571
+ if (kg) {
3572
+ const seedIds = [...query.entityIds ?? [], ...[...candidateMap.keys()]];
3573
+ const visited = /* @__PURE__ */ new Set();
3574
+ let frontier = seedIds;
3575
+ for (let depth = 0; depth < graphDepth; depth++) {
3576
+ const nextFrontier = [];
3577
+ for (const id of frontier) {
3578
+ if (visited.has(id)) continue;
3579
+ visited.add(id);
3580
+ const related = kg.related(id);
3581
+ for (const edge of related) {
3582
+ const targetId = edge.to;
3583
+ if (!visited.has(targetId)) {
3584
+ nextFrontier.push(targetId);
3585
+ const mem = storeMap.get(targetId);
3586
+ if (mem) {
3587
+ const existing = candidateMap.get(targetId);
3588
+ if (existing) {
3589
+ existing.sources.add("graph");
3590
+ } else {
3591
+ candidateMap.set(targetId, { value: mem, sources: /* @__PURE__ */ new Set(["graph"]) });
3318
3592
  }
3593
+ graphExpanded.push(targetId);
3319
3594
  }
3320
3595
  }
3321
3596
  }
3322
- frontier = nextFrontier;
3323
3597
  }
3598
+ frontier = nextFrontier;
3324
3599
  }
3325
- for (const [key, mem] of storeMap) {
3326
- if (!candidateMap.has(key)) {
3327
- candidateMap.set(key, { value: mem, sources: /* @__PURE__ */ new Set(["store"]) });
3328
- }
3329
- }
3330
- const ranked = [];
3331
- for (const [key, { value, sources }] of candidateMap) {
3332
- const score = scoreFn(value, ctx);
3333
- ranked.push({ key, value, score, sources: [...sources] });
3334
- }
3335
- ranked.sort((a, b) => b.score - a.score);
3336
- const packed = [];
3337
- let usedBudget = 0;
3338
- for (const entry of ranked) {
3339
- const c = costFn(entry.value);
3340
- if (usedBudget + c > budget && packed.length > 0) break;
3341
- packed.push(entry);
3342
- usedBudget += c;
3600
+ }
3601
+ for (const [key, mem] of storeMap) {
3602
+ if (!candidateMap.has(key)) {
3603
+ candidateMap.set(key, { value: mem, sources: /* @__PURE__ */ new Set(["store"]) });
3343
3604
  }
3344
- lastTrace = { vectorCandidates, graphExpanded, ranked, packed };
3345
- return packed;
3346
- },
3347
- {
3348
- name: "retrieval",
3349
- describeKind: "derived",
3350
- meta: aiMeta("retrieval_pipeline"),
3351
- initial: []
3352
3605
  }
3353
- );
3354
- graph.add("retrieval", retrievalDerived);
3355
- graph.connect("retrievalQuery", "retrieval");
3356
- graph.connect("store", "retrieval");
3357
- keepaliveSubs.push(retrievalDerived.subscribe(() => void 0));
3358
- retrievalNode = retrievalDerived;
3359
- retrieveFn = (query) => {
3360
- queryInput.down([[DATA, query]]);
3361
- const result = retrievalDerived.get();
3362
- if (lastTrace) {
3363
- traceState.down([[DATA, lastTrace]]);
3606
+ const ranked = [];
3607
+ for (const [key, { value, sources }] of candidateMap) {
3608
+ const score = scoreFn(value, ctx);
3609
+ ranked.push({ key, value, score, sources: [...sources] });
3364
3610
  }
3365
- return result;
3611
+ ranked.sort((a, b) => b.score - a.score);
3612
+ const packed = [];
3613
+ let usedBudget = 0;
3614
+ for (const entry of ranked) {
3615
+ const c = costFn(entry.value);
3616
+ if (usedBudget + c > budget && packed.length > 0) break;
3617
+ packed.push(entry);
3618
+ usedBudget += c;
3619
+ }
3620
+ const trace = {
3621
+ vectorCandidates,
3622
+ graphExpanded,
3623
+ ranked,
3624
+ packed
3625
+ };
3626
+ batch(() => {
3627
+ retrievalOutput.down([[DATA, packed]]);
3628
+ traceState.down([[DATA, trace]]);
3629
+ });
3630
+ return packed;
3366
3631
  };
3367
3632
  }
3368
3633
  graph.addDisposer(() => {
@@ -3466,7 +3731,7 @@ var AgentLoopGraph = class extends Graph {
3466
3731
  this._statusState.down([[DATA, "thinking"]]);
3467
3732
  });
3468
3733
  const msgs = this.chat.allMessages();
3469
- const toolSchemas = this.tools.schemas.get() ?? [];
3734
+ const toolSchemas = this.tools.schemas.cache ?? [];
3470
3735
  const response = await this._invokeLLM(msgs, toolSchemas, signal);
3471
3736
  if (signal.aborted) throw new Error("agentLoop: aborted");
3472
3737
  this.lastResponse.down([[DATA, response]]);
@@ -3501,7 +3766,7 @@ var AgentLoopGraph = class extends Graph {
3501
3766
  this._statusState.down([[DATA, "done"]]);
3502
3767
  this._running = false;
3503
3768
  this._abortController = null;
3504
- return this.lastResponse.get();
3769
+ return this.lastResponse.cache;
3505
3770
  } catch (err) {
3506
3771
  this._statusState.down([[DATA, "error"]]);
3507
3772
  this._running = false;
@@ -3997,7 +4262,7 @@ function demoShell(opts) {
3997
4262
  ([ref, _tick]) => {
3998
4263
  const demo = ref;
3999
4264
  if (!demo) return "";
4000
- return demo.toMermaid();
4265
+ return demo.describe({ format: "mermaid" });
4001
4266
  },
4002
4267
  { name: "graph/mermaid" }
4003
4268
  );
@@ -4053,7 +4318,6 @@ function demoShell(opts) {
4053
4318
  cb(line);
4054
4319
  });
4055
4320
  g.add("highlight/apply-code-scroll", applyCodeScroll);
4056
- g.connect("highlight/code-scroll", "highlight/apply-code-scroll");
4057
4321
  }
4058
4322
  if (onHighlight?.visual) {
4059
4323
  const cb = onHighlight.visual;
@@ -4061,7 +4325,6 @@ function demoShell(opts) {
4061
4325
  cb(selector);
4062
4326
  });
4063
4327
  g.add("highlight/apply-visual", applyVisual);
4064
- g.connect("highlight/visual", "highlight/apply-visual");
4065
4328
  }
4066
4329
  if (onHighlight?.graph) {
4067
4330
  const cb = onHighlight.graph;
@@ -4069,7 +4332,6 @@ function demoShell(opts) {
4069
4332
  cb(nodeId);
4070
4333
  });
4071
4334
  g.add("highlight/apply-graph", applyGraph);
4072
- g.connect("highlight/graph", "highlight/apply-graph");
4073
4335
  }
4074
4336
  const inspectSelected = state(null, {
4075
4337
  name: "inspect/selected-node"
@@ -4085,7 +4347,7 @@ function demoShell(opts) {
4085
4347
  try {
4086
4348
  const nd = demo.resolve(p);
4087
4349
  const nodeDesc = describeNode(nd, standardFields);
4088
- return { path: p, ...nodeDesc, value: nd.get() };
4350
+ return { path: p, ...nodeDesc, value: nd.cache };
4089
4351
  } catch {
4090
4352
  return null;
4091
4353
  }
@@ -4109,7 +4371,7 @@ function demoShell(opts) {
4109
4371
  [metaDebug, demoGraphTick],
4110
4372
  ([debug, _tick]) => {
4111
4373
  if (!debug) return "";
4112
- return g.toMermaid();
4374
+ return g.describe({ format: "mermaid" });
4113
4375
  },
4114
4376
  { name: "meta/shell-mermaid" }
4115
4377
  );
@@ -4175,35 +4437,7 @@ function demoShell(opts) {
4175
4437
  g.add("layout/graph-labels", graphLabels);
4176
4438
  g.add("layout/code-lines", codeLines);
4177
4439
  g.add("layout/side-width-hint", sideWidthHint);
4178
- g.connect("graph/describe", "layout/graph-labels");
4179
- g.connect("layout/code-text", "layout/code-lines");
4180
- g.connect("pane/side-width", "layout/code-lines");
4181
- g.connect("layout/graph-labels", "layout/side-width-hint");
4182
- }
4183
- g.connect("pane/main-ratio", "pane/main-width");
4184
- g.connect("viewport/width", "pane/main-width");
4185
- g.connect("pane/fullscreen", "pane/main-width");
4186
- g.connect("pane/main-width", "pane/side-width");
4187
- g.connect("viewport/width", "pane/side-width");
4188
- g.connect("pane/fullscreen", "pane/side-width");
4189
- g.connect("pane/side-split", "pane/graph-height-ratio");
4190
- g.connect("pane/fullscreen", "pane/graph-height-ratio");
4191
- g.connect("pane/graph-height-ratio", "pane/code-height-ratio");
4192
- g.connect("pane/fullscreen", "pane/code-height-ratio");
4193
- g.connect("demo/graph-ref", "graph/mermaid");
4194
- g.connect("demo/graph-tick", "graph/mermaid");
4195
- g.connect("demo/graph-ref", "graph/describe");
4196
- g.connect("demo/graph-tick", "graph/describe");
4197
- g.connect("hover/target", "highlight/code-scroll");
4198
- g.connect("hover/target", "highlight/visual");
4199
- g.connect("hover/target", "highlight/graph");
4200
- g.connect("inspect/selected-node", "inspect/node-detail");
4201
- g.connect("demo/graph-ref", "inspect/node-detail");
4202
- g.connect("demo/graph-tick", "inspect/node-detail");
4203
- g.connect("demo/graph-ref", "inspect/trace-log");
4204
- g.connect("demo/graph-tick", "inspect/trace-log");
4205
- g.connect("meta/debug", "meta/shell-mermaid");
4206
- g.connect("demo/graph-tick", "meta/shell-mermaid");
4440
+ }
4207
4441
  let tickCounter = 0;
4208
4442
  return {
4209
4443
  graph: g,
@@ -4288,14 +4522,14 @@ function _addBranch(graph, source, rulesNode, rule) {
4288
4522
  let sourcePhase2 = false;
4289
4523
  let sourceValue = _noValue;
4290
4524
  let pendingDirty = false;
4525
+ let latestRules = rulesNode.cache ?? [];
4291
4526
  function resolve(actions) {
4292
4527
  if (sourcePhase2) {
4293
4528
  sourcePhase2 = false;
4294
4529
  const value = sourceValue;
4295
4530
  sourceValue = _noValue;
4296
4531
  if (value !== _noValue) {
4297
- const currentRules = rulesNode.get();
4298
- const currentRule = currentRules.find((r) => r.name === rule.name);
4532
+ const currentRule = latestRules.find((r) => r.name === rule.name);
4299
4533
  let matches = false;
4300
4534
  try {
4301
4535
  matches = currentRule?.classify(value) ?? false;
@@ -4321,55 +4555,75 @@ function _addBranch(graph, source, rulesNode, rule) {
4321
4555
  }
4322
4556
  }
4323
4557
  }
4324
- const filterNode = node([source, rulesNode], () => void 0, {
4325
- describeKind: "operator",
4326
- meta: baseMeta2("stratify_branch", { branch: rule.name }),
4327
- onMessage(msg, depIndex, actions) {
4328
- const t = msg[0];
4329
- if (t === DIRTY) {
4330
- if (depIndex === 0) {
4331
- sourceDirty = true;
4332
- pendingDirty = true;
4333
- } else {
4334
- rulesDirty = true;
4558
+ const filterNode = node(
4559
+ [],
4560
+ (_data, filterActions) => {
4561
+ const srcUnsub = source.subscribe((msgs) => {
4562
+ for (const msg of msgs) {
4563
+ _handleStratifyMessage(msg, 0, filterActions);
4335
4564
  }
4336
- return true;
4337
- }
4338
- if (t === DATA || t === RESOLVED) {
4339
- if (depIndex === 0) {
4340
- sourceDirty = false;
4341
- sourcePhase2 = true;
4342
- sourceValue = t === DATA ? msg[1] : _noValue;
4343
- } else {
4344
- rulesDirty = false;
4565
+ });
4566
+ const rulesUnsub = rulesNode.subscribe((msgs) => {
4567
+ for (const msg of msgs) {
4568
+ _handleStratifyMessage(msg, 1, filterActions);
4345
4569
  }
4346
- if (sourceDirty || rulesDirty) return true;
4347
- resolve(actions);
4348
- return true;
4570
+ });
4571
+ return () => {
4572
+ srcUnsub();
4573
+ rulesUnsub();
4574
+ };
4575
+ },
4576
+ {
4577
+ describeKind: "derived",
4578
+ meta: baseMeta2("stratify_branch", { branch: rule.name }),
4579
+ completeWhenDepsComplete: false
4580
+ }
4581
+ );
4582
+ function _handleStratifyMessage(msg, depIndex, actions) {
4583
+ const t = msg[0];
4584
+ if (t === DIRTY) {
4585
+ if (depIndex === 0) {
4586
+ sourceDirty = true;
4587
+ pendingDirty = true;
4588
+ } else {
4589
+ rulesDirty = true;
4349
4590
  }
4350
- if (t === COMPLETE || t === ERROR || t === TEARDOWN) {
4591
+ return true;
4592
+ }
4593
+ if (t === DATA || t === RESOLVED) {
4594
+ if (depIndex === 0) {
4351
4595
  sourceDirty = false;
4352
- rulesDirty = false;
4353
- sourcePhase2 = false;
4354
- sourceValue = _noValue;
4355
- pendingDirty = false;
4356
- if (depIndex === 0) {
4357
- actions.down([msg]);
4596
+ sourcePhase2 = true;
4597
+ sourceValue = t === DATA ? msg[1] : _noValue;
4598
+ } else {
4599
+ if (t === DATA) {
4600
+ latestRules = msg[1];
4358
4601
  }
4359
- return true;
4602
+ rulesDirty = false;
4360
4603
  }
4361
- if (depIndex === 1) return true;
4362
- return false;
4363
- },
4364
- completeWhenDepsComplete: false
4365
- });
4604
+ if (sourceDirty || rulesDirty) return true;
4605
+ resolve(actions);
4606
+ return true;
4607
+ }
4608
+ if (t === COMPLETE || t === ERROR || t === TEARDOWN) {
4609
+ sourceDirty = false;
4610
+ rulesDirty = false;
4611
+ sourcePhase2 = false;
4612
+ sourceValue = _noValue;
4613
+ pendingDirty = false;
4614
+ if (depIndex === 0) {
4615
+ actions.down([msg]);
4616
+ }
4617
+ return true;
4618
+ }
4619
+ if (depIndex === 1) return true;
4620
+ return false;
4621
+ }
4366
4622
  graph.add(branchName, filterNode);
4367
- graph.connect("source", branchName);
4368
4623
  if (rule.ops) {
4369
4624
  const transformed = rule.ops(filterNode);
4370
4625
  const transformedName = `branch/${rule.name}/out`;
4371
4626
  graph.add(transformedName, transformed);
4372
- graph.connect(branchName, transformedName);
4373
4627
  }
4374
4628
  }
4375
4629
  function funnel(name, sources, stages, opts) {
@@ -4398,12 +4652,14 @@ function funnel(name, sources, stages, opts) {
4398
4652
  const stageInputPath = `${stage.name}::input`;
4399
4653
  const stageInput = g.resolve(stageInputPath);
4400
4654
  const bridgeName = `__bridge_${prevOutputPath}\u2192${stage.name}_input`;
4401
- const br = bridge(prevNode, stageInput, {
4402
- name: bridgeName,
4403
- down: DEFAULT_DOWN.filter((t) => t !== TEARDOWN)
4404
- });
4655
+ const br = effect(
4656
+ [prevNode],
4657
+ ([data]) => {
4658
+ stageInput.down([[DATA, data]]);
4659
+ },
4660
+ { name: bridgeName }
4661
+ );
4405
4662
  g.add(bridgeName, br);
4406
- g.connect(prevOutputPath, bridgeName);
4407
4663
  g.addDisposer(keepalive(br));
4408
4664
  prevOutputPath = `${stage.name}::output`;
4409
4665
  }
@@ -4423,39 +4679,41 @@ function feedback(graph, condition, reentry, opts) {
4423
4679
  const condNode = graph.resolve(condition);
4424
4680
  const reentryNode = graph.resolve(reentry);
4425
4681
  const feedbackEffectName = `__feedback_effect_${condition}`;
4426
- const feedbackEffect = node([condNode], void 0, {
4427
- name: feedbackEffectName,
4428
- describeKind: "effect",
4429
- meta: {
4430
- ...baseMeta2("feedback_effect", {
4431
- feedbackFrom: condition,
4432
- feedbackTo: reentry
4433
- }),
4434
- _internal: true
4682
+ const feedbackEffect = node(
4683
+ [],
4684
+ (_data, _feedbackActions) => {
4685
+ const unsub = condNode.subscribe((msgs) => {
4686
+ for (const msg of msgs) {
4687
+ const t = msg[0];
4688
+ if (t === DATA) {
4689
+ const condValue = msg[1];
4690
+ if (condValue == null) return;
4691
+ batch(() => {
4692
+ if (tryIncrementBounded(counter, maxIter)) {
4693
+ reentryNode.down([[DATA, condValue]]);
4694
+ }
4695
+ });
4696
+ } else if (t === COMPLETE || t === ERROR) {
4697
+ const terminal = t === ERROR && msg.length > 1 ? [ERROR, msg[1]] : [t];
4698
+ counter.down([terminal]);
4699
+ }
4700
+ }
4701
+ });
4702
+ return () => unsub();
4435
4703
  },
4436
- onMessage(msg, _depIndex, _actions) {
4437
- const t = msg[0];
4438
- if (t === DATA) {
4439
- const currentCount = counter.get();
4440
- if (currentCount >= maxIter) return true;
4441
- const condValue = msg[1];
4442
- if (condValue == null) return true;
4443
- batch(() => {
4444
- counter.down([[DATA, currentCount + 1]]);
4445
- reentryNode.down([[DATA, condValue]]);
4446
- });
4447
- return true;
4448
- }
4449
- if (t === COMPLETE || t === ERROR) {
4450
- const terminal = t === ERROR && msg.length > 1 ? [ERROR, msg[1]] : [t];
4451
- counter.down([terminal]);
4452
- return true;
4704
+ {
4705
+ name: feedbackEffectName,
4706
+ describeKind: "effect",
4707
+ meta: {
4708
+ ...baseMeta2("feedback_effect", {
4709
+ feedbackFrom: condition,
4710
+ feedbackTo: reentry
4711
+ }),
4712
+ _internal: true
4453
4713
  }
4454
- return false;
4455
4714
  }
4456
- });
4715
+ );
4457
4716
  graph.add(feedbackEffectName, feedbackEffect);
4458
- graph.connect(condition, feedbackEffectName);
4459
4717
  graph.addDisposer(keepalive(feedbackEffect));
4460
4718
  return graph;
4461
4719
  }
@@ -4467,8 +4725,9 @@ function budgetGate(source, constraints, opts) {
4467
4725
  let paused = false;
4468
4726
  let pendingResolved = false;
4469
4727
  const lockId = /* @__PURE__ */ Symbol("budget-gate");
4728
+ const latestValues = new Array(constraints.length);
4470
4729
  function checkBudget() {
4471
- return constraints.every((c) => c.check(c.node.get()));
4730
+ return constraints.every((c, i) => c.check(latestValues[i]));
4472
4731
  }
4473
4732
  function flushBuffer(actions) {
4474
4733
  while (buffer2.length > 0 && checkBudget()) {
@@ -4481,78 +4740,103 @@ function budgetGate(source, constraints, opts) {
4481
4740
  actions.down([[RESOLVED]]);
4482
4741
  }
4483
4742
  }
4484
- return node(allDeps, () => void 0, {
4485
- ...opts,
4486
- describeKind: "operator",
4487
- meta: baseMeta2("budget_gate", opts?.meta),
4488
- onMessage(msg, depIndex, actions) {
4489
- const t = msg[0];
4490
- if (depIndex === 0) {
4491
- if (t === DATA) {
4492
- if (checkBudget() && buffer2.length === 0) {
4493
- actions.emit(msg[1]);
4494
- } else {
4495
- buffer2.push(msg[1]);
4496
- if (!paused) {
4497
- paused = true;
4498
- actions.up([[PAUSE, lockId]]);
4743
+ return node(
4744
+ [],
4745
+ (_data, gateActions) => {
4746
+ for (let i = 0; i < constraints.length; i++) {
4747
+ latestValues[i] = constraints[i].node.cache;
4748
+ }
4749
+ const unsubs = [];
4750
+ for (let depIdx = 0; depIdx < allDeps.length; depIdx++) {
4751
+ const dep = allDeps[depIdx];
4752
+ unsubs.push(
4753
+ dep.subscribe((msgs) => {
4754
+ for (const msg of msgs) {
4755
+ _handleBudgetMessage(msg, depIdx, gateActions);
4499
4756
  }
4500
- }
4501
- return true;
4502
- }
4503
- if (t === DIRTY) {
4504
- actions.down([[DIRTY]]);
4505
- return true;
4506
- }
4507
- if (t === RESOLVED) {
4508
- if (buffer2.length === 0) {
4509
- actions.down([[RESOLVED]]);
4510
- } else {
4511
- pendingResolved = true;
4512
- }
4513
- return true;
4514
- }
4515
- if (t === COMPLETE || t === ERROR) {
4516
- for (const item of buffer2) {
4517
- actions.emit(item);
4518
- }
4519
- buffer2 = [];
4520
- pendingResolved = false;
4521
- if (paused) {
4522
- paused = false;
4523
- actions.up([[RESUME, lockId]]);
4524
- }
4525
- actions.down([msg]);
4526
- return true;
4527
- }
4528
- return false;
4757
+ })
4758
+ );
4529
4759
  }
4530
- if (t === DATA || t === RESOLVED) {
4531
- if (checkBudget() && buffer2.length > 0) {
4532
- flushBuffer(actions);
4533
- if (buffer2.length === 0 && paused) {
4534
- paused = false;
4535
- actions.up([[RESUME, lockId]]);
4760
+ return () => {
4761
+ for (const u of unsubs) u();
4762
+ };
4763
+ },
4764
+ {
4765
+ ...opts,
4766
+ describeKind: "derived",
4767
+ meta: baseMeta2("budget_gate", opts?.meta)
4768
+ }
4769
+ );
4770
+ function _handleBudgetMessage(msg, depIndex, actions) {
4771
+ const t = msg[0];
4772
+ if (depIndex === 0) {
4773
+ if (t === DATA) {
4774
+ if (checkBudget() && buffer2.length === 0) {
4775
+ actions.emit(msg[1]);
4776
+ } else {
4777
+ buffer2.push(msg[1]);
4778
+ if (!paused) {
4779
+ paused = true;
4780
+ actions.up([[PAUSE, lockId]]);
4536
4781
  }
4537
- } else if (!checkBudget() && !paused && buffer2.length > 0) {
4538
- paused = true;
4539
- actions.up([[PAUSE, lockId]]);
4540
4782
  }
4541
4783
  return true;
4542
4784
  }
4543
4785
  if (t === DIRTY) {
4786
+ actions.down([[DIRTY]]);
4544
4787
  return true;
4545
4788
  }
4546
- if (t === ERROR) {
4547
- actions.down([msg]);
4789
+ if (t === RESOLVED) {
4790
+ if (buffer2.length === 0) {
4791
+ actions.down([[RESOLVED]]);
4792
+ } else {
4793
+ pendingResolved = true;
4794
+ }
4548
4795
  return true;
4549
4796
  }
4550
- if (t === COMPLETE) {
4797
+ if (t === COMPLETE || t === ERROR) {
4798
+ for (const item of buffer2) {
4799
+ actions.emit(item);
4800
+ }
4801
+ buffer2 = [];
4802
+ pendingResolved = false;
4803
+ if (paused) {
4804
+ paused = false;
4805
+ actions.up([[RESUME, lockId]]);
4806
+ }
4807
+ actions.down([msg]);
4551
4808
  return true;
4552
4809
  }
4553
4810
  return false;
4554
4811
  }
4555
- });
4812
+ if (t === DATA) {
4813
+ latestValues[depIndex - 1] = msg[1];
4814
+ }
4815
+ if (t === DATA || t === RESOLVED) {
4816
+ if (checkBudget() && buffer2.length > 0) {
4817
+ flushBuffer(actions);
4818
+ if (buffer2.length === 0 && paused) {
4819
+ paused = false;
4820
+ actions.up([[RESUME, lockId]]);
4821
+ }
4822
+ } else if (!checkBudget() && !paused && buffer2.length > 0) {
4823
+ paused = true;
4824
+ actions.up([[PAUSE, lockId]]);
4825
+ }
4826
+ return true;
4827
+ }
4828
+ if (t === DIRTY) {
4829
+ return true;
4830
+ }
4831
+ if (t === ERROR) {
4832
+ actions.down([msg]);
4833
+ return true;
4834
+ }
4835
+ if (t === COMPLETE) {
4836
+ return true;
4837
+ }
4838
+ return false;
4839
+ }
4556
4840
  }
4557
4841
  function scorer(sources, weights, opts) {
4558
4842
  if (sources.length === 0) throw new RangeError("scorer requires at least one source");
@@ -4584,7 +4868,11 @@ function scorer(sources, weights, opts) {
4584
4868
  };
4585
4869
  },
4586
4870
  {
4587
- ...opts,
4871
+ ...opts ? {
4872
+ equals: opts.equals,
4873
+ resubscribable: opts.resubscribable,
4874
+ resetOnTeardown: opts.resetOnTeardown
4875
+ } : {},
4588
4876
  describeKind: "derived",
4589
4877
  meta: baseMeta2("scorer", opts?.meta)
4590
4878
  }
@@ -4672,12 +4960,6 @@ function observabilityGraph(name, opts) {
4672
4960
  }
4673
4961
  );
4674
4962
  g.add("correlate", correlateNode);
4675
- for (const b of branches) {
4676
- try {
4677
- g.connect(`stratify::branch/${b.name}`, "correlate");
4678
- } catch {
4679
- }
4680
- }
4681
4963
  const sloCheckFn = opts.sloCheck ?? (() => ({ pass: true }));
4682
4964
  const sloValue = derived([correlateNode], (vals) => vals[0], {
4683
4965
  meta: baseMeta3("observability", { stage: "slo_value" })
@@ -4687,8 +4969,6 @@ function observabilityGraph(name, opts) {
4687
4969
  });
4688
4970
  g.add("slo_value", sloValue);
4689
4971
  g.add("slo_verified", sloVerified);
4690
- g.connect("correlate", "slo_value");
4691
- g.connect("slo_value", "slo_verified");
4692
4972
  const weightValues = opts.weights ?? branches.map(() => 1);
4693
4973
  const signalNodes = branchNodes.map(
4694
4974
  (bn) => derived([bn], (vals) => vals[0] != null ? 1 : 0)
@@ -4714,8 +4994,6 @@ function observabilityGraph(name, opts) {
4714
4994
  }
4715
4995
  );
4716
4996
  g.add("output", output);
4717
- g.connect("alerts", "output");
4718
- g.connect("slo_verified", "output");
4719
4997
  const fbReentry = state(null, {
4720
4998
  meta: baseMeta3("observability", { stage: "feedback_reentry" })
4721
4999
  });
@@ -4732,7 +5010,6 @@ function observabilityGraph(name, opts) {
4732
5010
  }
4733
5011
  );
4734
5012
  g.add("feedback_condition", fbCondition);
4735
- g.connect("slo_verified", "feedback_condition");
4736
5013
  feedback(g, "feedback_condition", "feedback_reentry", {
4737
5014
  maxIterations: opts.maxFeedbackIterations ?? 5
4738
5015
  });
@@ -4754,7 +5031,6 @@ function issueTrackerGraph(name, opts) {
4754
5031
  meta: baseMeta3("issue_tracker", { stage: "extract" })
4755
5032
  });
4756
5033
  g.add("extract", extractNode);
4757
- g.connect("source", "extract");
4758
5034
  const verifyFn = opts.verify ?? (() => ({ valid: true }));
4759
5035
  const verifyNode = derived(
4760
5036
  [extractNode],
@@ -4767,7 +5043,6 @@ function issueTrackerGraph(name, opts) {
4767
5043
  }
4768
5044
  );
4769
5045
  g.add("verify", verifyNode);
4770
- g.connect("extract", "verify");
4771
5046
  const knownPatterns = state([], {
4772
5047
  meta: baseMeta3("issue_tracker", { stage: "known_patterns" })
4773
5048
  });
@@ -4783,8 +5058,6 @@ function issueTrackerGraph(name, opts) {
4783
5058
  { meta: baseMeta3("issue_tracker", { stage: "regression" }) }
4784
5059
  );
4785
5060
  g.add("regression", regressionNode);
4786
- g.connect("extract", "regression");
4787
- g.connect("known_patterns", "regression");
4788
5061
  const severitySignal = derived([extractNode], (vals) => {
4789
5062
  const issue = vals[0];
4790
5063
  return issue?.severity ?? 0;
@@ -4811,9 +5084,6 @@ function issueTrackerGraph(name, opts) {
4811
5084
  { meta: baseMeta3("issue_tracker", { stage: "output" }) }
4812
5085
  );
4813
5086
  g.add("output", output);
4814
- g.connect("verify", "output");
4815
- g.connect("regression", "output");
4816
- g.connect("priority", "output");
4817
5087
  const fbReentry = state(null, {
4818
5088
  meta: baseMeta3("issue_tracker", { stage: "feedback_reentry" })
4819
5089
  });
@@ -4833,7 +5103,6 @@ function issueTrackerGraph(name, opts) {
4833
5103
  }
4834
5104
  );
4835
5105
  g.add("feedback_condition", fbCondition);
4836
- g.connect("verify", "feedback_condition");
4837
5106
  feedback(g, "feedback_condition", "feedback_reentry", {
4838
5107
  maxIterations: opts.maxFeedbackIterations ?? 3
4839
5108
  });
@@ -4852,7 +5121,6 @@ function contentModerationGraph(name, opts) {
4852
5121
  meta: baseMeta3("content_moderation", { stage: "classify" })
4853
5122
  });
4854
5123
  g.add("classify", classifyNode);
4855
- g.connect("source", "classify");
4856
5124
  const strat = stratify("stratify", classifyNode, [
4857
5125
  { name: "safe", classify: (v) => v.label === "safe" },
4858
5126
  { name: "review", classify: (v) => v.label === "review" },
@@ -4880,7 +5148,6 @@ function contentModerationGraph(name, opts) {
4880
5148
  g.add("__review_accumulator", reviewAccumulator);
4881
5149
  g.addDisposer(keepalive(reviewAccumulator));
4882
5150
  try {
4883
- g.connect("stratify::branch/review", "__review_accumulator");
4884
5151
  } catch {
4885
5152
  }
4886
5153
  const policy2 = state(
@@ -4921,8 +5188,6 @@ function contentModerationGraph(name, opts) {
4921
5188
  { meta: baseMeta3("content_moderation", { stage: "output" }) }
4922
5189
  );
4923
5190
  g.add("output", output);
4924
- g.connect("classify", "output");
4925
- g.connect("priority", "output");
4926
5191
  const fbCondition = derived(
4927
5192
  [reviewLog.entries, policy2],
4928
5193
  (vals) => {
@@ -4959,7 +5224,6 @@ function dataQualityGraph(name, opts) {
4959
5224
  { meta: baseMeta3("data_quality", { stage: "validate" }) }
4960
5225
  );
4961
5226
  g.add("validate", validateNode);
4962
- g.connect("source", "validate");
4963
5227
  const detectAnomalyFn = opts.detectAnomaly ?? ((record) => ({
4964
5228
  anomaly: false,
4965
5229
  score: 0,
@@ -4971,7 +5235,6 @@ function dataQualityGraph(name, opts) {
4971
5235
  { meta: baseMeta3("data_quality", { stage: "anomaly" }) }
4972
5236
  );
4973
5237
  g.add("anomaly", anomalyNode);
4974
- g.connect("source", "anomaly");
4975
5238
  const baseline = state(null, {
4976
5239
  meta: baseMeta3("data_quality", {
4977
5240
  stage: "baseline",
@@ -4988,7 +5251,6 @@ function dataQualityGraph(name, opts) {
4988
5251
  }
4989
5252
  });
4990
5253
  g.add("__baseline_updater", baselineUpdater);
4991
- g.connect("validate", "__baseline_updater");
4992
5254
  keepalive(baselineUpdater);
4993
5255
  const detectDriftFn = opts.detectDrift ?? (() => ({ drift: false }));
4994
5256
  const driftNode = derived(
@@ -4997,8 +5259,6 @@ function dataQualityGraph(name, opts) {
4997
5259
  { meta: baseMeta3("data_quality", { stage: "drift" }) }
4998
5260
  );
4999
5261
  g.add("drift", driftNode);
5000
- g.connect("source", "drift");
5001
- g.connect("baseline", "drift");
5002
5262
  const suggestFn = opts.suggest ?? (() => null);
5003
5263
  const remediateNode = derived(
5004
5264
  [validateNode, anomalyNode],
@@ -5009,8 +5269,6 @@ function dataQualityGraph(name, opts) {
5009
5269
  { meta: baseMeta3("data_quality", { stage: "remediate" }) }
5010
5270
  );
5011
5271
  g.add("remediate", remediateNode);
5012
- g.connect("validate", "remediate");
5013
- g.connect("anomaly", "remediate");
5014
5272
  const output = derived(
5015
5273
  [validateNode, anomalyNode, driftNode, remediateNode],
5016
5274
  (vals) => ({
@@ -5022,10 +5280,6 @@ function dataQualityGraph(name, opts) {
5022
5280
  { meta: baseMeta3("data_quality", { stage: "output" }) }
5023
5281
  );
5024
5282
  g.add("output", output);
5025
- g.connect("validate", "output");
5026
- g.connect("anomaly", "output");
5027
- g.connect("drift", "output");
5028
- g.connect("remediate", "output");
5029
5283
  const validationRules = state([], {
5030
5284
  meta: baseMeta3("data_quality", { stage: "validation_rules" })
5031
5285
  });
@@ -5042,7 +5296,6 @@ function dataQualityGraph(name, opts) {
5042
5296
  }
5043
5297
  );
5044
5298
  g.add("feedback_condition", fbCondition);
5045
- g.connect("anomaly", "feedback_condition");
5046
5299
  feedback(g, "feedback_condition", "validation_rules", {
5047
5300
  maxIterations: opts.maxFeedbackIterations ?? 3
5048
5301
  });
@@ -5568,20 +5821,6 @@ ${catalogValidation.errors.join("\n")}`
5568
5821
  } catch {
5569
5822
  }
5570
5823
  }
5571
- for (const [name, raw] of Object.entries(spec.nodes)) {
5572
- if (raw.type === "template") continue;
5573
- const n = raw;
5574
- for (const dep of n.deps ?? []) {
5575
- try {
5576
- g.connect(dep, name);
5577
- } catch (err) {
5578
- const msg = err instanceof Error ? err.message : "";
5579
- if (!msg.includes("constructor deps") && !msg.includes("already")) {
5580
- throw err;
5581
- }
5582
- }
5583
- }
5584
- }
5585
5824
  for (const fb of spec.feedback ?? []) {
5586
5825
  feedback(g, fb.from, fb.to, {
5587
5826
  maxIterations: fb.maxIterations
@@ -6472,6 +6711,7 @@ function harnessLoop(name, opts) {
6472
6711
  }
6473
6712
  const routerInput = withLatestFrom(triageNode, triageInput);
6474
6713
  const router = effect([routerInput], ([pair]) => {
6714
+ if (pair == null) return;
6475
6715
  const [classification, triagePair] = pair;
6476
6716
  if (!classification || !classification.route) return;
6477
6717
  const intakeItem = triagePair?.[0];
@@ -6517,32 +6757,43 @@ function harnessLoop(name, opts) {
6517
6757
  retries: 1
6518
6758
  }
6519
6759
  );
6760
+ const executeContextNode = withLatestFrom(
6761
+ executeNode,
6762
+ executeInput
6763
+ );
6520
6764
  const verifyResults = new TopicGraph("verify-results", { retainedLimit });
6521
6765
  const verifyNode = promptNode(
6522
6766
  adapter,
6523
- [executeNode, executeInput],
6524
- opts.verifyPrompt ?? ((execution, item) => DEFAULT_VERIFY_PROMPT.replace("{{execution}}", JSON.stringify(execution)).replace(
6525
- "{{item}}",
6526
- JSON.stringify(item)
6527
- )),
6767
+ [executeContextNode],
6768
+ opts.verifyPrompt ?? ((ctxPair) => {
6769
+ const [execution, item] = ctxPair;
6770
+ return DEFAULT_VERIFY_PROMPT.replace("{{execution}}", JSON.stringify(execution)).replace(
6771
+ "{{item}}",
6772
+ JSON.stringify(item)
6773
+ );
6774
+ }),
6528
6775
  {
6529
6776
  name: "verify",
6530
6777
  format: "json",
6531
6778
  retries: 1
6532
6779
  }
6533
6780
  );
6534
- const verifyWithExec = withLatestFrom(verifyNode, executeNode);
6535
6781
  const verifyContext = withLatestFrom(
6536
- verifyWithExec,
6537
- executeInput
6782
+ verifyNode,
6783
+ executeContextNode
6538
6784
  );
6539
6785
  const maxReingestions = opts.maxReingestions ?? 1;
6540
6786
  const maxTotalRetries = Math.min(opts.maxTotalRetries ?? maxRetries * 10, 100);
6541
6787
  const maxTotalReingestions = Math.min(opts.maxTotalReingestions ?? maxReingestions * 10, 100);
6542
6788
  const totalRetries = state(0);
6543
6789
  const totalReingestions = state(0);
6544
- const fastRetry = effect([verifyContext], ([ctx]) => {
6545
- const [[vo, execRaw], item] = ctx;
6790
+ const fastRetry = node([verifyContext], (batchData, _actions) => {
6791
+ const batch2 = batchData[0];
6792
+ if (batch2 == null || batch2.length === 0) return;
6793
+ const ctxVal = batch2[batch2.length - 1];
6794
+ if (ctxVal == null) return;
6795
+ const [vo, execCtx] = ctxVal;
6796
+ const [execRaw, item] = execCtx ?? [null, null];
6546
6797
  if (!vo || !item) return;
6547
6798
  const exec = {
6548
6799
  item,
@@ -6567,8 +6818,7 @@ function harnessLoop(name, opts) {
6567
6818
  detail: vr.findings.join("; ")
6568
6819
  });
6569
6820
  const itemRetries = item._retries ?? 0;
6570
- if (errClass === "self-correctable" && itemRetries < maxRetries && (totalRetries.get() ?? 0) < maxTotalRetries) {
6571
- totalRetries.down([[DIRTY], [DATA, (totalRetries.get() ?? 0) + 1]]);
6821
+ if (errClass === "self-correctable" && itemRetries < maxRetries && tryIncrementBounded(totalRetries, maxTotalRetries)) {
6572
6822
  const key = trackingKey(item);
6573
6823
  const retryItem = {
6574
6824
  ...item,
@@ -6582,8 +6832,7 @@ function harnessLoop(name, opts) {
6582
6832
  verifyResults.publish(vr);
6583
6833
  const key = trackingKey(item);
6584
6834
  const itemReingestions = item._reingestions ?? 0;
6585
- if (itemReingestions < maxReingestions && (totalReingestions.get() ?? 0) < maxTotalReingestions) {
6586
- totalReingestions.down([[DIRTY], [DATA, (totalReingestions.get() ?? 0) + 1]]);
6835
+ if (itemReingestions < maxReingestions && tryIncrementBounded(totalReingestions, maxTotalReingestions)) {
6587
6836
  intake.publish({
6588
6837
  source: "eval",
6589
6838
  summary: `Verification failed for: ${key}`,
@@ -6636,9 +6885,9 @@ function harnessProfile(harness, opts) {
6636
6885
  return {
6637
6886
  ...base,
6638
6887
  queueDepths,
6639
- strategyEntries: harness.strategy.node.get()?.size ?? 0,
6640
- totalRetries: harness.totalRetries.get() ?? 0,
6641
- totalReingestions: harness.totalReingestions.get() ?? 0
6888
+ strategyEntries: harness.strategy.node.cache?.size ?? 0,
6889
+ totalRetries: harness.totalRetries.cache ?? 0,
6890
+ totalReingestions: harness.totalReingestions.cache ?? 0
6642
6891
  };
6643
6892
  }
6644
6893
 
@@ -6745,56 +6994,69 @@ function truncate(s, max) {
6745
6994
  // src/index.ts
6746
6995
  var version = "0.0.0";
6747
6996
  export {
6748
- CLEANUP_RESULT,
6749
6997
  COMPLETE,
6998
+ COMPLETE_MSG,
6999
+ COMPLETE_ONLY_BATCH,
6750
7000
  CircuitOpenError,
6751
7001
  DATA,
6752
7002
  DEFAULT_ACTOR,
6753
- DEFAULT_DOWN,
6754
7003
  DIRTY,
6755
- DictCheckpointAdapter,
6756
- DynamicNodeImpl,
7004
+ DIRTY_MSG,
7005
+ DIRTY_ONLY_BATCH,
7006
+ ENVELOPE_VERSION,
6757
7007
  ERROR,
6758
- FileCheckpointAdapter,
6759
7008
  GRAPH_META_SEGMENT,
6760
7009
  Graph,
7010
+ GraphReFlyConfig,
6761
7011
  GuardDenied,
6762
7012
  INVALIDATE,
7013
+ INVALIDATE_MSG,
7014
+ INVALIDATE_ONLY_BATCH,
6763
7015
  JsonCodec,
6764
- MemoryCheckpointAdapter,
6765
7016
  NS_PER_MS,
6766
7017
  NS_PER_SEC,
7018
+ NativeIndexBackend,
7019
+ NativeListBackend,
7020
+ NativeLogBackend,
7021
+ NativeMapBackend,
7022
+ NativePubSubBackend,
7023
+ NodeImpl,
6767
7024
  PAUSE,
6768
7025
  RESOLVED,
7026
+ RESOLVED_MSG,
7027
+ RESOLVED_ONLY_BATCH,
6769
7028
  RESUME,
7029
+ RateLimiterOverflowError,
6770
7030
  ResettableTimer,
7031
+ OVERHEAD as SIZEOF_OVERHEAD,
7032
+ SIZEOF_SYMBOL,
6771
7033
  START,
6772
- SqliteCheckpointAdapter,
7034
+ START_MSG,
6773
7035
  TEARDOWN,
7036
+ TEARDOWN_MSG,
7037
+ TEARDOWN_ONLY_BATCH,
6774
7038
  TimeoutError,
6775
7039
  accessHintForGuard,
6776
7040
  advanceVersion,
6777
7041
  ai_exports as ai,
6778
7042
  audit,
7043
+ autoTrackNode,
6779
7044
  batch,
6780
- bridge,
6781
7045
  buffer,
6782
7046
  bufferCount,
6783
7047
  bufferTime,
6784
- cache,
6785
7048
  cached,
6786
7049
  cascadingCache,
6787
7050
  catchError,
6788
- checkpointNodeValue,
6789
7051
  checkpointToRedis,
6790
7052
  checkpointToS3,
6791
7053
  circuitBreaker,
6792
- cleanupResult,
6793
7054
  combine,
6794
7055
  combineLatest,
6795
7056
  compat_exports as compat,
6796
7057
  concat,
6797
7058
  concatMap,
7059
+ configure,
6798
7060
  constant,
6799
7061
  core_exports as core,
6800
7062
  cqrs_exports as cqrs,
@@ -6803,14 +7065,19 @@ export {
6803
7065
  createTransport,
6804
7066
  createVersioning,
6805
7067
  createWatermarkController,
7068
+ csvRows,
6806
7069
  debounce,
6807
7070
  debounceTime,
7071
+ decodeEnvelope,
6808
7072
  decorrelatedJitter,
7073
+ defaultConfig,
6809
7074
  defaultHash,
6810
7075
  delay,
6811
7076
  demo_shell_exports as demoShell,
6812
7077
  derived,
6813
7078
  deserializeError,
7079
+ dictStorage,
7080
+ diffForWAL,
6814
7081
  distill,
6815
7082
  distinctUntilChanged,
6816
7083
  domain_templates_exports as domainTemplates,
@@ -6819,12 +7086,16 @@ export {
6819
7086
  effect,
6820
7087
  elementAt,
6821
7088
  empty,
7089
+ encodeEnvelope,
6822
7090
  escapeRegexChar,
6823
7091
  exhaustMap,
6824
7092
  exponential,
7093
+ externalBundle,
7094
+ externalProducer,
6825
7095
  extra_exports as extra,
6826
7096
  fallback,
6827
7097
  fibonacci,
7098
+ fileStorage,
6828
7099
  filter,
6829
7100
  find,
6830
7101
  first,
@@ -6842,6 +7113,8 @@ export {
6842
7113
  fromFSWatch,
6843
7114
  fromGitHook,
6844
7115
  fromHTTP,
7116
+ fromHTTPPoll,
7117
+ fromHTTPStream,
6845
7118
  fromIDBRequest,
6846
7119
  fromIDBTransaction,
6847
7120
  fromIter,
@@ -6857,44 +7130,42 @@ export {
6857
7130
  fromPulsar,
6858
7131
  fromRabbitMQ,
6859
7132
  fromRedisStream,
7133
+ fromSSE,
6860
7134
  fromSqlite,
7135
+ fromSqliteCursor,
6861
7136
  fromStatsD,
6862
7137
  fromSyslog,
6863
7138
  fromTimer,
6864
7139
  fromWebSocket,
7140
+ fromWebSocketReconnect,
6865
7141
  fromWebhook,
6866
7142
  globToRegExp,
6867
7143
  graph_exports as graph,
6868
7144
  graphProfile,
6869
7145
  graphspec_exports as graphspec,
6870
7146
  harness_exports as harness,
7147
+ indexedDbStorage,
6871
7148
  interval,
6872
7149
  isBatching,
6873
- isKnownMessageType,
6874
- isLocalOnly,
6875
- isPhase2Message,
6876
- isTerminalMessage,
6877
7150
  isV1,
6878
7151
  jotai_exports as jotai,
6879
7152
  keepalive,
6880
- knownMessageTypes,
6881
7153
  last,
6882
7154
  reactive_layout_exports as layout,
6883
7155
  linear,
6884
- logSlice,
6885
7156
  lru,
6886
7157
  map,
6887
7158
  matchesAnyPattern,
6888
7159
  matchesCron,
6889
7160
  memory_exports as memory,
7161
+ memoryStorage,
6890
7162
  merge,
6891
7163
  mergeMap,
6892
- messageTier,
6893
7164
  messaging_exports as messaging,
6894
7165
  monotonicNs,
6895
7166
  nameToSignal,
6896
7167
  nanostores_exports as nanostores,
6897
- negotiateCodec,
7168
+ ndjsonRows,
6898
7169
  nestjs_exports as nestjs,
6899
7170
  never,
6900
7171
  node,
@@ -6906,14 +7177,12 @@ export {
6906
7177
  parsePrometheusText,
6907
7178
  parseStatsD,
6908
7179
  parseSyslog,
6909
- partitionForBatch,
6910
7180
  patterns_exports as patterns,
6911
7181
  pausable,
6912
7182
  pipe,
6913
7183
  policy,
6914
7184
  policyFromRules,
6915
7185
  producer,
6916
- propagatesToMeta,
6917
7186
  pubsub,
6918
7187
  race,
6919
7188
  rateLimiter,
@@ -6924,20 +7193,20 @@ export {
6924
7193
  reactiveList,
6925
7194
  reactiveLog,
6926
7195
  reactiveMap,
7196
+ reactiveSink,
6927
7197
  reduce,
6928
7198
  reduction_exports as reduction,
7199
+ registerBuiltinCodecs,
7200
+ registerBuiltins,
6929
7201
  repeat,
6930
7202
  replay,
6931
7203
  replayWAL,
6932
7204
  rescue,
6933
7205
  resolveBackoffPreset,
6934
7206
  resolveDescribeFields,
6935
- restoreGraphCheckpoint,
6936
- restoreGraphCheckpointIndexedDb,
6937
7207
  retry,
7208
+ retrySource,
6938
7209
  sample,
6939
- saveGraphCheckpoint,
6940
- saveGraphCheckpointIndexedDb,
6941
7210
  scan,
6942
7211
  serializeError,
6943
7212
  share,
@@ -6947,6 +7216,7 @@ export {
6947
7216
  sizeof,
6948
7217
  skip,
6949
7218
  solid_exports as solid,
7219
+ sqliteStorage,
6950
7220
  state,
6951
7221
  svelte_exports as svelte,
6952
7222
  switchMap,
@@ -6957,12 +7227,12 @@ export {
6957
7227
  throttle,
6958
7228
  throttleTime,
6959
7229
  throwError,
6960
- tieredStorage,
6961
7230
  timeout,
6962
7231
  toArray,
6963
7232
  toCSV,
6964
7233
  toClickHouse,
6965
7234
  toFile,
7235
+ toHTTP,
6966
7236
  toKafka,
6967
7237
  toLoki,
6968
7238
  toMongo,
@@ -6971,14 +7241,15 @@ export {
6971
7241
  toPostgres,
6972
7242
  toPulsar,
6973
7243
  toRabbitMQ,
7244
+ toReadableStream,
6974
7245
  toRedisStream,
6975
7246
  toS3,
6976
7247
  toSSE,
7248
+ toSSEBytes,
6977
7249
  toSqlite,
6978
7250
  toTempo,
6979
7251
  toWebSocket,
6980
7252
  tokenBucket,
6981
- tokenTracker,
6982
7253
  valve,
6983
7254
  verifiable,
6984
7255
  version,