@graphrefly/graphrefly 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +30 -14
  2. package/dist/{chunk-5X3LAO3B.js → chunk-3EVXOI5C.js} +50 -5
  3. package/dist/chunk-3EVXOI5C.js.map +1 -0
  4. package/dist/chunk-47YJEZUJ.js +106 -0
  5. package/dist/chunk-47YJEZUJ.js.map +1 -0
  6. package/dist/{chunk-6W5SGIGB.js → chunk-BLCXEMAD.js} +129 -25
  7. package/dist/chunk-BLCXEMAD.js.map +1 -0
  8. package/dist/{chunk-QW7H3ICI.js → chunk-FGLZ5QID.js} +4 -4
  9. package/dist/{chunk-CP6MNKAA.js → chunk-ISGMZ2T3.js} +10 -4
  10. package/dist/{chunk-CP6MNKAA.js.map → chunk-ISGMZ2T3.js.map} +1 -1
  11. package/dist/{chunk-HP7OKEOE.js → chunk-L4J2K2RT.js} +3 -3
  12. package/dist/chunk-L4J2K2RT.js.map +1 -0
  13. package/dist/{chunk-ZERWUCGK.js → chunk-ONLYF6GA.js} +866 -206
  14. package/dist/chunk-ONLYF6GA.js.map +1 -0
  15. package/dist/{chunk-Z4Y4FMQN.js → chunk-OSR3G3DP.js} +7 -7
  16. package/dist/{chunk-KWXPDASV.js → chunk-PEBORXRA.js} +2 -2
  17. package/dist/chunk-WZ2Z2CRV.js +32 -0
  18. package/dist/chunk-WZ2Z2CRV.js.map +1 -0
  19. package/dist/compat/nestjs/index.cjs +226 -41
  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 +134 -20
  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 +939 -209
  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 +26 -3
  34. package/dist/graph/index.cjs +226 -41
  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-B3BoJjcb.d.cts} +58 -7
  40. package/dist/{graph-D18qmsNm.d.ts → graph-CmiUuhaN.d.ts} +58 -7
  41. package/dist/{index-B7eOdgEx.d.ts → index-Bf2X1YSI.d.ts} +3 -3
  42. package/dist/{index-BvhgZRHK.d.cts → index-Bl7hJcc3.d.cts} +4 -2
  43. package/dist/{index-Bvy_6CaN.d.ts → index-BrgtEG-C.d.ts} +47 -4
  44. package/dist/{index-D_geH2Bm.d.cts → index-BsuKSs4L.d.cts} +3 -3
  45. package/dist/{index-BtK55IE2.d.ts → index-CsUq2rrK.d.ts} +4 -2
  46. package/dist/{index-C3BMRmmp.d.cts → index-D0cx-Yht.d.cts} +3 -3
  47. package/dist/{index-Cz8og7-L.d.cts → index-D1hgSTzr.d.cts} +488 -60
  48. package/dist/{index-C5mqLhMX.d.cts → index-D8NIq6om.d.cts} +47 -4
  49. package/dist/{index-CP_QvbWu.d.ts → index-DFFNKYig.d.ts} +3 -3
  50. package/dist/{index-C3LRU4jB.d.ts → index-Pm68AYPh.d.ts} +488 -60
  51. package/dist/index.cjs +3005 -1776
  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 +396 -27
  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 +226 -41
  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-CAXzJ7hw.d.cts} +2 -2
  65. package/dist/{reactive-log-ohLmTXoZ.d.ts → reactive-log-DwNhOe0g.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-ZERWUCGK.js.map +0 -1
  73. /package/dist/{chunk-QW7H3ICI.js.map → chunk-FGLZ5QID.js.map} +0 -0
  74. /package/dist/{chunk-Z4Y4FMQN.js.map → chunk-OSR3G3DP.js.map} +0 -0
  75. /package/dist/{chunk-KWXPDASV.js.map → chunk-PEBORXRA.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,15 +81,18 @@ __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,
86
93
  fromRabbitMQ: () => fromRabbitMQ,
87
94
  fromRedisStream: () => fromRedisStream,
95
+ fromSqlite: () => fromSqlite,
88
96
  fromStatsD: () => fromStatsD,
89
97
  fromSyslog: () => fromSyslog,
90
98
  fromTimer: () => fromTimer,
@@ -96,6 +104,7 @@ __export(extra_exports, {
96
104
  last: () => last,
97
105
  linear: () => linear,
98
106
  logSlice: () => logSlice,
107
+ lru: () => lru,
99
108
  map: () => map,
100
109
  matchesAnyPattern: () => matchesAnyPattern,
101
110
  matchesCron: () => matchesCron,
@@ -145,6 +154,7 @@ __export(extra_exports, {
145
154
  throttle: () => throttle,
146
155
  throttleTime: () => throttleTime,
147
156
  throwError: () => throwError,
157
+ tieredStorage: () => tieredStorage,
148
158
  timeout: () => timeout,
149
159
  toArray: () => toArray,
150
160
  toCSV: () => toCSV,
@@ -162,6 +172,7 @@ __export(extra_exports, {
162
172
  toRedisStream: () => toRedisStream,
163
173
  toS3: () => toS3,
164
174
  toSSE: () => toSSE,
175
+ toSqlite: () => toSqlite,
165
176
  toTempo: () => toTempo,
166
177
  toWebSocket: () => toWebSocket,
167
178
  tokenBucket: () => tokenBucket,
@@ -328,10 +339,14 @@ function partitionForBatch(messages) {
328
339
  }
329
340
  return { immediate, deferred, terminal };
330
341
  }
331
- function emitWithBatch(emit, messages, phase = 2) {
342
+ function emitWithBatch(emit, messages, phase = 2, options) {
332
343
  if (messages.length === 0) {
333
344
  return;
334
345
  }
346
+ if (options?.strategy === "sequential") {
347
+ _emitSequential(emit, messages, phase);
348
+ return;
349
+ }
335
350
  const queue = phase === 3 ? pendingPhase3 : pendingPhase2;
336
351
  if (messages.length === 1) {
337
352
  const t = messages[0][0];
@@ -372,6 +387,29 @@ function emitWithBatch(emit, messages, phase = 2) {
372
387
  }
373
388
  }
374
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
+ }
375
413
 
376
414
  // src/core/clock.ts
377
415
  function monotonicNs() {
@@ -570,6 +608,7 @@ var NodeImpl = class {
570
608
  _producerStarted = false;
571
609
  _connecting = false;
572
610
  _manualEmitUsed = false;
611
+ _hasEmittedData = false;
573
612
  _sinkCount = 0;
574
613
  _singleDepSinkCount = 0;
575
614
  // --- Object/collection state ---
@@ -856,6 +895,7 @@ var NodeImpl = class {
856
895
  this._cleanup = void 0;
857
896
  cleanupFn?.();
858
897
  this._cached = void 0;
898
+ this._hasEmittedData = false;
859
899
  this._lastDepValues = void 0;
860
900
  }
861
901
  this._status = statusAfterMessage(this._status, m);
@@ -865,6 +905,7 @@ var NodeImpl = class {
865
905
  if (t === TEARDOWN) {
866
906
  if (this._opts.resetOnTeardown) {
867
907
  this._cached = void 0;
908
+ this._hasEmittedData = false;
868
909
  }
869
910
  const teardownCleanup = this._cleanup;
870
911
  this._cleanup = void 0;
@@ -895,7 +936,16 @@ var NodeImpl = class {
895
936
  }
896
937
  _emitAutoValue(value) {
897
938
  const wasDirty = this._status === "dirty";
898
- const unchanged = this._equals(this._cached, value);
939
+ let unchanged;
940
+ try {
941
+ unchanged = this._hasEmittedData && this._equals(this._cached, value);
942
+ } catch (eqErr) {
943
+ const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
944
+ const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, { cause: eqErr });
945
+ this._downInternal([[ERROR, wrapped]]);
946
+ return;
947
+ }
948
+ this._hasEmittedData = true;
899
949
  if (unchanged) {
900
950
  this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
901
951
  return;
@@ -942,7 +992,9 @@ var NodeImpl = class {
942
992
  if (out === void 0) return;
943
993
  this._emitAutoValue(out);
944
994
  } catch (err) {
945
- this._downInternal([[ERROR, err]]);
995
+ const errMsg = err instanceof Error ? err.message : String(err);
996
+ const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, { cause: err });
997
+ this._downInternal([[ERROR, wrapped]]);
946
998
  }
947
999
  }
948
1000
  _onDepDirty(index) {
@@ -977,7 +1029,11 @@ var NodeImpl = class {
977
1029
  try {
978
1030
  if (this._onMessage(msg, index, this._actions)) continue;
979
1031
  } catch (err) {
980
- this._downInternal([[ERROR, err]]);
1032
+ const errMsg = err instanceof Error ? err.message : String(err);
1033
+ const wrapped = new Error(`Node "${this.name}": onMessage threw: ${errMsg}`, {
1034
+ cause: err
1035
+ });
1036
+ this._downInternal([[ERROR, wrapped]]);
981
1037
  return;
982
1038
  }
983
1039
  }
@@ -1192,6 +1248,34 @@ function resolveBackoffPreset(name) {
1192
1248
  );
1193
1249
  }
1194
1250
 
1251
+ // src/core/timer.ts
1252
+ var ResettableTimer = class {
1253
+ _timer;
1254
+ _gen = 0;
1255
+ /** Schedule callback after delayMs. Cancels any pending timer. */
1256
+ start(delayMs, callback) {
1257
+ this.cancel();
1258
+ this._gen += 1;
1259
+ const gen = this._gen;
1260
+ this._timer = setTimeout(() => {
1261
+ this._timer = void 0;
1262
+ if (gen !== this._gen) return;
1263
+ callback();
1264
+ }, delayMs);
1265
+ }
1266
+ /** Cancel the pending timer (if any). */
1267
+ cancel() {
1268
+ if (this._timer !== void 0) {
1269
+ clearTimeout(this._timer);
1270
+ this._timer = void 0;
1271
+ }
1272
+ }
1273
+ /** Whether a timer is currently pending. */
1274
+ get pending() {
1275
+ return this._timer !== void 0;
1276
+ }
1277
+ };
1278
+
1195
1279
  // src/extra/resilience.ts
1196
1280
  function operatorOpts(opts) {
1197
1281
  return { describeKind: "operator", ...opts };
@@ -1221,14 +1305,7 @@ function retry(source, opts) {
1221
1305
  let stopped = false;
1222
1306
  let prevDelay = null;
1223
1307
  let unsub;
1224
- let timer;
1225
- let timerGen = 0;
1226
- function cancelTimer() {
1227
- if (timer !== void 0) {
1228
- clearTimeout(timer);
1229
- timer = void 0;
1230
- }
1231
- }
1308
+ const timer = new ResettableTimer();
1232
1309
  function disconnectUpstream() {
1233
1310
  unsub?.();
1234
1311
  unsub = void 0;
@@ -1244,20 +1321,18 @@ function retry(source, opts) {
1244
1321
  const delayNs = coerceDelayNs(raw === void 0 ? null : raw);
1245
1322
  prevDelay = delayNs;
1246
1323
  attempt += 1;
1247
- timerGen += 1;
1248
- const gen = timerGen;
1249
1324
  disconnectUpstream();
1250
1325
  const delayMs = delayNs > 0 ? delayNs / NS_PER_MS : 1;
1251
- timer = setTimeout(() => {
1252
- timer = void 0;
1253
- if (stopped || gen !== timerGen) return;
1326
+ timer.start(delayMs, () => {
1327
+ if (stopped) return;
1254
1328
  connect();
1255
- }, delayMs);
1329
+ });
1256
1330
  }
1257
1331
  function connect() {
1258
- cancelTimer();
1332
+ timer.cancel();
1259
1333
  disconnectUpstream();
1260
1334
  unsub = source.subscribe((msgs) => {
1335
+ if (stopped) return;
1261
1336
  for (const m of msgs) {
1262
1337
  const t = m[0];
1263
1338
  if (t === DIRTY) a.down([[DIRTY]]);
@@ -1279,8 +1354,7 @@ function retry(source, opts) {
1279
1354
  connect();
1280
1355
  return () => {
1281
1356
  stopped = true;
1282
- timerGen += 1;
1283
- cancelTimer();
1357
+ timer.cancel();
1284
1358
  disconnectUpstream();
1285
1359
  };
1286
1360
  },
@@ -1460,14 +1534,7 @@ function rateLimiter(source, maxEvents, windowNs) {
1460
1534
  (_d, a) => {
1461
1535
  const times = [];
1462
1536
  const pending = [];
1463
- let timer;
1464
- let timerGen = 0;
1465
- function cancelTimer() {
1466
- if (timer !== void 0) {
1467
- clearTimeout(timer);
1468
- timer = void 0;
1469
- }
1470
- }
1537
+ const timer = new ResettableTimer();
1471
1538
  function prune(now) {
1472
1539
  const boundary = now - windowNs;
1473
1540
  while (times.length > 0 && times[0] <= boundary) times.shift();
@@ -1481,15 +1548,10 @@ function rateLimiter(source, maxEvents, windowNs) {
1481
1548
  a.emit(pending.shift());
1482
1549
  } else {
1483
1550
  const oldest = times[0];
1484
- cancelTimer();
1485
- timerGen += 1;
1486
- const gen = timerGen;
1487
1551
  const delayNs = Math.max(0, oldest + windowNs - monotonicNs());
1488
- timer = setTimeout(() => {
1489
- timer = void 0;
1490
- if (gen !== timerGen) return;
1552
+ timer.start(delayNs / NS_PER_MS, () => {
1491
1553
  tryEmit();
1492
- }, delayNs / NS_PER_MS);
1554
+ });
1493
1555
  return;
1494
1556
  }
1495
1557
  }
@@ -1503,14 +1565,12 @@ function rateLimiter(source, maxEvents, windowNs) {
1503
1565
  tryEmit();
1504
1566
  } else if (t === RESOLVED) a.down([[RESOLVED]]);
1505
1567
  else if (t === COMPLETE) {
1506
- timerGen += 1;
1507
- cancelTimer();
1568
+ timer.cancel();
1508
1569
  pending.length = 0;
1509
1570
  times.length = 0;
1510
1571
  a.down([[COMPLETE]]);
1511
1572
  } else if (t === ERROR) {
1512
- timerGen += 1;
1513
- cancelTimer();
1573
+ timer.cancel();
1514
1574
  pending.length = 0;
1515
1575
  times.length = 0;
1516
1576
  a.down([m]);
@@ -1518,8 +1578,7 @@ function rateLimiter(source, maxEvents, windowNs) {
1518
1578
  }
1519
1579
  });
1520
1580
  return () => {
1521
- timerGen += 1;
1522
- cancelTimer();
1581
+ timer.cancel();
1523
1582
  unsub();
1524
1583
  };
1525
1584
  },
@@ -1580,6 +1639,147 @@ function withStatus(src, options) {
1580
1639
  error: out.meta.error
1581
1640
  };
1582
1641
  }
1642
+ var TimeoutError = class extends Error {
1643
+ name = "TimeoutError";
1644
+ constructor(ns) {
1645
+ super(`Timed out after ${ns / NS_PER_MS}ms`);
1646
+ }
1647
+ };
1648
+ function isNode(x) {
1649
+ return x != null && typeof x.subscribe === "function" && typeof x.get === "function";
1650
+ }
1651
+ function fallback(source, fb) {
1652
+ return producer(
1653
+ (_d, a) => {
1654
+ let fallbackUnsub;
1655
+ let sourceUnsub;
1656
+ sourceUnsub = source.subscribe((msgs) => {
1657
+ for (const m of msgs) {
1658
+ const t = m[0];
1659
+ if (t === DIRTY) a.down([[DIRTY]]);
1660
+ else if (t === DATA) a.emit(m[1]);
1661
+ else if (t === RESOLVED) a.down([[RESOLVED]]);
1662
+ else if (t === COMPLETE) a.down([[COMPLETE]]);
1663
+ else if (t === ERROR) {
1664
+ sourceUnsub?.();
1665
+ if (isNode(fb)) {
1666
+ fallbackUnsub = fb.subscribe((fMsgs) => {
1667
+ a.down(fMsgs);
1668
+ });
1669
+ const cur = fb.get();
1670
+ if (cur !== void 0) a.down([[DATA, cur]]);
1671
+ } else {
1672
+ a.emit(fb);
1673
+ a.down([[COMPLETE]]);
1674
+ }
1675
+ return;
1676
+ } else if (t === TEARDOWN) {
1677
+ fallbackUnsub?.();
1678
+ a.down([m]);
1679
+ return;
1680
+ } else a.down([m]);
1681
+ }
1682
+ });
1683
+ return () => {
1684
+ sourceUnsub?.();
1685
+ fallbackUnsub?.();
1686
+ };
1687
+ },
1688
+ {
1689
+ ...operatorOpts(),
1690
+ initial: source.get()
1691
+ }
1692
+ );
1693
+ }
1694
+ function timeout(source, timeoutNs) {
1695
+ if (timeoutNs <= 0) throw new RangeError("timeoutNs must be > 0");
1696
+ return producer(
1697
+ (_d, a) => {
1698
+ let stopped = false;
1699
+ const timer = new ResettableTimer();
1700
+ function startTimer() {
1701
+ const delayMs = timeoutNs / NS_PER_MS;
1702
+ timer.start(delayMs, () => {
1703
+ if (stopped) return;
1704
+ stopped = true;
1705
+ unsub();
1706
+ a.down([[ERROR, new TimeoutError(timeoutNs)]]);
1707
+ });
1708
+ }
1709
+ const unsub = source.subscribe((msgs) => {
1710
+ for (const m of msgs) {
1711
+ if (stopped) return;
1712
+ const t = m[0];
1713
+ if (t === DIRTY) a.down([[DIRTY]]);
1714
+ else if (t === DATA) {
1715
+ startTimer();
1716
+ a.emit(m[1]);
1717
+ } else if (t === RESOLVED) a.down([[RESOLVED]]);
1718
+ else if (t === COMPLETE) {
1719
+ timer.cancel();
1720
+ stopped = true;
1721
+ a.down([[COMPLETE]]);
1722
+ return;
1723
+ } else if (t === ERROR) {
1724
+ timer.cancel();
1725
+ stopped = true;
1726
+ a.down([m]);
1727
+ return;
1728
+ } else if (t === TEARDOWN) {
1729
+ timer.cancel();
1730
+ stopped = true;
1731
+ a.down([m]);
1732
+ return;
1733
+ } else a.down([m]);
1734
+ }
1735
+ });
1736
+ startTimer();
1737
+ return () => {
1738
+ stopped = true;
1739
+ timer.cancel();
1740
+ unsub();
1741
+ };
1742
+ },
1743
+ {
1744
+ ...operatorOpts(),
1745
+ initial: source.get()
1746
+ }
1747
+ );
1748
+ }
1749
+ function cache(source, ttlNs) {
1750
+ if (ttlNs <= 0) throw new RangeError("ttlNs must be > 0");
1751
+ let cachedValue;
1752
+ let cachedAt = 0;
1753
+ let hasCached = false;
1754
+ return producer(
1755
+ (_d, a) => {
1756
+ if (hasCached && monotonicNs() - cachedAt < ttlNs) {
1757
+ a.down([[DATA, cachedValue]]);
1758
+ }
1759
+ const unsub = source.subscribe((msgs) => {
1760
+ for (const m of msgs) {
1761
+ const t = m[0];
1762
+ if (t === DATA) {
1763
+ cachedValue = m[1];
1764
+ cachedAt = monotonicNs();
1765
+ hasCached = true;
1766
+ a.emit(cachedValue);
1767
+ } else if (t === DIRTY) a.down([[DIRTY]]);
1768
+ else if (t === RESOLVED) a.down([[RESOLVED]]);
1769
+ else if (t === COMPLETE) a.down([[COMPLETE]]);
1770
+ else if (t === ERROR) a.down([m]);
1771
+ else a.down([m]);
1772
+ }
1773
+ });
1774
+ return unsub;
1775
+ },
1776
+ {
1777
+ ...operatorOpts(),
1778
+ resubscribable: true,
1779
+ initial: source.get()
1780
+ }
1781
+ );
1782
+ }
1583
1783
 
1584
1784
  // src/extra/sources.ts
1585
1785
  var import_node_fs = require("fs");
@@ -1937,11 +2137,11 @@ function fromAsyncIter(iterable, opts) {
1937
2137
  };
1938
2138
  }, sourceOpts(rest));
1939
2139
  }
1940
- function isNode(x) {
2140
+ function isNode2(x) {
1941
2141
  return x != null && typeof x.subscribe === "function" && typeof x.get === "function";
1942
2142
  }
1943
2143
  function fromAny(input, opts) {
1944
- if (isNode(input)) {
2144
+ if (isNode2(input)) {
1945
2145
  return input;
1946
2146
  }
1947
2147
  if (isThenable(input)) {
@@ -2073,6 +2273,17 @@ function firstValueFrom(source) {
2073
2273
  var shareReplay = replay;
2074
2274
 
2075
2275
  // src/extra/adapters.ts
2276
+ function createSinkErrorHandler(userHandler) {
2277
+ const errorsNode = state(null);
2278
+ const handler = (err) => {
2279
+ userHandler?.(err);
2280
+ try {
2281
+ errorsNode.down([[DATA, err]]);
2282
+ } catch {
2283
+ }
2284
+ };
2285
+ return { errorsNode, handler };
2286
+ }
2076
2287
  function sourceOpts2(opts) {
2077
2288
  return { describeKind: "producer", ...opts };
2078
2289
  }
@@ -2375,7 +2586,7 @@ function toWebSocket(source, socket, opts) {
2375
2586
  };
2376
2587
  const inner = node([source], () => void 0, {
2377
2588
  describeKind: "effect",
2378
- onMessage(msg) {
2589
+ onMessage(msg, _depIndex, _actions) {
2379
2590
  if (msg[0] === DATA) {
2380
2591
  let serialized;
2381
2592
  try {
@@ -2823,10 +3034,11 @@ function toKafka(source, kafkaProducer, topic, opts) {
2823
3034
  onTransportError,
2824
3035
  ...rest
2825
3036
  } = opts ?? {};
3037
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
2826
3038
  const inner = node([source], () => void 0, {
2827
3039
  describeKind: "effect",
2828
3040
  ...rest,
2829
- onMessage(msg) {
3041
+ onMessage(msg, _depIndex, _actions) {
2830
3042
  if (msg[0] === DATA) {
2831
3043
  const value = msg[1];
2832
3044
  const key = keyExtractor?.(value) ?? null;
@@ -2834,7 +3046,7 @@ function toKafka(source, kafkaProducer, topic, opts) {
2834
3046
  try {
2835
3047
  serialized = serialize(value);
2836
3048
  } catch (err) {
2837
- onTransportError?.({
3049
+ handler({
2838
3050
  stage: "serialize",
2839
3051
  error: err instanceof Error ? err : new Error(String(err)),
2840
3052
  value
@@ -2845,7 +3057,7 @@ function toKafka(source, kafkaProducer, topic, opts) {
2845
3057
  topic,
2846
3058
  messages: [{ key, value: Buffer.from(serialized) }]
2847
3059
  }).catch((err) => {
2848
- onTransportError?.({
3060
+ handler({
2849
3061
  stage: "send",
2850
3062
  error: err instanceof Error ? err : new Error(String(err)),
2851
3063
  value
@@ -2856,8 +3068,15 @@ function toKafka(source, kafkaProducer, topic, opts) {
2856
3068
  return false;
2857
3069
  }
2858
3070
  });
2859
- return inner.subscribe(() => {
3071
+ const unsub = inner.subscribe(() => {
2860
3072
  });
3073
+ return {
3074
+ dispose: () => {
3075
+ unsub();
3076
+ errorsNode.down([[TEARDOWN]]);
3077
+ },
3078
+ errors: errorsNode
3079
+ };
2861
3080
  }
2862
3081
  function fromRedisStream(client, key, opts) {
2863
3082
  const {
@@ -2922,17 +3141,18 @@ function toRedisStream(source, client, key, opts) {
2922
3141
  onTransportError,
2923
3142
  ...rest
2924
3143
  } = opts ?? {};
3144
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
2925
3145
  const inner = node([source], () => void 0, {
2926
3146
  describeKind: "effect",
2927
3147
  ...rest,
2928
- onMessage(msg) {
3148
+ onMessage(msg, _depIndex, _actions) {
2929
3149
  if (msg[0] === DATA) {
2930
3150
  const value = msg[1];
2931
3151
  let fields;
2932
3152
  try {
2933
3153
  fields = serialize(value);
2934
3154
  } catch (err) {
2935
- onTransportError?.({
3155
+ handler({
2936
3156
  stage: "serialize",
2937
3157
  error: err instanceof Error ? err : new Error(String(err)),
2938
3158
  value
@@ -2941,7 +3161,7 @@ function toRedisStream(source, client, key, opts) {
2941
3161
  }
2942
3162
  const send = maxLen !== void 0 ? client.xadd(key, "MAXLEN", "~", String(maxLen), "*", ...fields) : client.xadd(key, "*", ...fields);
2943
3163
  void send.catch((err) => {
2944
- onTransportError?.({
3164
+ handler({
2945
3165
  stage: "send",
2946
3166
  error: err instanceof Error ? err : new Error(String(err)),
2947
3167
  value
@@ -2952,8 +3172,15 @@ function toRedisStream(source, client, key, opts) {
2952
3172
  return false;
2953
3173
  }
2954
3174
  });
2955
- return inner.subscribe(() => {
3175
+ const unsub = inner.subscribe(() => {
2956
3176
  });
3177
+ return {
3178
+ dispose: () => {
3179
+ unsub();
3180
+ errorsNode.down([[TEARDOWN]]);
3181
+ },
3182
+ errors: errorsNode
3183
+ };
2957
3184
  }
2958
3185
  function fromCSV(source, opts) {
2959
3186
  const {
@@ -3180,17 +3407,18 @@ function toPulsar(source, pulsarProducer, opts) {
3180
3407
  onTransportError,
3181
3408
  ...rest
3182
3409
  } = opts ?? {};
3410
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3183
3411
  const inner = node([source], () => void 0, {
3184
3412
  describeKind: "effect",
3185
3413
  ...rest,
3186
- onMessage(msg) {
3414
+ onMessage(msg, _depIndex, _actions) {
3187
3415
  if (msg[0] === DATA) {
3188
3416
  const value = msg[1];
3189
3417
  let data;
3190
3418
  try {
3191
3419
  data = serialize(value);
3192
3420
  } catch (err) {
3193
- onTransportError?.({
3421
+ handler({
3194
3422
  stage: "serialize",
3195
3423
  error: err instanceof Error ? err : new Error(String(err)),
3196
3424
  value
@@ -3202,7 +3430,7 @@ function toPulsar(source, pulsarProducer, opts) {
3202
3430
  partitionKey: keyExtractor?.(value),
3203
3431
  properties: propertiesExtractor?.(value)
3204
3432
  }).catch((err) => {
3205
- onTransportError?.({
3433
+ handler({
3206
3434
  stage: "send",
3207
3435
  error: err instanceof Error ? err : new Error(String(err)),
3208
3436
  value
@@ -3213,8 +3441,15 @@ function toPulsar(source, pulsarProducer, opts) {
3213
3441
  return false;
3214
3442
  }
3215
3443
  });
3216
- return inner.subscribe(() => {
3444
+ const unsub = inner.subscribe(() => {
3217
3445
  });
3446
+ return {
3447
+ dispose: () => {
3448
+ unsub();
3449
+ errorsNode.down([[TEARDOWN]]);
3450
+ },
3451
+ errors: errorsNode
3452
+ };
3218
3453
  }
3219
3454
  function fromNATS(client, subject, opts) {
3220
3455
  const decoder = new TextDecoder();
@@ -3270,17 +3505,18 @@ function toNATS(source, client, subject, opts) {
3270
3505
  onTransportError,
3271
3506
  ...rest
3272
3507
  } = opts ?? {};
3508
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3273
3509
  const inner = node([source], () => void 0, {
3274
3510
  describeKind: "effect",
3275
3511
  ...rest,
3276
- onMessage(msg) {
3512
+ onMessage(msg, _depIndex, _actions) {
3277
3513
  if (msg[0] === DATA) {
3278
3514
  const value = msg[1];
3279
3515
  let data;
3280
3516
  try {
3281
3517
  data = serialize(value);
3282
3518
  } catch (err) {
3283
- onTransportError?.({
3519
+ handler({
3284
3520
  stage: "serialize",
3285
3521
  error: err instanceof Error ? err : new Error(String(err)),
3286
3522
  value
@@ -3290,7 +3526,7 @@ function toNATS(source, client, subject, opts) {
3290
3526
  try {
3291
3527
  client.publish(subject, data);
3292
3528
  } catch (err) {
3293
- onTransportError?.({
3529
+ handler({
3294
3530
  stage: "send",
3295
3531
  error: err instanceof Error ? err : new Error(String(err)),
3296
3532
  value
@@ -3301,8 +3537,15 @@ function toNATS(source, client, subject, opts) {
3301
3537
  return false;
3302
3538
  }
3303
3539
  });
3304
- return inner.subscribe(() => {
3540
+ const unsub = inner.subscribe(() => {
3305
3541
  });
3542
+ return {
3543
+ dispose: () => {
3544
+ unsub();
3545
+ errorsNode.down([[TEARDOWN]]);
3546
+ },
3547
+ errors: errorsNode
3548
+ };
3306
3549
  }
3307
3550
  function fromRabbitMQ(channel, queue, opts) {
3308
3551
  const {
@@ -3364,17 +3607,18 @@ function toRabbitMQ(source, channel, exchange, opts) {
3364
3607
  onTransportError,
3365
3608
  ...rest
3366
3609
  } = opts ?? {};
3610
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3367
3611
  const inner = node([source], () => void 0, {
3368
3612
  describeKind: "effect",
3369
3613
  ...rest,
3370
- onMessage(msg) {
3614
+ onMessage(msg, _depIndex, _actions) {
3371
3615
  if (msg[0] === DATA) {
3372
3616
  const value = msg[1];
3373
3617
  let routingKey;
3374
3618
  try {
3375
3619
  routingKey = routingKeyExtractor(value);
3376
3620
  } catch (err) {
3377
- onTransportError?.({
3621
+ handler({
3378
3622
  stage: "routing_key",
3379
3623
  error: err instanceof Error ? err : new Error(String(err)),
3380
3624
  value
@@ -3385,7 +3629,7 @@ function toRabbitMQ(source, channel, exchange, opts) {
3385
3629
  try {
3386
3630
  content = serialize(value);
3387
3631
  } catch (err) {
3388
- onTransportError?.({
3632
+ handler({
3389
3633
  stage: "serialize",
3390
3634
  error: err instanceof Error ? err : new Error(String(err)),
3391
3635
  value
@@ -3395,7 +3639,7 @@ function toRabbitMQ(source, channel, exchange, opts) {
3395
3639
  try {
3396
3640
  channel.publish(exchange, routingKey, content);
3397
3641
  } catch (err) {
3398
- onTransportError?.({
3642
+ handler({
3399
3643
  stage: "send",
3400
3644
  error: err instanceof Error ? err : new Error(String(err)),
3401
3645
  value
@@ -3406,8 +3650,15 @@ function toRabbitMQ(source, channel, exchange, opts) {
3406
3650
  return false;
3407
3651
  }
3408
3652
  });
3409
- return inner.subscribe(() => {
3653
+ const unsub = inner.subscribe(() => {
3410
3654
  });
3655
+ return {
3656
+ dispose: () => {
3657
+ unsub();
3658
+ errorsNode.down([[TEARDOWN]]);
3659
+ },
3660
+ errors: errorsNode
3661
+ };
3411
3662
  }
3412
3663
  function toFile(source, writer, opts) {
3413
3664
  const {
@@ -3419,8 +3670,10 @@ function toFile(source, writer, opts) {
3419
3670
  mode: _mode,
3420
3671
  ...rest
3421
3672
  } = opts ?? {};
3673
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3422
3674
  let buffer2 = [];
3423
3675
  let timer;
3676
+ let disposed = false;
3424
3677
  const doFlush = () => {
3425
3678
  if (buffer2.length === 0) return;
3426
3679
  const chunk = buffer2.join("");
@@ -3428,7 +3681,7 @@ function toFile(source, writer, opts) {
3428
3681
  try {
3429
3682
  writer.write(chunk);
3430
3683
  } catch (err) {
3431
- onTransportError?.({
3684
+ handler({
3432
3685
  stage: "send",
3433
3686
  error: err instanceof Error ? err : new Error(String(err)),
3434
3687
  value: chunk
@@ -3436,7 +3689,7 @@ function toFile(source, writer, opts) {
3436
3689
  }
3437
3690
  };
3438
3691
  const scheduleFlush = () => {
3439
- if (flushIntervalMs > 0 && timer === void 0) {
3692
+ if (flushIntervalMs > 0 && timer === void 0 && !disposed) {
3440
3693
  timer = setTimeout(() => {
3441
3694
  timer = void 0;
3442
3695
  doFlush();
@@ -3447,14 +3700,14 @@ function toFile(source, writer, opts) {
3447
3700
  const inner = node([source], () => void 0, {
3448
3701
  describeKind: "effect",
3449
3702
  ...rest,
3450
- onMessage(msg) {
3703
+ onMessage(msg, _depIndex, _actions) {
3451
3704
  if (msg[0] === DATA) {
3452
3705
  const value = msg[1];
3453
3706
  let line;
3454
3707
  try {
3455
3708
  line = serialize(value);
3456
3709
  } catch (err) {
3457
- onTransportError?.({
3710
+ handler({
3458
3711
  stage: "serialize",
3459
3712
  error: err instanceof Error ? err : new Error(String(err)),
3460
3713
  value
@@ -3469,7 +3722,7 @@ function toFile(source, writer, opts) {
3469
3722
  try {
3470
3723
  writer.write(line);
3471
3724
  } catch (err) {
3472
- onTransportError?.({
3725
+ handler({
3473
3726
  stage: "send",
3474
3727
  error: err instanceof Error ? err : new Error(String(err)),
3475
3728
  value
@@ -3478,7 +3731,7 @@ function toFile(source, writer, opts) {
3478
3731
  }
3479
3732
  return true;
3480
3733
  }
3481
- if (msg[0] === COMPLETE || msg[0] === TEARDOWN) {
3734
+ if (messageTier(msg[0]) >= 3) {
3482
3735
  doFlush();
3483
3736
  }
3484
3737
  return false;
@@ -3487,18 +3740,25 @@ function toFile(source, writer, opts) {
3487
3740
  const unsub = inner.subscribe(() => {
3488
3741
  });
3489
3742
  const dispose = () => {
3743
+ if (disposed) return;
3744
+ disposed = true;
3490
3745
  if (timer !== void 0) {
3491
3746
  clearTimeout(timer);
3492
3747
  timer = void 0;
3493
3748
  }
3494
3749
  doFlush();
3495
- writer.end();
3750
+ try {
3751
+ writer.end();
3752
+ } catch {
3753
+ }
3496
3754
  unsub();
3755
+ errorsNode.down([[TEARDOWN]]);
3497
3756
  };
3498
3757
  return {
3499
3758
  dispose,
3759
+ errors: errorsNode,
3500
3760
  flush: async () => {
3501
- doFlush();
3761
+ if (!disposed) doFlush();
3502
3762
  }
3503
3763
  };
3504
3764
  }
@@ -3549,25 +3809,29 @@ function toClickHouse(source, client, table, opts) {
3549
3809
  onTransportError,
3550
3810
  ...rest
3551
3811
  } = opts ?? {};
3812
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3552
3813
  let buffer2 = [];
3553
3814
  let timer;
3554
- let lastFlush = Promise.resolve();
3815
+ let disposed = false;
3816
+ const inFlight = /* @__PURE__ */ new Set();
3555
3817
  const doFlush = () => {
3556
3818
  if (buffer2.length === 0) return Promise.resolve();
3557
3819
  const batch2 = buffer2;
3558
3820
  buffer2 = [];
3559
3821
  try {
3560
3822
  const p = client.insert({ table, values: batch2, format }).catch((err) => {
3561
- onTransportError?.({
3823
+ handler({
3562
3824
  stage: "send",
3563
3825
  error: err instanceof Error ? err : new Error(String(err)),
3564
3826
  value: batch2
3565
3827
  });
3828
+ }).finally(() => {
3829
+ inFlight.delete(p);
3566
3830
  });
3567
- lastFlush = p;
3831
+ inFlight.add(p);
3568
3832
  return p;
3569
3833
  } catch (err) {
3570
- onTransportError?.({
3834
+ handler({
3571
3835
  stage: "send",
3572
3836
  error: err instanceof Error ? err : new Error(String(err)),
3573
3837
  value: batch2
@@ -3576,7 +3840,7 @@ function toClickHouse(source, client, table, opts) {
3576
3840
  }
3577
3841
  };
3578
3842
  const scheduleFlush = () => {
3579
- if (timer === void 0) {
3843
+ if (timer === void 0 && !disposed) {
3580
3844
  timer = setTimeout(() => {
3581
3845
  timer = void 0;
3582
3846
  doFlush();
@@ -3586,13 +3850,13 @@ function toClickHouse(source, client, table, opts) {
3586
3850
  const inner = node([source], () => void 0, {
3587
3851
  describeKind: "effect",
3588
3852
  ...rest,
3589
- onMessage(msg) {
3853
+ onMessage(msg, _depIndex, _actions) {
3590
3854
  if (msg[0] === DATA) {
3591
3855
  const value = msg[1];
3592
3856
  try {
3593
3857
  buffer2.push(transform(value));
3594
3858
  } catch (err) {
3595
- onTransportError?.({
3859
+ handler({
3596
3860
  stage: "serialize",
3597
3861
  error: err instanceof Error ? err : new Error(String(err)),
3598
3862
  value
@@ -3603,7 +3867,7 @@ function toClickHouse(source, client, table, opts) {
3603
3867
  else scheduleFlush();
3604
3868
  return true;
3605
3869
  }
3606
- if (msg[0] === COMPLETE || msg[0] === TEARDOWN) {
3870
+ if (messageTier(msg[0]) >= 3) {
3607
3871
  doFlush();
3608
3872
  }
3609
3873
  return false;
@@ -3612,16 +3876,24 @@ function toClickHouse(source, client, table, opts) {
3612
3876
  const unsub = inner.subscribe(() => {
3613
3877
  });
3614
3878
  const dispose = () => {
3879
+ if (disposed) return;
3880
+ disposed = true;
3615
3881
  if (timer !== void 0) {
3616
3882
  clearTimeout(timer);
3617
3883
  timer = void 0;
3618
3884
  }
3619
3885
  doFlush();
3620
3886
  unsub();
3887
+ errorsNode.down([[TEARDOWN]]);
3621
3888
  };
3622
3889
  return {
3623
3890
  dispose,
3624
- flush: () => doFlush().then(() => lastFlush)
3891
+ errors: errorsNode,
3892
+ flush: () => {
3893
+ const p = disposed ? Promise.resolve() : doFlush();
3894
+ return p.then(() => Promise.all(inFlight)).then(() => {
3895
+ });
3896
+ }
3625
3897
  };
3626
3898
  }
3627
3899
  function toS3(source, client, bucket, opts) {
@@ -3638,10 +3910,12 @@ function toS3(source, client, bucket, opts) {
3638
3910
  onTransportError,
3639
3911
  ...rest
3640
3912
  } = opts ?? {};
3913
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3641
3914
  let buffer2 = [];
3642
3915
  let timer;
3643
3916
  let seq = 0;
3644
- let lastFlush = Promise.resolve();
3917
+ let disposed = false;
3918
+ const inFlight = /* @__PURE__ */ new Set();
3645
3919
  const doFlush = () => {
3646
3920
  if (buffer2.length === 0) return Promise.resolve();
3647
3921
  const batch2 = buffer2;
@@ -3654,16 +3928,18 @@ function toS3(source, client, bucket, opts) {
3654
3928
  try {
3655
3929
  const p = client.putObject({ Bucket: bucket, Key: key, Body: body, ContentType: contentType }).then(() => {
3656
3930
  }).catch((err) => {
3657
- onTransportError?.({
3931
+ handler({
3658
3932
  stage: "send",
3659
3933
  error: err instanceof Error ? err : new Error(String(err)),
3660
3934
  value: batch2
3661
3935
  });
3936
+ }).finally(() => {
3937
+ inFlight.delete(p);
3662
3938
  });
3663
- lastFlush = p;
3939
+ inFlight.add(p);
3664
3940
  return p;
3665
3941
  } catch (err) {
3666
- onTransportError?.({
3942
+ handler({
3667
3943
  stage: "send",
3668
3944
  error: err instanceof Error ? err : new Error(String(err)),
3669
3945
  value: batch2
@@ -3672,7 +3948,7 @@ function toS3(source, client, bucket, opts) {
3672
3948
  }
3673
3949
  };
3674
3950
  const scheduleFlush = () => {
3675
- if (timer === void 0) {
3951
+ if (timer === void 0 && !disposed) {
3676
3952
  timer = setTimeout(() => {
3677
3953
  timer = void 0;
3678
3954
  doFlush();
@@ -3682,13 +3958,13 @@ function toS3(source, client, bucket, opts) {
3682
3958
  const inner = node([source], () => void 0, {
3683
3959
  describeKind: "effect",
3684
3960
  ...rest,
3685
- onMessage(msg) {
3961
+ onMessage(msg, _depIndex, _actions) {
3686
3962
  if (msg[0] === DATA) {
3687
3963
  const value = msg[1];
3688
3964
  try {
3689
3965
  buffer2.push(transform(value));
3690
3966
  } catch (err) {
3691
- onTransportError?.({
3967
+ handler({
3692
3968
  stage: "serialize",
3693
3969
  error: err instanceof Error ? err : new Error(String(err)),
3694
3970
  value
@@ -3699,7 +3975,7 @@ function toS3(source, client, bucket, opts) {
3699
3975
  else scheduleFlush();
3700
3976
  return true;
3701
3977
  }
3702
- if (msg[0] === COMPLETE || msg[0] === TEARDOWN) {
3978
+ if (messageTier(msg[0]) >= 3) {
3703
3979
  doFlush();
3704
3980
  }
3705
3981
  return false;
@@ -3708,16 +3984,24 @@ function toS3(source, client, bucket, opts) {
3708
3984
  const unsub = inner.subscribe(() => {
3709
3985
  });
3710
3986
  const dispose = () => {
3987
+ if (disposed) return;
3988
+ disposed = true;
3711
3989
  if (timer !== void 0) {
3712
3990
  clearTimeout(timer);
3713
3991
  timer = void 0;
3714
3992
  }
3715
3993
  doFlush();
3716
3994
  unsub();
3995
+ errorsNode.down([[TEARDOWN]]);
3717
3996
  };
3718
3997
  return {
3719
3998
  dispose,
3720
- flush: () => doFlush().then(() => lastFlush)
3999
+ errors: errorsNode,
4000
+ flush: () => {
4001
+ const p = disposed ? Promise.resolve() : doFlush();
4002
+ return p.then(() => Promise.all(inFlight)).then(() => {
4003
+ });
4004
+ }
3721
4005
  };
3722
4006
  }
3723
4007
  function toPostgres(source, client, table, opts) {
@@ -3729,17 +4013,18 @@ function toPostgres(source, client, table, opts) {
3729
4013
  onTransportError,
3730
4014
  ...rest
3731
4015
  } = opts ?? {};
4016
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3732
4017
  const inner = node([source], () => void 0, {
3733
4018
  describeKind: "effect",
3734
4019
  ...rest,
3735
- onMessage(msg) {
4020
+ onMessage(msg, _depIndex, _actions) {
3736
4021
  if (msg[0] === DATA) {
3737
4022
  const value = msg[1];
3738
4023
  let query;
3739
4024
  try {
3740
4025
  query = toSQL(value, table);
3741
4026
  } catch (err) {
3742
- onTransportError?.({
4027
+ handler({
3743
4028
  stage: "serialize",
3744
4029
  error: err instanceof Error ? err : new Error(String(err)),
3745
4030
  value
@@ -3747,7 +4032,7 @@ function toPostgres(source, client, table, opts) {
3747
4032
  return true;
3748
4033
  }
3749
4034
  void client.query(query.sql, query.params).catch((err) => {
3750
- onTransportError?.({
4035
+ handler({
3751
4036
  stage: "send",
3752
4037
  error: err instanceof Error ? err : new Error(String(err)),
3753
4038
  value
@@ -3758,22 +4043,30 @@ function toPostgres(source, client, table, opts) {
3758
4043
  return false;
3759
4044
  }
3760
4045
  });
3761
- return inner.subscribe(() => {
4046
+ const unsub = inner.subscribe(() => {
3762
4047
  });
4048
+ return {
4049
+ dispose: () => {
4050
+ unsub();
4051
+ errorsNode.down([[TEARDOWN]]);
4052
+ },
4053
+ errors: errorsNode
4054
+ };
3763
4055
  }
3764
4056
  function toMongo(source, collection, opts) {
3765
4057
  const { toDocument = (v) => v, onTransportError, ...rest } = opts ?? {};
4058
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3766
4059
  const inner = node([source], () => void 0, {
3767
4060
  describeKind: "effect",
3768
4061
  ...rest,
3769
- onMessage(msg) {
4062
+ onMessage(msg, _depIndex, _actions) {
3770
4063
  if (msg[0] === DATA) {
3771
4064
  const value = msg[1];
3772
4065
  let doc;
3773
4066
  try {
3774
4067
  doc = toDocument(value);
3775
4068
  } catch (err) {
3776
- onTransportError?.({
4069
+ handler({
3777
4070
  stage: "serialize",
3778
4071
  error: err instanceof Error ? err : new Error(String(err)),
3779
4072
  value
@@ -3781,7 +4074,7 @@ function toMongo(source, collection, opts) {
3781
4074
  return true;
3782
4075
  }
3783
4076
  void collection.insertOne(doc).catch((err) => {
3784
- onTransportError?.({
4077
+ handler({
3785
4078
  stage: "send",
3786
4079
  error: err instanceof Error ? err : new Error(String(err)),
3787
4080
  value
@@ -3792,8 +4085,15 @@ function toMongo(source, collection, opts) {
3792
4085
  return false;
3793
4086
  }
3794
4087
  });
3795
- return inner.subscribe(() => {
4088
+ const unsub = inner.subscribe(() => {
3796
4089
  });
4090
+ return {
4091
+ dispose: () => {
4092
+ unsub();
4093
+ errorsNode.down([[TEARDOWN]]);
4094
+ },
4095
+ errors: errorsNode
4096
+ };
3797
4097
  }
3798
4098
  function toLoki(source, client, opts) {
3799
4099
  const {
@@ -3803,17 +4103,18 @@ function toLoki(source, client, opts) {
3803
4103
  onTransportError,
3804
4104
  ...rest
3805
4105
  } = opts ?? {};
4106
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3806
4107
  const inner = node([source], () => void 0, {
3807
4108
  describeKind: "effect",
3808
4109
  ...rest,
3809
- onMessage(msg) {
4110
+ onMessage(msg, _depIndex, _actions) {
3810
4111
  if (msg[0] === DATA) {
3811
4112
  const value = msg[1];
3812
4113
  let line;
3813
4114
  try {
3814
4115
  line = toLine(value);
3815
4116
  } catch (err) {
3816
- onTransportError?.({
4117
+ handler({
3817
4118
  stage: "serialize",
3818
4119
  error: err instanceof Error ? err : new Error(String(err)),
3819
4120
  value
@@ -3824,7 +4125,7 @@ function toLoki(source, client, opts) {
3824
4125
  try {
3825
4126
  streamLabels = toLabels ? { ...labels, ...toLabels(value) } : labels;
3826
4127
  } catch (err) {
3827
- onTransportError?.({
4128
+ handler({
3828
4129
  stage: "serialize",
3829
4130
  error: err instanceof Error ? err : new Error(String(err)),
3830
4131
  value
@@ -3833,7 +4134,7 @@ function toLoki(source, client, opts) {
3833
4134
  }
3834
4135
  const ts = `${wallClockNs()}`;
3835
4136
  void client.push({ streams: [{ stream: streamLabels, values: [[ts, line]] }] }).catch((err) => {
3836
- onTransportError?.({
4137
+ handler({
3837
4138
  stage: "send",
3838
4139
  error: err instanceof Error ? err : new Error(String(err)),
3839
4140
  value
@@ -3844,22 +4145,30 @@ function toLoki(source, client, opts) {
3844
4145
  return false;
3845
4146
  }
3846
4147
  });
3847
- return inner.subscribe(() => {
4148
+ const unsub = inner.subscribe(() => {
3848
4149
  });
4150
+ return {
4151
+ dispose: () => {
4152
+ unsub();
4153
+ errorsNode.down([[TEARDOWN]]);
4154
+ },
4155
+ errors: errorsNode
4156
+ };
3849
4157
  }
3850
4158
  function toTempo(source, client, opts) {
3851
4159
  const { toResourceSpans = (v) => [v], onTransportError, ...rest } = opts ?? {};
4160
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
3852
4161
  const inner = node([source], () => void 0, {
3853
4162
  describeKind: "effect",
3854
4163
  ...rest,
3855
- onMessage(msg) {
4164
+ onMessage(msg, _depIndex, _actions) {
3856
4165
  if (msg[0] === DATA) {
3857
4166
  const value = msg[1];
3858
4167
  let spans;
3859
4168
  try {
3860
4169
  spans = toResourceSpans(value);
3861
4170
  } catch (err) {
3862
- onTransportError?.({
4171
+ handler({
3863
4172
  stage: "serialize",
3864
4173
  error: err instanceof Error ? err : new Error(String(err)),
3865
4174
  value
@@ -3867,7 +4176,7 @@ function toTempo(source, client, opts) {
3867
4176
  return true;
3868
4177
  }
3869
4178
  void client.push({ resourceSpans: spans }).catch((err) => {
3870
- onTransportError?.({
4179
+ handler({
3871
4180
  stage: "send",
3872
4181
  error: err instanceof Error ? err : new Error(String(err)),
3873
4182
  value
@@ -3878,15 +4187,22 @@ function toTempo(source, client, opts) {
3878
4187
  return false;
3879
4188
  }
3880
4189
  });
3881
- return inner.subscribe(() => {
4190
+ const unsub = inner.subscribe(() => {
3882
4191
  });
4192
+ return {
4193
+ dispose: () => {
4194
+ unsub();
4195
+ errorsNode.down([[TEARDOWN]]);
4196
+ },
4197
+ errors: errorsNode
4198
+ };
3883
4199
  }
3884
4200
  function checkpointToS3(graph, client, bucket, opts) {
3885
4201
  const { prefix = "checkpoints/", debounceMs, compactEvery, onError } = opts ?? {};
3886
4202
  const adapter = {
3887
- save(data) {
4203
+ save(_key, data) {
3888
4204
  const ms = Math.floor(wallClockNs() / 1e6);
3889
- const key = `${prefix}${graph.name}/checkpoint-${ms}.json`;
4205
+ const s3Key = `${prefix}${graph.name}/checkpoint-${ms}.json`;
3890
4206
  let body;
3891
4207
  try {
3892
4208
  body = JSON.stringify(data);
@@ -3896,7 +4212,7 @@ function checkpointToS3(graph, client, bucket, opts) {
3896
4212
  }
3897
4213
  void client.putObject({
3898
4214
  Bucket: bucket,
3899
- Key: key,
4215
+ Key: s3Key,
3900
4216
  Body: body,
3901
4217
  ContentType: "application/json"
3902
4218
  }).catch((err) => onError?.(err));
@@ -3906,9 +4222,9 @@ function checkpointToS3(graph, client, bucket, opts) {
3906
4222
  }
3907
4223
  function checkpointToRedis(graph, client, opts) {
3908
4224
  const { prefix = "graphrefly:checkpoint:", debounceMs, compactEvery, onError } = opts ?? {};
3909
- const key = `${prefix}${graph.name}`;
4225
+ const redisKey = `${prefix}${graph.name}`;
3910
4226
  const adapter = {
3911
- save(data) {
4227
+ save(_key, data) {
3912
4228
  let body;
3913
4229
  try {
3914
4230
  body = JSON.stringify(data);
@@ -3916,11 +4232,250 @@ function checkpointToRedis(graph, client, opts) {
3916
4232
  onError?.(err);
3917
4233
  return;
3918
4234
  }
3919
- void client.set(key, body).catch((err) => onError?.(err));
4235
+ void client.set(redisKey, body).catch((err) => onError?.(err));
3920
4236
  }
3921
4237
  };
3922
4238
  return graph.autoCheckpoint(adapter, { debounceMs, compactEvery, onError });
3923
4239
  }
4240
+ function fromSqlite(db, query, opts) {
4241
+ const { mapRow = (r) => r, params, ...rest } = opts ?? {};
4242
+ return producer(
4243
+ (_d, a) => {
4244
+ let mapped;
4245
+ try {
4246
+ const rows = db.query(query, params);
4247
+ mapped = rows.map(mapRow);
4248
+ } catch (err) {
4249
+ a.down([[ERROR, err instanceof Error ? err : new Error(String(err))]]);
4250
+ return void 0;
4251
+ }
4252
+ batch(() => {
4253
+ for (const item of mapped) {
4254
+ a.down([[DATA, item]]);
4255
+ }
4256
+ a.down([[COMPLETE]]);
4257
+ });
4258
+ return void 0;
4259
+ },
4260
+ { describeKind: "producer", completeWhenDepsComplete: false, ...rest }
4261
+ );
4262
+ }
4263
+ function toSqlite(source, db, table, opts) {
4264
+ if (table.includes("\0") || table.length === 0) {
4265
+ throw new Error(`toSqlite: invalid table name: ${JSON.stringify(table)}`);
4266
+ }
4267
+ const {
4268
+ toSQL = (v, t) => ({
4269
+ sql: `INSERT INTO "${t.replace(/"/g, '""')}" (data) VALUES (?)`,
4270
+ params: [JSON.stringify(v)]
4271
+ }),
4272
+ onTransportError,
4273
+ batchInsert = false,
4274
+ maxBatchSize = 1e3,
4275
+ flushIntervalMs = 0,
4276
+ ...rest
4277
+ } = opts ?? {};
4278
+ const { errorsNode, handler } = createSinkErrorHandler(onTransportError);
4279
+ const pendingInserts = [];
4280
+ let flushing = false;
4281
+ let disposed = false;
4282
+ let timer;
4283
+ function flushTransaction() {
4284
+ if (pendingInserts.length === 0 || flushing) return;
4285
+ flushing = true;
4286
+ try {
4287
+ db.query("BEGIN", []);
4288
+ } catch (err) {
4289
+ flushing = false;
4290
+ handler({
4291
+ stage: "send",
4292
+ error: err instanceof Error ? err : new Error(String(err)),
4293
+ value: void 0
4294
+ });
4295
+ return;
4296
+ }
4297
+ const batch2 = pendingInserts.splice(0);
4298
+ let firstError;
4299
+ for (const q of batch2) {
4300
+ try {
4301
+ db.query(q.sql, q.params);
4302
+ } catch (err) {
4303
+ firstError = err instanceof Error ? err : new Error(String(err));
4304
+ break;
4305
+ }
4306
+ }
4307
+ if (firstError) {
4308
+ try {
4309
+ db.query("ROLLBACK", []);
4310
+ } catch {
4311
+ }
4312
+ handler({ stage: "send", error: firstError, value: void 0 });
4313
+ } else {
4314
+ try {
4315
+ db.query("COMMIT", []);
4316
+ } catch (err) {
4317
+ handler({
4318
+ stage: "send",
4319
+ error: err instanceof Error ? err : new Error(String(err)),
4320
+ value: void 0
4321
+ });
4322
+ }
4323
+ }
4324
+ flushing = false;
4325
+ }
4326
+ const scheduleFlush = () => {
4327
+ if (batchInsert && flushIntervalMs > 0 && timer === void 0 && !disposed) {
4328
+ timer = setTimeout(() => {
4329
+ timer = void 0;
4330
+ flushTransaction();
4331
+ }, flushIntervalMs);
4332
+ }
4333
+ };
4334
+ const inner = node([source], () => void 0, {
4335
+ describeKind: "effect",
4336
+ ...rest,
4337
+ onMessage(msg, _depIndex, _actions) {
4338
+ if (msg[0] === DATA) {
4339
+ const value = msg[1];
4340
+ let query;
4341
+ try {
4342
+ query = toSQL(value, table);
4343
+ } catch (err) {
4344
+ handler({
4345
+ stage: "serialize",
4346
+ error: err instanceof Error ? err : new Error(String(err)),
4347
+ value
4348
+ });
4349
+ return true;
4350
+ }
4351
+ if (batchInsert) {
4352
+ pendingInserts.push(query);
4353
+ if (pendingInserts.length >= maxBatchSize) flushTransaction();
4354
+ else scheduleFlush();
4355
+ } else {
4356
+ try {
4357
+ db.query(query.sql, query.params);
4358
+ } catch (err) {
4359
+ handler({
4360
+ stage: "send",
4361
+ error: err instanceof Error ? err : new Error(String(err)),
4362
+ value
4363
+ });
4364
+ }
4365
+ }
4366
+ return true;
4367
+ }
4368
+ if (batchInsert && messageTier(msg[0]) >= 3) {
4369
+ flushTransaction();
4370
+ }
4371
+ return false;
4372
+ }
4373
+ });
4374
+ const unsub = inner.subscribe(() => {
4375
+ });
4376
+ const dispose = () => {
4377
+ if (disposed) return;
4378
+ disposed = true;
4379
+ if (timer !== void 0) {
4380
+ clearTimeout(timer);
4381
+ timer = void 0;
4382
+ }
4383
+ if (batchInsert) flushTransaction();
4384
+ unsub();
4385
+ errorsNode.down([[TEARDOWN]]);
4386
+ };
4387
+ return {
4388
+ dispose,
4389
+ errors: errorsNode,
4390
+ flush: batchInsert ? async () => {
4391
+ if (!disposed) flushTransaction();
4392
+ } : void 0
4393
+ };
4394
+ }
4395
+ function fromPrisma(model, opts) {
4396
+ const { args, mapRow = (r) => r, ...rest } = opts ?? {};
4397
+ return producer(
4398
+ (_d, a) => {
4399
+ let active = true;
4400
+ void model.findMany(args).then((rows) => {
4401
+ if (!active) return;
4402
+ const mapped = rows.map(mapRow);
4403
+ batch(() => {
4404
+ for (const item of mapped) {
4405
+ a.emit(item);
4406
+ }
4407
+ });
4408
+ a.down([[COMPLETE]]);
4409
+ }).catch((err) => {
4410
+ if (!active) return;
4411
+ try {
4412
+ a.down([[ERROR, err instanceof Error ? err : new Error(String(err))]]);
4413
+ } catch {
4414
+ }
4415
+ });
4416
+ return () => {
4417
+ active = false;
4418
+ };
4419
+ },
4420
+ { ...rest, describeKind: "producer", completeWhenDepsComplete: false }
4421
+ );
4422
+ }
4423
+ function fromDrizzle(query, opts) {
4424
+ const { mapRow = (r) => r, ...rest } = opts ?? {};
4425
+ return producer(
4426
+ (_d, a) => {
4427
+ let active = true;
4428
+ void query.execute().then((rows) => {
4429
+ if (!active) return;
4430
+ const mapped = rows.map(mapRow);
4431
+ batch(() => {
4432
+ for (const item of mapped) {
4433
+ a.emit(item);
4434
+ }
4435
+ });
4436
+ a.down([[COMPLETE]]);
4437
+ }).catch((err) => {
4438
+ if (!active) return;
4439
+ try {
4440
+ a.down([[ERROR, err instanceof Error ? err : new Error(String(err))]]);
4441
+ } catch {
4442
+ }
4443
+ });
4444
+ return () => {
4445
+ active = false;
4446
+ };
4447
+ },
4448
+ { ...rest, describeKind: "producer", completeWhenDepsComplete: false }
4449
+ );
4450
+ }
4451
+ function fromKysely(query, opts) {
4452
+ const { mapRow = (r) => r, ...rest } = opts ?? {};
4453
+ return producer(
4454
+ (_d, a) => {
4455
+ let active = true;
4456
+ void query.execute().then((rows) => {
4457
+ if (!active) return;
4458
+ const mapped = rows.map(mapRow);
4459
+ batch(() => {
4460
+ for (const item of mapped) {
4461
+ a.emit(item);
4462
+ }
4463
+ });
4464
+ a.down([[COMPLETE]]);
4465
+ }).catch((err) => {
4466
+ if (!active) return;
4467
+ try {
4468
+ a.down([[ERROR, err instanceof Error ? err : new Error(String(err))]]);
4469
+ } catch {
4470
+ }
4471
+ });
4472
+ return () => {
4473
+ active = false;
4474
+ };
4475
+ },
4476
+ { ...rest, describeKind: "producer", completeWhenDepsComplete: false }
4477
+ );
4478
+ }
3924
4479
 
3925
4480
  // src/extra/backpressure.ts
3926
4481
  var nextLockId = 0;
@@ -3966,6 +4521,205 @@ function createWatermarkController(sendUp, opts) {
3966
4521
  };
3967
4522
  }
3968
4523
 
4524
+ // src/extra/cascading-cache.ts
4525
+ function lru() {
4526
+ const map2 = /* @__PURE__ */ new Map();
4527
+ let head = null;
4528
+ let tail = null;
4529
+ function unlink(n) {
4530
+ if (n.prev) n.prev.next = n.next;
4531
+ else head = n.next;
4532
+ if (n.next) n.next.prev = n.prev;
4533
+ else tail = n.prev;
4534
+ n.prev = null;
4535
+ n.next = null;
4536
+ }
4537
+ function pushFront(n) {
4538
+ n.next = head;
4539
+ n.prev = null;
4540
+ if (head) head.prev = n;
4541
+ head = n;
4542
+ if (tail === null) tail = n;
4543
+ }
4544
+ return {
4545
+ insert(key) {
4546
+ if (map2.has(key)) {
4547
+ this.touch(key);
4548
+ return;
4549
+ }
4550
+ const n = { key, prev: null, next: null };
4551
+ map2.set(key, n);
4552
+ pushFront(n);
4553
+ },
4554
+ touch(key) {
4555
+ const n = map2.get(key);
4556
+ if (!n) return;
4557
+ unlink(n);
4558
+ pushFront(n);
4559
+ },
4560
+ delete(key) {
4561
+ const n = map2.get(key);
4562
+ if (!n) return;
4563
+ unlink(n);
4564
+ map2.delete(key);
4565
+ },
4566
+ evict(count) {
4567
+ const victims = [];
4568
+ for (let i = 0; i < count && tail !== null; i++) {
4569
+ const n = tail;
4570
+ victims.push(n.key);
4571
+ unlink(n);
4572
+ map2.delete(n.key);
4573
+ }
4574
+ return victims;
4575
+ },
4576
+ size() {
4577
+ return map2.size;
4578
+ }
4579
+ };
4580
+ }
4581
+ function cascadingCache(tiers, opts) {
4582
+ const entries = /* @__PURE__ */ new Map();
4583
+ const maxSize = opts?.maxSize ?? 0;
4584
+ const policy = maxSize > 0 ? opts?.eviction ?? lru() : null;
4585
+ const writeThrough = opts?.writeThrough ?? false;
4586
+ function promote(key, value, hitTierIndex) {
4587
+ for (let i = 0; i < hitTierIndex; i++) {
4588
+ const tier = tiers[i];
4589
+ if (tier.save) tier.save(key, value);
4590
+ }
4591
+ }
4592
+ function cascade(key, nd) {
4593
+ for (let tierIndex = 0; tierIndex < tiers.length; tierIndex++) {
4594
+ let result;
4595
+ try {
4596
+ result = tiers[tierIndex].load(key);
4597
+ } catch {
4598
+ continue;
4599
+ }
4600
+ if (result != null) {
4601
+ nd.down([[DATA, result]]);
4602
+ promote(key, result, tierIndex);
4603
+ return;
4604
+ }
4605
+ }
4606
+ }
4607
+ function evictIfNeeded() {
4608
+ if (!policy || maxSize <= 0) return;
4609
+ while (policy.size() >= maxSize) {
4610
+ const victims = policy.evict(1);
4611
+ if (victims.length === 0) break;
4612
+ for (const key of victims) {
4613
+ const nd = entries.get(key);
4614
+ if (nd) {
4615
+ const value = nd.get();
4616
+ if (value !== void 0) {
4617
+ for (let i = tiers.length - 1; i >= 0; i--) {
4618
+ if (tiers[i].save) {
4619
+ tiers[i].save(key, value);
4620
+ for (let j = 0; j < i; j++) {
4621
+ if (tiers[j].clear) tiers[j].clear(key);
4622
+ }
4623
+ break;
4624
+ }
4625
+ }
4626
+ }
4627
+ nd.down([[TEARDOWN]]);
4628
+ }
4629
+ entries.delete(key);
4630
+ }
4631
+ }
4632
+ }
4633
+ return {
4634
+ load(key) {
4635
+ const existing = entries.get(key);
4636
+ if (existing) {
4637
+ policy?.touch(key);
4638
+ return existing;
4639
+ }
4640
+ if (policy && maxSize > 0 && policy.size() >= maxSize) {
4641
+ evictIfNeeded();
4642
+ }
4643
+ const nd = state(void 0);
4644
+ entries.set(key, nd);
4645
+ if (policy) {
4646
+ policy.insert(key);
4647
+ }
4648
+ cascade(key, nd);
4649
+ return nd;
4650
+ },
4651
+ save(key, value) {
4652
+ if (writeThrough) {
4653
+ for (const tier of tiers) {
4654
+ if (tier.save) tier.save(key, value);
4655
+ }
4656
+ } else if (tiers[0]?.save) {
4657
+ tiers[0].save(key, value);
4658
+ }
4659
+ const existing = entries.get(key);
4660
+ if (existing) {
4661
+ existing.down([[DATA, value]]);
4662
+ policy?.touch(key);
4663
+ } else {
4664
+ if (policy && maxSize > 0 && policy.size() >= maxSize) {
4665
+ evictIfNeeded();
4666
+ }
4667
+ const nd = state(value);
4668
+ entries.set(key, nd);
4669
+ if (policy) {
4670
+ policy.insert(key);
4671
+ }
4672
+ }
4673
+ },
4674
+ invalidate(key) {
4675
+ const existing = entries.get(key);
4676
+ if (existing) {
4677
+ cascade(key, existing);
4678
+ }
4679
+ },
4680
+ delete(key) {
4681
+ policy?.delete(key);
4682
+ const nd = entries.get(key);
4683
+ if (nd) nd.down([[TEARDOWN]]);
4684
+ entries.delete(key);
4685
+ for (const tier of tiers) {
4686
+ if (tier.clear) tier.clear(key);
4687
+ }
4688
+ },
4689
+ has(key) {
4690
+ return entries.has(key);
4691
+ },
4692
+ get size() {
4693
+ return entries.size;
4694
+ }
4695
+ };
4696
+ }
4697
+ function adapterToTier(adapter) {
4698
+ return {
4699
+ load: (key) => adapter.load(key),
4700
+ save: (key, value) => adapter.save(key, value),
4701
+ clear: (key) => adapter.clear(key)
4702
+ };
4703
+ }
4704
+ function tieredStorage(adapters, opts) {
4705
+ const inner = cascadingCache(adapters.map(adapterToTier), {
4706
+ maxSize: opts?.maxSize,
4707
+ eviction: opts?.eviction,
4708
+ writeThrough: true
4709
+ });
4710
+ return {
4711
+ load: (key) => inner.load(key),
4712
+ save: (key, value) => inner.save(key, value),
4713
+ invalidate: (key) => inner.invalidate(key),
4714
+ delete: (key) => inner.delete(key),
4715
+ has: (key) => inner.has(key),
4716
+ get size() {
4717
+ return inner.size;
4718
+ },
4719
+ cache: inner
4720
+ };
4721
+ }
4722
+
3969
4723
  // src/extra/checkpoint.ts
3970
4724
  var import_node_crypto2 = require("crypto");
3971
4725
  var import_node_fs2 = require("fs");
@@ -3986,60 +4740,61 @@ function sortJsonValue(value) {
3986
4740
  }
3987
4741
  return out;
3988
4742
  }
3989
- function warnNonJsonValues(data) {
3990
- for (const [path, node2] of Object.entries(data.nodes)) {
3991
- const v = node2.value;
3992
- if (v === void 0 || v === null) continue;
3993
- if (typeof v === "function" || typeof v === "symbol" || typeof v === "bigint") {
3994
- console.warn(
3995
- `checkpoint: node "${path}" has non-JSON-serializable value (${typeof v}); it will be lost on round-trip`
3996
- );
3997
- }
3998
- }
3999
- }
4000
- function stableSnapshotJson(data) {
4001
- warnNonJsonValues(data);
4743
+ function stableJsonString(data) {
4002
4744
  return `${JSON.stringify(sortJsonValue(data), void 0, 0)}
4003
4745
  `;
4004
4746
  }
4005
4747
  var MemoryCheckpointAdapter = class {
4006
- #data = null;
4007
- save(data) {
4008
- this.#data = JSON.parse(JSON.stringify(data));
4748
+ #data = /* @__PURE__ */ new Map();
4749
+ save(key, data) {
4750
+ this.#data.set(key, JSON.parse(JSON.stringify(data)));
4751
+ }
4752
+ load(key) {
4753
+ const v = this.#data.get(key);
4754
+ return v === void 0 ? null : JSON.parse(JSON.stringify(v));
4009
4755
  }
4010
- load() {
4011
- return this.#data === null ? null : JSON.parse(JSON.stringify(this.#data));
4756
+ clear(key) {
4757
+ this.#data.delete(key);
4012
4758
  }
4013
4759
  };
4014
4760
  var DictCheckpointAdapter = class {
4015
4761
  #storage;
4016
- #key;
4017
- constructor(storage, key = "graphrefly_checkpoint") {
4762
+ constructor(storage) {
4018
4763
  this.#storage = storage;
4019
- this.#key = key;
4020
4764
  }
4021
- save(data) {
4022
- this.#storage[this.#key] = JSON.parse(JSON.stringify(data));
4765
+ save(key, data) {
4766
+ this.#storage[key] = JSON.parse(JSON.stringify(data));
4023
4767
  }
4024
- load() {
4025
- const raw = this.#storage[this.#key];
4026
- return raw !== null && typeof raw === "object" && !Array.isArray(raw) ? JSON.parse(JSON.stringify(raw)) : null;
4768
+ load(key) {
4769
+ const raw = this.#storage[key];
4770
+ return raw === void 0 ? null : JSON.parse(JSON.stringify(raw));
4771
+ }
4772
+ clear(key) {
4773
+ delete this.#storage[key];
4027
4774
  }
4028
4775
  };
4029
4776
  var FileCheckpointAdapter = class {
4030
- #path;
4031
- constructor(path) {
4032
- this.#path = path;
4033
- }
4034
- save(data) {
4035
- const dir = (0, import_node_path2.dirname)(this.#path);
4036
- (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
4037
- const payload = stableSnapshotJson(data);
4038
- const base = (0, import_node_path2.basename)(this.#path);
4777
+ #dir;
4778
+ constructor(dir) {
4779
+ this.#dir = dir;
4780
+ }
4781
+ #pathFor(key) {
4782
+ const safeName = key.replace(
4783
+ /[^a-zA-Z0-9_-]/g,
4784
+ (c) => `%${c.charCodeAt(0).toString(16).padStart(2, "0")}`
4785
+ );
4786
+ return (0, import_node_path2.join)(this.#dir, `${safeName}.json`);
4787
+ }
4788
+ save(key, data) {
4789
+ (0, import_node_fs2.mkdirSync)(this.#dir, { recursive: true });
4790
+ const filePath = this.#pathFor(key);
4791
+ const payload = stableJsonString(data);
4792
+ const base = (0, import_node_path2.basename)(filePath);
4793
+ const dir = (0, import_node_path2.dirname)(filePath);
4039
4794
  const tmp = (0, import_node_path2.join)(dir, `.${base}.${(0, import_node_crypto2.randomBytes)(8).toString("hex")}.tmp`);
4040
4795
  try {
4041
4796
  (0, import_node_fs2.writeFileSync)(tmp, payload, "utf8");
4042
- (0, import_node_fs2.renameSync)(tmp, this.#path);
4797
+ (0, import_node_fs2.renameSync)(tmp, filePath);
4043
4798
  } catch (e) {
4044
4799
  try {
4045
4800
  (0, import_node_fs2.unlinkSync)(tmp);
@@ -4048,36 +4803,42 @@ var FileCheckpointAdapter = class {
4048
4803
  throw e;
4049
4804
  }
4050
4805
  }
4051
- load() {
4806
+ load(key) {
4052
4807
  try {
4053
- const text = (0, import_node_fs2.readFileSync)(this.#path, "utf8").trim();
4808
+ const text = (0, import_node_fs2.readFileSync)(this.#pathFor(key), "utf8").trim();
4054
4809
  if (!text) return null;
4055
- const data = JSON.parse(text);
4056
- return data !== null && typeof data === "object" && !Array.isArray(data) ? data : null;
4810
+ return JSON.parse(text);
4057
4811
  } catch {
4058
4812
  return null;
4059
4813
  }
4060
4814
  }
4815
+ clear(key) {
4816
+ try {
4817
+ (0, import_node_fs2.unlinkSync)(this.#pathFor(key));
4818
+ } catch (e) {
4819
+ if (e.code !== "ENOENT") throw e;
4820
+ }
4821
+ }
4061
4822
  };
4062
4823
  var SqliteCheckpointAdapter = class {
4063
4824
  #db;
4064
- #key;
4065
- constructor(path, key = "graphrefly_checkpoint") {
4825
+ constructor(path) {
4066
4826
  this.#db = new import_node_sqlite.DatabaseSync(path);
4067
- this.#key = key;
4068
4827
  this.#db.exec(
4069
4828
  `CREATE TABLE IF NOT EXISTS graphrefly_checkpoint (k TEXT PRIMARY KEY, v TEXT NOT NULL)`
4070
4829
  );
4071
4830
  }
4072
- save(data) {
4073
- const payload = stableSnapshotJson(data).trimEnd();
4074
- this.#db.prepare(`INSERT OR REPLACE INTO graphrefly_checkpoint (k, v) VALUES (?, ?)`).run(this.#key, payload);
4831
+ save(key, data) {
4832
+ const payload = stableJsonString(data).trimEnd();
4833
+ this.#db.prepare(`INSERT OR REPLACE INTO graphrefly_checkpoint (k, v) VALUES (?, ?)`).run(key, payload);
4075
4834
  }
4076
- load() {
4077
- const row = this.#db.prepare(`SELECT v FROM graphrefly_checkpoint WHERE k = ?`).get(this.#key);
4835
+ load(key) {
4836
+ const row = this.#db.prepare(`SELECT v FROM graphrefly_checkpoint WHERE k = ?`).get(key);
4078
4837
  if (row === void 0 || typeof row.v !== "string" || row.v.trim() === "") return null;
4079
- const parsed = JSON.parse(row.v);
4080
- return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
4838
+ return JSON.parse(row.v);
4839
+ }
4840
+ clear(key) {
4841
+ this.#db.prepare(`DELETE FROM graphrefly_checkpoint WHERE k = ?`).run(key);
4081
4842
  }
4082
4843
  /** Close the underlying SQLite connection (safe to call more than once). */
4083
4844
  close() {
@@ -4088,10 +4849,10 @@ var SqliteCheckpointAdapter = class {
4088
4849
  }
4089
4850
  };
4090
4851
  function saveGraphCheckpoint(graph, adapter) {
4091
- adapter.save(graph.snapshot());
4852
+ adapter.save(graph.name, graph.snapshot());
4092
4853
  }
4093
4854
  function restoreGraphCheckpoint(graph, adapter) {
4094
- const data = adapter.load();
4855
+ const data = adapter.load(graph.name);
4095
4856
  if (data === null) return false;
4096
4857
  graph.restore(data);
4097
4858
  return true;
@@ -5956,48 +6717,6 @@ function audit(source, ms, opts) {
5956
6717
  }
5957
6718
  });
5958
6719
  }
5959
- function timeout(source, ms, opts) {
5960
- const { with: withPayload, ...timeoutNodeOpts } = opts ?? {};
5961
- let timer;
5962
- const err = withPayload ?? new Error("timeout");
5963
- function arm(a) {
5964
- clearTimeout(timer);
5965
- timer = setTimeout(() => {
5966
- timer = void 0;
5967
- a.down([[ERROR, err]]);
5968
- }, ms);
5969
- }
5970
- return node(
5971
- [source],
5972
- ([_v], a) => {
5973
- arm(a);
5974
- return () => clearTimeout(timer);
5975
- },
5976
- {
5977
- ...operatorOpts3(timeoutNodeOpts),
5978
- completeWhenDepsComplete: false,
5979
- onMessage(msg, _i, a) {
5980
- const t = msg[0];
5981
- if (t === DATA) {
5982
- arm(a);
5983
- a.down([msg]);
5984
- return true;
5985
- }
5986
- if (t === COMPLETE || t === ERROR) {
5987
- clearTimeout(timer);
5988
- a.down([msg]);
5989
- return true;
5990
- }
5991
- if (t === DIRTY || t === RESOLVED) {
5992
- a.down([msg]);
5993
- return true;
5994
- }
5995
- a.down([msg]);
5996
- return true;
5997
- }
5998
- }
5999
- );
6000
- }
6001
6720
  function buffer(source, notifier, opts) {
6002
6721
  const buf = [];
6003
6722
  return node([source, notifier], () => void 0, {
@@ -7554,11 +8273,14 @@ function workerSelf(target, opts) {
7554
8273
  NS_PER_MS,
7555
8274
  NS_PER_SEC,
7556
8275
  SqliteCheckpointAdapter,
8276
+ TimeoutError,
7557
8277
  audit,
7558
8278
  buffer,
7559
8279
  bufferCount,
7560
8280
  bufferTime,
8281
+ cache,
7561
8282
  cached,
8283
+ cascadingCache,
7562
8284
  catchError,
7563
8285
  checkpointNodeValue,
7564
8286
  checkpointToRedis,
@@ -7583,6 +8305,7 @@ function workerSelf(target, opts) {
7583
8305
  escapeRegexChar,
7584
8306
  exhaustMap,
7585
8307
  exponential,
8308
+ fallback,
7586
8309
  fibonacci,
7587
8310
  filter,
7588
8311
  find,
@@ -7595,6 +8318,7 @@ function workerSelf(target, opts) {
7595
8318
  fromCSV,
7596
8319
  fromClickHouseWatch,
7597
8320
  fromCron,
8321
+ fromDrizzle,
7598
8322
  fromEvent,
7599
8323
  fromFSWatch,
7600
8324
  fromGitHook,
@@ -7603,15 +8327,18 @@ function workerSelf(target, opts) {
7603
8327
  fromIDBTransaction,
7604
8328
  fromIter,
7605
8329
  fromKafka,
8330
+ fromKysely,
7606
8331
  fromMCP,
7607
8332
  fromNATS,
7608
8333
  fromNDJSON,
7609
8334
  fromOTel,
8335
+ fromPrisma,
7610
8336
  fromPrometheus,
7611
8337
  fromPromise,
7612
8338
  fromPulsar,
7613
8339
  fromRabbitMQ,
7614
8340
  fromRedisStream,
8341
+ fromSqlite,
7615
8342
  fromStatsD,
7616
8343
  fromSyslog,
7617
8344
  fromTimer,
@@ -7623,6 +8350,7 @@ function workerSelf(target, opts) {
7623
8350
  last,
7624
8351
  linear,
7625
8352
  logSlice,
8353
+ lru,
7626
8354
  map,
7627
8355
  matchesAnyPattern,
7628
8356
  matchesCron,
@@ -7672,6 +8400,7 @@ function workerSelf(target, opts) {
7672
8400
  throttle,
7673
8401
  throttleTime,
7674
8402
  throwError,
8403
+ tieredStorage,
7675
8404
  timeout,
7676
8405
  toArray,
7677
8406
  toCSV,
@@ -7689,6 +8418,7 @@ function workerSelf(target, opts) {
7689
8418
  toRedisStream,
7690
8419
  toS3,
7691
8420
  toSSE,
8421
+ toSqlite,
7692
8422
  toTempo,
7693
8423
  toWebSocket,
7694
8424
  tokenBucket,