@graphrefly/graphrefly 0.22.0 → 0.24.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-QA3RP5NH.js → chunk-5DJTTKX3.js} +111 -17
  2. package/dist/chunk-5DJTTKX3.js.map +1 -0
  3. package/dist/{chunk-BLD3IFYF.js → chunk-5WGT55R4.js} +9 -7
  4. package/dist/{chunk-BLD3IFYF.js.map → chunk-5WGT55R4.js.map} +1 -1
  5. package/dist/{chunk-IR3KMOLX.js → chunk-AOCBDH4T.js} +3 -383
  6. package/dist/chunk-AOCBDH4T.js.map +1 -0
  7. package/dist/{chunk-TH6COGOP.js → chunk-H4RVA4VE.js} +2 -2
  8. package/dist/chunk-HWPIFSW2.js +36 -0
  9. package/dist/chunk-HWPIFSW2.js.map +1 -0
  10. package/dist/{chunk-MQBQOFDS.js → chunk-IPLKX3L2.js} +12 -31
  11. package/dist/chunk-IPLKX3L2.js.map +1 -0
  12. package/dist/{chunk-44HD4BTA.js → chunk-MW4VAKAO.js} +3 -3
  13. package/dist/chunk-PY4XCDLR.js +391 -0
  14. package/dist/chunk-PY4XCDLR.js.map +1 -0
  15. package/dist/{chunk-RHI3GHZW.js → chunk-QOWVNWOC.js} +3 -3
  16. package/dist/{chunk-EQUZ5NLD.js → chunk-TDEXAMGO.js} +11 -16
  17. package/dist/chunk-TDEXAMGO.js.map +1 -0
  18. package/dist/{chunk-NXC35KC5.js → chunk-XOFWRC73.js} +3 -3
  19. package/dist/compat/nestjs/index.cjs +110 -16
  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 +110 -16
  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 +110 -16
  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 +110 -16
  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-DFr0diXB.d.ts → graph-B6NFqv3z.d.ts} +3 -3
  40. package/dist/{graph-ab1yPwIB.d.cts → graph-D-3JIQme.d.cts} +3 -3
  41. package/dist/{index-BvWfZCTt.d.cts → index-1z8vRTCt.d.cts} +3 -3
  42. package/dist/{index-Dy04P4W3.d.cts → index-AMWewNDe.d.cts} +2 -2
  43. package/dist/{index-C9z6rU9P.d.cts → index-BJB7t9gg.d.cts} +19 -15
  44. package/dist/{index-BbYZma8G.d.ts → index-BysCTzJz.d.ts} +3 -3
  45. package/dist/{index-HdJx_BjO.d.ts → index-C-TXEa7C.d.ts} +19 -15
  46. package/dist/{index-DsGxLfwL.d.ts → index-CYkjxu3s.d.ts} +2 -2
  47. package/dist/{index-BHm3Ba5q.d.ts → index-D7XgsUt7.d.ts} +2 -2
  48. package/dist/{index-D36MAQ3f.d.ts → index-DiobMNwE.d.ts} +3 -3
  49. package/dist/{index-DrJq9B1T.d.cts → index-J7Kc0oIQ.d.cts} +3 -3
  50. package/dist/{index-DLE1Sp-L.d.cts → index-b5BYtczN.d.cts} +2 -2
  51. package/dist/index.cjs +129 -46
  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 +36 -42
  56. package/dist/index.js.map +1 -1
  57. package/dist/{meta-n3FoVWML.d.ts → meta-CnkLA_43.d.ts} +1 -1
  58. package/dist/{meta--fr9sxRM.d.cts → meta-DWbkoq1s.d.cts} +1 -1
  59. package/dist/{node-C5UD5MGq.d.cts → node-B-f-Lu-k.d.cts} +57 -13
  60. package/dist/{node-C5UD5MGq.d.ts → node-B-f-Lu-k.d.ts} +57 -13
  61. package/dist/{observable-DWydVy5b.d.cts → observable-DBnrwcar.d.cts} +1 -1
  62. package/dist/{observable-CQRBtEbq.d.ts → observable-uP-wy_uK.d.ts} +1 -1
  63. package/dist/patterns/reactive-layout/index.cjs +224 -129
  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-Bew05Xy6.d.cts → storage-BuTdpCI1.d.cts} +1 -1
  69. package/dist/{storage-C9fZfMfM.d.ts → storage-F2X1U1x0.d.ts} +1 -1
  70. package/package.json +3 -2
  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-TH6COGOP.js.map → chunk-H4RVA4VE.js.map} +0 -0
  76. /package/dist/{chunk-44HD4BTA.js.map → chunk-MW4VAKAO.js.map} +0 -0
  77. /package/dist/{chunk-RHI3GHZW.js.map → chunk-QOWVNWOC.js.map} +0 -0
  78. /package/dist/{chunk-NXC35KC5.js.map → chunk-XOFWRC73.js.map} +0 -0
