@graphrefly/graphrefly 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/{chunk-RHI3GHZW.js → chunk-263BEJJO.js} +3 -3
  2. package/dist/{chunk-44HD4BTA.js → chunk-2GQLMQVJ.js} +3 -3
  3. package/dist/chunk-32N5A454.js +36 -0
  4. package/dist/chunk-32N5A454.js.map +1 -0
  5. package/dist/{chunk-IR3KMOLX.js → chunk-CWYPA63G.js} +3 -383
  6. package/dist/chunk-CWYPA63G.js.map +1 -0
  7. package/dist/{chunk-TH6COGOP.js → chunk-HVBX5KIW.js} +2 -2
  8. package/dist/chunk-JFONSPNF.js +391 -0
  9. package/dist/chunk-JFONSPNF.js.map +1 -0
  10. package/dist/{chunk-QA3RP5NH.js → chunk-NZMBRXQV.js} +101 -5
  11. package/dist/chunk-NZMBRXQV.js.map +1 -0
  12. package/dist/{chunk-MQBQOFDS.js → chunk-PNUZM7PC.js} +12 -31
  13. package/dist/chunk-PNUZM7PC.js.map +1 -0
  14. package/dist/{chunk-EQUZ5NLD.js → chunk-PX6PDUJ5.js} +11 -16
  15. package/dist/chunk-PX6PDUJ5.js.map +1 -0
  16. package/dist/{chunk-NXC35KC5.js → chunk-XRFJJ2IU.js} +3 -3
  17. package/dist/{chunk-BLD3IFYF.js → chunk-XTLYW4FR.js} +9 -7
  18. package/dist/{chunk-BLD3IFYF.js.map → chunk-XTLYW4FR.js.map} +1 -1
  19. package/dist/compat/nestjs/index.cjs +100 -4
  20. package/dist/compat/nestjs/index.cjs.map +1 -1
  21. package/dist/compat/nestjs/index.d.cts +6 -6
  22. package/dist/compat/nestjs/index.d.ts +6 -6
  23. package/dist/compat/nestjs/index.js +9 -7
  24. package/dist/core/index.cjs +100 -4
  25. package/dist/core/index.cjs.map +1 -1
  26. package/dist/core/index.d.cts +3 -3
  27. package/dist/core/index.d.ts +3 -3
  28. package/dist/core/index.js +3 -3
  29. package/dist/extra/index.cjs +100 -4
  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 +9 -7
  34. package/dist/graph/index.cjs +100 -4
  35. package/dist/graph/index.cjs.map +1 -1
  36. package/dist/graph/index.d.cts +5 -5
  37. package/dist/graph/index.d.ts +5 -5
  38. package/dist/graph/index.js +4 -4
  39. package/dist/{graph-ab1yPwIB.d.cts → graph-BtdSRHUc.d.cts} +3 -3
  40. package/dist/{graph-DFr0diXB.d.ts → graph-CEO2FkLY.d.ts} +3 -3
  41. package/dist/{index-BvWfZCTt.d.cts → index-B0tfuXwV.d.cts} +3 -3
  42. package/dist/{index-Dy04P4W3.d.cts → index-BFGjXbiP.d.cts} +2 -2
  43. package/dist/{index-DrJq9B1T.d.cts → index-BPlWVAKY.d.cts} +3 -3
  44. package/dist/{index-C9z6rU9P.d.cts → index-BUj3ASVe.d.cts} +25 -7
  45. package/dist/{index-DLE1Sp-L.d.cts → index-C59uSJAH.d.cts} +2 -2
  46. package/dist/{index-DsGxLfwL.d.ts → index-CkElcUY6.d.ts} +2 -2
  47. package/dist/{index-HdJx_BjO.d.ts → index-DSPc5rkv.d.ts} +25 -7
  48. package/dist/{index-D36MAQ3f.d.ts → index-DgscL7v0.d.ts} +3 -3
  49. package/dist/{index-BbYZma8G.d.ts → index-RXN94sHK.d.ts} +3 -3
  50. package/dist/{index-BHm3Ba5q.d.ts → index-jEtF4N7L.d.ts} +2 -2
  51. package/dist/index.cjs +109 -14
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.cts +15 -15
  54. package/dist/index.d.ts +15 -15
  55. package/dist/index.js +26 -22
  56. package/dist/index.js.map +1 -1
  57. package/dist/{meta-n3FoVWML.d.ts → meta-3QjzotRv.d.ts} +1 -1
  58. package/dist/{meta--fr9sxRM.d.cts → meta-B-Lbs4-O.d.cts} +1 -1
  59. package/dist/{node-C5UD5MGq.d.cts → node-C7PD3sn9.d.cts} +42 -0
  60. package/dist/{node-C5UD5MGq.d.ts → node-C7PD3sn9.d.ts} +42 -0
  61. package/dist/{observable-CQRBtEbq.d.ts → observable-EyO-moQY.d.ts} +1 -1
  62. package/dist/{observable-DWydVy5b.d.cts → observable-axpzv1K2.d.cts} +1 -1
  63. package/dist/patterns/reactive-layout/index.cjs +214 -117
  64. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  65. package/dist/patterns/reactive-layout/index.d.cts +5 -5
  66. package/dist/patterns/reactive-layout/index.d.ts +5 -5
  67. package/dist/patterns/reactive-layout/index.js +6 -4
  68. package/dist/{storage-C9fZfMfM.d.ts → storage-CHT5WE9m.d.ts} +1 -1
  69. package/dist/{storage-Bew05Xy6.d.cts → storage-DIgAr7M_.d.cts} +1 -1
  70. package/package.json +2 -1
  71. package/dist/chunk-EQUZ5NLD.js.map +0 -1
  72. package/dist/chunk-IR3KMOLX.js.map +0 -1
  73. package/dist/chunk-MQBQOFDS.js.map +0 -1
  74. package/dist/chunk-QA3RP5NH.js.map +0 -1
  75. /package/dist/{chunk-RHI3GHZW.js.map → chunk-263BEJJO.js.map} +0 -0
  76. /package/dist/{chunk-44HD4BTA.js.map → chunk-2GQLMQVJ.js.map} +0 -0
  77. /package/dist/{chunk-TH6COGOP.js.map → chunk-HVBX5KIW.js.map} +0 -0
  78. /package/dist/{chunk-NXC35KC5.js.map → chunk-XRFJJ2IU.js.map} +0 -0
