@graphrefly/graphrefly 0.6.0 → 0.8.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 (75) hide show
  1. package/README.md +30 -14
  2. package/dist/{chunk-HP7OKEOE.js → chunk-A2AJJOSJ.js} +3 -3
  3. package/dist/chunk-A2AJJOSJ.js.map +1 -0
  4. package/dist/{chunk-CP6MNKAA.js → chunk-E7OH6ZAZ.js} +10 -4
  5. package/dist/{chunk-CP6MNKAA.js.map → chunk-E7OH6ZAZ.js.map} +1 -1
  6. package/dist/chunk-LR2CLSEF.js +106 -0
  7. package/dist/chunk-LR2CLSEF.js.map +1 -0
  8. package/dist/{chunk-5X3LAO3B.js → chunk-QTZSBQGJ.js} +79 -20
  9. package/dist/chunk-QTZSBQGJ.js.map +1 -0
  10. package/dist/{chunk-V3UACY6A.js → chunk-TZLX4KIT.js} +790 -203
  11. package/dist/chunk-TZLX4KIT.js.map +1 -0
  12. package/dist/{chunk-QW7H3ICI.js → chunk-UCW3VWMN.js} +4 -4
  13. package/dist/{chunk-6W5SGIGB.js → chunk-WYI7YW54.js} +142 -30
  14. package/dist/chunk-WYI7YW54.js.map +1 -0
  15. package/dist/chunk-WZ2Z2CRV.js +32 -0
  16. package/dist/chunk-WZ2Z2CRV.js.map +1 -0
  17. package/dist/{chunk-Z4Y4FMQN.js → chunk-XCZPGOVP.js} +7 -7
  18. package/dist/{chunk-KWXPDASV.js → chunk-YWTP2XRJ.js} +2 -2
  19. package/dist/compat/nestjs/index.cjs +268 -61
  20. package/dist/compat/nestjs/index.cjs.map +1 -1
  21. package/dist/compat/nestjs/index.d.cts +4 -4
  22. package/dist/compat/nestjs/index.d.ts +4 -4
  23. package/dist/compat/nestjs/index.js +8 -7
  24. package/dist/core/index.cjs +163 -35
  25. package/dist/core/index.cjs.map +1 -1
  26. package/dist/core/index.d.cts +2 -2
  27. package/dist/core/index.d.ts +2 -2
  28. package/dist/core/index.js +10 -4
  29. package/dist/extra/index.cjs +892 -221
  30. package/dist/extra/index.cjs.map +1 -1
  31. package/dist/extra/index.d.cts +4 -4
  32. package/dist/extra/index.d.ts +4 -4
  33. package/dist/extra/index.js +22 -3
  34. package/dist/graph/index.cjs +268 -61
  35. package/dist/graph/index.cjs.map +1 -1
  36. package/dist/graph/index.d.cts +3 -3
  37. package/dist/graph/index.d.ts +3 -3
  38. package/dist/graph/index.js +4 -4
  39. package/dist/{graph-CL_ZDAj9.d.cts → graph-DqTICAY2.d.cts} +69 -12
  40. package/dist/{graph-D18qmsNm.d.ts → graph-X9uwnD_z.d.ts} +69 -12
  41. package/dist/{index-C3BMRmmp.d.cts → index-3U0WxdD-.d.cts} +3 -3
  42. package/dist/{index-Bk_idZm1.d.cts → index-BP1t_38S.d.cts} +406 -61
  43. package/dist/{index-BtK55IE2.d.ts → index-BPCeYDS4.d.ts} +4 -2
  44. package/dist/{index-Bvy_6CaN.d.ts → index-BVG5pjin.d.ts} +50 -5
  45. package/dist/{index-C5mqLhMX.d.cts → index-BYEgosAX.d.cts} +50 -5
  46. package/dist/{index-D_geH2Bm.d.cts → index-BYa2YMat.d.cts} +3 -3
  47. package/dist/{index-CP_QvbWu.d.ts → index-DLO8wnYU.d.ts} +3 -3
  48. package/dist/{index-B7eOdgEx.d.ts → index-DMv1Etbi.d.ts} +3 -3
  49. package/dist/{index-BvhgZRHK.d.cts → index-DbwgQ4Cw.d.cts} +4 -2
  50. package/dist/{index-B2jmzVxL.d.ts → index-a5gHmH5b.d.ts} +406 -61
  51. package/dist/index.cjs +2966 -1790
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.cts +112 -14
  54. package/dist/index.d.ts +112 -14
  55. package/dist/index.js +385 -20
  56. package/dist/index.js.map +1 -1
  57. package/dist/{meta-BsF6Sag9.d.cts → meta-BJEU8fYz.d.cts} +31 -4
  58. package/dist/{meta-BsF6Sag9.d.ts → meta-BJEU8fYz.d.ts} +31 -4
  59. package/dist/patterns/reactive-layout/index.cjs +268 -61
  60. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  61. package/dist/patterns/reactive-layout/index.d.cts +3 -3
  62. package/dist/patterns/reactive-layout/index.d.ts +3 -3
  63. package/dist/patterns/reactive-layout/index.js +4 -4
  64. package/dist/{reactive-log-BfvfNWQh.d.cts → reactive-log-BfX6bOSZ.d.cts} +2 -2
  65. package/dist/{reactive-log-ohLmTXoZ.d.ts → reactive-log-RhgIog2Z.d.ts} +2 -2
  66. package/package.json +29 -18
  67. package/dist/chunk-5X3LAO3B.js.map +0 -1
  68. package/dist/chunk-6W5SGIGB.js.map +0 -1
  69. package/dist/chunk-HP7OKEOE.js.map +0 -1
  70. package/dist/chunk-O3PI7W45.js +0 -68
  71. package/dist/chunk-O3PI7W45.js.map +0 -1
  72. package/dist/chunk-V3UACY6A.js.map +0 -1
  73. /package/dist/{chunk-QW7H3ICI.js.map → chunk-UCW3VWMN.js.map} +0 -0
  74. /package/dist/{chunk-Z4Y4FMQN.js.map → chunk-XCZPGOVP.js.map} +0 -0
  75. /package/dist/{chunk-KWXPDASV.js.map → chunk-YWTP2XRJ.js.map} +0 -0