@@ -1,5 +1,5 @@
1
- export { E as ENVELOPE_VERSION, a as EvictedSubgraphInfo, b as EvictionPolicy, G as GraphCodec, J as JsonCodec, L as LazyGraphCodec, O as SIZEOF_OVERHEAD, S as SIZEOF_SYMBOL, W as WALEntry, c as createDagCborCodec, d as createDagCborZstdCodec, e as decodeEnvelope, f as encodeEnvelope, r as registerBuiltinCodecs, g as replayWAL, s as sizeof } from '../index-Dy04P4W3.cjs';
2
- export { D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, g as GraphCheckpointRecord, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, r as GraphPersistSnapshot, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from '../graph-ab1yPwIB.cjs';
3
- import '../node-C5UD5MGq.cjs';
4
- import '../meta--fr9sxRM.cjs';
5
- import '../storage-Bew05Xy6.cjs';
1
+ export { E as ENVELOPE_VERSION, a as EvictedSubgraphInfo, b as EvictionPolicy, G as GraphCodec, J as JsonCodec, L as LazyGraphCodec, O as SIZEOF_OVERHEAD, S as SIZEOF_SYMBOL, W as WALEntry, c as createDagCborCodec, d as createDagCborZstdCodec, e as decodeEnvelope, f as encodeEnvelope, r as registerBuiltinCodecs, g as replayWAL, s as sizeof } from '../index-AMWewNDe.cjs';
2
+ export { D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, g as GraphCheckpointRecord, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, r as GraphPersistSnapshot, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from '../graph-D-3JIQme.cjs';
3
+ import '../node-B-f-Lu-k.cjs';
4
+ import '../meta-DWbkoq1s.cjs';
5
+ import '../storage-BuTdpCI1.cjs';
@@ -1,5 +1,5 @@
1
- export { E as ENVELOPE_VERSION, a as EvictedSubgraphInfo, b as EvictionPolicy, G as GraphCodec, J as JsonCodec, L as LazyGraphCodec, O as SIZEOF_OVERHEAD, S as SIZEOF_SYMBOL, W as WALEntry, c as createDagCborCodec, d as createDagCborZstdCodec, e as decodeEnvelope, f as encodeEnvelope, r as registerBuiltinCodecs, g as replayWAL, s as sizeof } from '../index-DsGxLfwL.js';
2
- export { D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, g as GraphCheckpointRecord, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, r as GraphPersistSnapshot, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from '../graph-DFr0diXB.js';
3
- import '../node-C5UD5MGq.js';
4
- import '../meta-n3FoVWML.js';
5
- import '../storage-C9fZfMfM.js';
1
+ export { E as ENVELOPE_VERSION, a as EvictedSubgraphInfo, b as EvictionPolicy, G as GraphCodec, J as JsonCodec, L as LazyGraphCodec, O as SIZEOF_OVERHEAD, S as SIZEOF_SYMBOL, W as WALEntry, c as createDagCborCodec, d as createDagCborZstdCodec, e as decodeEnvelope, f as encodeEnvelope, r as registerBuiltinCodecs, g as replayWAL, s as sizeof } from '../index-CYkjxu3s.js';
2
+ export { D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, g as GraphCheckpointRecord, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, r as GraphPersistSnapshot, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from '../graph-B6NFqv3z.js';
3
+ import '../node-B-f-Lu-k.js';
4
+ import '../meta-CnkLA_43.js';
5
+ import '../storage-F2X1U1x0.js';
@@ -1,4 +1,4 @@
1
- import "../chunk-44HD4BTA.js";
1
+ import "../chunk-MW4VAKAO.js";
2
2
  import {
3
3
  GRAPH_META_SEGMENT,
4
4
  Graph,
@@ -8,8 +8,8 @@ import {
8
8
  graphProfile,
9
9
  reachable,
10
10
  sizeof
11
- } from "../chunk-NXC35KC5.js";
12
- import "../chunk-TH6COGOP.js";
11
+ } from "../chunk-XOFWRC73.js";
12
+ import "../chunk-H4RVA4VE.js";
13
13
  import "../chunk-7TAQJHQV.js";
14
14
  import {
15
15
  ENVELOPE_VERSION,
@@ -20,7 +20,7 @@ import {
20
20
  encodeEnvelope,
21
21
  registerBuiltinCodecs,
22
22
  replayWAL
23
- } from "../chunk-QA3RP5NH.js";
23
+ } from "../chunk-5DJTTKX3.js";
24
24
  export {
25
25
  ENVELOPE_VERSION,
26
26
  GRAPH_META_SEGMENT,
@@ -1,6 +1,6 @@
1
- import { k as GraphReFlyConfig, a6 as VersioningLevel, N as Node, A as Actor, t as Messages, K as NodeSink } from './node-C5UD5MGq.js';
2
- import { b as DescribeNodeOutput, D as DescribeDetail, a as DescribeField } from './meta-n3FoVWML.js';
3
- import { a as StorageTier, S as StorageHandle } from './storage-C9fZfMfM.js';
1
+ import { k as GraphReFlyConfig, a6 as VersioningLevel, N as Node, A as Actor, t as Messages, K as NodeSink } from './node-B-f-Lu-k.js';
2
+ import { b as DescribeNodeOutput, D as DescribeDetail, a as DescribeField } from './meta-CnkLA_43.js';
3
+ import { a as StorageTier, S as StorageHandle } from './storage-F2X1U1x0.js';
4
4
 
5
5
  /**
6
6
  * Graph profiling and inspection utilities.
@@ -1,6 +1,6 @@
1
- import { k as GraphReFlyConfig, a6 as VersioningLevel, N as Node, A as Actor, t as Messages, K as NodeSink } from './node-C5UD5MGq.cjs';
2
- import { b as DescribeNodeOutput, D as DescribeDetail, a as DescribeField } from './meta--fr9sxRM.cjs';
3
- import { a as StorageTier, S as StorageHandle } from './storage-Bew05Xy6.cjs';
1
+ import { k as GraphReFlyConfig, a6 as VersioningLevel, N as Node, A as Actor, t as Messages, K as NodeSink } from './node-B-f-Lu-k.cjs';
2
+ import { b as DescribeNodeOutput, D as DescribeDetail, a as DescribeField } from './meta-DWbkoq1s.cjs';
3
+ import { a as StorageTier, S as StorageHandle } from './storage-BuTdpCI1.cjs';
4
4
 
5
5
  /**
6
6
  * Graph profiling and inspection utilities.
@@ -1,6 +1,6 @@
1
- import { a as NodeOptions, N as Node, M as Message, t as Messages, a6 as VersioningLevel } from './node-C5UD5MGq.cjs';
2
- import { a as StorageTier, I as IndexedDbStorageSpec, S as StorageHandle, d as dictStorage, f as fileStorage, b as fromIDBRequest, c as fromIDBTransaction, i as indexedDbStorage, m as memoryStorage, s as sqliteStorage } from './storage-Bew05Xy6.cjs';
3
- import { T as ToObservableOptions, t as toObservable } from './observable-DWydVy5b.cjs';
1
+ import { a as NodeOptions, N as Node, M as Message, t as Messages, a6 as VersioningLevel } from './node-B-f-Lu-k.cjs';
2
+ import { a as StorageTier, I as IndexedDbStorageSpec, S as StorageHandle, d as dictStorage, f as fileStorage, b as fromIDBRequest, c as fromIDBTransaction, i as indexedDbStorage, m as memoryStorage, s as sqliteStorage } from './storage-BuTdpCI1.cjs';
3
+ import { T as ToObservableOptions, t as toObservable } from './observable-DBnrwcar.cjs';
4
4
 
5
5
  /**
6
6
  * External-register helpers — the common `register({emit, error, complete})`
@@ -1,5 +1,5 @@
1
- import { k as GraphReFlyConfig } from './node-C5UD5MGq.cjs';
2
- import { r as GraphPersistSnapshot, g as GraphCheckpointRecord, D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from './graph-ab1yPwIB.cjs';
1
+ import { k as GraphReFlyConfig } from './node-B-f-Lu-k.cjs';
2
+ import { r as GraphPersistSnapshot, g as GraphCheckpointRecord, D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from './graph-D-3JIQme.cjs';
3
3
 
4
4
  /**
5
5
  * Approximate in-memory size estimation for arbitrary JS values.
@@ -1,13 +1,21 @@
1
- import { t as Messages, a as NodeOptions, F as FnCtx, N as Node, b as NodeActions, x as NodeFnCleanup, A as Actor, C as COMPLETE, c as COMPLETE_MSG, d as COMPLETE_ONLY_BATCH, D as DATA, e as DEFAULT_ACTOR, f as DIRTY, g as DIRTY_MSG, h as DIRTY_ONLY_BATCH, i as DepRecord, E as ERROR, G as GlobalInspectorEvent, j as GlobalInspectorHook, k as GraphReFlyConfig, l as GuardAction, m as GuardDenied, n as GuardDeniedDetails, H as HashFn, I as INVALIDATE, o as INVALIDATE_MSG, p as INVALIDATE_ONLY_BATCH, M as Message, q as MessageContext, r as MessageTypeRegistration, s as MessageTypeRegistrationInput, u as NodeCtx, v as NodeDescribeKind, w as NodeFn, y as NodeGuard, z as NodeImpl, B as NodeInspectorHook, J as NodeInspectorHookEvent, K as NodeSink, L as NodeStatus, O as NodeTransportOptions, P as NodeVersionInfo, Q as OnMessageHandler, R as OnSubscribeHandler, S as PAUSE, T as PolicyAllow, U as PolicyDeny, V as PolicyRuleData, W as RESOLVED, X as RESOLVED_MSG, Y as RESOLVED_ONLY_BATCH, Z as RESUME, _ as START, $ as START_MSG, a0 as SubscribeContext, a1 as TEARDOWN, a2 as TEARDOWN_MSG, a3 as TEARDOWN_ONLY_BATCH, a4 as V0, a5 as V1, a6 as VersioningLevel, a7 as VersioningOptions, a8 as accessHintForGuard, a9 as advanceVersion, aa as configure, ab as createVersioning, ac as defaultConfig, ad as defaultHash, ae as isV1, af as node, ag as normalizeActor, ah as policy, ai as policyFromRules, aj as registerBuiltins } from './node-C5UD5MGq.cjs';
2
- import { D as DescribeDetail, a as DescribeField, b as DescribeNodeOutput, r as resolveDescribeFields } from './meta--fr9sxRM.cjs';
1
+ import { t as Messages, a as NodeOptions, F as FnCtx, N as Node, b as NodeActions, x as NodeFnCleanup, A as Actor, C as COMPLETE, c as COMPLETE_MSG, d as COMPLETE_ONLY_BATCH, D as DATA, e as DEFAULT_ACTOR, f as DIRTY, g as DIRTY_MSG, h as DIRTY_ONLY_BATCH, i as DepRecord, E as ERROR, G as GlobalInspectorEvent, j as GlobalInspectorHook, k as GraphReFlyConfig, l as GuardAction, m as GuardDenied, n as GuardDeniedDetails, H as HashFn, I as INVALIDATE, o as INVALIDATE_MSG, p as INVALIDATE_ONLY_BATCH, M as Message, q as MessageContext, r as MessageTypeRegistration, s as MessageTypeRegistrationInput, u as NodeCtx, v as NodeDescribeKind, w as NodeFn, y as NodeGuard, z as NodeImpl, B as NodeInspectorHook, J as NodeInspectorHookEvent, K as NodeSink, L as NodeStatus, O as NodeTransportOptions, P as NodeVersionInfo, Q as OnMessageHandler, R as OnSubscribeHandler, S as PAUSE, T as PolicyAllow, U as PolicyDeny, V as PolicyRuleData, W as RESOLVED, X as RESOLVED_MSG, Y as RESOLVED_ONLY_BATCH, Z as RESUME, _ as START, $ as START_MSG, a0 as SubscribeContext, a1 as TEARDOWN, a2 as TEARDOWN_MSG, a3 as TEARDOWN_ONLY_BATCH, a4 as V0, a5 as V1, a6 as VersioningLevel, a7 as VersioningOptions, a8 as accessHintForGuard, a9 as advanceVersion, aa as configure, ab as createVersioning, ac as defaultConfig, ad as defaultHash, ae as isV1, af as node, ag as normalizeActor, ah as policy, ai as policyFromRules, aj as registerBuiltins } from './node-B-f-Lu-k.cjs';
2
+ import { D as DescribeDetail, a as DescribeField, b as DescribeNodeOutput, r as resolveDescribeFields } from './meta-DWbkoq1s.cjs';
3
3
 
4
4
  /**
5
- * Batch deferral for tier-3+ messages.
5
+ * Batch deferral for tier-3+ messages, plus per-node emit coalescing inside
6
+ * explicit `batch()` scopes.
6
7
  *
7
- * §1.3.7 — Inside a batch, tier 0–2 signals propagate immediately. Tier 3
8
- * (DATA/RESOLVED), tier 4 (COMPLETE/ERROR), and tier 5 (TEARDOWN) are queued
9
- * and drained in ascending phase order after the outermost `batch()` callback
10
- * returns.
8
+ * **Canonical invariant:** GRAPHREFLY-SPEC.md §1.3.7 — inside a batch,
9
+ * tier 0–2 signals propagate immediately; tier 3 (DATA/RESOLVED), tier 4
10
+ * (COMPLETE/ERROR), and tier 5 (TEARDOWN) are queued and drained in ascending
11
+ * phase order after the outermost `batch()` callback returns.
12
+ *
13
+ * **Per-node emit coalescing (Bug 2 fix, 2026-04-17).** Inside an explicit
14
+ * `batch()` scope, consecutive emissions from the same node accumulate in
15
+ * `NodeImpl._batchPendingMessages` (see JSDoc there) instead of each producing
16
+ * a separate downstream wave. K `.emit()` calls to the same source collapse to
17
+ * one coalesced `downWithBatch` call per child edge at batch end. Outside batch
18
+ * (or during drain), coalescing does NOT apply — each emit produces its own wave.
11
19
  *
12
20
  * **Phase vocabulary:**
13
21
  * - Phase 1 = tiers 0–2 — immediate, never queued.
@@ -15,14 +23,10 @@ import { D as DescribeDetail, a as DescribeField, b as DescribeNodeOutput, r as
15
23
  * - Phase 3 = tier 4 — {@link drainPhase3}. Terminal signals.
16
24
  * - Phase 4 = tier 5 — {@link drainPhase4}. TEARDOWN (unified deferral).
17
25
  *
18
- * Drain rule: lowest non-empty phase first. Re-enqueues during drain bump the
19
- * loop back to the lowest non-empty phase, preserving "earlier values settle
20
- * before later terminals/teardown" across callback re-entry.
21
- *
22
- * **Pre-sorted input invariant.** `downWithBatch` assumes `messages` is
23
- * already sorted in ascending tier order (produced by `_frameBatch` in
24
- * `node.ts`). The walker exploits monotonicity for a single O(n) pass and
25
- * slices at phase boundaries without re-sorting.
26
+ * Drain rule: fire any pending flush hooks first, then the lowest non-empty
27
+ * phase. Re-enqueues during drain (and hooks registered by reentrant batches
28
+ * inside subscriber callbacks) bump the loop back to the top so newly-added
29
+ * hooks and closures get processed.
26
30
  */
27
31
 
28
32
  /**
@@ -1,6 +1,6 @@
1
- import { a as NodeOptions, N as Node, M as Message, t as Messages, a6 as VersioningLevel } from './node-C5UD5MGq.js';
2
- import { a as StorageTier, I as IndexedDbStorageSpec, S as StorageHandle, d as dictStorage, f as fileStorage, b as fromIDBRequest, c as fromIDBTransaction, i as indexedDbStorage, m as memoryStorage, s as sqliteStorage } from './storage-C9fZfMfM.js';
3
- import { T as ToObservableOptions, t as toObservable } from './observable-CQRBtEbq.js';
1
+ import { a as NodeOptions, N as Node, M as Message, t as Messages, a6 as VersioningLevel } from './node-B-f-Lu-k.js';
2
+ import { a as StorageTier, I as IndexedDbStorageSpec, S as StorageHandle, d as dictStorage, f as fileStorage, b as fromIDBRequest, c as fromIDBTransaction, i as indexedDbStorage, m as memoryStorage, s as sqliteStorage } from './storage-F2X1U1x0.js';
3
+ import { T as ToObservableOptions, t as toObservable } from './observable-uP-wy_uK.js';
4
4
 
5
5
  /**
6
6
  * External-register helpers — the common `register({emit, error, complete})`
@@ -1,13 +1,21 @@
1
- import { t as Messages, a as NodeOptions, F as FnCtx, N as Node, b as NodeActions, x as NodeFnCleanup, A as Actor, C as COMPLETE, c as COMPLETE_MSG, d as COMPLETE_ONLY_BATCH, D as DATA, e as DEFAULT_ACTOR, f as DIRTY, g as DIRTY_MSG, h as DIRTY_ONLY_BATCH, i as DepRecord, E as ERROR, G as GlobalInspectorEvent, j as GlobalInspectorHook, k as GraphReFlyConfig, l as GuardAction, m as GuardDenied, n as GuardDeniedDetails, H as HashFn, I as INVALIDATE, o as INVALIDATE_MSG, p as INVALIDATE_ONLY_BATCH, M as Message, q as MessageContext, r as MessageTypeRegistration, s as MessageTypeRegistrationInput, u as NodeCtx, v as NodeDescribeKind, w as NodeFn, y as NodeGuard, z as NodeImpl, B as NodeInspectorHook, J as NodeInspectorHookEvent, K as NodeSink, L as NodeStatus, O as NodeTransportOptions, P as NodeVersionInfo, Q as OnMessageHandler, R as OnSubscribeHandler, S as PAUSE, T as PolicyAllow, U as PolicyDeny, V as PolicyRuleData, W as RESOLVED, X as RESOLVED_MSG, Y as RESOLVED_ONLY_BATCH, Z as RESUME, _ as START, $ as START_MSG, a0 as SubscribeContext, a1 as TEARDOWN, a2 as TEARDOWN_MSG, a3 as TEARDOWN_ONLY_BATCH, a4 as V0, a5 as V1, a6 as VersioningLevel, a7 as VersioningOptions, a8 as accessHintForGuard, a9 as advanceVersion, aa as configure, ab as createVersioning, ac as defaultConfig, ad as defaultHash, ae as isV1, af as node, ag as normalizeActor, ah as policy, ai as policyFromRules, aj as registerBuiltins } from './node-C5UD5MGq.js';
2
- import { D as DescribeDetail, a as DescribeField, b as DescribeNodeOutput, r as resolveDescribeFields } from './meta-n3FoVWML.js';
1
+ import { t as Messages, a as NodeOptions, F as FnCtx, N as Node, b as NodeActions, x as NodeFnCleanup, A as Actor, C as COMPLETE, c as COMPLETE_MSG, d as COMPLETE_ONLY_BATCH, D as DATA, e as DEFAULT_ACTOR, f as DIRTY, g as DIRTY_MSG, h as DIRTY_ONLY_BATCH, i as DepRecord, E as ERROR, G as GlobalInspectorEvent, j as GlobalInspectorHook, k as GraphReFlyConfig, l as GuardAction, m as GuardDenied, n as GuardDeniedDetails, H as HashFn, I as INVALIDATE, o as INVALIDATE_MSG, p as INVALIDATE_ONLY_BATCH, M as Message, q as MessageContext, r as MessageTypeRegistration, s as MessageTypeRegistrationInput, u as NodeCtx, v as NodeDescribeKind, w as NodeFn, y as NodeGuard, z as NodeImpl, B as NodeInspectorHook, J as NodeInspectorHookEvent, K as NodeSink, L as NodeStatus, O as NodeTransportOptions, P as NodeVersionInfo, Q as OnMessageHandler, R as OnSubscribeHandler, S as PAUSE, T as PolicyAllow, U as PolicyDeny, V as PolicyRuleData, W as RESOLVED, X as RESOLVED_MSG, Y as RESOLVED_ONLY_BATCH, Z as RESUME, _ as START, $ as START_MSG, a0 as SubscribeContext, a1 as TEARDOWN, a2 as TEARDOWN_MSG, a3 as TEARDOWN_ONLY_BATCH, a4 as V0, a5 as V1, a6 as VersioningLevel, a7 as VersioningOptions, a8 as accessHintForGuard, a9 as advanceVersion, aa as configure, ab as createVersioning, ac as defaultConfig, ad as defaultHash, ae as isV1, af as node, ag as normalizeActor, ah as policy, ai as policyFromRules, aj as registerBuiltins } from './node-B-f-Lu-k.js';
2
+ import { D as DescribeDetail, a as DescribeField, b as DescribeNodeOutput, r as resolveDescribeFields } from './meta-CnkLA_43.js';
3
3
 
4
4
  /**
5
- * Batch deferral for tier-3+ messages.
5
+ * Batch deferral for tier-3+ messages, plus per-node emit coalescing inside
6
+ * explicit `batch()` scopes.
6
7
  *
7
- * §1.3.7 — Inside a batch, tier 0–2 signals propagate immediately. Tier 3
8
- * (DATA/RESOLVED), tier 4 (COMPLETE/ERROR), and tier 5 (TEARDOWN) are queued
9
- * and drained in ascending phase order after the outermost `batch()` callback
10
- * returns.
8
+ * **Canonical invariant:** GRAPHREFLY-SPEC.md §1.3.7 — inside a batch,
9
+ * tier 0–2 signals propagate immediately; tier 3 (DATA/RESOLVED), tier 4
10
+ * (COMPLETE/ERROR), and tier 5 (TEARDOWN) are queued and drained in ascending
11
+ * phase order after the outermost `batch()` callback returns.
12
+ *
13
+ * **Per-node emit coalescing (Bug 2 fix, 2026-04-17).** Inside an explicit
14
+ * `batch()` scope, consecutive emissions from the same node accumulate in
15
+ * `NodeImpl._batchPendingMessages` (see JSDoc there) instead of each producing
16
+ * a separate downstream wave. K `.emit()` calls to the same source collapse to
17
+ * one coalesced `downWithBatch` call per child edge at batch end. Outside batch
18
+ * (or during drain), coalescing does NOT apply — each emit produces its own wave.
11
19
  *
12
20
  * **Phase vocabulary:**
13
21
  * - Phase 1 = tiers 0–2 — immediate, never queued.
@@ -15,14 +23,10 @@ import { D as DescribeDetail, a as DescribeField, b as DescribeNodeOutput, r as
15
23
  * - Phase 3 = tier 4 — {@link drainPhase3}. Terminal signals.
16
24
  * - Phase 4 = tier 5 — {@link drainPhase4}. TEARDOWN (unified deferral).
17
25
  *
18
- * Drain rule: lowest non-empty phase first. Re-enqueues during drain bump the
19
- * loop back to the lowest non-empty phase, preserving "earlier values settle
20
- * before later terminals/teardown" across callback re-entry.
21
- *
22
- * **Pre-sorted input invariant.** `downWithBatch` assumes `messages` is
23
- * already sorted in ascending tier order (produced by `_frameBatch` in
24
- * `node.ts`). The walker exploits monotonicity for a single O(n) pass and
25
- * slices at phase boundaries without re-sorting.
26
+ * Drain rule: fire any pending flush hooks first, then the lowest non-empty
27
+ * phase. Re-enqueues during drain (and hooks registered by reentrant batches
28
+ * inside subscriber callbacks) bump the loop back to the top so newly-added
29
+ * hooks and closures get processed.
26
30
  */
27
31
 
28
32
  /**
@@ -1,5 +1,5 @@
1
- import { k as GraphReFlyConfig } from './node-C5UD5MGq.js';
2
- import { r as GraphPersistSnapshot, g as GraphCheckpointRecord, D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from './graph-DFr0diXB.js';
1
+ import { k as GraphReFlyConfig } from './node-B-f-Lu-k.js';
2
+ import { r as GraphPersistSnapshot, g as GraphCheckpointRecord, D as DescribeFilter, e as GRAPH_META_SEGMENT, G as Graph, f as GraphActorOptions, b as GraphAttachStorageOptions, h as GraphDescribeOptions, i as GraphDescribeOutput, j as GraphDiagramDirection, k as GraphDiagramOptions, l as GraphDiffChange, m as GraphDiffResult, n as GraphFactoryContext, o as GraphNodeFactory, p as GraphObserveAll, q as GraphObserveOne, a as GraphOptions, d as GraphProfileOptions, c as GraphProfileResult, s as GraphVersionChange, t as GraphWALDiff, N as NodeProfile, O as ObserveDetail, u as ObserveEvent, v as ObserveOptions, w as ObserveResult, x as ObserveTheme, y as ObserveThemeName, R as ReachableDirection, z as ReachableOptions, T as TraceEntry, A as diffForWAL, B as graphProfile, C as reachable } from './graph-B6NFqv3z.js';
3
3
 
4
4
  /**
5
5
  * Approximate in-memory size estimation for arbitrary JS values.
@@ -1,5 +1,5 @@
1
- import { N as Node } from './node-C5UD5MGq.js';
2
- import { G as Graph } from './graph-DFr0diXB.js';
1
+ import { N as Node } from './node-B-f-Lu-k.js';
2
+ import { G as Graph } from './graph-B6NFqv3z.js';
3
3
 
4
4
  /** Pluggable measurement backend. */
5
5
  interface MeasurementAdapter {
@@ -1,8 +1,8 @@
1
- import { T as ToObservableOptions, t as toObservable } from './observable-CQRBtEbq.js';
1
+ import { T as ToObservableOptions, t as toObservable } from './observable-uP-wy_uK.js';
2
2
  import { OnModuleInit, OnModuleDestroy, ExecutionContext, CanActivate, DynamicModule } from '@nestjs/common';
3
3
  import { ModuleRef } from '@nestjs/core';
4
- import { G as Graph, a as GraphOptions, r as GraphPersistSnapshot } from './graph-DFr0diXB.js';
5
- import { A as Actor, N as Node } from './node-C5UD5MGq.js';
4
+ import { G as Graph, a as GraphOptions, r as GraphPersistSnapshot } from './graph-B6NFqv3z.js';
5
+ import { A as Actor, N as Node } from './node-B-f-Lu-k.js';
6
6
 
7
7
  /** Class constructor key for decorator registries and Nest `ModuleRef.get()`. */
8
8
  type DecoratorHostConstructor = abstract new (...args: unknown[]) => unknown;
@@ -1,8 +1,8 @@
1
- import { T as ToObservableOptions, t as toObservable } from './observable-DWydVy5b.cjs';
1
+ import { T as ToObservableOptions, t as toObservable } from './observable-DBnrwcar.cjs';
2
2
  import { OnModuleInit, OnModuleDestroy, ExecutionContext, CanActivate, DynamicModule } from '@nestjs/common';
3
3
  import { ModuleRef } from '@nestjs/core';
4
- import { G as Graph, a as GraphOptions, r as GraphPersistSnapshot } from './graph-ab1yPwIB.cjs';
5
- import { A as Actor, N as Node } from './node-C5UD5MGq.cjs';
4
+ import { G as Graph, a as GraphOptions, r as GraphPersistSnapshot } from './graph-D-3JIQme.cjs';
5
+ import { A as Actor, N as Node } from './node-B-f-Lu-k.cjs';
6
6
 
7
7
  /** Class constructor key for decorator registries and Nest `ModuleRef.get()`. */
8
8
  type DecoratorHostConstructor = abstract new (...args: unknown[]) => unknown;
@@ -1,5 +1,5 @@
1
- import { N as Node } from './node-C5UD5MGq.cjs';
2
- import { G as Graph } from './graph-ab1yPwIB.cjs';
1
+ import { N as Node } from './node-B-f-Lu-k.cjs';
2
+ import { G as Graph } from './graph-D-3JIQme.cjs';
3
3
 
4
4
  /** Pluggable measurement backend. */
5
5
  interface MeasurementAdapter {
package/dist/index.cjs CHANGED
@@ -544,9 +544,20 @@ var flushInProgress = false;
544
544
  var drainPhase2 = [];
545
545
  var drainPhase3 = [];
546
546
  var drainPhase4 = [];
547
+ var flushHooks = [];
547
548
  function isBatching() {
548
549
  return batchDepth > 0 || flushInProgress;
549
550
  }
551
+ function isExplicitlyBatching() {
552
+ return batchDepth > 0;
553
+ }
554
+ function registerBatchFlushHook(hook) {
555
+ if (batchDepth > 0) {
556
+ flushHooks.push(hook);
557
+ } else {
558
+ hook();
559
+ }
560
+ }
550
561
  function batch(fn) {
551
562
  batchDepth += 1;
552
563
  let threw = false;
@@ -560,6 +571,13 @@ function batch(fn) {
560
571
  if (batchDepth === 0) {
561
572
  if (threw) {
562
573
  if (!flushInProgress) {
574
+ const hooks = flushHooks.splice(0);
575
+ for (const h of hooks) {
576
+ try {
577
+ h();
578
+ } catch {
579
+ }
580
+ }
563
581
  drainPhase2.length = 0;
564
582
  drainPhase3.length = 0;
565
583
  drainPhase4.length = 0;
@@ -576,7 +594,18 @@ function drainPending() {
576
594
  const errors = [];
577
595
  let iterations = 0;
578
596
  try {
579
- while (drainPhase2.length > 0 || drainPhase3.length > 0 || drainPhase4.length > 0) {
597
+ while (drainPhase2.length > 0 || drainPhase3.length > 0 || drainPhase4.length > 0 || ownsFlush && flushHooks.length > 0) {
598
+ if (ownsFlush && flushHooks.length > 0) {
599
+ const hooks = flushHooks.splice(0);
600
+ for (const h of hooks) {
601
+ try {
602
+ h();
603
+ } catch (e) {
604
+ errors.push(e);
605
+ }
606
+ }
607
+ continue;
608
+ }
580
609
  iterations += 1;
581
610
  if (iterations > MAX_DRAIN_ITERATIONS) {
582
611
  drainPhase2.length = 0;
@@ -1266,6 +1295,22 @@ var NodeImpl = class _NodeImpl {
1266
1295
  * treats `0` as "wave settled" — O(1) check for full dep settlement.
1267
1296
  */
1268
1297
  _dirtyDepCount = 0;
1298
+ // --- Per-batch emit accumulator (Bug 2: K+1 fan-in fix) ---
1299
+ /**
1300
+ * Inside an explicit `batch(() => ...)` scope, every `_emit` accumulates
1301
+ * its already-framed messages here instead of dispatching synchronously.
1302
+ * At batch end, `_flushBatchPending` runs (registered via
1303
+ * `registerBatchFlushHook`) and delivers the whole accumulated batch as
1304
+ * one `downWithBatch` call — collapsing what would otherwise be K
1305
+ * separate sink invocations into one. This is the fix for the diamond
1306
+ * fan-in K+1 over-fire.
1307
+ *
1308
+ * `null` outside batch (or after flush). Only ever appended to within
1309
+ * a single explicit batch lifetime; reset to `null` on flush. State
1310
+ * updates (cache, version, status) still happen per-emit via
1311
+ * `_updateState` — only the downstream delivery is coalesced.
1312
+ */
1313
+ _batchPendingMessages = null;
1269
1314
  // --- PAUSE/RESUME lock tracking (C0) ---
1270
1315
  /**
1271
1316
  * Set of active pause locks held against this node. Every `[PAUSE, lockId]`
@@ -1643,7 +1688,10 @@ var NodeImpl = class _NodeImpl {
1643
1688
  dep.unsub = noopUnsub;
1644
1689
  dep.unsub = dep.node.subscribe((msgs) => {
1645
1690
  if (dep.unsub === null) return;
1691
+ const tierOf = this._config.tierOf;
1692
+ let sawSettlement = false;
1646
1693
  for (const m of msgs) {
1694
+ if (tierOf(m[0]) >= 3) sawSettlement = true;
1647
1695
  this._config.onMessage(
1648
1696
  this,
1649
1697
  m,
@@ -1651,6 +1699,7 @@ var NodeImpl = class _NodeImpl {
1651
1699
  this._actions
1652
1700
  );
1653
1701
  }
1702
+ if (sawSettlement) this._maybeRunFnOnSettlement();
1654
1703
  });
1655
1704
  subscribedCount++;
1656
1705
  }
@@ -1705,7 +1754,10 @@ var NodeImpl = class _NodeImpl {
1705
1754
  try {
1706
1755
  record.unsub = depNode.subscribe((msgs) => {
1707
1756
  if (record.unsub === null) return;
1757
+ const tierOf = this._config.tierOf;
1758
+ let sawSettlement = false;
1708
1759
  for (const m of msgs) {
1760
+ if (tierOf(m[0]) >= 3) sawSettlement = true;
1709
1761
  this._config.onMessage(
1710
1762
  this,
1711
1763
  m,
@@ -1713,6 +1765,7 @@ var NodeImpl = class _NodeImpl {
1713
1765
  this._actions
1714
1766
  );
1715
1767
  }
1768
+ if (sawSettlement) this._maybeRunFnOnSettlement();
1716
1769
  });
1717
1770
  } catch (err) {
1718
1771
  record.unsub = null;
@@ -1834,7 +1887,6 @@ var NodeImpl = class _NodeImpl {
1834
1887
  }
1835
1888
  return;
1836
1889
  }
1837
- this._maybeRunFnOnSettlement();
1838
1890
  }
1839
1891
  // --- Centralized dep-state transitions (A3 settlement counters) ---
1840
1892
  //
@@ -2080,37 +2132,35 @@ var NodeImpl = class _NodeImpl {
2080
2132
  // --- Emit pipeline ---
2081
2133
  /**
2082
2134
  * @internal The unified dispatch waist — one call = one wave.
2135
+ * See `GRAPHREFLY-SPEC.md` §1.3.1 for protocol context — the stages
2136
+ * below are the implementation order.
2083
2137
  *
2084
2138
  * Pipeline stages, in order:
2085
2139
  *
2086
- * 1. Early-return on empty batch.
2087
- * 2. Terminal filter — post-COMPLETE/ERROR only TEARDOWN/INVALIDATE
2140
+ * 1. Terminal filter — post-COMPLETE/ERROR only TEARDOWN/INVALIDATE
2088
2141
  * still propagate so graph teardown and cache-clear still work.
2089
- * 3. Tier sort (stable) — the batch can be in any order when it
2142
+ * 2. Tier sort (stable) — the batch can be in any order when it
2090
2143
  * arrives; the walker downstream (`downWithBatch`) assumes
2091
2144
  * ascending tier monotone, and so does `_updateState`'s tier-3
2092
2145
  * slice walk. This is the single source of truth for ordering.
2093
- * 4. Synthetic DIRTY prefix — if a tier-3 payload is present, no
2146
+ * 3. Synthetic DIRTY prefix — if a tier-3 payload is present, no
2094
2147
  * DIRTY is already in the batch, and the node isn't already in
2095
2148
  * `"dirty"` status, prepend `[DIRTY]` after any tier-0 START
2096
2149
  * entries. Guarantees spec §1.3.1 (DIRTY precedes DATA within
2097
2150
  * the same batch) uniformly across every entry point.
2098
- * 5. PAUSE/RESUME lock bookkeeping (C0) — update `_pauseLocks`,
2151
+ * 4. PAUSE/RESUME lock bookkeeping (C0) — update `_pauseLocks`,
2099
2152
  * derive `_paused`, filter unknown-lockId RESUME, replay
2100
2153
  * bufferAll buffer on final lock release.
2101
- * 6. Meta TEARDOWN fan-out — notify meta children before
2154
+ * 5. Meta TEARDOWN fan-out — notify meta children before
2102
2155
  * `_updateState`'s TEARDOWN branch calls `_deactivate`. Hoisted
2103
2156
  * out of the walk to keep `_updateState` re-entrance-free.
2104
- * 7. `_updateState` — walk the batch in tier order, advancing
2157
+ * 6. `_updateState` — walk the batch in tier order, advancing
2105
2158
  * `_cached` / `_status` / `_versioning` and running equals
2106
2159
  * substitution on tier-3 DATA (§3.5.1). Returns
2107
2160
  * `{finalMessages, equalsError?}`.
2108
- * 8. `downWithBatch` dispatch (or bufferAll capture if paused with
2161
+ * 7. `downWithBatch` dispatch (or bufferAll capture if paused with
2109
2162
  * `pausable: "resumeAll"`).
2110
- * 9. Recursive ERROR emission if equals threw mid-walk.
2111
- *
2112
- * `node.down` / `node.emit` / `actions.down` / `actions.emit` all
2113
- * converge here — the unified `_emit` waist (spec §1.3.1).
2163
+ * 8. Recursive ERROR emission if equals threw mid-walk.
2114
2164
  */
2115
2165
  _emit(messages) {
2116
2166
  if (messages.length === 0) return;
@@ -2206,10 +2256,10 @@ var NodeImpl = class _NodeImpl {
2206
2256
  }
2207
2257
  }
2208
2258
  if (immediate.length > 0) {
2209
- downWithBatch(this._deliverToSinks, immediate, tierOf);
2259
+ this._dispatchOrAccumulate(immediate);
2210
2260
  }
2211
2261
  } else {
2212
- downWithBatch(this._deliverToSinks, finalMessages, this._config.tierOf);
2262
+ this._dispatchOrAccumulate(finalMessages);
2213
2263
  }
2214
2264
  }
2215
2265
  if (equalsError != null) {
@@ -2332,6 +2382,50 @@ var NodeImpl = class _NodeImpl {
2332
2382
  const snapshot = [...this._sinks];
2333
2383
  for (const sink of snapshot) sink(messages);
2334
2384
  };
2385
+ /**
2386
+ * @internal Dispatch entry point that respects the per-batch emit
2387
+ * accumulator (Bug 2). Inside an explicit `batch()` scope, append to
2388
+ * `_batchPendingMessages` and register a flush hook on first append.
2389
+ * Outside batch — or during a drain (where `flushInProgress` is true
2390
+ * but `batchDepth` is 0) — dispatch synchronously through `downWithBatch`.
2391
+ *
2392
+ * Per-emit state updates (`_frameBatch`, `_updateState`) have already
2393
+ * happened by the time we reach here; only the **downstream delivery**
2394
+ * is coalesced. Cache, version, and status are visible mid-batch on
2395
+ * the emitting node itself.
2396
+ */
2397
+ _dispatchOrAccumulate(messages) {
2398
+ if (isExplicitlyBatching()) {
2399
+ if (this._batchPendingMessages === null) {
2400
+ this._batchPendingMessages = [];
2401
+ registerBatchFlushHook(() => this._flushBatchPending());
2402
+ }
2403
+ for (const m of messages) this._batchPendingMessages.push(m);
2404
+ return;
2405
+ }
2406
+ downWithBatch(this._deliverToSinks, messages, this._config.tierOf);
2407
+ }
2408
+ /**
2409
+ * @internal Flushes the accumulated batch through `downWithBatch` and
2410
+ * clears the pending state. Idempotent — safe to call when pending is
2411
+ * already null or empty (e.g. on a `batch()` throw, where the hook
2412
+ * fires for cleanup but the drainPhase queues are wiped after).
2413
+ *
2414
+ * Critical: the accumulated batch is interleaved per-emit framings like
2415
+ * `[DIRTY, DATA(1), DIRTY, DATA(2)]` — non-monotone tier order. We must
2416
+ * re-frame to sort by tier before handing to `downWithBatch`, which
2417
+ * assumes pre-sorted input. `_frameBatch` also handles the synthetic
2418
+ * DIRTY prepend rule (no-op here — `hasDirty` is true since each
2419
+ * accumulated emit already carries its own DIRTY prefix).
2420
+ */
2421
+ _flushBatchPending() {
2422
+ const pending = this._batchPendingMessages;
2423
+ if (pending === null) return;
2424
+ this._batchPendingMessages = null;
2425
+ if (pending.length === 0) return;
2426
+ const framed = this._frameBatch(pending);
2427
+ downWithBatch(this._deliverToSinks, framed, this._config.tierOf);
2428
+ }
2335
2429
  };
2336
2430
  var isNodeArray = (value) => Array.isArray(value);
2337
2431
  var isNodeOptionsObject = (value) => typeof value === "object" && value != null && !Array.isArray(value);
@@ -7182,6 +7276,10 @@ __export(graph_exports, {
7182
7276
  });
7183
7277
 
7184
7278
  // src/patterns/_internal.ts
7279
+ function emitToMeta(metaNode, value) {
7280
+ if (metaNode == null) return;
7281
+ downWithBatch((msgs) => metaNode.down(msgs), [[DATA, value]], defaultConfig.tierOf);
7282
+ }
7185
7283
  function tryIncrementBounded(counter, cap) {
7186
7284
  const cur = counter.cache ?? 0;
7187
7285
  if (cur >= cap) return false;
@@ -8087,20 +8185,12 @@ function useStore4(node2) {
8087
8185
  function useSubscribeRecord4(keys, factory) {
8088
8186
  const result = (0, import_vue.shallowRef)({});
8089
8187
  const activeSubs = /* @__PURE__ */ new Map();
8090
- let disposed = false;
8091
- let batchPending = false;
8092
- function scheduleBatch() {
8093
- if (batchPending) return;
8094
- batchPending = true;
8095
- queueMicrotask(() => {
8096
- if (disposed) return;
8097
- batchPending = false;
8098
- const snap = {};
8099
- for (const [key, entry] of activeSubs) {
8100
- snap[key] = { ...entry.values };
8101
- }
8102
- result.value = snap;
8103
- });
8188
+ function flushResult() {
8189
+ const snap = {};
8190
+ for (const [key, entry] of activeSubs) {
8191
+ snap[key] = { ...entry.values };
8192
+ }
8193
+ result.value = snap;
8104
8194
  }
8105
8195
  function sync(newKeys) {
8106
8196
  for (const entry of activeSubs.values()) {
@@ -8117,7 +8207,7 @@ function useSubscribeRecord4(keys, factory) {
8117
8207
  values[field] = node2.cache;
8118
8208
  const unsub = node2.subscribe(() => {
8119
8209
  values[field] = node2.cache;
8120
- scheduleBatch();
8210
+ flushResult();
8121
8211
  });
8122
8212
  subs.push(unsub);
8123
8213
  }
@@ -8136,7 +8226,6 @@ function useSubscribeRecord4(keys, factory) {
8136
8226
  (0, import_vue.watch)(readKeys, (newKeys) => sync(newKeys ?? []), { immediate: true });
8137
8227
  if ((0, import_vue.getCurrentScope)()) {
8138
8228
  (0, import_vue.onScopeDispose)(() => {
8139
- disposed = true;
8140
8229
  for (const entry of activeSubs.values()) {
8141
8230
  for (const unsub of entry.subs) unsub();
8142
8231
  }
@@ -8165,18 +8254,17 @@ function create(initializer) {
8165
8254
  g.add("state", s);
8166
8255
  const getState = () => s.cache;
8167
8256
  const setState = (partial, replace) => {
8168
- const prev = getState();
8257
+ const prev = s.cache;
8169
8258
  const next = typeof partial === "function" ? partial(prev) : partial;
8170
- const nextState = replace ? next : { ...prev, ...next };
8171
- s.emit(nextState);
8259
+ s.emit(replace ? next : { ...prev, ...next });
8172
8260
  };
8173
8261
  const api = {
8174
8262
  getState,
8175
8263
  setState,
8176
8264
  getInitialState: () => initialValue,
8177
8265
  subscribe: (listener) => {
8178
- let prev = getState();
8179
8266
  let initial = true;
8267
+ let prev = s.cache;
8180
8268
  return s.subscribe((msgs) => {
8181
8269
  for (const [t, v] of msgs) {
8182
8270
  if (t === DATA) {
@@ -18324,13 +18412,9 @@ function reactiveLayout(opts) {
18324
18412
  const hitRate = lookups === 0 ? 1 : measureStats.hits / lookups;
18325
18413
  const meta = segmentsNode.meta;
18326
18414
  if (meta) {
18327
- const hr = hitRate;
18328
- const len = result.length;
18329
- const el = elapsed;
18330
- const tierOf = defaultConfig.tierOf;
18331
- downWithBatch((msgs) => meta["cache-hit-rate"]?.down(msgs), [[DATA, hr]], tierOf);
18332
- downWithBatch((msgs) => meta["segment-count"]?.down(msgs), [[DATA, len]], tierOf);
18333
- downWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, el]], tierOf);
18415
+ emitToMeta(meta["cache-hit-rate"], hitRate);
18416
+ emitToMeta(meta["segment-count"], result.length);
18417
+ emitToMeta(meta["layout-time-ns"], elapsed);
18334
18418
  }
18335
18419
  actions.emit(result);
18336
18420
  return () => {
@@ -21659,9 +21743,8 @@ function reactiveBlockLayout(opts) {
21659
21743
  const elapsed = monotonicNs() - t0;
21660
21744
  const meta = measuredBlocksNode.meta;
21661
21745
  if (meta) {
21662
- const tierOf = defaultConfig.tierOf;
21663
- downWithBatch((msgs) => meta["block-count"]?.down(msgs), [[DATA, result.length]], tierOf);
21664
- downWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, elapsed]], tierOf);
21746
+ emitToMeta(meta["block-count"], result.length);
21747
+ emitToMeta(meta["layout-time-ns"], elapsed);
21665
21748
  }
21666
21749
  actions.emit(result);
21667
21750
  return () => {