@@ -390,9 +390,20 @@ var flushInProgress = false;
390
390
  var drainPhase2 = [];
391
391
  var drainPhase3 = [];
392
392
  var drainPhase4 = [];
393
+ var flushHooks = [];
393
394
  function isBatching() {
394
395
  return batchDepth > 0 || flushInProgress;
395
396
  }
397
+ function isExplicitlyBatching() {
398
+ return batchDepth > 0;
399
+ }
400
+ function registerBatchFlushHook(hook) {
401
+ if (batchDepth > 0) {
402
+ flushHooks.push(hook);
403
+ } else {
404
+ hook();
405
+ }
406
+ }
396
407
  function batch(fn) {
397
408
  batchDepth += 1;
398
409
  let threw = false;
@@ -406,6 +417,13 @@ function batch(fn) {
406
417
  if (batchDepth === 0) {
407
418
  if (threw) {
408
419
  if (!flushInProgress) {
420
+ const hooks = flushHooks.splice(0);
421
+ for (const h of hooks) {
422
+ try {
423
+ h();
424
+ } catch {
425
+ }
426
+ }
409
427
  drainPhase2.length = 0;
410
428
  drainPhase3.length = 0;
411
429
  drainPhase4.length = 0;
@@ -422,7 +440,18 @@ function drainPending() {
422
440
  const errors = [];
423
441
  let iterations = 0;
424
442
  try {
425
- while (drainPhase2.length > 0 || drainPhase3.length > 0 || drainPhase4.length > 0) {
443
+ while (drainPhase2.length > 0 || drainPhase3.length > 0 || drainPhase4.length > 0 || ownsFlush && flushHooks.length > 0) {
444
+ if (ownsFlush && flushHooks.length > 0) {
445
+ const hooks = flushHooks.splice(0);
446
+ for (const h of hooks) {
447
+ try {
448
+ h();
449
+ } catch (e) {
450
+ errors.push(e);
451
+ }
452
+ }
453
+ continue;
454
+ }
426
455
  iterations += 1;
427
456
  if (iterations > MAX_DRAIN_ITERATIONS) {
428
457
  drainPhase2.length = 0;
@@ -1071,6 +1100,22 @@ var NodeImpl = class _NodeImpl {
1071
1100
  * treats `0` as "wave settled" — O(1) check for full dep settlement.
1072
1101
  */
1073
1102
  _dirtyDepCount = 0;
1103
+ // --- Per-batch emit accumulator (Bug 2: K+1 fan-in fix) ---
1104
+ /**
1105
+ * Inside an explicit `batch(() => ...)` scope, every `_emit` accumulates
1106
+ * its already-framed messages here instead of dispatching synchronously.
1107
+ * At batch end, `_flushBatchPending` runs (registered via
1108
+ * `registerBatchFlushHook`) and delivers the whole accumulated batch as
1109
+ * one `downWithBatch` call — collapsing what would otherwise be K
1110
+ * separate sink invocations into one. This is the fix for the diamond
1111
+ * fan-in K+1 over-fire.
1112
+ *
1113
+ * `null` outside batch (or after flush). Only ever appended to within
1114
+ * a single explicit batch lifetime; reset to `null` on flush. State
1115
+ * updates (cache, version, status) still happen per-emit via
1116
+ * `_updateState` — only the downstream delivery is coalesced.
1117
+ */
1118
+ _batchPendingMessages = null;
1074
1119
  // --- PAUSE/RESUME lock tracking (C0) ---
1075
1120
  /**
1076
1121
  * Set of active pause locks held against this node. Every `[PAUSE, lockId]`
@@ -1448,7 +1493,10 @@ var NodeImpl = class _NodeImpl {
1448
1493
  dep.unsub = noopUnsub;
1449
1494
  dep.unsub = dep.node.subscribe((msgs) => {
1450
1495
  if (dep.unsub === null) return;
1496
+ const tierOf = this._config.tierOf;
1497
+ let sawSettlement = false;
1451
1498
  for (const m of msgs) {
1499
+ if (tierOf(m[0]) >= 3) sawSettlement = true;
1452
1500
  this._config.onMessage(
1453
1501
  this,
1454
1502
  m,
@@ -1456,6 +1504,7 @@ var NodeImpl = class _NodeImpl {
1456
1504
  this._actions
1457
1505
  );
1458
1506
  }
1507
+ if (sawSettlement) this._maybeRunFnOnSettlement();
1459
1508
  });
1460
1509
  subscribedCount++;
1461
1510
  }
@@ -1510,7 +1559,10 @@ var NodeImpl = class _NodeImpl {
1510
1559
  try {
1511
1560
  record.unsub = depNode.subscribe((msgs) => {
1512
1561
  if (record.unsub === null) return;
1562
+ const tierOf = this._config.tierOf;
1563
+ let sawSettlement = false;
1513
1564
  for (const m of msgs) {
1565
+ if (tierOf(m[0]) >= 3) sawSettlement = true;
1514
1566
  this._config.onMessage(
1515
1567
  this,
1516
1568
  m,
@@ -1518,6 +1570,7 @@ var NodeImpl = class _NodeImpl {
1518
1570
  this._actions
1519
1571
  );
1520
1572
  }
1573
+ if (sawSettlement) this._maybeRunFnOnSettlement();
1521
1574
  });
1522
1575
  } catch (err) {
1523
1576
  record.unsub = null;
@@ -1639,7 +1692,6 @@ var NodeImpl = class _NodeImpl {
1639
1692
  }
1640
1693
  return;
1641
1694
  }
1642
- this._maybeRunFnOnSettlement();
1643
1695
  }
1644
1696
  // --- Centralized dep-state transitions (A3 settlement counters) ---
1645
1697
  //
@@ -2011,10 +2063,10 @@ var NodeImpl = class _NodeImpl {
2011
2063
  }
2012
2064
  }
2013
2065
  if (immediate.length > 0) {
2014
- downWithBatch(this._deliverToSinks, immediate, tierOf);
2066
+ this._dispatchOrAccumulate(immediate);
2015
2067
  }
2016
2068
  } else {
2017
- downWithBatch(this._deliverToSinks, finalMessages, this._config.tierOf);
2069
+ this._dispatchOrAccumulate(finalMessages);
2018
2070
  }
2019
2071
  }
2020
2072
  if (equalsError != null) {
@@ -2137,6 +2189,50 @@ var NodeImpl = class _NodeImpl {
2137
2189
  const snapshot = [...this._sinks];
2138
2190
  for (const sink of snapshot) sink(messages);
2139
2191
  };
2192
+ /**
2193
+ * @internal Dispatch entry point that respects the per-batch emit
2194
+ * accumulator (Bug 2). Inside an explicit `batch()` scope, append to
2195
+ * `_batchPendingMessages` and register a flush hook on first append.
2196
+ * Outside batch — or during a drain (where `flushInProgress` is true
2197
+ * but `batchDepth` is 0) — dispatch synchronously through `downWithBatch`.
2198
+ *
2199
+ * Per-emit state updates (`_frameBatch`, `_updateState`) have already
2200
+ * happened by the time we reach here; only the **downstream delivery**
2201
+ * is coalesced. Cache, version, and status are visible mid-batch on
2202
+ * the emitting node itself.
2203
+ */
2204
+ _dispatchOrAccumulate(messages) {
2205
+ if (isExplicitlyBatching()) {
2206
+ if (this._batchPendingMessages === null) {
2207
+ this._batchPendingMessages = [];
2208
+ registerBatchFlushHook(() => this._flushBatchPending());
2209
+ }
2210
+ for (const m of messages) this._batchPendingMessages.push(m);
2211
+ return;
2212
+ }
2213
+ downWithBatch(this._deliverToSinks, messages, this._config.tierOf);
2214
+ }
2215
+ /**
2216
+ * @internal Flushes the accumulated batch through `downWithBatch` and
2217
+ * clears the pending state. Idempotent — safe to call when pending is
2218
+ * already null or empty (e.g. on a `batch()` throw, where the hook
2219
+ * fires for cleanup but the drainPhase queues are wiped after).
2220
+ *
2221
+ * Critical: the accumulated batch is interleaved per-emit framings like
2222
+ * `[DIRTY, DATA(1), DIRTY, DATA(2)]` — non-monotone tier order. We must
2223
+ * re-frame to sort by tier before handing to `downWithBatch`, which
2224
+ * assumes pre-sorted input. `_frameBatch` also handles the synthetic
2225
+ * DIRTY prepend rule (no-op here — `hasDirty` is true since each
2226
+ * accumulated emit already carries its own DIRTY prefix).
2227
+ */
2228
+ _flushBatchPending() {
2229
+ const pending = this._batchPendingMessages;
2230
+ if (pending === null) return;
2231
+ this._batchPendingMessages = null;
2232
+ if (pending.length === 0) return;
2233
+ const framed = this._frameBatch(pending);
2234
+ downWithBatch(this._deliverToSinks, framed, this._config.tierOf);
2235
+ }
2140
2236
  };
2141
2237
  var isNodeArray = (value) => Array.isArray(value);
2142
2238
  var isNodeOptionsObject = (value) => typeof value === "object" && value != null && !Array.isArray(value);