@@ -27,11 +27,14 @@ __export(extra_exports, {
27
27
  NS_PER_MS: () => NS_PER_MS,
28
28
  NS_PER_SEC: () => NS_PER_SEC,
29
29
  SqliteCheckpointAdapter: () => SqliteCheckpointAdapter,
30
+ TimeoutError: () => TimeoutError,
30
31
  audit: () => audit,
31
32
  buffer: () => buffer,
32
33
  bufferCount: () => bufferCount,
33
34
  bufferTime: () => bufferTime,
35
+ cache: () => cache,
34
36
  cached: () => cached,
37
+ cascadingCache: () => cascadingCache,
35
38
  catchError: () => catchError,
36
39
  checkpointNodeValue: () => checkpointNodeValue,
37
40
  checkpointToRedis: () => checkpointToRedis,
@@ -56,6 +59,7 @@ __export(extra_exports, {
56
59
  escapeRegexChar: () => escapeRegexChar,
57
60
  exhaustMap: () => exhaustMap,
58
61
  exponential: () => exponential,
62
+ fallback: () => fallback,
59
63
  fibonacci: () => fibonacci,
60
64
  filter: () => filter,
61
65
  find: () => find,
@@ -68,6 +72,7 @@ __export(extra_exports, {
68
72
  fromCSV: () => fromCSV,
69
73
  fromClickHouseWatch: () => fromClickHouseWatch,
70
74
  fromCron: () => fromCron,
75
+ fromDrizzle: () => fromDrizzle,
71
76
  fromEvent: () => fromEvent,
72
77
  fromFSWatch: () => fromFSWatch,
73
78
  fromGitHook: () => fromGitHook,
@@ -76,10 +81,12 @@ __export(extra_exports, {
76
81
  fromIDBTransaction: () => fromIDBTransaction,
77
82
  fromIter: () => fromIter,
78
83
  fromKafka: () => fromKafka,
84
+ fromKysely: () => fromKysely,
79
85
  fromMCP: () => fromMCP,
80
86
  fromNATS: () => fromNATS,
81
87
  fromNDJSON: () => fromNDJSON,
82
88
  fromOTel: () => fromOTel,
89
+ fromPrisma: () => fromPrisma,
83
90
  fromPrometheus: () => fromPrometheus,
84
91
  fromPromise: () => fromPromise,
85
92
  fromPulsar: () => fromPulsar,
@@ -97,6 +104,7 @@ __export(extra_exports, {
97
104
  last: () => last,
98
105
  linear: () => linear,
99
106
  logSlice: () => logSlice,
107
+ lru: () => lru,
100
108
  map: () => map,
101
109
  matchesAnyPattern: () => matchesAnyPattern,
102
110
  matchesCron: () => matchesCron,
@@ -146,6 +154,7 @@ __export(extra_exports, {
146
154
  throttle: () => throttle,
147
155
  throttleTime: () => throttleTime,
148
156
  throwError: () => throwError,
157
+ tieredStorage: () => tieredStorage,
149
158
  timeout: () => timeout,
150
159
  toArray: () => toArray,
151
160
  toCSV: () => toCSV,
@@ -330,10 +339,14 @@ function partitionForBatch(messages) {
330
339
  }
331
340
  return { immediate, deferred, terminal };
332
341
  }
333
- function emitWithBatch(emit, messages, phase = 2) {
342
+ function emitWithBatch(emit, messages, phase = 2, options) {
334
343
  if (messages.length === 0) {
335
344
  return;
336
345
  }
346
+ if (options?.strategy === "sequential") {
347
+ _emitSequential(emit, messages, phase);
348
+ return;
349
+ }
337
350
  const queue = phase === 3 ? pendingPhase3 : pendingPhase2;
338
351
  if (messages.length === 1) {
339
352
  const t = messages[0][0];
@@ -374,6 +387,29 @@ function emitWithBatch(emit, messages, phase = 2) {
374
387
  }
375
388
  }
376
389
  }
390
+ function _emitSequential(emit, messages, phase = 2) {
391
+ const dataQueue = phase === 3 ? pendingPhase3 : pendingPhase2;
392
+ for (const msg of messages) {
393
+ const tier = messageTier(msg[0]);
394
+ if (tier === 2) {
395
+ if (isBatching()) {
396
+ const m = msg;
397
+ dataQueue.push(() => emit([m]));
398
+ } else {
399
+ emit([msg]);
400
+ }
401
+ } else if (tier >= 3) {
402
+ if (isBatching()) {
403
+ const m = msg;
404
+ pendingPhase3.push(() => emit([m]));
405
+ } else {
406
+ emit([msg]);
407
+ }
408
+ } else {
409
+ emit([msg]);
410
+ }
411
+ }
412
+ }
377
413
 
378
414
  // src/core/clock.ts
379
415
  function monotonicNs() {
@@ -472,6 +508,7 @@ function advanceVersion(info, newValue, hashFn) {
472
508
  }
473
509
 
474
510
  // src/core/node.ts
511
+ var NO_VALUE = /* @__PURE__ */ Symbol.for("graphrefly/NO_VALUE");
475
512
  function createIntBitSet() {
476
513
  let bits = 0;
477
514
  return {
@@ -601,10 +638,10 @@ var NodeImpl = class {
601
638
  this._hasDeps = deps.length > 0;
602
639
  this._autoComplete = opts.completeWhenDepsComplete ?? true;
603
640
  this._isSingleDep = deps.length === 1 && fn != null;
604
- this._cached = opts.initial;
641
+ this._cached = "initial" in opts ? opts.initial : NO_VALUE;
605
642
  this._status = this._hasDeps ? "disconnected" : "settled";
606
643
  this._hashFn = opts.versioningHash ?? defaultHash;
607
- this._versioning = opts.versioning != null ? createVersioning(opts.versioning, this._cached, {
644
+ this._versioning = opts.versioning != null ? createVersioning(opts.versioning, this._cached === NO_VALUE ? void 0 : this._cached, {
608
645
  id: opts.versioningId,
609
646
  hash: this._hashFn
610
647
  }) : void 0;
@@ -688,10 +725,14 @@ var NodeImpl = class {
688
725
  _applyVersioning(level, opts) {
689
726
  if (this._versioning != null) return;
690
727
  this._hashFn = opts?.hash ?? this._hashFn;
691
- this._versioning = createVersioning(level, this._cached, {
692
- id: opts?.id,
693
- hash: this._hashFn
694
- });
728
+ this._versioning = createVersioning(
729
+ level,
730
+ this._cached === NO_VALUE ? void 0 : this._cached,
731
+ {
732
+ id: opts?.id,
733
+ hash: this._hashFn
734
+ }
735
+ );
695
736
  }
696
737
  hasGuard() {
697
738
  return this._guard != null;
@@ -701,7 +742,7 @@ var NodeImpl = class {
701
742
  return this._guard(normalizeActor(actor), "observe");
702
743
  }
703
744
  get() {
704
- return this._cached;
745
+ return this._cached === NO_VALUE ? void 0 : this._cached;
705
746
  }
706
747
  down(messages, options) {
707
748
  if (messages.length === 0) return;
@@ -758,6 +799,7 @@ var NodeImpl = class {
758
799
  }
759
800
  if (this._terminal && this._opts.resubscribable) {
760
801
  this._terminal = false;
802
+ this._cached = NO_VALUE;
761
803
  this._status = this._hasDeps ? "disconnected" : "settled";
762
804
  this._opts.onResubscribe?.();
763
805
  }
@@ -857,7 +899,7 @@ var NodeImpl = class {
857
899
  const cleanupFn = this._cleanup;
858
900
  this._cleanup = void 0;
859
901
  cleanupFn?.();
860
- this._cached = void 0;
902
+ this._cached = NO_VALUE;
861
903
  this._lastDepValues = void 0;
862
904
  }
863
905
  this._status = statusAfterMessage(this._status, m);
@@ -866,7 +908,7 @@ var NodeImpl = class {
866
908
  }
867
909
  if (t === TEARDOWN) {
868
910
  if (this._opts.resetOnTeardown) {
869
- this._cached = void 0;
911
+ this._cached = NO_VALUE;
870
912
  }
871
913
  const teardownCleanup = this._cleanup;
872
914
  this._cleanup = void 0;
@@ -897,7 +939,15 @@ var NodeImpl = class {
897
939
  }
898
940
  _emitAutoValue(value) {
899
941
  const wasDirty = this._status === "dirty";
900
- const unchanged = this._equals(this._cached, value);
942
+ let unchanged;
943
+ try {
944
+ unchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);
945
+ } catch (eqErr) {
946
+ const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
947
+ const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, { cause: eqErr });
948
+ this._downInternal([[ERROR, wrapped]]);
949
+ return;
950
+ }
901
951
  if (unchanged) {
902
952
  this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
903
953
  return;
@@ -944,7 +994,9 @@ var NodeImpl = class {
944
994
  if (out === void 0) return;
945
995
  this._emitAutoValue(out);
946
996
  } catch (err) {
947
- this._downInternal([[ERROR, err]]);
997
+ const errMsg = err instanceof Error ? err.message : String(err);
998
+ const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, { cause: err });
999
+ this._downInternal([[ERROR, wrapped]]);
948
1000
  }
949
1001
  }
950
1002
  _onDepDirty(index) {
@@ -979,7 +1031,11 @@ var NodeImpl = class {
979
1031
  try {
980
1032
  if (this._onMessage(msg, index, this._actions)) continue;
981
1033
  } catch (err) {
982
- this._downInternal([[ERROR, err]]);
1034
+ const errMsg = err instanceof Error ? err.message : String(err);
1035
+ const wrapped = new Error(`Node "${this.name}": onMessage threw: ${errMsg}`, {
1036
+ cause: err
1037
+ });
1038
+ this._downInternal([[ERROR, wrapped]]);
983
1039
  return;
984
1040
  }
985
1041
  }
@@ -1194,6 +1250,34 @@ function resolveBackoffPreset(name) {
1194
1250
  );
1195
1251
  }
1196
1252
 
1253
+ // src/core/timer.ts
1254
+ var ResettableTimer = class {
1255
+ _timer;
1256
+ _gen = 0;
1257
+ /** Schedule callback after delayMs. Cancels any pending timer. */
1258
+ start(delayMs, callback) {
1259
+ this.cancel();
1260
+ this._gen += 1;
1261
+ const gen = this._gen;
1262
+ this._timer = setTimeout(() => {
1263
+ this._timer = void 0;
1264
+ if (gen !== this._gen) return;
1265
+ callback();
1266
+ }, delayMs);
1267
+ }
1268
+ /** Cancel the pending timer (if any). */
1269
+ cancel() {
1270
+ if (this._timer !== void 0) {
1271
+ clearTimeout(this._timer);
1272
+ this._timer = void 0;
1273
+ }
1274
+ }
1275
+ /** Whether a timer is currently pending. */
1276
+ get pending() {
1277
+ return this._timer !== void 0;
1278
+ }
1279
+ };
1280
+
1197
1281
  // src/extra/resilience.ts
1198
1282
  function operatorOpts(opts) {
1199
1283
  return { describeKind: "operator", ...opts };
@@ -1223,14 +1307,7 @@ function retry(source, opts) {
1223
1307
  let stopped = false;
1224
1308
  let prevDelay = null;
1225
1309
  let unsub;
1226
- let timer;
1227
- let timerGen = 0;
1228
- function cancelTimer() {
1229
- if (timer !== void 0) {
1230
- clearTimeout(timer);
1231
- timer = void 0;
1232
- }
1233
- }
1310
+ const timer = new ResettableTimer();
1234
1311
  function disconnectUpstream() {
1235
1312
  unsub?.();
1236
1313
  unsub = void 0;
@@ -1246,20 +1323,18 @@ function retry(source, opts) {
1246
1323
  const delayNs = coerceDelayNs(raw === void 0 ? null : raw);
1247
1324
  prevDelay = delayNs;
1248
1325
  attempt += 1;
1249
- timerGen += 1;
1250
- const gen = timerGen;
1251
1326
  disconnectUpstream();
1252
1327
  const delayMs = delayNs > 0 ? delayNs / NS_PER_MS : 1;
1253
- timer = setTimeout(() => {
1254
- timer = void 0;
1255
- if (stopped || gen !== timerGen) return;
1328
+ timer.start(delayMs, () => {
1329
+ if (stopped) return;
1256
1330
  connect();
1257
- }, delayMs);
1331
+ });
1258
1332
  }
1259
1333
  function connect() {
1260
- cancelTimer();
1334
+ timer.cancel();
1261
1335
  disconnectUpstream();
1262
1336
  unsub = source.subscribe((msgs) => {
1337
+ if (stopped) return;
1263
1338
  for (const m of msgs) {
1264
1339
  const t = m[0];
1265
1340
  if (t === DIRTY) a.down([[DIRTY]]);
@@ -1281,8 +1356,7 @@ function retry(source, opts) {
1281
1356
  connect();
1282
1357
  return () => {
1283
1358
  stopped = true;
1284
- timerGen += 1;
1285
- cancelTimer();
1359
+ timer.cancel();
1286
1360
  disconnectUpstream();
1287
1361
  };
1288
1362
  },
@@ -1462,14 +1536,7 @@ function rateLimiter(source, maxEvents, windowNs) {
1462
1536
  (_d, a) => {
1463
1537
  const times = [];
1464
1538
  const pending = [];
1465
- let timer;
1466
- let timerGen = 0;
1467
- function cancelTimer() {
1468
- if (timer !== void 0) {
1469
- clearTimeout(timer);
1470
- timer = void 0;
1471
- }
1472
- }
1539
+ const timer = new ResettableTimer();
1473
1540
  function prune(now) {
1474
1541
  const boundary = now - windowNs;
1475
1542
  while (times.length > 0 && times[0] <= boundary) times.shift();
@@ -1483,15 +1550,10 @@ function rateLimiter(source, maxEvents, windowNs) {
1483
1550
  a.emit(pending.shift());
1484
1551
  } else {
1485
1552
  const oldest = times[0];
1486
- cancelTimer();
1487
- timerGen += 1;
1488
- const gen = timerGen;
1489
1553
  const delayNs = Math.max(0, oldest + windowNs - monotonicNs());
1490
- timer = setTimeout(() => {
1491
- timer = void 0;
1492
- if (gen !== timerGen) return;
1554
+ timer.start(delayNs / NS_PER_MS, () => {
1493
1555
  tryEmit();
1494
- }, delayNs / NS_PER_MS);
1556
+ });
1495
1557
  return;
1496
1558
  }
1497
1559
  }
@@ -1505,14 +1567,12 @@ function rateLimiter(source, maxEvents, windowNs) {
1505
1567
  tryEmit();
1506
1568
  } else if (t === RESOLVED) a.down([[RESOLVED]]);
1507
1569
  else if (t === COMPLETE) {
1508
- timerGen += 1;
1509
- cancelTimer();
1570
+ timer.cancel();
1510
1571
  pending.length = 0;
1511
1572
  times.length = 0;
1512
1573
  a.down([[COMPLETE]]);
1513
1574
  } else if (t === ERROR) {
1514
- timerGen += 1;
1515
- cancelTimer();
1575
+ timer.cancel();
1516
1576
  pending.length = 0;
1517
1577
  times.length = 0;
1518
1578
  a.down([m]);
@@ -1520,8 +1580,7 @@ function rateLimiter(source, maxEvents, windowNs) {
1520
1580
  }
1521
1581
  });
1522
1582
  return () => {
1523
- timerGen += 1;
1524
- cancelTimer();
1583
+ timer.cancel();
1525
1584
  unsub();
1526
1585
  };
1527
1586
  },
@@ -1582,6 +1641,147 @@ function withStatus(src, options) {
1582
1641
  error: out.meta.error
1583
1642
  };
1584
1643
  }
1644
+ var TimeoutError = class extends Error {
1645
+ name = "TimeoutError";
1646
+ constructor(ns) {
1647
+ super(`Timed out after ${ns / NS_PER_MS}ms`);
1648
+ }
1649
+ };
1650
+ function isNode(x) {
1651
+ return x != null && typeof x.subscribe === "function" && typeof x.get === "function";
1652
+ }
1653
+ function fallback(source, fb) {
1654
+ return producer(
1655
+ (_d, a) => {
1656
+ let fallbackUnsub;
1657
+ let sourceUnsub;
1658
+ sourceUnsub = source.subscribe((msgs) => {
1659
+ for (const m of msgs) {
1660
+ const t = m[0];
1661
+ if (t === DIRTY) a.down([[DIRTY]]);
1662
+ else if (t === DATA) a.emit(m[1]);
1663
+ else if (t === RESOLVED) a.down([[RESOLVED]]);
1664
+ else if (t === COMPLETE) a.down([[COMPLETE]]);
1665
+ else if (t === ERROR) {
1666
+ sourceUnsub?.();
1667
+ if (isNode(fb)) {
1668
+ fallbackUnsub = fb.subscribe((fMsgs) => {
1669
+ a.down(fMsgs);
1670
+ });
1671
+ const cur = fb.get();
1672
+ if (cur !== void 0) a.down([[DATA, cur]]);
1673
+ } else {
1674
+ a.emit(fb);
1675
+ a.down([[COMPLETE]]);
1676
+ }
1677
+ return;
1678
+ } else if (t === TEARDOWN) {
1679
+ fallbackUnsub?.();
1680
+ a.down([m]);
1681
+ return;
1682
+ } else a.down([m]);
1683
+ }
1684
+ });
1685
+ return () => {
1686
+ sourceUnsub?.();
1687
+ fallbackUnsub?.();
1688
+ };
1689
+ },
1690
+ {
1691
+ ...operatorOpts(),
1692
+ initial: source.get()
1693
+ }
1694
+ );
1695
+ }
1696
+ function timeout(source, timeoutNs) {
1697
+ if (timeoutNs <= 0) throw new RangeError("timeoutNs must be > 0");
1698
+ return producer(
1699
+ (_d, a) => {
1700
+ let stopped = false;
1701
+ const timer = new ResettableTimer();
1702
+ function startTimer() {
1703
+ const delayMs = timeoutNs / NS_PER_MS;
1704
+ timer.start(delayMs, () => {
1705
+ if (stopped) return;
1706
+ stopped = true;
1707
+ unsub();
1708
+ a.down([[ERROR, new TimeoutError(timeoutNs)]]);
1709
+ });
1710
+ }
1711
+ const unsub = source.subscribe((msgs) => {
1712
+ for (const m of msgs) {
1713
+ if (stopped) return;
1714
+ const t = m[0];
1715
+ if (t === DIRTY) a.down([[DIRTY]]);
1716
+ else if (t === DATA) {
1717
+ startTimer();
1718
+ a.emit(m[1]);
1719
+ } else if (t === RESOLVED) a.down([[RESOLVED]]);
1720
+ else if (t === COMPLETE) {
1721
+ timer.cancel();
1722
+ stopped = true;
1723
+ a.down([[COMPLETE]]);
1724
+ return;
1725
+ } else if (t === ERROR) {
1726
+ timer.cancel();
1727
+ stopped = true;
1728
+ a.down([m]);
1729
+ return;
1730
+ } else if (t === TEARDOWN) {
1731
+ timer.cancel();
1732
+ stopped = true;
1733
+ a.down([m]);
1734
+ return;
1735
+ } else a.down([m]);
1736
+ }
1737
+ });
1738
+ startTimer();
1739
+ return () => {
1740
+ stopped = true;
1741
+ timer.cancel();
1742
+ unsub();
1743
+ };
1744
+ },
1745
+ {
1746
+ ...operatorOpts(),
1747
+ initial: source.get()
1748
+ }
1749
+ );
1750
+ }
1751
+ function cache(source, ttlNs) {
1752
+ if (ttlNs <= 0) throw new RangeError("ttlNs must be > 0");
1753
+ let cachedValue;
1754
+ let cachedAt = 0;
1755
+ let hasCached = false;
1756
+ return producer(
1757
+ (_d, a) => {
1758
+ if (hasCached && monotonicNs() - cachedAt < ttlNs) {
1759
+ a.down([[DATA, cachedValue]]);
1760
+ }
1761
+ const unsub = source.subscribe((msgs) => {
1762
+ for (const m of msgs) {
1763
+ const t = m[0];
1764
+ if (t === DATA) {
1765
+ cachedValue = m[1];
1766
+ cachedAt = monotonicNs();
1767
+ hasCached = true;
1768
+ a.emit(cachedValue);
1769
+ } else if (t === DIRTY) a.down([[DIRTY]]);
1770
+ else if (t === RESOLVED) a.down([[RESOLVED]]);
1771
+ else if (t === COMPLETE) a.down([[COMPLETE]]);
1772
+ else if (t === ERROR) a.down([m]);
1773
+ else a.down([m]);
1774
+ }
1775
+ });
1776
+ return unsub;
1777
+ },
1778
+ {
1779
+ ...operatorOpts(),
1780
+ resubscribable: true,
1781
+ initial: source.get()
1782
+ }
1783
+ );
1784
+ }
1585
1785
 
1586
1786
  // src/extra/sources.ts
1587
1787
  var import_node_fs = require("fs");
@@ -1939,11 +2139,11 @@ function fromAsyncIter(iterable, opts) {
1939
2139
  };
1940
2140
  }, sourceOpts(rest));
1941
2141
  }
1942
- function isNode(x) {
2142
+ function isNode2(x) {
1943
2143
  return x != null && typeof x.subscribe === "function" && typeof x.get === "function";
1944
2144
  }
1945
2145
  function fromAny(input, opts) {
1946
- if (isNode(input)) {
2146
+ if (isNode2(input)) {
1947
2147
  return input;
1948
2148
  }
1949
2149
  if (isThenable(input)) {
@@ -2075,6 +2275,17 @@ function firstValueFrom(source) {
2075
2275
  var shareReplay = replay;
2076
2276
 
2077
2277
  // src/extra/adapters.ts
2278
+ function createSinkErrorHandler(userHandler) {
2279
+ const errorsNode = state(null);
2280
+ const handler = (err) => {
2281
+ userHandler?.(err);
2282
+ try {
2283
+ errorsNode.down([[DATA, err]]);
2284
+ } catch {
2285
+ }
2286
+ };
2287
+ return { errorsNode, handler };
2288
+ }
2078
2289
  function sourceOpts2(opts) {
2079
2290
  return { describeKind: "producer", ...opts };
2080
2291
  }
@@ -2825,6 +3036,7 @@ function toKafka(source, kafkaProducer, topic, opts) {
2825
3036
  onTransportError,
2826
3037
  ...rest
2827
3038
  } = opts ?? {};
3039
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
2828
3040
  const inner = node([source], () => void 0, {
2829
3041
  describeKind: "effect",
2830
3042
  ...rest,
@@ -2836,7 +3048,7 @@ function toKafka(source, kafkaProducer, topic, opts) {
2836
3048
  try {
2837
3049
  serialized = serialize(value);
2838
3050
  } catch (err) {
2839
- onTransportError?.({
3051
+ handler({
2840
3052
  stage: "serialize",
2841
3053
  error: err instanceof Error ? err : new Error(String(err)),
2842
3054
  value
@@ -2847,7 +3059,7 @@ function toKafka(source, kafkaProducer, topic, opts) {
2847
3059
  topic,
2848
3060
  messages: [{ key, value: Buffer.from(serialized) }]
2849
3061
  }).catch((err) => {
2850
- onTransportError?.({
3062
+ handler({
2851
3063
  stage: "send",
2852
3064
  error: err instanceof Error ? err : new Error(String(err)),
2853
3065
  value
@@ -2858,8 +3070,15 @@ function toKafka(source, kafkaProducer, topic, opts) {
2858
3070
  return false;
2859
3071
  }
2860
3072
  });
2861
- return inner.subscribe(() => {
3073
+ const unsub = inner.subscribe(() => {
2862
3074
  });
3075
+ return {
3076
+ dispose: () => {
3077
+ unsub();
3078
+ errorsNode.down([[TEARDOWN]]);
3079
+ },
3080
+ errors: errorsNode
3081
+ };
2863
3082
  }
2864
3083
  function fromRedisStream(client, key, opts) {
2865
3084
  const {
@@ -2924,6 +3143,7 @@ function toRedisStream(source, client, key, opts) {
2924
3143
  onTransportError,
2925
3144
  ...rest
2926
3145
  } = opts ?? {};
3146
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
2927
3147
  const inner = node([source], () => void 0, {
2928
3148
  describeKind: "effect",
2929
3149
  ...rest,
@@ -2934,7 +3154,7 @@ function toRedisStream(source, client, key, opts) {
2934
3154
  try {
2935
3155
  fields = serialize(value);
2936
3156
  } catch (err) {
2937
- onTransportError?.({
3157
+ handler({
2938
3158
  stage: "serialize",
2939
3159
  error: err instanceof Error ? err : new Error(String(err)),
2940
3160
  value
@@ -2943,7 +3163,7 @@ function toRedisStream(source, client, key, opts) {
2943
3163
  }
2944
3164
  const send = maxLen !== void 0 ? client.xadd(key, "MAXLEN", "~", String(maxLen), "*", ...fields) : client.xadd(key, "*", ...fields);
2945
3165
  void send.catch((err) => {
2946
- onTransportError?.({
3166
+ handler({
2947
3167
  stage: "send",
2948
3168
  error: err instanceof Error ? err : new Error(String(err)),
2949
3169
  value
@@ -2954,8 +3174,15 @@ function toRedisStream(source, client, key, opts) {
2954
3174
  return false;
2955
3175
  }
2956
3176
  });
2957
- return inner.subscribe(() => {
3177
+ const unsub = inner.subscribe(() => {
2958
3178
  });
3179
+ return {
3180
+ dispose: () => {
3181
+ unsub();
3182
+ errorsNode.down([[TEARDOWN]]);
3183
+ },
3184
+ errors: errorsNode
3185
+ };
2959
3186
  }
2960
3187
  function fromCSV(source, opts) {
2961
3188
  const {
@@ -3182,6 +3409,7 @@ function toPulsar(source, pulsarProducer, opts) {
3182
3409
  onTransportError,
3183
3410
  ...rest
3184
3411
  } = opts ?? {};
3412
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3185
3413
  const inner = node([source], () => void 0, {
3186
3414
  describeKind: "effect",
3187
3415
  ...rest,
@@ -3192,7 +3420,7 @@ function toPulsar(source, pulsarProducer, opts) {
3192
3420
  try {
3193
3421
  data = serialize(value);
3194
3422
  } catch (err) {
3195
- onTransportError?.({
3423
+ handler({
3196
3424
  stage: "serialize",
3197
3425
  error: err instanceof Error ? err : new Error(String(err)),
3198
3426
  value
@@ -3204,7 +3432,7 @@ function toPulsar(source, pulsarProducer, opts) {
3204
3432
  partitionKey: keyExtractor?.(value),
3205
3433
  properties: propertiesExtractor?.(value)
3206
3434
  }).catch((err) => {
3207
- onTransportError?.({
3435
+ handler({
3208
3436
  stage: "send",
3209
3437
  error: err instanceof Error ? err : new Error(String(err)),
3210
3438
  value
@@ -3215,8 +3443,15 @@ function toPulsar(source, pulsarProducer, opts) {
3215
3443
  return false;
3216
3444
  }
3217
3445
  });
3218
- return inner.subscribe(() => {
3446
+ const unsub = inner.subscribe(() => {
3219
3447
  });
3448
+ return {
3449
+ dispose: () => {
3450
+ unsub();
3451
+ errorsNode.down([[TEARDOWN]]);
3452
+ },
3453
+ errors: errorsNode
3454
+ };
3220
3455
  }
3221
3456
  function fromNATS(client, subject, opts) {
3222
3457
  const decoder = new TextDecoder();
@@ -3272,6 +3507,7 @@ function toNATS(source, client, subject, opts) {
3272
3507
  onTransportError,
3273
3508
  ...rest
3274
3509
  } = opts ?? {};
3510
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3275
3511
  const inner = node([source], () => void 0, {
3276
3512
  describeKind: "effect",
3277
3513
  ...rest,
@@ -3282,7 +3518,7 @@ function toNATS(source, client, subject, opts) {
3282
3518
  try {
3283
3519
  data = serialize(value);
3284
3520
  } catch (err) {
3285
- onTransportError?.({
3521
+ handler({
3286
3522
  stage: "serialize",
3287
3523
  error: err instanceof Error ? err : new Error(String(err)),
3288
3524
  value
@@ -3292,7 +3528,7 @@ function toNATS(source, client, subject, opts) {
3292
3528
  try {
3293
3529
  client.publish(subject, data);
3294
3530
  } catch (err) {
3295
- onTransportError?.({
3531
+ handler({
3296
3532
  stage: "send",
3297
3533
  error: err instanceof Error ? err : new Error(String(err)),
3298
3534
  value
@@ -3303,8 +3539,15 @@ function toNATS(source, client, subject, opts) {
3303
3539
  return false;
3304
3540
  }
3305
3541
  });
3306
- return inner.subscribe(() => {
3542
+ const unsub = inner.subscribe(() => {
3307
3543
  });
3544
+ return {
3545
+ dispose: () => {
3546
+ unsub();
3547
+ errorsNode.down([[TEARDOWN]]);
3548
+ },
3549
+ errors: errorsNode
3550
+ };
3308
3551
  }
3309
3552
  function fromRabbitMQ(channel, queue, opts) {
3310
3553
  const {
@@ -3366,6 +3609,7 @@ function toRabbitMQ(source, channel, exchange, opts) {
3366
3609
  onTransportError,
3367
3610
  ...rest
3368
3611
  } = opts ?? {};
3612
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3369
3613
  const inner = node([source], () => void 0, {
3370
3614
  describeKind: "effect",
3371
3615
  ...rest,
@@ -3376,7 +3620,7 @@ function toRabbitMQ(source, channel, exchange, opts) {
3376
3620
  try {
3377
3621
  routingKey = routingKeyExtractor(value);
3378
3622
  } catch (err) {
3379
- onTransportError?.({
3623
+ handler({
3380
3624
  stage: "routing_key",
3381
3625
  error: err instanceof Error ? err : new Error(String(err)),
3382
3626
  value
@@ -3387,7 +3631,7 @@ function toRabbitMQ(source, channel, exchange, opts) {
3387
3631
  try {
3388
3632
  content = serialize(value);
3389
3633
  } catch (err) {
3390
- onTransportError?.({
3634
+ handler({
3391
3635
  stage: "serialize",
3392
3636
  error: err instanceof Error ? err : new Error(String(err)),
3393
3637
  value
@@ -3397,7 +3641,7 @@ function toRabbitMQ(source, channel, exchange, opts) {
3397
3641
  try {
3398
3642
  channel.publish(exchange, routingKey, content);
3399
3643
  } catch (err) {
3400
- onTransportError?.({
3644
+ handler({
3401
3645
  stage: "send",
3402
3646
  error: err instanceof Error ? err : new Error(String(err)),
3403
3647
  value
@@ -3408,8 +3652,15 @@ function toRabbitMQ(source, channel, exchange, opts) {
3408
3652
  return false;
3409
3653
  }
3410
3654
  });
3411
- return inner.subscribe(() => {
3655
+ const unsub = inner.subscribe(() => {
3412
3656
  });
3657
+ return {
3658
+ dispose: () => {
3659
+ unsub();
3660
+ errorsNode.down([[TEARDOWN]]);
3661
+ },
3662
+ errors: errorsNode
3663
+ };
3413
3664
  }
3414
3665
  function toFile(source, writer, opts) {
3415
3666
  const {
@@ -3421,8 +3672,10 @@ function toFile(source, writer, opts) {
3421
3672
  mode: _mode,
3422
3673
  ...rest
3423
3674
  } = opts ?? {};
3675
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3424
3676
  let buffer2 = [];
3425
3677
  let timer;
3678
+ let disposed = false;
3426
3679
  const doFlush = () => {
3427
3680
  if (buffer2.length === 0) return;
3428
3681
  const chunk = buffer2.join("");
@@ -3430,7 +3683,7 @@ function toFile(source, writer, opts) {
3430
3683
  try {
3431
3684
  writer.write(chunk);
3432
3685
  } catch (err) {
3433
- onTransportError?.({
3686
+ handler({
3434
3687
  stage: "send",
3435
3688
  error: err instanceof Error ? err : new Error(String(err)),
3436
3689
  value: chunk
@@ -3438,7 +3691,7 @@ function toFile(source, writer, opts) {
3438
3691
  }
3439
3692
  };
3440
3693
  const scheduleFlush = () => {
3441
- if (flushIntervalMs > 0 && timer === void 0) {
3694
+ if (flushIntervalMs > 0 && timer === void 0 && !disposed) {
3442
3695
  timer = setTimeout(() => {
3443
3696
  timer = void 0;
3444
3697
  doFlush();
@@ -3456,7 +3709,7 @@ function toFile(source, writer, opts) {
3456
3709
  try {
3457
3710
  line = serialize(value);
3458
3711
  } catch (err) {
3459
- onTransportError?.({
3712
+ handler({
3460
3713
  stage: "serialize",
3461
3714
  error: err instanceof Error ? err : new Error(String(err)),
3462
3715
  value
@@ -3471,7 +3724,7 @@ function toFile(source, writer, opts) {
3471
3724
  try {
3472
3725
  writer.write(line);
3473
3726
  } catch (err) {
3474
- onTransportError?.({
3727
+ handler({
3475
3728
  stage: "send",
3476
3729
  error: err instanceof Error ? err : new Error(String(err)),
3477
3730
  value
@@ -3480,7 +3733,7 @@ function toFile(source, writer, opts) {
3480
3733
  }
3481
3734
  return true;
3482
3735
  }
3483
- if (msg[0] === COMPLETE || msg[0] === TEARDOWN) {
3736
+ if (messageTier(msg[0]) >= 3) {
3484
3737
  doFlush();
3485
3738
  }
3486
3739
  return false;
@@ -3489,18 +3742,25 @@ function toFile(source, writer, opts) {
3489
3742
  const unsub = inner.subscribe(() => {
3490
3743
  });
3491
3744
  const dispose = () => {
3745
+ if (disposed) return;
3746
+ disposed = true;
3492
3747
  if (timer !== void 0) {
3493
3748
  clearTimeout(timer);
3494
3749
  timer = void 0;
3495
3750
  }
3496
3751
  doFlush();
3497
- writer.end();
3752
+ try {
3753
+ writer.end();
3754
+ } catch {
3755
+ }
3498
3756
  unsub();
3757
+ errorsNode.down([[TEARDOWN]]);
3499
3758
  };
3500
3759
  return {
3501
3760
  dispose,
3761
+ errors: errorsNode,
3502
3762
  flush: async () => {
3503
- doFlush();
3763
+ if (!disposed) doFlush();
3504
3764
  }
3505
3765
  };
3506
3766
  }
@@ -3551,25 +3811,29 @@ function toClickHouse(source, client, table, opts) {
3551
3811
  onTransportError,
3552
3812
  ...rest
3553
3813
  } = opts ?? {};
3814
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3554
3815
  let buffer2 = [];
3555
3816
  let timer;
3556
- let lastFlush = Promise.resolve();
3817
+ let disposed = false;
3818
+ const inFlight = /* @__PURE__ */ new Set();
3557
3819
  const doFlush = () => {
3558
3820
  if (buffer2.length === 0) return Promise.resolve();
3559
3821
  const batch2 = buffer2;
3560
3822
  buffer2 = [];
3561
3823
  try {
3562
3824
  const p = client.insert({ table, values: batch2, format }).catch((err) => {
3563
- onTransportError?.({
3825
+ handler({
3564
3826
  stage: "send",
3565
3827
  error: err instanceof Error ? err : new Error(String(err)),
3566
3828
  value: batch2
3567
3829
  });
3830
+ }).finally(() => {
3831
+ inFlight.delete(p);
3568
3832
  });
3569
- lastFlush = p;
3833
+ inFlight.add(p);
3570
3834
  return p;
3571
3835
  } catch (err) {
3572
- onTransportError?.({
3836
+ handler({
3573
3837
  stage: "send",
3574
3838
  error: err instanceof Error ? err : new Error(String(err)),
3575
3839
  value: batch2
@@ -3578,7 +3842,7 @@ function toClickHouse(source, client, table, opts) {
3578
3842
  }
3579
3843
  };
3580
3844
  const scheduleFlush = () => {
3581
- if (timer === void 0) {
3845
+ if (timer === void 0 && !disposed) {
3582
3846
  timer = setTimeout(() => {
3583
3847
  timer = void 0;
3584
3848
  doFlush();
@@ -3594,7 +3858,7 @@ function toClickHouse(source, client, table, opts) {
3594
3858
  try {
3595
3859
  buffer2.push(transform(value));
3596
3860
  } catch (err) {
3597
- onTransportError?.({
3861
+ handler({
3598
3862
  stage: "serialize",
3599
3863
  error: err instanceof Error ? err : new Error(String(err)),
3600
3864
  value
@@ -3605,7 +3869,7 @@ function toClickHouse(source, client, table, opts) {
3605
3869
  else scheduleFlush();
3606
3870
  return true;
3607
3871
  }
3608
- if (msg[0] === COMPLETE || msg[0] === TEARDOWN) {
3872
+ if (messageTier(msg[0]) >= 3) {
3609
3873
  doFlush();
3610
3874
  }
3611
3875
  return false;
@@ -3614,16 +3878,24 @@ function toClickHouse(source, client, table, opts) {
3614
3878
  const unsub = inner.subscribe(() => {
3615
3879
  });
3616
3880
  const dispose = () => {
3881
+ if (disposed) return;
3882
+ disposed = true;
3617
3883
  if (timer !== void 0) {
3618
3884
  clearTimeout(timer);
3619
3885
  timer = void 0;
3620
3886
  }
3621
3887
  doFlush();
3622
3888
  unsub();
3889
+ errorsNode.down([[TEARDOWN]]);
3623
3890
  };
3624
3891
  return {
3625
3892
  dispose,
3626
- flush: () => doFlush().then(() => lastFlush)
3893
+ errors: errorsNode,
3894
+ flush: () => {
3895
+ const p = disposed ? Promise.resolve() : doFlush();
3896
+ return p.then(() => Promise.all(inFlight)).then(() => {
3897
+ });
3898
+ }
3627
3899
  };
3628
3900
  }
3629
3901
  function toS3(source, client, bucket, opts) {
@@ -3640,10 +3912,12 @@ function toS3(source, client, bucket, opts) {
3640
3912
  onTransportError,
3641
3913
  ...rest
3642
3914
  } = opts ?? {};
3915
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3643
3916
  let buffer2 = [];
3644
3917
  let timer;
3645
3918
  let seq = 0;
3646
- let lastFlush = Promise.resolve();
3919
+ let disposed = false;
3920
+ const inFlight = /* @__PURE__ */ new Set();
3647
3921
  const doFlush = () => {
3648
3922
  if (buffer2.length === 0) return Promise.resolve();
3649
3923
  const batch2 = buffer2;
@@ -3656,16 +3930,18 @@ function toS3(source, client, bucket, opts) {
3656
3930
  try {
3657
3931
  const p = client.putObject({ Bucket: bucket, Key: key, Body: body, ContentType: contentType }).then(() => {
3658
3932
  }).catch((err) => {
3659
- onTransportError?.({
3933
+ handler({
3660
3934
  stage: "send",
3661
3935
  error: err instanceof Error ? err : new Error(String(err)),
3662
3936
  value: batch2
3663
3937
  });
3938
+ }).finally(() => {
3939
+ inFlight.delete(p);
3664
3940
  });
3665
- lastFlush = p;
3941
+ inFlight.add(p);
3666
3942
  return p;
3667
3943
  } catch (err) {
3668
- onTransportError?.({
3944
+ handler({
3669
3945
  stage: "send",
3670
3946
  error: err instanceof Error ? err : new Error(String(err)),
3671
3947
  value: batch2
@@ -3674,7 +3950,7 @@ function toS3(source, client, bucket, opts) {
3674
3950
  }
3675
3951
  };
3676
3952
  const scheduleFlush = () => {
3677
- if (timer === void 0) {
3953
+ if (timer === void 0 && !disposed) {
3678
3954
  timer = setTimeout(() => {
3679
3955
  timer = void 0;
3680
3956
  doFlush();
@@ -3690,7 +3966,7 @@ function toS3(source, client, bucket, opts) {
3690
3966
  try {
3691
3967
  buffer2.push(transform(value));
3692
3968
  } catch (err) {
3693
- onTransportError?.({
3969
+ handler({
3694
3970
  stage: "serialize",
3695
3971
  error: err instanceof Error ? err : new Error(String(err)),
3696
3972
  value
@@ -3701,7 +3977,7 @@ function toS3(source, client, bucket, opts) {
3701
3977
  else scheduleFlush();
3702
3978
  return true;
3703
3979
  }
3704
- if (msg[0] === COMPLETE || msg[0] === TEARDOWN) {
3980
+ if (messageTier(msg[0]) >= 3) {
3705
3981
  doFlush();
3706
3982
  }
3707
3983
  return false;
@@ -3710,16 +3986,24 @@ function toS3(source, client, bucket, opts) {
3710
3986
  const unsub = inner.subscribe(() => {
3711
3987
  });
3712
3988
  const dispose = () => {
3989
+ if (disposed) return;
3990
+ disposed = true;
3713
3991
  if (timer !== void 0) {
3714
3992
  clearTimeout(timer);
3715
3993
  timer = void 0;
3716
3994
  }
3717
3995
  doFlush();
3718
3996
  unsub();
3997
+ errorsNode.down([[TEARDOWN]]);
3719
3998
  };
3720
3999
  return {
3721
4000
  dispose,
3722
- flush: () => doFlush().then(() => lastFlush)
4001
+ errors: errorsNode,
4002
+ flush: () => {
4003
+ const p = disposed ? Promise.resolve() : doFlush();
4004
+ return p.then(() => Promise.all(inFlight)).then(() => {
4005
+ });
4006
+ }
3723
4007
  };
3724
4008
  }
3725
4009
  function toPostgres(source, client, table, opts) {
@@ -3731,6 +4015,7 @@ function toPostgres(source, client, table, opts) {
3731
4015
  onTransportError,
3732
4016
  ...rest
3733
4017
  } = opts ?? {};
4018
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3734
4019
  const inner = node([source], () => void 0, {
3735
4020
  describeKind: "effect",
3736
4021
  ...rest,
@@ -3741,7 +4026,7 @@ function toPostgres(source, client, table, opts) {
3741
4026
  try {
3742
4027
  query = toSQL(value, table);
3743
4028
  } catch (err) {
3744
- onTransportError?.({
4029
+ handler({
3745
4030
  stage: "serialize",
3746
4031
  error: err instanceof Error ? err : new Error(String(err)),
3747
4032
  value
@@ -3749,7 +4034,7 @@ function toPostgres(source, client, table, opts) {
3749
4034
  return true;
3750
4035
  }
3751
4036
  void client.query(query.sql, query.params).catch((err) => {
3752
- onTransportError?.({
4037
+ handler({
3753
4038
  stage: "send",
3754
4039
  error: err instanceof Error ? err : new Error(String(err)),
3755
4040
  value
@@ -3760,11 +4045,19 @@ function toPostgres(source, client, table, opts) {
3760
4045
  return false;
3761
4046
  }
3762
4047
  });
3763
- return inner.subscribe(() => {
4048
+ const unsub = inner.subscribe(() => {
3764
4049
  });
4050
+ return {
4051
+ dispose: () => {
4052
+ unsub();
4053
+ errorsNode.down([[TEARDOWN]]);
4054
+ },
4055
+ errors: errorsNode
4056
+ };
3765
4057
  }
3766
4058
  function toMongo(source, collection, opts) {
3767
4059
  const { toDocument = (v) => v, onTransportError, ...rest } = opts ?? {};
4060
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3768
4061
  const inner = node([source], () => void 0, {
3769
4062
  describeKind: "effect",
3770
4063
  ...rest,
@@ -3775,7 +4068,7 @@ function toMongo(source, collection, opts) {
3775
4068
  try {
3776
4069
  doc = toDocument(value);
3777
4070
  } catch (err) {
3778
- onTransportError?.({
4071
+ handler({
3779
4072
  stage: "serialize",
3780
4073
  error: err instanceof Error ? err : new Error(String(err)),
3781
4074
  value
@@ -3783,7 +4076,7 @@ function toMongo(source, collection, opts) {
3783
4076
  return true;
3784
4077
  }
3785
4078
  void collection.insertOne(doc).catch((err) => {
3786
- onTransportError?.({
4079
+ handler({
3787
4080
  stage: "send",
3788
4081
  error: err instanceof Error ? err : new Error(String(err)),
3789
4082
  value
@@ -3794,8 +4087,15 @@ function toMongo(source, collection, opts) {
3794
4087
  return false;
3795
4088
  }
3796
4089
  });
3797
- return inner.subscribe(() => {
4090
+ const unsub = inner.subscribe(() => {
3798
4091
  });
4092
+ return {
4093
+ dispose: () => {
4094
+ unsub();
4095
+ errorsNode.down([[TEARDOWN]]);
4096
+ },
4097
+ errors: errorsNode
4098
+ };
3799
4099
  }
3800
4100
  function toLoki(source, client, opts) {
3801
4101
  const {
@@ -3805,6 +4105,7 @@ function toLoki(source, client, opts) {
3805
4105
  onTransportError,
3806
4106
  ...rest
3807
4107
  } = opts ?? {};
4108
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3808
4109
  const inner = node([source], () => void 0, {
3809
4110
  describeKind: "effect",
3810
4111
  ...rest,
@@ -3815,7 +4116,7 @@ function toLoki(source, client, opts) {
3815
4116
  try {
3816
4117
  line = toLine(value);
3817
4118
  } catch (err) {
3818
- onTransportError?.({
4119
+ handler({
3819
4120
  stage: "serialize",
3820
4121
  error: err instanceof Error ? err : new Error(String(err)),
3821
4122
  value
@@ -3826,7 +4127,7 @@ function toLoki(source, client, opts) {
3826
4127
  try {
3827
4128
  streamLabels = toLabels ? { ...labels, ...toLabels(value) } : labels;
3828
4129
  } catch (err) {
3829
- onTransportError?.({
4130
+ handler({
3830
4131
  stage: "serialize",
3831
4132
  error: err instanceof Error ? err : new Error(String(err)),
3832
4133
  value
@@ -3835,7 +4136,7 @@ function toLoki(source, client, opts) {
3835
4136
  }
3836
4137
  const ts = `${wallClockNs()}`;
3837
4138
  void client.push({ streams: [{ stream: streamLabels, values: [[ts, line]] }] }).catch((err) => {
3838
- onTransportError?.({
4139
+ handler({
3839
4140
  stage: "send",
3840
4141
  error: err instanceof Error ? err : new Error(String(err)),
3841
4142
  value
@@ -3846,11 +4147,19 @@ function toLoki(source, client, opts) {
3846
4147
  return false;
3847
4148
  }
3848
4149
  });
3849
- return inner.subscribe(() => {
4150
+ const unsub = inner.subscribe(() => {
3850
4151
  });
4152
+ return {
4153
+ dispose: () => {
4154
+ unsub();
4155
+ errorsNode.down([[TEARDOWN]]);
4156
+ },
4157
+ errors: errorsNode
4158
+ };
3851
4159
  }
3852
4160
  function toTempo(source, client, opts) {
3853
4161
  const { toResourceSpans = (v) => [v], onTransportError, ...rest } = opts ?? {};
4162
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3854
4163
  const inner = node([source], () => void 0, {
3855
4164
  describeKind: "effect",
3856
4165
  ...rest,
@@ -3861,7 +4170,7 @@ function toTempo(source, client, opts) {
3861
4170
  try {
3862
4171
  spans = toResourceSpans(value);
3863
4172
  } catch (err) {
3864
- onTransportError?.({
4173
+ handler({
3865
4174
  stage: "serialize",
3866
4175
  error: err instanceof Error ? err : new Error(String(err)),
3867
4176
  value
@@ -3869,7 +4178,7 @@ function toTempo(source, client, opts) {
3869
4178
  return true;
3870
4179
  }
3871
4180
  void client.push({ resourceSpans: spans }).catch((err) => {
3872
- onTransportError?.({
4181
+ handler({
3873
4182
  stage: "send",
3874
4183
  error: err instanceof Error ? err : new Error(String(err)),
3875
4184
  value
@@ -3880,15 +4189,22 @@ function toTempo(source, client, opts) {
3880
4189
  return false;
3881
4190
  }
3882
4191
  });
3883
- return inner.subscribe(() => {
4192
+ const unsub = inner.subscribe(() => {
3884
4193
  });
4194
+ return {
4195
+ dispose: () => {
4196
+ unsub();
4197
+ errorsNode.down([[TEARDOWN]]);
4198
+ },
4199
+ errors: errorsNode
4200
+ };
3885
4201
  }
3886
4202
  function checkpointToS3(graph, client, bucket, opts) {
3887
4203
  const { prefix = "checkpoints/", debounceMs, compactEvery, onError } = opts ?? {};
3888
4204
  const adapter = {
3889
- save(data) {
4205
+ save(_key, data) {
3890
4206
  const ms = Math.floor(wallClockNs() / 1e6);
3891
- const key = `${prefix}${graph.name}/checkpoint-${ms}.json`;
4207
+ const s3Key = `${prefix}${graph.name}/checkpoint-${ms}.json`;
3892
4208
  let body;
3893
4209
  try {
3894
4210
  body = JSON.stringify(data);
@@ -3898,7 +4214,7 @@ function checkpointToS3(graph, client, bucket, opts) {
3898
4214
  }
3899
4215
  void client.putObject({
3900
4216
  Bucket: bucket,
3901
- Key: key,
4217
+ Key: s3Key,
3902
4218
  Body: body,
3903
4219
  ContentType: "application/json"
3904
4220
  }).catch((err) => onError?.(err));
@@ -3908,9 +4224,9 @@ function checkpointToS3(graph, client, bucket, opts) {
3908
4224
  }
3909
4225
  function checkpointToRedis(graph, client, opts) {
3910
4226
  const { prefix = "graphrefly:checkpoint:", debounceMs, compactEvery, onError } = opts ?? {};
3911
- const key = `${prefix}${graph.name}`;
4227
+ const redisKey = `${prefix}${graph.name}`;
3912
4228
  const adapter = {
3913
- save(data) {
4229
+ save(_key, data) {
3914
4230
  let body;
3915
4231
  try {
3916
4232
  body = JSON.stringify(data);
@@ -3918,7 +4234,7 @@ function checkpointToRedis(graph, client, opts) {
3918
4234
  onError?.(err);
3919
4235
  return;
3920
4236
  }
3921
- void client.set(key, body).catch((err) => onError?.(err));
4237
+ void client.set(redisKey, body).catch((err) => onError?.(err));
3922
4238
  }
3923
4239
  };
3924
4240
  return graph.autoCheckpoint(adapter, { debounceMs, compactEvery, onError });
@@ -3956,8 +4272,67 @@ function toSqlite(source, db, table, opts) {
3956
4272
  params: [JSON.stringify(v)]
3957
4273
  }),
3958
4274
  onTransportError,
4275
+ batchInsert = false,
4276
+ maxBatchSize = 1e3,
4277
+ flushIntervalMs = 0,
3959
4278
  ...rest
3960
4279
  } = opts ?? {};
4280
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
4281
+ const pendingInserts = [];
4282
+ let flushing = false;
4283
+ let disposed = false;
4284
+ let timer;
4285
+ function flushTransaction() {
4286
+ if (pendingInserts.length === 0 || flushing) return;
4287
+ flushing = true;
4288
+ try {
4289
+ db.query("BEGIN", []);
4290
+ } catch (err) {
4291
+ flushing = false;
4292
+ handler({
4293
+ stage: "send",
4294
+ error: err instanceof Error ? err : new Error(String(err)),
4295
+ value: void 0
4296
+ });
4297
+ return;
4298
+ }
4299
+ const batch2 = pendingInserts.splice(0);
4300
+ let firstError;
4301
+ for (const q of batch2) {
4302
+ try {
4303
+ db.query(q.sql, q.params);
4304
+ } catch (err) {
4305
+ firstError = err instanceof Error ? err : new Error(String(err));
4306
+ break;
4307
+ }
4308
+ }
4309
+ if (firstError) {
4310
+ try {
4311
+ db.query("ROLLBACK", []);
4312
+ } catch {
4313
+ }
4314
+ handler({ stage: "send", error: firstError, value: void 0 });
4315
+ } else {
4316
+ try {
4317
+ db.query("COMMIT", []);
4318
+ } catch (err) {
4319
+ handler({
4320
+ stage: "send",
4321
+ error: err instanceof Error ? err : new Error(String(err)),
4322
+ value: void 0
4323
+ });
4324
+ }
4325
+ }
4326
+ flushing = false;
4327
+ }
4328
+ const scheduleFlush = () => {
4329
+ if (batchInsert && flushIntervalMs > 0 && timer === void 0 && !disposed) {
4330
+ timer = setTimeout(() => {
4331
+ timer = void 0;
4332
+ flushTransaction();
4333
+ }, flushIntervalMs);
4334
+ }
4335
+ };
3961
4336
  const inner = node([source], () => void 0, {
3962
4337
  describeKind: "effect",
3963
4338
  ...rest,
@@ -3968,29 +4343,140 @@ function toSqlite(source, db, table, opts) {
3968
4343
  try {
3969
4344
  query = toSQL(value, table);
3970
4345
  } catch (err) {
3971
- onTransportError?.({
4346
+ handler({
3972
4347
  stage: "serialize",
3973
4348
  error: err instanceof Error ? err : new Error(String(err)),
3974
4349
  value
3975
4350
  });
3976
4351
  return true;
3977
4352
  }
3978
- try {
3979
- db.query(query.sql, query.params);
3980
- } catch (err) {
3981
- onTransportError?.({
3982
- stage: "send",
3983
- error: err instanceof Error ? err : new Error(String(err)),
3984
- value
3985
- });
4353
+ if (batchInsert) {
4354
+ pendingInserts.push(query);
4355
+ if (pendingInserts.length >= maxBatchSize) flushTransaction();
4356
+ else scheduleFlush();
4357
+ } else {
4358
+ try {
4359
+ db.query(query.sql, query.params);
4360
+ } catch (err) {
4361
+ handler({
4362
+ stage: "send",
4363
+ error: err instanceof Error ? err : new Error(String(err)),
4364
+ value
4365
+ });
4366
+ }
3986
4367
  }
3987
4368
  return true;
3988
4369
  }
4370
+ if (batchInsert && messageTier(msg[0]) >= 3) {
4371
+ flushTransaction();
4372
+ }
3989
4373
  return false;
3990
4374
  }
3991
4375
  });
3992
- return inner.subscribe(() => {
4376
+ const unsub = inner.subscribe(() => {
3993
4377
  });
4378
+ const dispose = () => {
4379
+ if (disposed) return;
4380
+ disposed = true;
4381
+ if (timer !== void 0) {
4382
+ clearTimeout(timer);
4383
+ timer = void 0;
4384
+ }
4385
+ if (batchInsert) flushTransaction();
4386
+ unsub();
4387
+ errorsNode.down([[TEARDOWN]]);
4388
+ };
4389
+ return {
4390
+ dispose,
4391
+ errors: errorsNode,
4392
+ flush: batchInsert ? async () => {
4393
+ if (!disposed) flushTransaction();
4394
+ } : void 0
4395
+ };
4396
+ }
4397
+ function fromPrisma(model, opts) {
4398
+ const { args, mapRow = (r) => r, ...rest } = opts ?? {};
4399
+ return producer(
4400
+ (_d, a) => {
4401
+ let active = true;
4402
+ void model.findMany(args).then((rows) => {
4403
+ if (!active) return;
4404
+ const mapped = rows.map(mapRow);
4405
+ batch(() => {
4406
+ for (const item of mapped) {
4407
+ a.emit(item);
4408
+ }
4409
+ });
4410
+ a.down([[COMPLETE]]);
4411
+ }).catch((err) => {
4412
+ if (!active) return;
4413
+ try {
4414
+ a.down([[ERROR, err instanceof Error ? err : new Error(String(err))]]);
4415
+ } catch {
4416
+ }
4417
+ });
4418
+ return () => {
4419
+ active = false;
4420
+ };
4421
+ },
4422
+ { ...rest, describeKind: "producer", completeWhenDepsComplete: false }
4423
+ );
4424
+ }
4425
+ function fromDrizzle(query, opts) {
4426
+ const { mapRow = (r) => r, ...rest } = opts ?? {};
4427
+ return producer(
4428
+ (_d, a) => {
4429
+ let active = true;
4430
+ void query.execute().then((rows) => {
4431
+ if (!active) return;
4432
+ const mapped = rows.map(mapRow);
4433
+ batch(() => {
4434
+ for (const item of mapped) {
4435
+ a.emit(item);
4436
+ }
4437
+ });
4438
+ a.down([[COMPLETE]]);
4439
+ }).catch((err) => {
4440
+ if (!active) return;
4441
+ try {
4442
+ a.down([[ERROR, err instanceof Error ? err : new Error(String(err))]]);
4443
+ } catch {
4444
+ }
4445
+ });
4446
+ return () => {
4447
+ active = false;
4448
+ };
4449
+ },
4450
+ { ...rest, describeKind: "producer", completeWhenDepsComplete: false }
4451
+ );
4452
+ }
4453
+ function fromKysely(query, opts) {
4454
+ const { mapRow = (r) => r, ...rest } = opts ?? {};
4455
+ return producer(
4456
+ (_d, a) => {
4457
+ let active = true;
4458
+ void query.execute().then((rows) => {
4459
+ if (!active) return;
4460
+ const mapped = rows.map(mapRow);
4461
+ batch(() => {
4462
+ for (const item of mapped) {
4463
+ a.emit(item);
4464
+ }
4465
+ });
4466
+ a.down([[COMPLETE]]);
4467
+ }).catch((err) => {
4468
+ if (!active) return;
4469
+ try {
4470
+ a.down([[ERROR, err instanceof Error ? err : new Error(String(err))]]);
4471
+ } catch {
4472
+ }
4473
+ });
4474
+ return () => {
4475
+ active = false;
4476
+ };
4477
+ },
4478
+ { ...rest, describeKind: "producer", completeWhenDepsComplete: false }
4479
+ );
3994
4480
  }
3995
4481
 
3996
4482
  // src/extra/backpressure.ts
@@ -4037,6 +4523,205 @@ function createWatermarkController(sendUp, opts) {
4037
4523
  };
4038
4524
  }
4039
4525
 
4526
+ // src/extra/cascading-cache.ts
4527
+ function lru() {
4528
+ const map2 = /* @__PURE__ */ new Map();
4529
+ let head = null;
4530
+ let tail = null;
4531
+ function unlink(n) {
4532
+ if (n.prev) n.prev.next = n.next;
4533
+ else head = n.next;
4534
+ if (n.next) n.next.prev = n.prev;
4535
+ else tail = n.prev;
4536
+ n.prev = null;
4537
+ n.next = null;
4538
+ }
4539
+ function pushFront(n) {
4540
+ n.next = head;
4541
+ n.prev = null;
4542
+ if (head) head.prev = n;
4543
+ head = n;
4544
+ if (tail === null) tail = n;
4545
+ }
4546
+ return {
4547
+ insert(key) {
4548
+ if (map2.has(key)) {
4549
+ this.touch(key);
4550
+ return;
4551
+ }
4552
+ const n = { key, prev: null, next: null };
4553
+ map2.set(key, n);
4554
+ pushFront(n);
4555
+ },
4556
+ touch(key) {
4557
+ const n = map2.get(key);
4558
+ if (!n) return;
4559
+ unlink(n);
4560
+ pushFront(n);
4561
+ },
4562
+ delete(key) {
4563
+ const n = map2.get(key);
4564
+ if (!n) return;
4565
+ unlink(n);
4566
+ map2.delete(key);
4567
+ },
4568
+ evict(count) {
4569
+ const victims = [];
4570
+ for (let i = 0; i < count && tail !== null; i++) {
4571
+ const n = tail;
4572
+ victims.push(n.key);
4573
+ unlink(n);
4574
+ map2.delete(n.key);
4575
+ }
4576
+ return victims;
4577
+ },
4578
+ size() {
4579
+ return map2.size;
4580
+ }
4581
+ };
4582
+ }
4583
+ function cascadingCache(tiers, opts) {
4584
+ const entries = /* @__PURE__ */ new Map();
4585
+ const maxSize = opts?.maxSize ?? 0;
4586
+ const policy = maxSize > 0 ? opts?.eviction ?? lru() : null;
4587
+ const writeThrough = opts?.writeThrough ?? false;
4588
+ function promote(key, value, hitTierIndex) {
4589
+ for (let i = 0; i < hitTierIndex; i++) {
4590
+ const tier = tiers[i];
4591
+ if (tier.save) tier.save(key, value);
4592
+ }
4593
+ }
4594
+ function cascade(key, nd) {
4595
+ for (let tierIndex = 0; tierIndex < tiers.length; tierIndex++) {
4596
+ let result;
4597
+ try {
4598
+ result = tiers[tierIndex].load(key);
4599
+ } catch {
4600
+ continue;
4601
+ }
4602
+ if (result != null) {
4603
+ nd.down([[DATA, result]]);
4604
+ promote(key, result, tierIndex);
4605
+ return;
4606
+ }
4607
+ }
4608
+ }
4609
+ function evictIfNeeded() {
4610
+ if (!policy || maxSize <= 0) return;
4611
+ while (policy.size() >= maxSize) {
4612
+ const victims = policy.evict(1);
4613
+ if (victims.length === 0) break;
4614
+ for (const key of victims) {
4615
+ const nd = entries.get(key);
4616
+ if (nd) {
4617
+ const value = nd.get();
4618
+ if (value !== void 0) {
4619
+ for (let i = tiers.length - 1; i >= 0; i--) {
4620
+ if (tiers[i].save) {
4621
+ tiers[i].save(key, value);
4622
+ for (let j = 0; j < i; j++) {
4623
+ if (tiers[j].clear) tiers[j].clear(key);
4624
+ }
4625
+ break;
4626
+ }
4627
+ }
4628
+ }
4629
+ nd.down([[TEARDOWN]]);
4630
+ }
4631
+ entries.delete(key);
4632
+ }
4633
+ }
4634
+ }
4635
+ return {
4636
+ load(key) {
4637
+ const existing = entries.get(key);
4638
+ if (existing) {
4639
+ policy?.touch(key);
4640
+ return existing;
4641
+ }
4642
+ if (policy && maxSize > 0 && policy.size() >= maxSize) {
4643
+ evictIfNeeded();
4644
+ }
4645
+ const nd = state(void 0);
4646
+ entries.set(key, nd);
4647
+ if (policy) {
4648
+ policy.insert(key);
4649
+ }
4650
+ cascade(key, nd);
4651
+ return nd;
4652
+ },
4653
+ save(key, value) {
4654
+ if (writeThrough) {
4655
+ for (const tier of tiers) {
4656
+ if (tier.save) tier.save(key, value);
4657
+ }
4658
+ } else if (tiers[0]?.save) {
4659
+ tiers[0].save(key, value);
4660
+ }
4661
+ const existing = entries.get(key);
4662
+ if (existing) {
4663
+ existing.down([[DATA, value]]);
4664
+ policy?.touch(key);
4665
+ } else {
4666
+ if (policy && maxSize > 0 && policy.size() >= maxSize) {
4667
+ evictIfNeeded();
4668
+ }
4669
+ const nd = state(value);
4670
+ entries.set(key, nd);
4671
+ if (policy) {
4672
+ policy.insert(key);
4673
+ }
4674
+ }
4675
+ },
4676
+ invalidate(key) {
4677
+ const existing = entries.get(key);
4678
+ if (existing) {
4679
+ cascade(key, existing);
4680
+ }
4681
+ },
4682
+ delete(key) {
4683
+ policy?.delete(key);
4684
+ const nd = entries.get(key);
4685
+ if (nd) nd.down([[TEARDOWN]]);
4686
+ entries.delete(key);
4687
+ for (const tier of tiers) {
4688
+ if (tier.clear) tier.clear(key);
4689
+ }
4690
+ },
4691
+ has(key) {
4692
+ return entries.has(key);
4693
+ },
4694
+ get size() {
4695
+ return entries.size;
4696
+ }
4697
+ };
4698
+ }
4699
+ function adapterToTier(adapter) {
4700
+ return {
4701
+ load: (key) => adapter.load(key),
4702
+ save: (key, value) => adapter.save(key, value),
4703
+ clear: (key) => adapter.clear(key)
4704
+ };
4705
+ }
4706
+ function tieredStorage(adapters, opts) {
4707
+ const inner = cascadingCache(adapters.map(adapterToTier), {
4708
+ maxSize: opts?.maxSize,
4709
+ eviction: opts?.eviction,
4710
+ writeThrough: true
4711
+ });
4712
+ return {
4713
+ load: (key) => inner.load(key),
4714
+ save: (key, value) => inner.save(key, value),
4715
+ invalidate: (key) => inner.invalidate(key),
4716
+ delete: (key) => inner.delete(key),
4717
+ has: (key) => inner.has(key),
4718
+ get size() {
4719
+ return inner.size;
4720
+ },
4721
+ cache: inner
4722
+ };
4723
+ }
4724
+
4040
4725
  // src/extra/checkpoint.ts
4041
4726
  var import_node_crypto2 = require("crypto");
4042
4727
  var import_node_fs2 = require("fs");
@@ -4057,60 +4742,61 @@ function sortJsonValue(value) {
4057
4742
  }
4058
4743
  return out;
4059
4744
  }
4060
- function warnNonJsonValues(data) {
4061
- for (const [path, node2] of Object.entries(data.nodes)) {
4062
- const v = node2.value;
4063
- if (v === void 0 || v === null) continue;
4064
- if (typeof v === "function" || typeof v === "symbol" || typeof v === "bigint") {
4065
- console.warn(
4066
- `checkpoint: node "${path}" has non-JSON-serializable value (${typeof v}); it will be lost on round-trip`
4067
- );
4068
- }
4069
- }
4070
- }
4071
- function stableSnapshotJson(data) {
4072
- warnNonJsonValues(data);
4745
+ function stableJsonString(data) {
4073
4746
  return `${JSON.stringify(sortJsonValue(data), void 0, 0)}
4074
4747
  `;
4075
4748
  }
4076
4749
  var MemoryCheckpointAdapter = class {
4077
- #data = null;
4078
- save(data) {
4079
- this.#data = JSON.parse(JSON.stringify(data));
4750
+ #data = /* @__PURE__ */ new Map();
4751
+ save(key, data) {
4752
+ this.#data.set(key, JSON.parse(JSON.stringify(data)));
4753
+ }
4754
+ load(key) {
4755
+ const v = this.#data.get(key);
4756
+ return v === void 0 ? null : JSON.parse(JSON.stringify(v));
4080
4757
  }
4081
- load() {
4082
- return this.#data === null ? null : JSON.parse(JSON.stringify(this.#data));
4758
+ clear(key) {
4759
+ this.#data.delete(key);
4083
4760
  }
4084
4761
  };
4085
4762
  var DictCheckpointAdapter = class {
4086
4763
  #storage;
4087
- #key;
4088
- constructor(storage, key = "graphrefly_checkpoint") {
4764
+ constructor(storage) {
4089
4765
  this.#storage = storage;
4090
- this.#key = key;
4091
4766
  }
4092
- save(data) {
4093
- this.#storage[this.#key] = JSON.parse(JSON.stringify(data));
4767
+ save(key, data) {
4768
+ this.#storage[key] = JSON.parse(JSON.stringify(data));
4769
+ }
4770
+ load(key) {
4771
+ const raw = this.#storage[key];
4772
+ return raw === void 0 ? null : JSON.parse(JSON.stringify(raw));
4094
4773
  }
4095
- load() {
4096
- const raw = this.#storage[this.#key];
4097
- return raw !== null && typeof raw === "object" && !Array.isArray(raw) ? JSON.parse(JSON.stringify(raw)) : null;
4774
+ clear(key) {
4775
+ delete this.#storage[key];
4098
4776
  }
4099
4777
  };
4100
4778
  var FileCheckpointAdapter = class {
4101
- #path;
4102
- constructor(path) {
4103
- this.#path = path;
4104
- }
4105
- save(data) {
4106
- const dir = (0, import_node_path2.dirname)(this.#path);
4107
- (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
4108
- const payload = stableSnapshotJson(data);
4109
- const base = (0, import_node_path2.basename)(this.#path);
4779
+ #dir;
4780
+ constructor(dir) {
4781
+ this.#dir = dir;
4782
+ }
4783
+ #pathFor(key) {
4784
+ const safeName = key.replace(
4785
+ /[^a-zA-Z0-9_-]/g,
4786
+ (c) => `%${c.charCodeAt(0).toString(16).padStart(2, "0")}`
4787
+ );
4788
+ return (0, import_node_path2.join)(this.#dir, `${safeName}.json`);
4789
+ }
4790
+ save(key, data) {
4791
+ (0, import_node_fs2.mkdirSync)(this.#dir, { recursive: true });
4792
+ const filePath = this.#pathFor(key);
4793
+ const payload = stableJsonString(data);
4794
+ const base = (0, import_node_path2.basename)(filePath);
4795
+ const dir = (0, import_node_path2.dirname)(filePath);
4110
4796
  const tmp = (0, import_node_path2.join)(dir, `.${base}.${(0, import_node_crypto2.randomBytes)(8).toString("hex")}.tmp`);
4111
4797
  try {
4112
4798
  (0, import_node_fs2.writeFileSync)(tmp, payload, "utf8");
4113
- (0, import_node_fs2.renameSync)(tmp, this.#path);
4799
+ (0, import_node_fs2.renameSync)(tmp, filePath);
4114
4800
  } catch (e) {
4115
4801
  try {
4116
4802
  (0, import_node_fs2.unlinkSync)(tmp);
@@ -4119,36 +4805,42 @@ var FileCheckpointAdapter = class {
4119
4805
  throw e;
4120
4806
  }
4121
4807
  }
4122
- load() {
4808
+ load(key) {
4123
4809
  try {
4124
- const text = (0, import_node_fs2.readFileSync)(this.#path, "utf8").trim();
4810
+ const text = (0, import_node_fs2.readFileSync)(this.#pathFor(key), "utf8").trim();
4125
4811
  if (!text) return null;
4126
- const data = JSON.parse(text);
4127
- return data !== null && typeof data === "object" && !Array.isArray(data) ? data : null;
4812
+ return JSON.parse(text);
4128
4813
  } catch {
4129
4814
  return null;
4130
4815
  }
4131
4816
  }
4817
+ clear(key) {
4818
+ try {
4819
+ (0, import_node_fs2.unlinkSync)(this.#pathFor(key));
4820
+ } catch (e) {
4821
+ if (e.code !== "ENOENT") throw e;
4822
+ }
4823
+ }
4132
4824
  };
4133
4825
  var SqliteCheckpointAdapter = class {
4134
4826
  #db;
4135
- #key;
4136
- constructor(path, key = "graphrefly_checkpoint") {
4827
+ constructor(path) {
4137
4828
  this.#db = new import_node_sqlite.DatabaseSync(path);
4138
- this.#key = key;
4139
4829
  this.#db.exec(
4140
4830
  `CREATE TABLE IF NOT EXISTS graphrefly_checkpoint (k TEXT PRIMARY KEY, v TEXT NOT NULL)`
4141
4831
  );
4142
4832
  }
4143
- save(data) {
4144
- const payload = stableSnapshotJson(data).trimEnd();
4145
- this.#db.prepare(`INSERT OR REPLACE INTO graphrefly_checkpoint (k, v) VALUES (?, ?)`).run(this.#key, payload);
4833
+ save(key, data) {
4834
+ const payload = stableJsonString(data).trimEnd();
4835
+ this.#db.prepare(`INSERT OR REPLACE INTO graphrefly_checkpoint (k, v) VALUES (?, ?)`).run(key, payload);
4146
4836
  }
4147
- load() {
4148
- const row = this.#db.prepare(`SELECT v FROM graphrefly_checkpoint WHERE k = ?`).get(this.#key);
4837
+ load(key) {
4838
+ const row = this.#db.prepare(`SELECT v FROM graphrefly_checkpoint WHERE k = ?`).get(key);
4149
4839
  if (row === void 0 || typeof row.v !== "string" || row.v.trim() === "") return null;
4150
- const parsed = JSON.parse(row.v);
4151
- return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
4840
+ return JSON.parse(row.v);
4841
+ }
4842
+ clear(key) {
4843
+ this.#db.prepare(`DELETE FROM graphrefly_checkpoint WHERE k = ?`).run(key);
4152
4844
  }
4153
4845
  /** Close the underlying SQLite connection (safe to call more than once). */
4154
4846
  close() {
@@ -4159,10 +4851,10 @@ var SqliteCheckpointAdapter = class {
4159
4851
  }
4160
4852
  };
4161
4853
  function saveGraphCheckpoint(graph, adapter) {
4162
- adapter.save(graph.snapshot());
4854
+ adapter.save(graph.name, graph.snapshot());
4163
4855
  }
4164
4856
  function restoreGraphCheckpoint(graph, adapter) {
4165
- const data = adapter.load();
4857
+ const data = adapter.load(graph.name);
4166
4858
  if (data === null) return false;
4167
4859
  graph.restore(data);
4168
4860
  return true;
@@ -4451,7 +5143,7 @@ var DynamicNodeImpl = class {
4451
5143
  _actions;
4452
5144
  _boundEmitToSinks;
4453
5145
  // Mutable state
4454
- _cached;
5146
+ _cached = NO_VALUE;
4455
5147
  _status = "disconnected";
4456
5148
  _terminal = false;
4457
5149
  _connected = false;
@@ -4545,7 +5237,7 @@ var DynamicNodeImpl = class {
4545
5237
  return this._guard(normalizeActor(actor), "observe");
4546
5238
  }
4547
5239
  get() {
4548
- return this._cached;
5240
+ return this._cached === NO_VALUE ? void 0 : this._cached;
4549
5241
  }
4550
5242
  down(messages, options) {
4551
5243
  if (messages.length === 0) return;
@@ -4603,6 +5295,7 @@ var DynamicNodeImpl = class {
4603
5295
  }
4604
5296
  if (this._terminal && this._resubscribable) {
4605
5297
  this._terminal = false;
5298
+ this._cached = NO_VALUE;
4606
5299
  this._status = "disconnected";
4607
5300
  this._onResubscribe?.();
4608
5301
  }
@@ -4680,10 +5373,13 @@ var DynamicNodeImpl = class {
4680
5373
  const t = m[0];
4681
5374
  if (t === DATA) this._cached = m[1];
4682
5375
  if (t === INVALIDATE) {
4683
- this._cached = void 0;
5376
+ this._cached = NO_VALUE;
5377
+ this._status = "dirty";
4684
5378
  }
4685
- if (t === DATA || t === RESOLVED) {
5379
+ if (t === DATA) {
4686
5380
  this._status = "settled";
5381
+ } else if (t === RESOLVED) {
5382
+ this._status = "resolved";
4687
5383
  } else if (t === DIRTY) {
4688
5384
  this._status = "dirty";
4689
5385
  } else if (t === COMPLETE) {
@@ -4694,7 +5390,7 @@ var DynamicNodeImpl = class {
4694
5390
  this._terminal = true;
4695
5391
  }
4696
5392
  if (t === TEARDOWN) {
4697
- if (this._resetOnTeardown) this._cached = void 0;
5393
+ if (this._resetOnTeardown) this._cached = NO_VALUE;
4698
5394
  try {
4699
5395
  this._propagateToMeta(t);
4700
5396
  } finally {
@@ -4717,7 +5413,15 @@ var DynamicNodeImpl = class {
4717
5413
  }
4718
5414
  _emitAutoValue(value) {
4719
5415
  const wasDirty = this._status === "dirty";
4720
- const unchanged = this._equals(this._cached, value);
5416
+ let unchanged;
5417
+ try {
5418
+ unchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);
5419
+ } catch (eqErr) {
5420
+ const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
5421
+ const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, { cause: eqErr });
5422
+ this._downInternal([[ERROR, wrapped]]);
5423
+ return;
5424
+ }
4721
5425
  if (unchanged) {
4722
5426
  this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
4723
5427
  return;
@@ -6027,48 +6731,6 @@ function audit(source, ms, opts) {
6027
6731
  }
6028
6732
  });
6029
6733
  }
6030
- function timeout(source, ms, opts) {
6031
- const { with: withPayload, ...timeoutNodeOpts } = opts ?? {};
6032
- let timer;
6033
- const err = withPayload ?? new Error("timeout");
6034
- function arm(a) {
6035
- clearTimeout(timer);
6036
- timer = setTimeout(() => {
6037
- timer = void 0;
6038
- a.down([[ERROR, err]]);
6039
- }, ms);
6040
- }
6041
- return node(
6042
- [source],
6043
- ([_v], a) => {
6044
- arm(a);
6045
- return () => clearTimeout(timer);
6046
- },
6047
- {
6048
- ...operatorOpts3(timeoutNodeOpts),
6049
- completeWhenDepsComplete: false,
6050
- onMessage(msg, _i, a) {
6051
- const t = msg[0];
6052
- if (t === DATA) {
6053
- arm(a);
6054
- a.down([msg]);
6055
- return true;
6056
- }
6057
- if (t === COMPLETE || t === ERROR) {
6058
- clearTimeout(timer);
6059
- a.down([msg]);
6060
- return true;
6061
- }
6062
- if (t === DIRTY || t === RESOLVED) {
6063
- a.down([msg]);
6064
- return true;
6065
- }
6066
- a.down([msg]);
6067
- return true;
6068
- }
6069
- }
6070
- );
6071
- }
6072
6734
  function buffer(source, notifier, opts) {
6073
6735
  const buf = [];
6074
6736
  return node([source, notifier], () => void 0, {
@@ -7625,11 +8287,14 @@ function workerSelf(target, opts) {
7625
8287
  NS_PER_MS,
7626
8288
  NS_PER_SEC,
7627
8289
  SqliteCheckpointAdapter,
8290
+ TimeoutError,
7628
8291
  audit,
7629
8292
  buffer,
7630
8293
  bufferCount,
7631
8294
  bufferTime,
8295
+ cache,
7632
8296
  cached,
8297
+ cascadingCache,
7633
8298
  catchError,
7634
8299
  checkpointNodeValue,
7635
8300
  checkpointToRedis,
@@ -7654,6 +8319,7 @@ function workerSelf(target, opts) {
7654
8319
  escapeRegexChar,
7655
8320
  exhaustMap,
7656
8321
  exponential,
8322
+ fallback,
7657
8323
  fibonacci,
7658
8324
  filter,
7659
8325
  find,
@@ -7666,6 +8332,7 @@ function workerSelf(target, opts) {
7666
8332
  fromCSV,
7667
8333
  fromClickHouseWatch,
7668
8334
  fromCron,
8335
+ fromDrizzle,
7669
8336
  fromEvent,
7670
8337
  fromFSWatch,
7671
8338
  fromGitHook,
@@ -7674,10 +8341,12 @@ function workerSelf(target, opts) {
7674
8341
  fromIDBTransaction,
7675
8342
  fromIter,
7676
8343
  fromKafka,
8344
+ fromKysely,
7677
8345
  fromMCP,
7678
8346
  fromNATS,
7679
8347
  fromNDJSON,
7680
8348
  fromOTel,
8349
+ fromPrisma,
7681
8350
  fromPrometheus,
7682
8351
  fromPromise,
7683
8352
  fromPulsar,
@@ -7695,6 +8364,7 @@ function workerSelf(target, opts) {
7695
8364
  last,
7696
8365
  linear,
7697
8366
  logSlice,
8367
+ lru,
7698
8368
  map,
7699
8369
  matchesAnyPattern,
7700
8370
  matchesCron,
@@ -7744,6 +8414,7 @@ function workerSelf(target, opts) {
7744
8414
  throttle,
7745
8415
  throttleTime,
7746
8416
  throwError,
8417
+ tieredStorage,
7747
8418
  timeout,
7748
8419
  toArray,
7749
8420
  toCSV,