@graphrefly/graphrefly 0.24.0 → 0.26.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 (184) hide show
  1. package/README.md +8 -0
  2. package/dist/{chunk-QOWVNWOC.js → chunk-3ZWCKRHX.js} +27 -25
  3. package/dist/{chunk-QOWVNWOC.js.map → chunk-3ZWCKRHX.js.map} +1 -1
  4. package/dist/chunk-6LDQFTYS.js +102 -0
  5. package/dist/chunk-6LDQFTYS.js.map +1 -0
  6. package/dist/{chunk-5WGT55R4.js → chunk-AMCG74RZ.js} +195 -24
  7. package/dist/chunk-AMCG74RZ.js.map +1 -0
  8. package/dist/{chunk-AOCBDH4T.js → chunk-BVZYTZ5H.js} +76 -103
  9. package/dist/chunk-BVZYTZ5H.js.map +1 -0
  10. package/dist/chunk-FQMKGR6L.js +330 -0
  11. package/dist/chunk-FQMKGR6L.js.map +1 -0
  12. package/dist/chunk-HXZEYDUR.js +94 -0
  13. package/dist/chunk-HXZEYDUR.js.map +1 -0
  14. package/dist/{chunk-IPLKX3L2.js → chunk-IZYUSJC7.js} +16 -14
  15. package/dist/{chunk-IPLKX3L2.js.map → chunk-IZYUSJC7.js.map} +1 -1
  16. package/dist/chunk-J22W6HV3.js +107 -0
  17. package/dist/chunk-J22W6HV3.js.map +1 -0
  18. package/dist/{chunk-HWPIFSW2.js → chunk-JSCT3CR4.js} +6 -4
  19. package/dist/{chunk-HWPIFSW2.js.map → chunk-JSCT3CR4.js.map} +1 -1
  20. package/dist/chunk-JYXEWPH4.js +62 -0
  21. package/dist/chunk-JYXEWPH4.js.map +1 -0
  22. package/dist/chunk-LCE3GF5P.js +866 -0
  23. package/dist/chunk-LCE3GF5P.js.map +1 -0
  24. package/dist/chunk-MJ2NKQQL.js +119 -0
  25. package/dist/chunk-MJ2NKQQL.js.map +1 -0
  26. package/dist/chunk-N6UR7YVY.js +198 -0
  27. package/dist/chunk-N6UR7YVY.js.map +1 -0
  28. package/dist/chunk-OHISZPOJ.js +97 -0
  29. package/dist/chunk-OHISZPOJ.js.map +1 -0
  30. package/dist/{chunk-5DJTTKX3.js → chunk-PHOUUNK7.js} +74 -111
  31. package/dist/chunk-PHOUUNK7.js.map +1 -0
  32. package/dist/{chunk-PY4XCDLR.js → chunk-RB6QPHJ7.js} +8 -6
  33. package/dist/{chunk-PY4XCDLR.js.map → chunk-RB6QPHJ7.js.map} +1 -1
  34. package/dist/chunk-SN4YWWYO.js +171 -0
  35. package/dist/chunk-SN4YWWYO.js.map +1 -0
  36. package/dist/chunk-SX52TAR4.js +110 -0
  37. package/dist/chunk-SX52TAR4.js.map +1 -0
  38. package/dist/{chunk-XOFWRC73.js → chunk-THTWHNU4.js} +319 -24
  39. package/dist/chunk-THTWHNU4.js.map +1 -0
  40. package/dist/{chunk-H4RVA4VE.js → chunk-VYPWMZ6H.js} +2 -2
  41. package/dist/chunk-XGPU467M.js +136 -0
  42. package/dist/chunk-XGPU467M.js.map +1 -0
  43. package/dist/{chunk-TDEXAMGO.js → chunk-ZQMEI34O.js} +206 -574
  44. package/dist/chunk-ZQMEI34O.js.map +1 -0
  45. package/dist/compat/index.cjs +7656 -0
  46. package/dist/compat/index.cjs.map +1 -0
  47. package/dist/compat/index.d.cts +18 -0
  48. package/dist/compat/index.d.ts +18 -0
  49. package/dist/compat/index.js +49 -0
  50. package/dist/compat/index.js.map +1 -0
  51. package/dist/compat/jotai/index.cjs +2048 -0
  52. package/dist/compat/jotai/index.cjs.map +1 -0
  53. package/dist/compat/jotai/index.d.cts +2 -0
  54. package/dist/compat/jotai/index.d.ts +2 -0
  55. package/dist/compat/jotai/index.js +9 -0
  56. package/dist/compat/jotai/index.js.map +1 -0
  57. package/dist/compat/nanostores/index.cjs +2175 -0
  58. package/dist/compat/nanostores/index.cjs.map +1 -0
  59. package/dist/compat/nanostores/index.d.cts +2 -0
  60. package/dist/compat/nanostores/index.d.ts +2 -0
  61. package/dist/compat/nanostores/index.js +23 -0
  62. package/dist/compat/nanostores/index.js.map +1 -0
  63. package/dist/compat/nestjs/index.cjs +350 -16
  64. package/dist/compat/nestjs/index.cjs.map +1 -1
  65. package/dist/compat/nestjs/index.d.cts +6 -6
  66. package/dist/compat/nestjs/index.d.ts +6 -6
  67. package/dist/compat/nestjs/index.js +10 -9
  68. package/dist/compat/react/index.cjs +141 -0
  69. package/dist/compat/react/index.cjs.map +1 -0
  70. package/dist/compat/react/index.d.cts +2 -0
  71. package/dist/compat/react/index.d.ts +2 -0
  72. package/dist/compat/react/index.js +12 -0
  73. package/dist/compat/react/index.js.map +1 -0
  74. package/dist/compat/solid/index.cjs +128 -0
  75. package/dist/compat/solid/index.cjs.map +1 -0
  76. package/dist/compat/solid/index.d.cts +2 -0
  77. package/dist/compat/solid/index.d.ts +2 -0
  78. package/dist/compat/solid/index.js +12 -0
  79. package/dist/compat/solid/index.js.map +1 -0
  80. package/dist/compat/svelte/index.cjs +131 -0
  81. package/dist/compat/svelte/index.cjs.map +1 -0
  82. package/dist/compat/svelte/index.d.cts +2 -0
  83. package/dist/compat/svelte/index.d.ts +2 -0
  84. package/dist/compat/svelte/index.js +12 -0
  85. package/dist/compat/svelte/index.js.map +1 -0
  86. package/dist/compat/vue/index.cjs +146 -0
  87. package/dist/compat/vue/index.cjs.map +1 -0
  88. package/dist/compat/vue/index.d.cts +3 -0
  89. package/dist/compat/vue/index.d.ts +3 -0
  90. package/dist/compat/vue/index.js +12 -0
  91. package/dist/compat/vue/index.js.map +1 -0
  92. package/dist/compat/zustand/index.cjs +4931 -0
  93. package/dist/compat/zustand/index.cjs.map +1 -0
  94. package/dist/compat/zustand/index.d.cts +5 -0
  95. package/dist/compat/zustand/index.d.ts +5 -0
  96. package/dist/compat/zustand/index.js +12 -0
  97. package/dist/compat/zustand/index.js.map +1 -0
  98. package/dist/core/index.cjs +53 -4
  99. package/dist/core/index.cjs.map +1 -1
  100. package/dist/core/index.d.cts +3 -3
  101. package/dist/core/index.d.ts +3 -3
  102. package/dist/core/index.js +26 -24
  103. package/dist/demo-shell-26p5fVxn.d.cts +102 -0
  104. package/dist/demo-shell-DEp-nMTl.d.ts +102 -0
  105. package/dist/extra/index.cjs +290 -110
  106. package/dist/extra/index.cjs.map +1 -1
  107. package/dist/extra/index.d.cts +5 -4
  108. package/dist/extra/index.d.ts +5 -4
  109. package/dist/extra/index.js +8 -5
  110. package/dist/extra/sources.cjs +2486 -0
  111. package/dist/extra/sources.cjs.map +1 -0
  112. package/dist/extra/sources.d.cts +465 -0
  113. package/dist/extra/sources.d.ts +465 -0
  114. package/dist/extra/sources.js +57 -0
  115. package/dist/extra/sources.js.map +1 -0
  116. package/dist/graph/index.cjs +408 -14
  117. package/dist/graph/index.cjs.map +1 -1
  118. package/dist/graph/index.d.cts +5 -5
  119. package/dist/graph/index.d.ts +5 -5
  120. package/dist/graph/index.js +13 -5
  121. package/dist/{graph-D-3JIQme.d.cts → graph-6tZ5jEzr.d.cts} +195 -4
  122. package/dist/{graph-B6NFqv3z.d.ts → graph-DQ69XU0g.d.ts} +195 -4
  123. package/dist/index-B4MP_8V_.d.cts +37 -0
  124. package/dist/index-BEfE8H_G.d.cts +121 -0
  125. package/dist/{index-D7XgsUt7.d.ts → index-BW1z3BN9.d.ts} +169 -127
  126. package/dist/index-BYOHF0zP.d.ts +34 -0
  127. package/dist/index-B_IP40nB.d.cts +36 -0
  128. package/dist/index-Bd_fwmLf.d.cts +45 -0
  129. package/dist/{index-BysCTzJz.d.ts → index-BeIdBfcb.d.cts} +121 -547
  130. package/dist/index-BjI6ty9z.d.ts +121 -0
  131. package/dist/index-Bxb5ZYc9.d.cts +34 -0
  132. package/dist/{index-BJB7t9gg.d.cts → index-C0ZXMaXO.d.cts} +2 -2
  133. package/dist/{index-b5BYtczN.d.cts → index-C8mdwMXc.d.cts} +169 -127
  134. package/dist/index-CDAjUFIv.d.ts +36 -0
  135. package/dist/index-CPgZ5wRl.d.ts +44 -0
  136. package/dist/{index-AMWewNDe.d.cts → index-CUwyr1Kk.d.cts} +33 -4
  137. package/dist/index-CUyrtuOf.d.cts +127 -0
  138. package/dist/{index-C-TXEa7C.d.ts → index-CY2TljO4.d.ts} +2 -2
  139. package/dist/index-CmnuOibw.d.ts +37 -0
  140. package/dist/{index-DiobMNwE.d.ts → index-CuYwdKO-.d.ts} +3 -3
  141. package/dist/index-DFhjO4Gg.d.cts +44 -0
  142. package/dist/{index-1z8vRTCt.d.cts → index-DdD5MVDL.d.ts} +121 -547
  143. package/dist/index-DrISNAOm.d.ts +45 -0
  144. package/dist/index-QBpffFW-.d.cts +86 -0
  145. package/dist/{index-J7Kc0oIQ.d.cts → index-_oMEWlDq.d.cts} +3 -3
  146. package/dist/{index-CYkjxu3s.d.ts → index-eJ6T_qGM.d.ts} +33 -4
  147. package/dist/index-qldRdbQw.d.ts +86 -0
  148. package/dist/index-xdGjv0nO.d.ts +127 -0
  149. package/dist/index.cjs +2334 -195
  150. package/dist/index.cjs.map +1 -1
  151. package/dist/index.d.cts +1007 -648
  152. package/dist/index.d.ts +1007 -648
  153. package/dist/index.js +1204 -1172
  154. package/dist/index.js.map +1 -1
  155. package/dist/{meta-CnkLA_43.d.ts → meta-BGqSZ7mt.d.ts} +1 -1
  156. package/dist/{meta-DWbkoq1s.d.cts → meta-C0-8XW6Q.d.cts} +1 -1
  157. package/dist/{node-B-f-Lu-k.d.cts → node-C_IBuvX2.d.cts} +26 -1
  158. package/dist/{node-B-f-Lu-k.d.ts → node-C_IBuvX2.d.ts} +26 -1
  159. package/dist/{observable-DBnrwcar.d.cts → observable-Crr1jgzx.d.cts} +1 -1
  160. package/dist/{observable-uP-wy_uK.d.ts → observable-DCk45RH5.d.ts} +1 -1
  161. package/dist/patterns/demo-shell.cjs +5604 -0
  162. package/dist/patterns/demo-shell.cjs.map +1 -0
  163. package/dist/patterns/demo-shell.d.cts +6 -0
  164. package/dist/patterns/demo-shell.d.ts +6 -0
  165. package/dist/patterns/demo-shell.js +15 -0
  166. package/dist/patterns/demo-shell.js.map +1 -0
  167. package/dist/patterns/reactive-layout/index.cjs +843 -29
  168. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  169. package/dist/patterns/reactive-layout/index.d.cts +6 -5
  170. package/dist/patterns/reactive-layout/index.d.ts +6 -5
  171. package/dist/patterns/reactive-layout/index.js +25 -10
  172. package/dist/reactive-layout-BaOQefHu.d.cts +183 -0
  173. package/dist/reactive-layout-D9gejYXE.d.ts +183 -0
  174. package/dist/{storage-BuTdpCI1.d.cts → storage-BMycWEh2.d.ts} +9 -1
  175. package/dist/{storage-F2X1U1x0.d.ts → storage-DiqWHzVI.d.cts} +9 -1
  176. package/package.json +32 -2
  177. package/dist/chunk-5DJTTKX3.js.map +0 -1
  178. package/dist/chunk-5WGT55R4.js.map +0 -1
  179. package/dist/chunk-AOCBDH4T.js.map +0 -1
  180. package/dist/chunk-MW4VAKAO.js +0 -47
  181. package/dist/chunk-MW4VAKAO.js.map +0 -1
  182. package/dist/chunk-TDEXAMGO.js.map +0 -1
  183. package/dist/chunk-XOFWRC73.js.map +0 -1
  184. /package/dist/{chunk-H4RVA4VE.js.map → chunk-VYPWMZ6H.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/extra/observable.ts","../src/extra/backpressure.ts","../src/extra/reactive-log.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// RxJS bridge — reactive interop between GraphReFly nodes and RxJS Observables.\n// ---------------------------------------------------------------------------\n// Usage:\n// import { toObservable } from '@graphrefly/graphrefly-ts/extra';\n// const values$ = toObservable(myNode); // Observable<T>\n// const msgs$ = toObservable(myNode, { raw: true }); // Observable<Messages>\n// ---------------------------------------------------------------------------\n\nimport { Observable } from \"rxjs\";\nimport { COMPLETE, DATA, ERROR, type Messages } from \"../core/messages.js\";\nimport type { Node } from \"../core/node.js\";\n\n/** Options for {@link toObservable}. */\nexport type ToObservableOptions = {\n\t/**\n\t * When `true`, emit raw `Messages` batches instead of extracted `DATA` values.\n\t * Terminal batches are still emitted as the final `next()` before the\n\t * Observable signal (error/complete).\n\t */\n\traw?: boolean;\n};\n\n/**\n * Bridge a `Node<T>` to an RxJS `Observable`.\n *\n * Default mode emits the node's value on each `DATA` message. Maps `ERROR` to\n * `subscriber.error()` and `COMPLETE` to `subscriber.complete()`.\n * Protocol-internal signals (DIRTY, RESOLVED, PAUSE, etc.) are skipped.\n *\n * With `{ raw: true }`, emits full `[[Type, Data?], ...]` message batches.\n * The Observable terminates on ERROR or COMPLETE (the terminal batch is still\n * emitted as the final `next()` before the Observable signal).\n *\n * For graph-level observation, use `toObservable(graph.resolve(path))` or\n * subscribe to `graph.observe()` directly.\n *\n * Unsubscribing the Observable unsubscribes the node.\n */\nexport function toObservable<T>(\n\tnode: Node<T>,\n\toptions?: ToObservableOptions & { raw?: false },\n): Observable<T>;\nexport function toObservable<T>(\n\tnode: Node<T>,\n\toptions: ToObservableOptions & { raw: true },\n): Observable<Messages>;\nexport function toObservable<T>(\n\tnode: Node<T>,\n\toptions?: ToObservableOptions,\n): Observable<T | Messages> {\n\tif (options?.raw) {\n\t\treturn new Observable<Messages>((subscriber) => {\n\t\t\tconst unsub = node.subscribe((msgs) => {\n\t\t\t\tif (subscriber.closed) return;\n\t\t\t\tsubscriber.next(msgs);\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\t\tsubscriber.error(m[1]);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\t\tsubscriber.complete();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn unsub;\n\t\t});\n\t}\n\n\treturn new Observable<T>((subscriber) => {\n\t\tconst unsub = node.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (subscriber.closed) return;\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tsubscriber.next(m[1] as T);\n\t\t\t\t} else if (m[0] === ERROR) {\n\t\t\t\t\tsubscriber.error(m[1]);\n\t\t\t\t\treturn;\n\t\t\t\t} else if (m[0] === COMPLETE) {\n\t\t\t\t\tsubscriber.complete();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn unsub;\n\t});\n}\n","/**\n * Watermark-based backpressure controller — reactive PAUSE/RESUME flow control.\n *\n * Purely synchronous, event-driven. No timers, no polling, no Promises.\n * Each controller instance uses a unique lockId so multiple controllers\n * on the same upstream node do not collide.\n *\n * @module\n */\n\nimport { type Messages, PAUSE, RESUME } from \"../core/messages.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type WatermarkOptions = {\n\t/** Pending count at which PAUSE is sent upstream. */\n\thighWaterMark: number;\n\t/** Pending count at which RESUME is sent upstream (after being paused). */\n\tlowWaterMark: number;\n};\n\nexport type WatermarkController = {\n\t/** Call when a DATA message is buffered/enqueued. Returns `true` if PAUSE was just sent. */\n\tonEnqueue(): boolean;\n\t/** Call when a buffered item is consumed. Returns `true` if RESUME was just sent. */\n\tonDequeue(): boolean;\n\t/** Current un-consumed item count. */\n\treadonly pending: number;\n\t/** Whether upstream is currently paused by this controller. */\n\treadonly paused: boolean;\n\t/** Dispose: if paused, sends RESUME to unblock upstream. */\n\tdispose(): void;\n};\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nlet nextLockId = 0;\n\n/**\n * Creates a watermark-based backpressure controller.\n *\n * @param sendUp - Callback that delivers messages upstream (typically `handle.up`).\n * @param opts - High/low watermark thresholds (item counts).\n * @returns A {@link WatermarkController}.\n *\n * @example\n * ```ts\n * const handle = graph.observe(\"fast-source\");\n * const wm = createWatermarkController(\n * (msgs) => handle.up(msgs),\n * { highWaterMark: 64, lowWaterMark: 16 },\n * );\n *\n * // In sink callback:\n * handle.subscribe((msgs) => {\n * for (const msg of msgs) {\n * if (msg[0] === DATA) {\n * buffer.push(msg[1]);\n * wm.onEnqueue();\n * }\n * }\n * });\n *\n * // When consumer drains:\n * const item = buffer.shift();\n * wm.onDequeue();\n * ```\n *\n * @category extra\n */\nexport function createWatermarkController(\n\tsendUp: (messages: Messages) => void,\n\topts: WatermarkOptions,\n): WatermarkController {\n\tif (opts.highWaterMark < 1) throw new RangeError(\"highWaterMark must be >= 1\");\n\tif (opts.lowWaterMark < 0) throw new RangeError(\"lowWaterMark must be >= 0\");\n\tif (opts.lowWaterMark >= opts.highWaterMark)\n\t\tthrow new RangeError(\"lowWaterMark must be < highWaterMark\");\n\tconst lockId = Symbol(`bp-${++nextLockId}`);\n\tlet pending = 0;\n\tlet paused = false;\n\n\treturn {\n\t\tonEnqueue(): boolean {\n\t\t\tpending += 1;\n\t\t\tif (!paused && pending >= opts.highWaterMark) {\n\t\t\t\tpaused = true;\n\t\t\t\tsendUp([[PAUSE, lockId]]);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\tonDequeue(): boolean {\n\t\t\tif (pending > 0) pending -= 1;\n\t\t\tif (paused && pending <= opts.lowWaterMark) {\n\t\t\t\tpaused = false;\n\t\t\t\tsendUp([[RESUME, lockId]]);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\tget pending() {\n\t\t\treturn pending;\n\t\t},\n\t\tget paused() {\n\t\t\treturn paused;\n\t\t},\n\t\tdispose() {\n\t\t\tif (paused) {\n\t\t\t\tpaused = false;\n\t\t\t\tsendUp([[RESUME, lockId]]);\n\t\t\t}\n\t\t},\n\t};\n}\n","/**\n * Reactive append-only log (roadmap §3.2) — emits `readonly T[]` snapshots directly.\n *\n * Internal version counter drives efficient equality without leaking `Versioned`\n * into the public API (spec §5.12).\n *\n * **Wave 4 refactor (2026-04-15):** Introduces the `LogBackend<T>` pluggable-backend\n * interface. The default `NativeLogBackend` uses a ring buffer when `maxSize` is set\n * (O(1) append + trim) and a flat array otherwise. `tail(n)` and `slice(start, stop)`\n * are memoized — repeat calls with identical arguments return the same derived node,\n * bounding the keepalive-subscription footprint. The standalone `logSlice` factory\n * has been removed; use `log.slice(start, stop)` instead.\n */\nimport { batch } from \"../core/batch.js\";\nimport { DATA, DIRTY } from \"../core/messages.js\";\nimport type { Node } from \"../core/node.js\";\nimport { derived, state } from \"../core/sugar.js\";\nimport type { VersioningLevel } from \"../core/versioning.js\";\n\nexport type ReactiveLogOptions<T> = {\n\tname?: string;\n\tmaxSize?: number;\n\t/**\n\t * Optional versioning level for the underlying `entries` state node. Set\n\t * at construction time; cannot be changed later. Pass `0` for V0 identity\n\t * + monotonic version counter, or `1` for V1 + content-addressed cid.\n\t */\n\tversioning?: VersioningLevel;\n\t/**\n\t * Storage backend. Defaults to `NativeLogBackend` (ring buffer if `maxSize` is set,\n\t * flat array otherwise). Users can plug in persistent / RRB-tree backends via\n\t * the {@link LogBackend} interface.\n\t */\n\tbackend?: LogBackend<T>;\n};\n\nexport type ReactiveLogBundle<T> = {\n\t/** Emits `readonly T[]` on each append/clear/trim (two-phase). */\n\treadonly entries: Node<readonly T[]>;\n\t/** Current entry count (O(1)). */\n\treadonly size: number;\n\t/** Positional access (O(1)); returns `undefined` on out-of-range. Supports negative indices (Python-style). */\n\tat: (index: number) => T | undefined;\n\tappend: (value: T) => void;\n\t/**\n\t * Push all values, emit one snapshot. No-op if `values` is empty.\n\t * **Iterable consumption:** `values` is a `readonly T[]` — safe to pass arrays.\n\t */\n\tappendMany: (values: readonly T[]) => void;\n\tclear: () => void;\n\t/** Remove the first `n` entries (clamped to `size`). Throws on non-integer or negative `n`. */\n\ttrimHead: (n: number) => void;\n\t/**\n\t * Last `n` entries (or fewer) as a derived reactive view. Memoized with\n\t * an LRU cache (default cap 64) — repeat calls with the same `n` return\n\t * the same node. Throws on non-integer or negative `n`.\n\t *\n\t * **LRU eviction contract (D3(b)):** when a 65th distinct `n` is passed,\n\t * the least-recently-used cached view is evicted and its keepalive is\n\t * disposed. External holders of the evicted node will NOT receive further\n\t * updates — re-call `tail(n)` for a fresh node, or dispose proactively\n\t * via {@link disposeTail} / {@link disposeAllViews}. To avoid surprise:\n\t * resolve `tail(n)` at the point of use rather than caching the returned\n\t * node across many distinct `n`s.\n\t */\n\ttail: (n: number) => Node<readonly T[]>;\n\t/**\n\t * Reactive view of `entries.slice(start, stop)` — non-negative integer\n\t * `start`, non-negative integer `stop` (exclusive) or `undefined` (to end).\n\t * Memoized with an LRU cache (default cap 64) — repeat calls with the\n\t * same `(start, stop)` return the same node.\n\t *\n\t * Throws on non-integer `start`, negative `start`, non-integer `stop`, or\n\t * negative `stop` (P4 — the backend cannot cheaply honor JS-style\n\t * negative `stop` without scanning length; disallowed for a consistent\n\t * contract between backend, derived recomputation, and cached initial).\n\t *\n\t * **LRU eviction contract (D3(b)):** same as {@link tail} — past 64\n\t * distinct `(start, stop)` pairs, the oldest cached view is evicted and\n\t * its keepalive disposed. External holders stop receiving updates.\n\t */\n\tslice: (start: number, stop?: number) => Node<readonly T[]>;\n\t/**\n\t * Releases the cached `tail(n)` view if present (disposes its keepalive\n\t * subscription). Subsequent `tail(n)` calls create a fresh node. No-op if\n\t * `n` was not cached. Returns `true` if a view was disposed.\n\t */\n\tdisposeTail: (n: number) => boolean;\n\t/**\n\t * Releases the cached `slice(start, stop?)` view if present. No-op if not cached.\n\t */\n\tdisposeSlice: (start: number, stop?: number) => boolean;\n\t/** Releases all cached tail/slice views and their keepalive subscriptions. */\n\tdisposeAllViews: () => void;\n\t/**\n\t * Releases all internal keepalive subscriptions so the bundle can be\n\t * GC'd — currently equivalent to {@link disposeAllViews}, but exposed as\n\t * a uniform API across all reactive data structures for lifecycle\n\t * symmetry (mirrors `reactiveMap.dispose` / `reactiveList.dispose` /\n\t * `reactiveIndex.dispose`). Idempotent. D6(a).\n\t */\n\tdispose: () => void;\n};\n\n// ── Backend interface ─────────────────────────────────────────────────────\n\n/**\n * Storage contract for {@link reactiveLog}. Implementations own the mutable state and\n * expose a monotonic `version` counter that increments on every structural change.\n *\n * The reactive layer reads `version` to decide when to emit; it does not inspect\n * internal representation. Users can plug in persistent / ring-buffer / skip-list\n * backends without touching the reactive emission logic.\n *\n * @remarks Post-1.0 op-log changesets will extend this interface with a\n * `changesSince(version: number): Iterable<Change>` method. Current consumers\n * should treat all methods here as stable.\n *\n * @category extra\n */\nexport interface LogBackend<T> {\n\t/** Monotonic mutation counter; increments on every append/trim/clear that changes state. */\n\treadonly version: number;\n\t/** Number of entries currently stored. */\n\treadonly size: number;\n\t/** O(1) positional access; returns `undefined` on out-of-range. */\n\tat(index: number): T | undefined;\n\t/** Append a value. Applies `maxSize` head-drop if configured. Advances `version`. */\n\tappend(value: T): void;\n\t/** Append a batch; advances `version` once. No-op if `values.length === 0`. */\n\tappendMany(values: readonly T[]): void;\n\t/** Remove all entries. Returns count removed. Advances `version` only if non-zero. */\n\tclear(): number;\n\t/** Remove the first `n` entries (clamped). Returns count removed. Throws on negative `n`. */\n\ttrimHead(n: number): number;\n\t/** Fresh snapshot array for `[start, stop)`. Throws on negative `start`. */\n\tslice(start: number, stop?: number): readonly T[];\n\t/** Last `n` entries as a fresh array. Throws on negative `n`. */\n\ttail(n: number): readonly T[];\n\t/** Full snapshot as a fresh array. */\n\ttoArray(): readonly T[];\n}\n\n/**\n * Default append-only log backend.\n *\n * - When `maxSize` is set: uses a **ring buffer** with `_head` index and circular\n * modular arithmetic. Append and trim become O(1); snapshot is O(size) unrolling.\n * - When `maxSize` is unset: uses a flat array with standard push/splice.\n *\n * `appendMany` pre-trims oversize input: if `values.length > maxSize`, only the\n * tail of `values` is pushed (the rest would be immediately evicted).\n *\n * @category extra\n */\nexport class NativeLogBackend<T> implements LogBackend<T> {\n\tprivate _version = 0;\n\tprivate readonly _maxSize?: number;\n\tprivate readonly _buf: T[];\n\tprivate _head = 0;\n\tprivate _size = 0;\n\n\tconstructor(initial?: readonly T[], maxSize?: number) {\n\t\tif (maxSize !== undefined && maxSize < 1) {\n\t\t\tthrow new RangeError(\"maxSize must be >= 1\");\n\t\t}\n\t\tthis._maxSize = maxSize;\n\t\tif (maxSize !== undefined) {\n\t\t\t// Ring buffer mode — pre-allocate fixed size\n\t\t\tthis._buf = new Array(maxSize);\n\t\t\tif (initial && initial.length > 0) {\n\t\t\t\tconst take = Math.min(initial.length, maxSize);\n\t\t\t\tconst start = initial.length - take;\n\t\t\t\tfor (let i = 0; i < take; i++) {\n\t\t\t\t\tthis._buf[i] = initial[start + i]!;\n\t\t\t\t}\n\t\t\t\tthis._size = take;\n\t\t\t}\n\t\t} else {\n\t\t\t// Unbounded mode — dynamic array\n\t\t\tthis._buf = initial ? [...initial] : [];\n\t\t\tthis._size = this._buf.length;\n\t\t}\n\t}\n\n\tget version(): number {\n\t\treturn this._version;\n\t}\n\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\tat(index: number): T | undefined {\n\t\tif (!Number.isInteger(index)) return undefined;\n\t\t// P5: Python-style negative index — `-1` returns the last entry.\n\t\tconst i = index >= 0 ? index : this._size + index;\n\t\tif (i < 0 || i >= this._size) return undefined;\n\t\tif (this._maxSize !== undefined) {\n\t\t\treturn this._buf[(this._head + i) % this._maxSize];\n\t\t}\n\t\treturn this._buf[i];\n\t}\n\n\tappend(value: T): void {\n\t\tthis._rawAppend(value);\n\t\tthis._version += 1;\n\t}\n\n\tappendMany(values: readonly T[]): void {\n\t\tif (values.length === 0) return;\n\t\t// Pre-trim oversize input in ring mode — skip values that would be\n\t\t// immediately evicted. Iterate with a start index instead of\n\t\t// allocating an intermediate slice. F2.\n\t\tconst start =\n\t\t\tthis._maxSize !== undefined && values.length > this._maxSize\n\t\t\t\t? values.length - this._maxSize\n\t\t\t\t: 0;\n\t\tfor (let i = start; i < values.length; i++) {\n\t\t\tthis._rawAppend(values[i] as T);\n\t\t}\n\t\tthis._version += 1;\n\t}\n\n\tclear(): number {\n\t\tif (this._size === 0) return 0;\n\t\tconst n = this._size;\n\t\tif (this._maxSize === undefined) {\n\t\t\tthis._buf.length = 0;\n\t\t} else {\n\t\t\t// Ring buffer: only null the currently-live window so the GC can\n\t\t\t// reclaim ref-typed `T`. Iterating the full capacity would be O(cap)\n\t\t\t// even when only a few slots are in use (P6). Non-live slots are\n\t\t\t// already `undefined` (pre-allocation state) or whatever a prior\n\t\t\t// trim/clear left — they hold no live refs.\n\t\t\tfor (let i = 0; i < n; i++) {\n\t\t\t\tthis._buf[(this._head + i) % this._maxSize] = undefined as unknown as T;\n\t\t\t}\n\t\t}\n\t\tthis._head = 0;\n\t\tthis._size = 0;\n\t\tthis._version += 1;\n\t\treturn n;\n\t}\n\n\ttrimHead(n: number): number {\n\t\tif (!Number.isInteger(n) || n < 0) {\n\t\t\tthrow new RangeError(`trimHead: n must be a non-negative integer (got ${n})`);\n\t\t}\n\t\tif (n === 0 || this._size === 0) return 0;\n\t\tconst removed = Math.min(n, this._size);\n\t\tif (this._maxSize === undefined) {\n\t\t\tthis._buf.splice(0, removed);\n\t\t} else {\n\t\t\t// Null trimmed slots so the GC can reclaim ref-typed T (P4 extension).\n\t\t\tfor (let i = 0; i < removed; i++) {\n\t\t\t\tthis._buf[(this._head + i) % this._maxSize] = undefined as unknown as T;\n\t\t\t}\n\t\t\tthis._head = (this._head + removed) % this._maxSize;\n\t\t}\n\t\tthis._size -= removed;\n\t\tthis._version += 1;\n\t\treturn removed;\n\t}\n\n\tslice(start: number, stop?: number): readonly T[] {\n\t\tif (!Number.isInteger(start) || start < 0) {\n\t\t\tthrow new RangeError(`slice: start must be a non-negative integer (got ${start})`);\n\t\t}\n\t\t// P4: reject negative `stop` explicitly so the bundle / backend / derived\n\t\t// contract stays consistent. Previously stop was silently clamped to 0,\n\t\t// producing `[]` in the backend but a different value under JS semantics\n\t\t// in the derived recomputation — a latent bug for negative inputs.\n\t\tif (stop !== undefined && (!Number.isInteger(stop) || stop < 0)) {\n\t\t\tthrow new RangeError(`slice: stop must be a non-negative integer or undefined (got ${stop})`);\n\t\t}\n\t\tconst end = stop === undefined ? this._size : Math.min(Math.max(stop, 0), this._size);\n\t\tconst s = Math.min(start, this._size);\n\t\tif (s >= end) return [];\n\t\tconst len = end - s;\n\t\tif (this._maxSize === undefined) {\n\t\t\treturn this._buf.slice(s, end);\n\t\t}\n\t\tconst out: T[] = new Array(len);\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tout[i] = this._buf[(this._head + s + i) % this._maxSize]!;\n\t\t}\n\t\treturn out;\n\t}\n\n\ttail(n: number): readonly T[] {\n\t\tif (!Number.isInteger(n) || n < 0) {\n\t\t\tthrow new RangeError(`tail: n must be a non-negative integer (got ${n})`);\n\t\t}\n\t\tif (n === 0 || this._size === 0) return [];\n\t\tconst take = Math.min(n, this._size);\n\t\treturn this.slice(this._size - take, this._size);\n\t}\n\n\ttoArray(): readonly T[] {\n\t\tif (this._maxSize === undefined) {\n\t\t\treturn [...this._buf];\n\t\t}\n\t\tconst out: T[] = new Array(this._size);\n\t\tfor (let i = 0; i < this._size; i++) {\n\t\t\tout[i] = this._buf[(this._head + i) % this._maxSize]!;\n\t\t}\n\t\treturn out;\n\t}\n\n\t/** Internal append without version bump — used by `appendMany`. */\n\tprivate _rawAppend(value: T): void {\n\t\tif (this._maxSize === undefined) {\n\t\t\tthis._buf.push(value);\n\t\t\tthis._size = this._buf.length;\n\t\t\treturn;\n\t\t}\n\t\tif (this._size < this._maxSize) {\n\t\t\tthis._buf[(this._head + this._size) % this._maxSize] = value;\n\t\t\tthis._size += 1;\n\t\t} else {\n\t\t\t// Overwrite slot at head, advance head.\n\t\t\tthis._buf[this._head] = value;\n\t\t\tthis._head = (this._head + 1) % this._maxSize;\n\t\t}\n\t}\n}\n\n// ── Reactive wrapper ──────────────────────────────────────────────────────\n\n/** Installs a keepalive subscription; returns the disposer so callers can release it. */\nfunction keepaliveDerived(n: Node<unknown>): () => void {\n\treturn n.subscribe(() => {});\n}\n\n/** Default cap on the LRU view cache for `tail(n)` / `slice(start, stop?)`. D2(c). */\nconst DEFAULT_VIEW_CACHE_MAX = 64;\n\n/**\n * Creates an append-only reactive log with immutable array snapshots.\n *\n * @param initial - Optional seed entries (copied; pre-trimmed to `maxSize` if set).\n * @param options - `name`, `maxSize`, and optional pluggable `backend`.\n * @returns Bundle with `entries` (state node), `append`/`appendMany`/`clear`/`trimHead`,\n * `size` / `at`, and memoized derived views `tail(n)` / `slice(start, stop?)`.\n *\n * @remarks\n * **Backend:** The default {@link NativeLogBackend} uses a ring buffer when `maxSize`\n * is set (O(1) append + trim) and a flat array otherwise. For persistent/structural-\n * sharing semantics plug in a custom {@link LogBackend}.\n *\n * **`initial` + custom `backend` (F5):** When you supply `options.backend`, the\n * `initial` argument is IGNORED — seed the backend yourself before passing it in.\n * The `initial` seed only applies to the default `NativeLogBackend`.\n *\n * **Memoized views:** {@link ReactiveLogBundle.tail} and {@link ReactiveLogBundle.slice}\n * cache derived nodes per-argument. Repeat calls with the same `n` / `(start, stop)`\n * return the same node, bounding keepalive-subscription count to one per unique argument.\n *\n * @example\n * ```ts\n * import { reactiveLog } from \"@graphrefly/graphrefly-ts\";\n *\n * const lg = reactiveLog<number>([1, 2], { name: \"audit\", maxSize: 100 });\n * lg.append(3);\n * lg.entries.subscribe((msgs) => console.log(msgs));\n * const last5 = lg.tail(5); // derived node\n * const window = lg.slice(10, 20); // derived node\n * ```\n *\n * @category extra\n */\nexport function reactiveLog<T>(\n\tinitial?: readonly T[],\n\toptions: ReactiveLogOptions<T> = {},\n): ReactiveLogBundle<T> {\n\tconst { name, maxSize, versioning, backend: userBackend } = options;\n\tconst backend: LogBackend<T> = userBackend ?? new NativeLogBackend<T>(initial, maxSize);\n\n\tconst entries = state<readonly T[]>(backend.toArray(), {\n\t\tname,\n\t\tdescribeKind: \"state\",\n\t\tequals: (a, b) => a === b,\n\t\t...(versioning != null ? { versioning } : {}),\n\t});\n\n\tfunction pushSnapshot(): void {\n\t\tconst snapshot = backend.toArray();\n\t\tbatch(() => {\n\t\t\tentries.down([[DIRTY]]);\n\t\t\tentries.down([[DATA, snapshot]]);\n\t\t});\n\t}\n\n\t// Memoization caches for derived views (D2(c)). Each cache is an LRU keyed by\n\t// the unique view argument, bounded by `DEFAULT_VIEW_CACHE_MAX`. On cache miss\n\t// past the cap, the least-recently-used entry is evicted and its keepalive\n\t// disposer is called so the underlying derived node can be GC'd. Callers can\n\t// also release views proactively via `disposeTail` / `disposeSlice` /\n\t// `disposeAllViews`. Iteration order of `Map` is insertion order, so moving\n\t// an entry to the end on hit is the LRU \"touch\".\n\ttype ViewEntry = { node: Node<readonly T[]>; dispose: () => void };\n\tconst tailCache = new Map<number, ViewEntry>();\n\tconst sliceCache = new Map<string, ViewEntry>();\n\n\tfunction sliceKey(start: number, stop?: number): string {\n\t\treturn `${start}:${stop === undefined ? \"END\" : stop}`;\n\t}\n\n\tfunction evictOldestIfFull<K>(cache: Map<K, ViewEntry>): void {\n\t\tif (cache.size < DEFAULT_VIEW_CACHE_MAX) return;\n\t\tconst first = cache.keys().next();\n\t\tif (first.done) return;\n\t\tconst oldest = cache.get(first.value);\n\t\tif (oldest !== undefined) oldest.dispose();\n\t\tcache.delete(first.value);\n\t}\n\n\t/**\n\t * D4(a): try/finally defense-in-depth — if a custom backend op throws\n\t * mid-mutation, surface the partial state via pushSnapshot so subscribers\n\t * don't see a stale cache. Matches the pattern in reactive-map and\n\t * reactive-index. Native ops are atomic by contract; this only matters\n\t * for user-supplied backends.\n\t */\n\tfunction wrapMutation<R>(op: () => R): R {\n\t\tconst prev = backend.version;\n\t\ttry {\n\t\t\treturn op();\n\t\t} finally {\n\t\t\tif (backend.version !== prev) pushSnapshot();\n\t\t}\n\t}\n\n\treturn {\n\t\tentries,\n\n\t\tget size(): number {\n\t\t\treturn backend.size;\n\t\t},\n\n\t\tat(index: number): T | undefined {\n\t\t\treturn backend.at(index);\n\t\t},\n\n\t\tappend(value: T): void {\n\t\t\twrapMutation(() => backend.append(value));\n\t\t},\n\n\t\tappendMany(values: readonly T[]): void {\n\t\t\tif (values.length === 0) return;\n\t\t\twrapMutation(() => backend.appendMany(values));\n\t\t},\n\n\t\tclear(): void {\n\t\t\twrapMutation(() => backend.clear());\n\t\t\t// NOTE: cached tail/slice derived views are intentionally NOT\n\t\t\t// disposed here. Disposing would kill the keepalive on any node\n\t\t\t// a caller already holds externally, silently stopping their\n\t\t\t// updates. The derived nodes recompute from the new empty\n\t\t\t// snapshot when `entries` emits post-clear, so `.cache` on an\n\t\t\t// outstanding view settles to `[]` without any manual\n\t\t\t// reset. (Initial snapshots, if inspected before the next wave,\n\t\t\t// may be stale — callers who care can `disposeTail` / `slice`\n\t\t\t// explicitly.)\n\t\t},\n\n\t\ttrimHead(n: number): void {\n\t\t\twrapMutation(() => backend.trimHead(n));\n\t\t},\n\n\t\ttail(n: number): Node<readonly T[]> {\n\t\t\tif (!Number.isInteger(n) || n < 0) {\n\t\t\t\tthrow new RangeError(`tail: n must be a non-negative integer (got ${n})`);\n\t\t\t}\n\t\t\tconst hit = tailCache.get(n);\n\t\t\tif (hit !== undefined) {\n\t\t\t\t// LRU touch: move to end of insertion order.\n\t\t\t\ttailCache.delete(n);\n\t\t\t\ttailCache.set(n, hit);\n\t\t\t\treturn hit.node;\n\t\t\t}\n\t\t\tevictOldestIfFull(tailCache);\n\t\t\tconst node_ = derived(\n\t\t\t\t[entries],\n\t\t\t\t([s]) => {\n\t\t\t\t\tconst list = s as readonly T[];\n\t\t\t\t\tif (n === 0 || list.length === 0) return [];\n\t\t\t\t\treturn list.slice(Math.max(0, list.length - n));\n\t\t\t\t},\n\t\t\t\t{ initial: backend.tail(n), describeKind: \"derived\" },\n\t\t\t);\n\t\t\tconst dispose = keepaliveDerived(node_);\n\t\t\ttailCache.set(n, { node: node_, dispose });\n\t\t\treturn node_;\n\t\t},\n\n\t\tslice(start: number, stop?: number): Node<readonly T[]> {\n\t\t\tif (!Number.isInteger(start) || start < 0) {\n\t\t\t\tthrow new RangeError(`slice: start must be a non-negative integer (got ${start})`);\n\t\t\t}\n\t\t\t// P4: reject negative stop explicitly to keep bundle / backend / derived\n\t\t\t// consistent (JS `Array.prototype.slice` supports negative stop, but the\n\t\t\t// backend can't cheaply honor it without scanning length, so we disallow).\n\t\t\tif (stop !== undefined && (!Number.isInteger(stop) || stop < 0)) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`slice: stop must be a non-negative integer or undefined (got ${stop})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst key = sliceKey(start, stop);\n\t\t\tconst hit = sliceCache.get(key);\n\t\t\tif (hit !== undefined) {\n\t\t\t\tsliceCache.delete(key);\n\t\t\t\tsliceCache.set(key, hit);\n\t\t\t\treturn hit.node;\n\t\t\t}\n\t\t\tevictOldestIfFull(sliceCache);\n\t\t\tconst node_ = derived(\n\t\t\t\t[entries],\n\t\t\t\t([s]) => {\n\t\t\t\t\tconst list = s as readonly T[];\n\t\t\t\t\treturn stop === undefined ? list.slice(start) : list.slice(start, stop);\n\t\t\t\t},\n\t\t\t\t{ initial: backend.slice(start, stop), describeKind: \"derived\" },\n\t\t\t);\n\t\t\tconst dispose = keepaliveDerived(node_);\n\t\t\tsliceCache.set(key, { node: node_, dispose });\n\t\t\treturn node_;\n\t\t},\n\n\t\tdisposeTail(n: number): boolean {\n\t\t\tconst hit = tailCache.get(n);\n\t\t\tif (hit === undefined) return false;\n\t\t\thit.dispose();\n\t\t\ttailCache.delete(n);\n\t\t\treturn true;\n\t\t},\n\n\t\tdisposeSlice(start: number, stop?: number): boolean {\n\t\t\tconst key = sliceKey(start, stop);\n\t\t\tconst hit = sliceCache.get(key);\n\t\t\tif (hit === undefined) return false;\n\t\t\thit.dispose();\n\t\t\tsliceCache.delete(key);\n\t\t\treturn true;\n\t\t},\n\n\t\tdisposeAllViews(): void {\n\t\t\tfor (const entry of tailCache.values()) entry.dispose();\n\t\t\ttailCache.clear();\n\t\t\tfor (const entry of sliceCache.values()) entry.dispose();\n\t\t\tsliceCache.clear();\n\t\t},\n\n\t\tdispose(): void {\n\t\t\t// D6(a): currently identical to disposeAllViews. Exposed as a\n\t\t\t// uniform lifecycle API across all 4 reactive data structures.\n\t\t\tfor (const entry of tailCache.values()) entry.dispose();\n\t\t\ttailCache.clear();\n\t\t\tfor (const entry of sliceCache.values()) entry.dispose();\n\t\t\tsliceCache.clear();\n\t\t},\n\t};\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/extra/observable.ts","../src/extra/backpressure.ts","../src/extra/reactive-log.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// RxJS bridge — reactive interop between GraphReFly nodes and RxJS Observables.\n// ---------------------------------------------------------------------------\n// Usage:\n// import { toObservable } from '@graphrefly/graphrefly-ts/extra';\n// const values$ = toObservable(myNode); // Observable<T>\n// const msgs$ = toObservable(myNode, { raw: true }); // Observable<Messages>\n// ---------------------------------------------------------------------------\n\nimport { Observable } from \"rxjs\";\nimport { COMPLETE, DATA, ERROR, type Messages } from \"../core/messages.js\";\nimport type { Node } from \"../core/node.js\";\n\n/** Options for {@link toObservable}. */\nexport type ToObservableOptions = {\n\t/**\n\t * When `true`, emit raw `Messages` batches instead of extracted `DATA` values.\n\t * Terminal batches are still emitted as the final `next()` before the\n\t * Observable signal (error/complete).\n\t */\n\traw?: boolean;\n};\n\n/**\n * Bridge a `Node<T>` to an RxJS `Observable`.\n *\n * Default mode emits the node's value on each `DATA` message. Maps `ERROR` to\n * `subscriber.error()` and `COMPLETE` to `subscriber.complete()`.\n * Protocol-internal signals (DIRTY, RESOLVED, PAUSE, etc.) are skipped.\n *\n * With `{ raw: true }`, emits full `[[Type, Data?], ...]` message batches.\n * The Observable terminates on ERROR or COMPLETE (the terminal batch is still\n * emitted as the final `next()` before the Observable signal).\n *\n * For graph-level observation, use `toObservable(graph.resolve(path))` or\n * subscribe to `graph.observe()` directly.\n *\n * Unsubscribing the Observable unsubscribes the node.\n */\nexport function toObservable<T>(\n\tnode: Node<T>,\n\toptions?: ToObservableOptions & { raw?: false },\n): Observable<T>;\nexport function toObservable<T>(\n\tnode: Node<T>,\n\toptions: ToObservableOptions & { raw: true },\n): Observable<Messages>;\nexport function toObservable<T>(\n\tnode: Node<T>,\n\toptions?: ToObservableOptions,\n): Observable<T | Messages> {\n\tif (options?.raw) {\n\t\treturn new Observable<Messages>((subscriber) => {\n\t\t\tconst unsub = node.subscribe((msgs) => {\n\t\t\t\tif (subscriber.closed) return;\n\t\t\t\tsubscriber.next(msgs);\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\t\tsubscriber.error(m[1]);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\t\tsubscriber.complete();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn unsub;\n\t\t});\n\t}\n\n\treturn new Observable<T>((subscriber) => {\n\t\tconst unsub = node.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (subscriber.closed) return;\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tsubscriber.next(m[1] as T);\n\t\t\t\t} else if (m[0] === ERROR) {\n\t\t\t\t\tsubscriber.error(m[1]);\n\t\t\t\t\treturn;\n\t\t\t\t} else if (m[0] === COMPLETE) {\n\t\t\t\t\tsubscriber.complete();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn unsub;\n\t});\n}\n","/**\n * Watermark-based backpressure controller — reactive PAUSE/RESUME flow control.\n *\n * Purely synchronous, event-driven. No timers, no polling, no Promises.\n * Each controller instance uses a unique lockId so multiple controllers\n * on the same upstream node do not collide.\n *\n * @module\n */\n\nimport { type Messages, PAUSE, RESUME } from \"../core/messages.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type WatermarkOptions = {\n\t/** Pending count at which PAUSE is sent upstream. */\n\thighWaterMark: number;\n\t/** Pending count at which RESUME is sent upstream (after being paused). */\n\tlowWaterMark: number;\n};\n\nexport type WatermarkController = {\n\t/** Call when a DATA message is buffered/enqueued. Returns `true` if PAUSE was just sent. */\n\tonEnqueue(): boolean;\n\t/** Call when a buffered item is consumed. Returns `true` if RESUME was just sent. */\n\tonDequeue(): boolean;\n\t/** Current un-consumed item count. */\n\treadonly pending: number;\n\t/** Whether upstream is currently paused by this controller. */\n\treadonly paused: boolean;\n\t/** Dispose: if paused, sends RESUME to unblock upstream. */\n\tdispose(): void;\n};\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nlet nextLockId = 0;\n\n/**\n * Creates a watermark-based backpressure controller.\n *\n * @param sendUp - Callback that delivers messages upstream (typically `handle.up`).\n * @param opts - High/low watermark thresholds (item counts).\n * @returns A {@link WatermarkController}.\n *\n * @example\n * ```ts\n * const handle = graph.observe(\"fast-source\");\n * const wm = createWatermarkController(\n * (msgs) => handle.up(msgs),\n * { highWaterMark: 64, lowWaterMark: 16 },\n * );\n *\n * // In sink callback:\n * handle.subscribe((msgs) => {\n * for (const msg of msgs) {\n * if (msg[0] === DATA) {\n * buffer.push(msg[1]);\n * wm.onEnqueue();\n * }\n * }\n * });\n *\n * // When consumer drains:\n * const item = buffer.shift();\n * wm.onDequeue();\n * ```\n *\n * @category extra\n */\nexport function createWatermarkController(\n\tsendUp: (messages: Messages) => void,\n\topts: WatermarkOptions,\n): WatermarkController {\n\tif (opts.highWaterMark < 1) throw new RangeError(\"highWaterMark must be >= 1\");\n\tif (opts.lowWaterMark < 0) throw new RangeError(\"lowWaterMark must be >= 0\");\n\tif (opts.lowWaterMark >= opts.highWaterMark)\n\t\tthrow new RangeError(\"lowWaterMark must be < highWaterMark\");\n\tconst lockId = Symbol(`bp-${++nextLockId}`);\n\tlet pending = 0;\n\tlet paused = false;\n\n\treturn {\n\t\tonEnqueue(): boolean {\n\t\t\tpending += 1;\n\t\t\tif (!paused && pending >= opts.highWaterMark) {\n\t\t\t\tpaused = true;\n\t\t\t\tsendUp([[PAUSE, lockId]]);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\tonDequeue(): boolean {\n\t\t\tif (pending > 0) pending -= 1;\n\t\t\tif (paused && pending <= opts.lowWaterMark) {\n\t\t\t\tpaused = false;\n\t\t\t\tsendUp([[RESUME, lockId]]);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\tget pending() {\n\t\t\treturn pending;\n\t\t},\n\t\tget paused() {\n\t\t\treturn paused;\n\t\t},\n\t\tdispose() {\n\t\t\tif (paused) {\n\t\t\t\tpaused = false;\n\t\t\t\tsendUp([[RESUME, lockId]]);\n\t\t\t}\n\t\t},\n\t};\n}\n","/**\n * Reactive append-only log (roadmap §3.2) — emits `readonly T[]` snapshots directly.\n *\n * Internal version counter drives efficient equality without leaking `Versioned`\n * into the public API (spec §5.12).\n *\n * **Wave 4 refactor (2026-04-15):** Introduces the `LogBackend<T>` pluggable-backend\n * interface. The default `NativeLogBackend` uses a ring buffer when `maxSize` is set\n * (O(1) append + trim) and a flat array otherwise. `tail(n)` and `slice(start, stop)`\n * are memoized — repeat calls with identical arguments return the same derived node,\n * bounding the keepalive-subscription footprint. The standalone `logSlice` factory\n * has been removed; use `log.slice(start, stop)` instead.\n */\nimport { batch } from \"../core/batch.js\";\nimport { DATA, DIRTY } from \"../core/messages.js\";\nimport type { Node } from \"../core/node.js\";\nimport { derived, state } from \"../core/sugar.js\";\nimport type { VersioningLevel } from \"../core/versioning.js\";\n\nexport type ReactiveLogOptions<T> = {\n\tname?: string;\n\tmaxSize?: number;\n\t/**\n\t * Optional versioning level for the underlying `entries` state node. Set\n\t * at construction time; cannot be changed later. Pass `0` for V0 identity\n\t * + monotonic version counter, or `1` for V1 + content-addressed cid.\n\t */\n\tversioning?: VersioningLevel;\n\t/**\n\t * Storage backend. Defaults to `NativeLogBackend` (ring buffer if `maxSize` is set,\n\t * flat array otherwise). Users can plug in persistent / RRB-tree backends via\n\t * the {@link LogBackend} interface.\n\t */\n\tbackend?: LogBackend<T>;\n};\n\nexport type ReactiveLogBundle<T> = {\n\t/** Emits `readonly T[]` on each append/clear/trim (two-phase). */\n\treadonly entries: Node<readonly T[]>;\n\t/** Current entry count (O(1)). */\n\treadonly size: number;\n\t/** Positional access (O(1)); returns `undefined` on out-of-range. Supports negative indices (Python-style). */\n\tat: (index: number) => T | undefined;\n\tappend: (value: T) => void;\n\t/**\n\t * Push all values, emit one snapshot. No-op if `values` is empty.\n\t * **Iterable consumption:** `values` is a `readonly T[]` — safe to pass arrays.\n\t */\n\tappendMany: (values: readonly T[]) => void;\n\tclear: () => void;\n\t/** Remove the first `n` entries (clamped to `size`). Throws on non-integer or negative `n`. */\n\ttrimHead: (n: number) => void;\n\t/**\n\t * Last `n` entries (or fewer) as a derived reactive view. Memoized with\n\t * an LRU cache (default cap 64) — repeat calls with the same `n` return\n\t * the same node. Throws on non-integer or negative `n`.\n\t *\n\t * **LRU eviction contract (D3(b)):** when a 65th distinct `n` is passed,\n\t * the least-recently-used cached view is evicted and its keepalive is\n\t * disposed. External holders of the evicted node will NOT receive further\n\t * updates — re-call `tail(n)` for a fresh node, or dispose proactively\n\t * via {@link disposeTail} / {@link disposeAllViews}. To avoid surprise:\n\t * resolve `tail(n)` at the point of use rather than caching the returned\n\t * node across many distinct `n`s.\n\t */\n\ttail: (n: number) => Node<readonly T[]>;\n\t/**\n\t * Reactive view of `entries.slice(start, stop)` — non-negative integer\n\t * `start`, non-negative integer `stop` (exclusive) or `undefined` (to end).\n\t * Memoized with an LRU cache (default cap 64) — repeat calls with the\n\t * same `(start, stop)` return the same node.\n\t *\n\t * Throws on non-integer `start`, negative `start`, non-integer `stop`, or\n\t * negative `stop` (P4 — the backend cannot cheaply honor JS-style\n\t * negative `stop` without scanning length; disallowed for a consistent\n\t * contract between backend, derived recomputation, and cached initial).\n\t *\n\t * **LRU eviction contract (D3(b)):** same as {@link tail} — past 64\n\t * distinct `(start, stop)` pairs, the oldest cached view is evicted and\n\t * its keepalive disposed. External holders stop receiving updates.\n\t */\n\tslice: (start: number, stop?: number) => Node<readonly T[]>;\n\t/**\n\t * Releases the cached `tail(n)` view if present (disposes its keepalive\n\t * subscription). Subsequent `tail(n)` calls create a fresh node. No-op if\n\t * `n` was not cached. Returns `true` if a view was disposed.\n\t */\n\tdisposeTail: (n: number) => boolean;\n\t/**\n\t * Releases the cached `slice(start, stop?)` view if present. No-op if not cached.\n\t */\n\tdisposeSlice: (start: number, stop?: number) => boolean;\n\t/** Releases all cached tail/slice views and their keepalive subscriptions. */\n\tdisposeAllViews: () => void;\n\t/**\n\t * Releases all internal keepalive subscriptions so the bundle can be\n\t * GC'd — currently equivalent to {@link disposeAllViews}, but exposed as\n\t * a uniform API across all reactive data structures for lifecycle\n\t * symmetry (mirrors `reactiveMap.dispose` / `reactiveList.dispose` /\n\t * `reactiveIndex.dispose`). Idempotent. D6(a).\n\t */\n\tdispose: () => void;\n};\n\n// ── Backend interface ─────────────────────────────────────────────────────\n\n/**\n * Storage contract for {@link reactiveLog}. Implementations own the mutable state and\n * expose a monotonic `version` counter that increments on every structural change.\n *\n * The reactive layer reads `version` to decide when to emit; it does not inspect\n * internal representation. Users can plug in persistent / ring-buffer / skip-list\n * backends without touching the reactive emission logic.\n *\n * @remarks Post-1.0 op-log changesets will extend this interface with a\n * `changesSince(version: number): Iterable<Change>` method. Current consumers\n * should treat all methods here as stable.\n *\n * @category extra\n */\nexport interface LogBackend<T> {\n\t/** Monotonic mutation counter; increments on every append/trim/clear that changes state. */\n\treadonly version: number;\n\t/** Number of entries currently stored. */\n\treadonly size: number;\n\t/** O(1) positional access; returns `undefined` on out-of-range. */\n\tat(index: number): T | undefined;\n\t/** Append a value. Applies `maxSize` head-drop if configured. Advances `version`. */\n\tappend(value: T): void;\n\t/** Append a batch; advances `version` once. No-op if `values.length === 0`. */\n\tappendMany(values: readonly T[]): void;\n\t/** Remove all entries. Returns count removed. Advances `version` only if non-zero. */\n\tclear(): number;\n\t/** Remove the first `n` entries (clamped). Returns count removed. Throws on negative `n`. */\n\ttrimHead(n: number): number;\n\t/** Fresh snapshot array for `[start, stop)`. Throws on negative `start`. */\n\tslice(start: number, stop?: number): readonly T[];\n\t/** Last `n` entries as a fresh array. Throws on negative `n`. */\n\ttail(n: number): readonly T[];\n\t/** Full snapshot as a fresh array. */\n\ttoArray(): readonly T[];\n}\n\n/**\n * Default append-only log backend.\n *\n * - When `maxSize` is set: uses a **ring buffer** with `_head` index and circular\n * modular arithmetic. Append and trim become O(1); snapshot is O(size) unrolling.\n * - When `maxSize` is unset: uses a flat array with standard push/splice.\n *\n * `appendMany` pre-trims oversize input: if `values.length > maxSize`, only the\n * tail of `values` is pushed (the rest would be immediately evicted).\n *\n * @category extra\n */\nexport class NativeLogBackend<T> implements LogBackend<T> {\n\tprivate _version = 0;\n\tprivate readonly _maxSize?: number;\n\tprivate readonly _buf: T[];\n\tprivate _head = 0;\n\tprivate _size = 0;\n\n\tconstructor(initial?: readonly T[], maxSize?: number) {\n\t\tif (maxSize !== undefined && maxSize < 1) {\n\t\t\tthrow new RangeError(\"maxSize must be >= 1\");\n\t\t}\n\t\tthis._maxSize = maxSize;\n\t\tif (maxSize !== undefined) {\n\t\t\t// Ring buffer mode — pre-allocate fixed size\n\t\t\tthis._buf = new Array(maxSize);\n\t\t\tif (initial && initial.length > 0) {\n\t\t\t\tconst take = Math.min(initial.length, maxSize);\n\t\t\t\tconst start = initial.length - take;\n\t\t\t\tfor (let i = 0; i < take; i++) {\n\t\t\t\t\tthis._buf[i] = initial[start + i]!;\n\t\t\t\t}\n\t\t\t\tthis._size = take;\n\t\t\t}\n\t\t} else {\n\t\t\t// Unbounded mode — dynamic array\n\t\t\tthis._buf = initial ? [...initial] : [];\n\t\t\tthis._size = this._buf.length;\n\t\t}\n\t}\n\n\tget version(): number {\n\t\treturn this._version;\n\t}\n\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\tat(index: number): T | undefined {\n\t\tif (!Number.isInteger(index)) return undefined;\n\t\t// P5: Python-style negative index — `-1` returns the last entry.\n\t\tconst i = index >= 0 ? index : this._size + index;\n\t\tif (i < 0 || i >= this._size) return undefined;\n\t\tif (this._maxSize !== undefined) {\n\t\t\treturn this._buf[(this._head + i) % this._maxSize];\n\t\t}\n\t\treturn this._buf[i];\n\t}\n\n\tappend(value: T): void {\n\t\tthis._rawAppend(value);\n\t\tthis._version += 1;\n\t}\n\n\tappendMany(values: readonly T[]): void {\n\t\tif (values.length === 0) return;\n\t\t// Pre-trim oversize input in ring mode — skip values that would be\n\t\t// immediately evicted. Iterate with a start index instead of\n\t\t// allocating an intermediate slice. F2.\n\t\tconst start =\n\t\t\tthis._maxSize !== undefined && values.length > this._maxSize\n\t\t\t\t? values.length - this._maxSize\n\t\t\t\t: 0;\n\t\tfor (let i = start; i < values.length; i++) {\n\t\t\tthis._rawAppend(values[i] as T);\n\t\t}\n\t\tthis._version += 1;\n\t}\n\n\tclear(): number {\n\t\tif (this._size === 0) return 0;\n\t\tconst n = this._size;\n\t\tif (this._maxSize === undefined) {\n\t\t\tthis._buf.length = 0;\n\t\t} else {\n\t\t\t// Ring buffer: only null the currently-live window so the GC can\n\t\t\t// reclaim ref-typed `T`. Iterating the full capacity would be O(cap)\n\t\t\t// even when only a few slots are in use (P6). Non-live slots are\n\t\t\t// already `undefined` (pre-allocation state) or whatever a prior\n\t\t\t// trim/clear left — they hold no live refs.\n\t\t\tfor (let i = 0; i < n; i++) {\n\t\t\t\tthis._buf[(this._head + i) % this._maxSize] = undefined as unknown as T;\n\t\t\t}\n\t\t}\n\t\tthis._head = 0;\n\t\tthis._size = 0;\n\t\tthis._version += 1;\n\t\treturn n;\n\t}\n\n\ttrimHead(n: number): number {\n\t\tif (!Number.isInteger(n) || n < 0) {\n\t\t\tthrow new RangeError(`trimHead: n must be a non-negative integer (got ${n})`);\n\t\t}\n\t\tif (n === 0 || this._size === 0) return 0;\n\t\tconst removed = Math.min(n, this._size);\n\t\tif (this._maxSize === undefined) {\n\t\t\tthis._buf.splice(0, removed);\n\t\t} else {\n\t\t\t// Null trimmed slots so the GC can reclaim ref-typed T (P4 extension).\n\t\t\tfor (let i = 0; i < removed; i++) {\n\t\t\t\tthis._buf[(this._head + i) % this._maxSize] = undefined as unknown as T;\n\t\t\t}\n\t\t\tthis._head = (this._head + removed) % this._maxSize;\n\t\t}\n\t\tthis._size -= removed;\n\t\tthis._version += 1;\n\t\treturn removed;\n\t}\n\n\tslice(start: number, stop?: number): readonly T[] {\n\t\tif (!Number.isInteger(start) || start < 0) {\n\t\t\tthrow new RangeError(`slice: start must be a non-negative integer (got ${start})`);\n\t\t}\n\t\t// P4: reject negative `stop` explicitly so the bundle / backend / derived\n\t\t// contract stays consistent. Previously stop was silently clamped to 0,\n\t\t// producing `[]` in the backend but a different value under JS semantics\n\t\t// in the derived recomputation — a latent bug for negative inputs.\n\t\tif (stop !== undefined && (!Number.isInteger(stop) || stop < 0)) {\n\t\t\tthrow new RangeError(`slice: stop must be a non-negative integer or undefined (got ${stop})`);\n\t\t}\n\t\tconst end = stop === undefined ? this._size : Math.min(Math.max(stop, 0), this._size);\n\t\tconst s = Math.min(start, this._size);\n\t\tif (s >= end) return [];\n\t\tconst len = end - s;\n\t\tif (this._maxSize === undefined) {\n\t\t\treturn this._buf.slice(s, end);\n\t\t}\n\t\tconst out: T[] = new Array(len);\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tout[i] = this._buf[(this._head + s + i) % this._maxSize]!;\n\t\t}\n\t\treturn out;\n\t}\n\n\ttail(n: number): readonly T[] {\n\t\tif (!Number.isInteger(n) || n < 0) {\n\t\t\tthrow new RangeError(`tail: n must be a non-negative integer (got ${n})`);\n\t\t}\n\t\tif (n === 0 || this._size === 0) return [];\n\t\tconst take = Math.min(n, this._size);\n\t\treturn this.slice(this._size - take, this._size);\n\t}\n\n\ttoArray(): readonly T[] {\n\t\tif (this._maxSize === undefined) {\n\t\t\treturn [...this._buf];\n\t\t}\n\t\tconst out: T[] = new Array(this._size);\n\t\tfor (let i = 0; i < this._size; i++) {\n\t\t\tout[i] = this._buf[(this._head + i) % this._maxSize]!;\n\t\t}\n\t\treturn out;\n\t}\n\n\t/** Internal append without version bump — used by `appendMany`. */\n\tprivate _rawAppend(value: T): void {\n\t\tif (this._maxSize === undefined) {\n\t\t\tthis._buf.push(value);\n\t\t\tthis._size = this._buf.length;\n\t\t\treturn;\n\t\t}\n\t\tif (this._size < this._maxSize) {\n\t\t\tthis._buf[(this._head + this._size) % this._maxSize] = value;\n\t\t\tthis._size += 1;\n\t\t} else {\n\t\t\t// Overwrite slot at head, advance head.\n\t\t\tthis._buf[this._head] = value;\n\t\t\tthis._head = (this._head + 1) % this._maxSize;\n\t\t}\n\t}\n}\n\n// ── Reactive wrapper ──────────────────────────────────────────────────────\n\n/** Installs a keepalive subscription; returns the disposer so callers can release it. */\nfunction keepaliveDerived(n: Node<unknown>): () => void {\n\treturn n.subscribe(() => {});\n}\n\n/** Default cap on the LRU view cache for `tail(n)` / `slice(start, stop?)`. D2(c). */\nconst DEFAULT_VIEW_CACHE_MAX = 64;\n\n/**\n * Creates an append-only reactive log with immutable array snapshots.\n *\n * @param initial - Optional seed entries (copied; pre-trimmed to `maxSize` if set).\n * @param options - `name`, `maxSize`, and optional pluggable `backend`.\n * @returns Bundle with `entries` (state node), `append`/`appendMany`/`clear`/`trimHead`,\n * `size` / `at`, and memoized derived views `tail(n)` / `slice(start, stop?)`.\n *\n * @remarks\n * **Backend:** The default {@link NativeLogBackend} uses a ring buffer when `maxSize`\n * is set (O(1) append + trim) and a flat array otherwise. For persistent/structural-\n * sharing semantics plug in a custom {@link LogBackend}.\n *\n * **`initial` + custom `backend` (F5):** When you supply `options.backend`, the\n * `initial` argument is IGNORED — seed the backend yourself before passing it in.\n * The `initial` seed only applies to the default `NativeLogBackend`.\n *\n * **Memoized views:** {@link ReactiveLogBundle.tail} and {@link ReactiveLogBundle.slice}\n * cache derived nodes per-argument. Repeat calls with the same `n` / `(start, stop)`\n * return the same node, bounding keepalive-subscription count to one per unique argument.\n *\n * @example\n * ```ts\n * import { reactiveLog } from \"@graphrefly/graphrefly-ts\";\n *\n * const lg = reactiveLog<number>([1, 2], { name: \"audit\", maxSize: 100 });\n * lg.append(3);\n * lg.entries.subscribe((msgs) => console.log(msgs));\n * const last5 = lg.tail(5); // derived node\n * const window = lg.slice(10, 20); // derived node\n * ```\n *\n * @category extra\n */\nexport function reactiveLog<T>(\n\tinitial?: readonly T[],\n\toptions: ReactiveLogOptions<T> = {},\n): ReactiveLogBundle<T> {\n\tconst { name, maxSize, versioning, backend: userBackend } = options;\n\tconst backend: LogBackend<T> = userBackend ?? new NativeLogBackend<T>(initial, maxSize);\n\n\tconst entries = state<readonly T[]>(backend.toArray(), {\n\t\tname,\n\t\tdescribeKind: \"state\",\n\t\tequals: (a, b) => a === b,\n\t\t...(versioning != null ? { versioning } : {}),\n\t});\n\n\tfunction pushSnapshot(): void {\n\t\tconst snapshot = backend.toArray();\n\t\tbatch(() => {\n\t\t\tentries.down([[DIRTY]]);\n\t\t\tentries.down([[DATA, snapshot]]);\n\t\t});\n\t}\n\n\t// Memoization caches for derived views (D2(c)). Each cache is an LRU keyed by\n\t// the unique view argument, bounded by `DEFAULT_VIEW_CACHE_MAX`. On cache miss\n\t// past the cap, the least-recently-used entry is evicted and its keepalive\n\t// disposer is called so the underlying derived node can be GC'd. Callers can\n\t// also release views proactively via `disposeTail` / `disposeSlice` /\n\t// `disposeAllViews`. Iteration order of `Map` is insertion order, so moving\n\t// an entry to the end on hit is the LRU \"touch\".\n\ttype ViewEntry = { node: Node<readonly T[]>; dispose: () => void };\n\tconst tailCache = new Map<number, ViewEntry>();\n\tconst sliceCache = new Map<string, ViewEntry>();\n\n\tfunction sliceKey(start: number, stop?: number): string {\n\t\treturn `${start}:${stop === undefined ? \"END\" : stop}`;\n\t}\n\n\tfunction evictOldestIfFull<K>(cache: Map<K, ViewEntry>): void {\n\t\tif (cache.size < DEFAULT_VIEW_CACHE_MAX) return;\n\t\tconst first = cache.keys().next();\n\t\tif (first.done) return;\n\t\tconst oldest = cache.get(first.value);\n\t\tif (oldest !== undefined) oldest.dispose();\n\t\tcache.delete(first.value);\n\t}\n\n\t/**\n\t * D4(a): try/finally defense-in-depth — if a custom backend op throws\n\t * mid-mutation, surface the partial state via pushSnapshot so subscribers\n\t * don't see a stale cache. Matches the pattern in reactive-map and\n\t * reactive-index. Native ops are atomic by contract; this only matters\n\t * for user-supplied backends.\n\t */\n\tfunction wrapMutation<R>(op: () => R): R {\n\t\tconst prev = backend.version;\n\t\ttry {\n\t\t\treturn op();\n\t\t} finally {\n\t\t\tif (backend.version !== prev) pushSnapshot();\n\t\t}\n\t}\n\n\treturn {\n\t\tentries,\n\n\t\tget size(): number {\n\t\t\treturn backend.size;\n\t\t},\n\n\t\tat(index: number): T | undefined {\n\t\t\treturn backend.at(index);\n\t\t},\n\n\t\tappend(value: T): void {\n\t\t\twrapMutation(() => backend.append(value));\n\t\t},\n\n\t\tappendMany(values: readonly T[]): void {\n\t\t\tif (values.length === 0) return;\n\t\t\twrapMutation(() => backend.appendMany(values));\n\t\t},\n\n\t\tclear(): void {\n\t\t\twrapMutation(() => backend.clear());\n\t\t\t// NOTE: cached tail/slice derived views are intentionally NOT\n\t\t\t// disposed here. Disposing would kill the keepalive on any node\n\t\t\t// a caller already holds externally, silently stopping their\n\t\t\t// updates. The derived nodes recompute from the new empty\n\t\t\t// snapshot when `entries` emits post-clear, so `.cache` on an\n\t\t\t// outstanding view settles to `[]` without any manual\n\t\t\t// reset. (Initial snapshots, if inspected before the next wave,\n\t\t\t// may be stale — callers who care can `disposeTail` / `slice`\n\t\t\t// explicitly.)\n\t\t},\n\n\t\ttrimHead(n: number): void {\n\t\t\twrapMutation(() => backend.trimHead(n));\n\t\t},\n\n\t\ttail(n: number): Node<readonly T[]> {\n\t\t\tif (!Number.isInteger(n) || n < 0) {\n\t\t\t\tthrow new RangeError(`tail: n must be a non-negative integer (got ${n})`);\n\t\t\t}\n\t\t\tconst hit = tailCache.get(n);\n\t\t\tif (hit !== undefined) {\n\t\t\t\t// LRU touch: move to end of insertion order.\n\t\t\t\ttailCache.delete(n);\n\t\t\t\ttailCache.set(n, hit);\n\t\t\t\treturn hit.node;\n\t\t\t}\n\t\t\tevictOldestIfFull(tailCache);\n\t\t\tconst node_ = derived(\n\t\t\t\t[entries],\n\t\t\t\t([s]) => {\n\t\t\t\t\tconst list = s as readonly T[];\n\t\t\t\t\tif (n === 0 || list.length === 0) return [];\n\t\t\t\t\treturn list.slice(Math.max(0, list.length - n));\n\t\t\t\t},\n\t\t\t\t{ initial: backend.tail(n), describeKind: \"derived\" },\n\t\t\t);\n\t\t\tconst dispose = keepaliveDerived(node_);\n\t\t\ttailCache.set(n, { node: node_, dispose });\n\t\t\treturn node_;\n\t\t},\n\n\t\tslice(start: number, stop?: number): Node<readonly T[]> {\n\t\t\tif (!Number.isInteger(start) || start < 0) {\n\t\t\t\tthrow new RangeError(`slice: start must be a non-negative integer (got ${start})`);\n\t\t\t}\n\t\t\t// P4: reject negative stop explicitly to keep bundle / backend / derived\n\t\t\t// consistent (JS `Array.prototype.slice` supports negative stop, but the\n\t\t\t// backend can't cheaply honor it without scanning length, so we disallow).\n\t\t\tif (stop !== undefined && (!Number.isInteger(stop) || stop < 0)) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`slice: stop must be a non-negative integer or undefined (got ${stop})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst key = sliceKey(start, stop);\n\t\t\tconst hit = sliceCache.get(key);\n\t\t\tif (hit !== undefined) {\n\t\t\t\tsliceCache.delete(key);\n\t\t\t\tsliceCache.set(key, hit);\n\t\t\t\treturn hit.node;\n\t\t\t}\n\t\t\tevictOldestIfFull(sliceCache);\n\t\t\tconst node_ = derived(\n\t\t\t\t[entries],\n\t\t\t\t([s]) => {\n\t\t\t\t\tconst list = s as readonly T[];\n\t\t\t\t\treturn stop === undefined ? list.slice(start) : list.slice(start, stop);\n\t\t\t\t},\n\t\t\t\t{ initial: backend.slice(start, stop), describeKind: \"derived\" },\n\t\t\t);\n\t\t\tconst dispose = keepaliveDerived(node_);\n\t\t\tsliceCache.set(key, { node: node_, dispose });\n\t\t\treturn node_;\n\t\t},\n\n\t\tdisposeTail(n: number): boolean {\n\t\t\tconst hit = tailCache.get(n);\n\t\t\tif (hit === undefined) return false;\n\t\t\thit.dispose();\n\t\t\ttailCache.delete(n);\n\t\t\treturn true;\n\t\t},\n\n\t\tdisposeSlice(start: number, stop?: number): boolean {\n\t\t\tconst key = sliceKey(start, stop);\n\t\t\tconst hit = sliceCache.get(key);\n\t\t\tif (hit === undefined) return false;\n\t\t\thit.dispose();\n\t\t\tsliceCache.delete(key);\n\t\t\treturn true;\n\t\t},\n\n\t\tdisposeAllViews(): void {\n\t\t\tfor (const entry of tailCache.values()) entry.dispose();\n\t\t\ttailCache.clear();\n\t\t\tfor (const entry of sliceCache.values()) entry.dispose();\n\t\t\tsliceCache.clear();\n\t\t},\n\n\t\tdispose(): void {\n\t\t\t// D6(a): currently identical to disposeAllViews. Exposed as a\n\t\t\t// uniform lifecycle API across all 4 reactive data structures.\n\t\t\tfor (const entry of tailCache.values()) entry.dispose();\n\t\t\ttailCache.clear();\n\t\t\tfor (const entry of sliceCache.values()) entry.dispose();\n\t\t\tsliceCache.clear();\n\t\t},\n\t};\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,171 @@
1
+ import {
2
+ nanostores_exports
3
+ } from "./chunk-N6UR7YVY.js";
4
+ import {
5
+ nestjs_exports
6
+ } from "./chunk-IZYUSJC7.js";
7
+ import {
8
+ react_exports
9
+ } from "./chunk-J22W6HV3.js";
10
+ import {
11
+ solid_exports
12
+ } from "./chunk-HXZEYDUR.js";
13
+ import {
14
+ svelte_exports
15
+ } from "./chunk-OHISZPOJ.js";
16
+ import {
17
+ vue_exports
18
+ } from "./chunk-MJ2NKQQL.js";
19
+ import {
20
+ zustand_exports
21
+ } from "./chunk-JYXEWPH4.js";
22
+ import {
23
+ jotai_exports
24
+ } from "./chunk-XGPU467M.js";
25
+ import {
26
+ autoTrackNode,
27
+ batch,
28
+ state
29
+ } from "./chunk-PHOUUNK7.js";
30
+ import {
31
+ COMPLETE,
32
+ DATA,
33
+ DIRTY,
34
+ ERROR,
35
+ __export
36
+ } from "./chunk-SX52TAR4.js";
37
+
38
+ // src/compat/index.ts
39
+ var compat_exports = {};
40
+ __export(compat_exports, {
41
+ jotai: () => jotai_exports,
42
+ nanostores: () => nanostores_exports,
43
+ nestjs: () => nestjs_exports,
44
+ react: () => react_exports,
45
+ signals: () => signals_exports,
46
+ solid: () => solid_exports,
47
+ svelte: () => svelte_exports,
48
+ vue: () => vue_exports,
49
+ zustand: () => zustand_exports
50
+ });
51
+
52
+ // src/compat/signals/index.ts
53
+ var signals_exports = {};
54
+ __export(signals_exports, {
55
+ Signal: () => Signal
56
+ });
57
+ var trackingStack = [];
58
+ function pull(n) {
59
+ let val = n.cache;
60
+ const unsub = n.subscribe((msgs) => {
61
+ for (const [t, v] of msgs) {
62
+ if (t === DATA) val = v;
63
+ }
64
+ });
65
+ unsub();
66
+ return val;
67
+ }
68
+ var SignalState = class {
69
+ /** @internal */
70
+ _node;
71
+ _equals;
72
+ constructor(initial, opts) {
73
+ this._equals = opts?.equals ?? Object.is;
74
+ this._node = state(initial, {
75
+ ...opts,
76
+ resubscribable: true,
77
+ resetOnTeardown: true
78
+ });
79
+ }
80
+ get() {
81
+ const tracker = trackingStack[trackingStack.length - 1];
82
+ if (tracker) {
83
+ if (this._node.status === "sentinel") {
84
+ pull(this._node);
85
+ }
86
+ return tracker(this._node);
87
+ }
88
+ if (this._node.status === "sentinel") {
89
+ return pull(this._node);
90
+ }
91
+ return this._node.cache;
92
+ }
93
+ set(value) {
94
+ if (this._equals(this.get(), value)) return;
95
+ batch(() => {
96
+ this._node.down([[DIRTY], [DATA, value]]);
97
+ });
98
+ }
99
+ };
100
+ var SignalComputed = class {
101
+ /** @internal */
102
+ _node;
103
+ constructor(computation, opts) {
104
+ this._node = autoTrackNode(
105
+ (track) => {
106
+ trackingStack.push(track);
107
+ try {
108
+ return computation();
109
+ } finally {
110
+ trackingStack.pop();
111
+ }
112
+ },
113
+ {
114
+ ...opts,
115
+ describeKind: "derived",
116
+ resubscribable: true,
117
+ resetOnTeardown: true
118
+ }
119
+ );
120
+ }
121
+ get() {
122
+ const tracker = trackingStack[trackingStack.length - 1];
123
+ if (tracker) {
124
+ if (this._node.status === "sentinel") {
125
+ pull(this._node);
126
+ }
127
+ return tracker(this._node);
128
+ }
129
+ if (this._node.status === "sentinel") {
130
+ return pull(this._node);
131
+ }
132
+ return this._node.cache;
133
+ }
134
+ };
135
+ var Signal = {
136
+ State: SignalState,
137
+ Computed: SignalComputed,
138
+ /**
139
+ * Subscribes to changes on a signal.
140
+ * Returns an unsubscribe callback.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * const count = new Signal.State(0);
145
+ * const unsub = Signal.sub(count, v => console.log(v));
146
+ * ```
147
+ */
148
+ sub: (signal, callback) => {
149
+ const handlers = typeof callback === "function" ? { data: callback, error: void 0, complete: void 0 } : callback;
150
+ let initial = true;
151
+ return signal._node.subscribe((msgs) => {
152
+ for (const [t, v] of msgs) {
153
+ if (t === DATA) {
154
+ if (initial) {
155
+ initial = false;
156
+ continue;
157
+ }
158
+ handlers.data?.(v);
159
+ }
160
+ if (t === ERROR) handlers.error?.(v);
161
+ if (t === COMPLETE) handlers.complete?.();
162
+ }
163
+ });
164
+ }
165
+ };
166
+
167
+ export {
168
+ signals_exports,
169
+ compat_exports
170
+ };
171
+ //# sourceMappingURL=chunk-SN4YWWYO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/compat/index.ts","../src/compat/signals/index.ts"],"sourcesContent":["/**\n * Compat layer: compatibility wrappers for other state management libraries (Phase 5.1b).\n *\n * Framework adapters are optional peers. Install only what you use:\n * - `@graphrefly/graphrefly-ts/compat/react` -> `react`, `react-dom`\n * - `@graphrefly/graphrefly-ts/compat/vue` -> `vue`\n * - `@graphrefly/graphrefly-ts/compat/svelte` -> `svelte`\n * - `@graphrefly/graphrefly-ts/compat/solid` -> `solid-js`\n */\nexport * as jotai from \"./jotai/index.js\";\nexport * as nanostores from \"./nanostores/index.js\";\nexport * as nestjs from \"./nestjs/index.js\";\nexport * as react from \"./react/index.js\";\nexport * as signals from \"./signals/index.js\";\nexport * as solid from \"./solid/index.js\";\nexport * as svelte from \"./svelte/index.js\";\nexport * as vue from \"./vue/index.js\";\nexport * as zustand from \"./zustand/index.js\";\n","import { batch } from \"../../core/batch.js\";\nimport { COMPLETE, DATA, DIRTY, ERROR, type Messages } from \"../../core/messages.js\";\nimport type { Node } from \"../../core/node.js\";\nimport { autoTrackNode, state, type TrackFn } from \"../../core/sugar.js\";\n\n/**\n * Options for creating signals.\n *\n * @category compat\n */\nexport interface SignalOptions {\n\t/** Optional identifier for the underlying node. */\n\tname?: string;\n\t/** Custom equality function for change detection. */\n\tequals?: (a: any, b: any) => boolean;\n}\n\n/**\n * Common interface for all reactive signals.\n *\n * @category compat\n */\nexport interface AnySignal<T> {\n\t/** Returns the current value of the signal. */\n\tget(): T;\n\t/** @internal The underlying GraphReFly node. */\n\t_node: Node<T>;\n}\n\n/**\n * Global stack of active tracking contexts.\n * Since computation evaluation is fully synchronous, we push the tracking `get`\n * function before execution and pop it after. This prevents memory leaks without\n * needing WeakRefs, as the stack is always empty when idle.\n */\nconst trackingStack: TrackFn[] = [];\n\n/**\n * Helper to pull a disconnected node, forcing a synchronous resolution\n * cycle so that `get()` returns a fresh value even if the signal is unmounted.\n */\nfunction pull<T>(n: Node<T>): T {\n\tlet val: T | undefined | null = n.cache;\n\tconst unsub = n.subscribe((msgs: Messages) => {\n\t\tfor (const [t, v] of msgs) {\n\t\t\tif (t === DATA) val = v as T;\n\t\t}\n\t});\n\tunsub();\n\treturn val as T;\n}\n\n/**\n * TC39 `Signal.State` — a writable signal backed by a GraphReFly `state` node.\n * Automatically registers itself as a dependency if read inside a `Computed`.\n *\n * @example\n * ```ts\n * const count = new Signal.State(0);\n * count.get(); // 0\n * count.set(1);\n * count.get(); // 1\n * ```\n */\nclass SignalState<T> implements AnySignal<T> {\n\t/** @internal */\n\t_node: Node<T>;\n\tprivate readonly _equals: (a: T, b: T) => boolean;\n\n\tconstructor(initial: T, opts?: SignalOptions) {\n\t\tthis._equals = (opts?.equals ?? Object.is) as (a: T, b: T) => boolean;\n\t\tthis._node = state<T>(initial, {\n\t\t\t...opts,\n\t\t\tresubscribable: true,\n\t\t\tresetOnTeardown: true,\n\t\t});\n\t}\n\n\tget(): T {\n\t\t// If we are evaluating inside a computed node, track this read!\n\t\tconst tracker = trackingStack[trackingStack.length - 1];\n\t\tif (tracker) {\n\t\t\tif (this._node.status === \"sentinel\") {\n\t\t\t\tpull(this._node);\n\t\t\t}\n\t\t\treturn tracker(this._node) as T;\n\t\t}\n\n\t\tif (this._node.status === \"sentinel\") {\n\t\t\treturn pull(this._node);\n\t\t}\n\t\treturn this._node.cache as T;\n\t}\n\n\tset(value: T): void {\n\t\tif (this._equals(this.get(), value)) return;\n\t\tbatch(() => {\n\t\t\tthis._node.down([[DIRTY], [DATA, value]]);\n\t\t});\n\t}\n}\n\n/**\n * TC39 `Signal.Computed` — a read-only signal backed by `dynamicNode`.\n * Automatically tracks dependencies when `get()` is called on other signals\n * during its computation.\n *\n * @example\n * ```ts\n * const count = new Signal.State(0);\n * const doubled = new Signal.Computed(() => count.get() * 2);\n * ```\n */\nclass SignalComputed<T> implements AnySignal<T> {\n\t/** @internal */\n\t_node: Node<T>;\n\n\tconstructor(computation: () => T, opts?: SignalOptions) {\n\t\tthis._node = autoTrackNode<T>(\n\t\t\t(track) => {\n\t\t\t\ttrackingStack.push(track);\n\t\t\t\ttry {\n\t\t\t\t\treturn computation();\n\t\t\t\t} finally {\n\t\t\t\t\ttrackingStack.pop();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t...opts,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tresubscribable: true,\n\t\t\t\tresetOnTeardown: true,\n\t\t\t},\n\t\t);\n\t}\n\n\tget(): T {\n\t\t// Computed nodes can themselves be dependencies of other Computed nodes.\n\t\tconst tracker = trackingStack[trackingStack.length - 1];\n\t\tif (tracker) {\n\t\t\tif (this._node.status === \"sentinel\") {\n\t\t\t\tpull(this._node);\n\t\t\t}\n\t\t\treturn tracker(this._node) as T;\n\t\t}\n\n\t\tif (this._node.status === \"sentinel\") {\n\t\t\treturn pull(this._node);\n\t\t}\n\t\treturn this._node.cache as T;\n\t}\n}\n\n/**\n * TC39 Signals-compatible namespace. Wraps GraphReFly primitives.\n * Provides auto-tracking conforming to the TS39 signals proposal.\n *\n * @category compat\n */\nexport const Signal = {\n\tState: SignalState,\n\tComputed: SignalComputed,\n\n\t/**\n\t * Subscribes to changes on a signal.\n\t * Returns an unsubscribe callback.\n\t *\n\t * @example\n\t * ```ts\n\t * const count = new Signal.State(0);\n\t * const unsub = Signal.sub(count, v => console.log(v));\n\t * ```\n\t */\n\tsub: <T>(\n\t\tsignal: AnySignal<T>,\n\t\tcallback:\n\t\t\t| ((value: T) => void)\n\t\t\t| {\n\t\t\t\t\tdata?: (value: T) => void;\n\t\t\t\t\terror?: (err: unknown) => void;\n\t\t\t\t\tcomplete?: () => void;\n\t\t\t },\n\t): (() => void) => {\n\t\tconst handlers =\n\t\t\ttypeof callback === \"function\"\n\t\t\t\t? { data: callback as (value: T) => void, error: undefined, complete: undefined }\n\t\t\t\t: callback;\n\t\t// Skip the initial push-on-subscribe DATA — Signal.sub fires on changes only.\n\t\tlet initial = true;\n\t\treturn signal._node.subscribe((msgs) => {\n\t\t\tfor (const [t, v] of msgs) {\n\t\t\t\tif (t === DATA) {\n\t\t\t\t\tif (initial) {\n\t\t\t\t\t\tinitial = false;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\thandlers.data?.(v as T);\n\t\t\t\t}\n\t\t\t\tif (t === ERROR) handlers.error?.(v);\n\t\t\t\tif (t === COMPLETE) handlers.complete?.();\n\t\t\t}\n\t\t});\n\t},\n} as const;\n\nexport type { SignalComputed, SignalState };\n"],"mappings":"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","names":[]}
@@ -0,0 +1,110 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
5
+ var __typeError = (msg) => {
6
+ throw TypeError(msg);
7
+ };
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
12
+ }) : x)(function(x) {
13
+ if (typeof require !== "undefined") return require.apply(this, arguments);
14
+ throw Error('Dynamic require of "' + x + '" is not supported');
15
+ });
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
21
+ var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
22
+ var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
23
+ var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
24
+ var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
25
+ var __runInitializers = (array, flags, self, value) => {
26
+ for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
27
+ return value;
28
+ };
29
+ var __decorateElement = (array, flags, name, decorators, target, extra) => {
30
+ var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
31
+ var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
32
+ var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
33
+ var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name]() {
34
+ return __privateGet(this, extra);
35
+ }, set [name](x) {
36
+ return __privateSet(this, extra, x);
37
+ } }, name));
38
+ k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
39
+ for (var i = decorators.length - 1; i >= 0; i--) {
40
+ ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
41
+ if (k) {
42
+ ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
43
+ if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
44
+ if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
45
+ }
46
+ it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
47
+ if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
48
+ else if (typeof it !== "object" || it === null) __typeError("Object expected");
49
+ else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
50
+ }
51
+ return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
52
+ };
53
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
54
+ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
55
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
56
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
57
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
58
+
59
+ // src/core/messages.ts
60
+ var START = /* @__PURE__ */ Symbol.for("graphrefly/START");
61
+ var DATA = /* @__PURE__ */ Symbol.for("graphrefly/DATA");
62
+ var DIRTY = /* @__PURE__ */ Symbol.for("graphrefly/DIRTY");
63
+ var RESOLVED = /* @__PURE__ */ Symbol.for("graphrefly/RESOLVED");
64
+ var INVALIDATE = /* @__PURE__ */ Symbol.for("graphrefly/INVALIDATE");
65
+ var PAUSE = /* @__PURE__ */ Symbol.for("graphrefly/PAUSE");
66
+ var RESUME = /* @__PURE__ */ Symbol.for("graphrefly/RESUME");
67
+ var TEARDOWN = /* @__PURE__ */ Symbol.for("graphrefly/TEARDOWN");
68
+ var COMPLETE = /* @__PURE__ */ Symbol.for("graphrefly/COMPLETE");
69
+ var ERROR = /* @__PURE__ */ Symbol.for("graphrefly/ERROR");
70
+ var DIRTY_MSG = Object.freeze([DIRTY]);
71
+ var RESOLVED_MSG = Object.freeze([RESOLVED]);
72
+ var INVALIDATE_MSG = Object.freeze([INVALIDATE]);
73
+ var START_MSG = Object.freeze([START]);
74
+ var COMPLETE_MSG = Object.freeze([COMPLETE]);
75
+ var TEARDOWN_MSG = Object.freeze([TEARDOWN]);
76
+ var DIRTY_ONLY_BATCH = Object.freeze([DIRTY_MSG]);
77
+ var RESOLVED_ONLY_BATCH = Object.freeze([RESOLVED_MSG]);
78
+ var INVALIDATE_ONLY_BATCH = Object.freeze([INVALIDATE_MSG]);
79
+ var COMPLETE_ONLY_BATCH = Object.freeze([COMPLETE_MSG]);
80
+ var TEARDOWN_ONLY_BATCH = Object.freeze([TEARDOWN_MSG]);
81
+
82
+ export {
83
+ __require,
84
+ __export,
85
+ __decoratorStart,
86
+ __runInitializers,
87
+ __decorateElement,
88
+ START,
89
+ DATA,
90
+ DIRTY,
91
+ RESOLVED,
92
+ INVALIDATE,
93
+ PAUSE,
94
+ RESUME,
95
+ TEARDOWN,
96
+ COMPLETE,
97
+ ERROR,
98
+ DIRTY_MSG,
99
+ RESOLVED_MSG,
100
+ INVALIDATE_MSG,
101
+ START_MSG,
102
+ COMPLETE_MSG,
103
+ TEARDOWN_MSG,
104
+ DIRTY_ONLY_BATCH,
105
+ RESOLVED_ONLY_BATCH,
106
+ INVALIDATE_ONLY_BATCH,
107
+ COMPLETE_ONLY_BATCH,
108
+ TEARDOWN_ONLY_BATCH
109
+ };
110
+ //# sourceMappingURL=chunk-SX52TAR4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/messages.ts"],"sourcesContent":["/**\n * GraphReFly message protocol — §1 `~/src/graphrefly/GRAPHREFLY-SPEC.md`.\n * Emissions are always `[[Type, Data?], ...]` (no single-tuple shorthand).\n *\n * This file is protocol-pure:\n * - Message type symbols (10 built-ins).\n * - `Message` / `Messages` tuple types.\n * - `MessageTypeRegistration` interface (shape of a registry entry).\n *\n * It does NOT own the registry, tier lookups, or any cross-cutting singleton\n * state — that lives in `GraphReFlyConfig` (see `config.ts`) so custom\n * protocols can build isolated instances. Import this module when you need\n * the symbol constants or the tuple types; import `config.ts` when you need\n * tier / wire-crossing / registry lookups.\n */\n\n/** Subscribe-time handshake. Delivered to each new sink at the top of `subscribe()`. Tier 0. */\nexport const START = Symbol.for(\"graphrefly/START\");\n/** Value delivery (`DATA`, value). Tier 3 — deferred inside `batch()`. */\nexport const DATA = Symbol.for(\"graphrefly/DATA\");\n/** Phase 1: value about to change. Tier 1 — immediate. */\nexport const DIRTY = Symbol.for(\"graphrefly/DIRTY\");\n/** Phase 2: dirty pass completed, value unchanged. Tier 3 — deferred inside `batch()`. */\nexport const RESOLVED = Symbol.for(\"graphrefly/RESOLVED\");\n/** Clear cached state; do not auto-emit. Tier 1 — immediate. */\nexport const INVALIDATE = Symbol.for(\"graphrefly/INVALIDATE\");\n/** Suspend activity. Tier 2 — immediate. */\nexport const PAUSE = Symbol.for(\"graphrefly/PAUSE\");\n/** Resume after pause. Tier 2 — immediate. */\nexport const RESUME = Symbol.for(\"graphrefly/RESUME\");\n/** Permanent cleanup. Tier 5 — deferred to batch phase 4. */\nexport const TEARDOWN = Symbol.for(\"graphrefly/TEARDOWN\");\n/** Clean termination. Tier 4 — deferred to batch phase 3. */\nexport const COMPLETE = Symbol.for(\"graphrefly/COMPLETE\");\n/** Error termination. Tier 4 — deferred to batch phase 3. */\nexport const ERROR = Symbol.for(\"graphrefly/ERROR\");\n\n/** One protocol tuple: `[Type, optional payload]`. */\nexport type Message = readonly [symbol, unknown?];\n\n/** A batch of tuples — the wire shape for `node.down()` / `node.up()`. */\nexport type Messages = readonly Message[];\n\n// ---------------------------------------------------------------------------\n// Interned singletons for payload-free tuples\n// ---------------------------------------------------------------------------\n//\n// Every emission path used to allocate fresh `[[DIRTY]]`, `[[RESOLVED]]`,\n// etc. — two arrays per emit in the hot path. Since none of these tuples\n// carry a payload, one frozen instance is indistinguishable from a\n// fresh one. We intern them at module load and reuse forever. Only\n// `[DATA, v]`, `[ERROR, e]`, `[PAUSE, lockId]`, `[RESUME, lockId]` still\n// allocate per-call because they carry payloads.\n//\n// Downstream code MUST treat these as immutable. `Object.freeze` makes\n// accidental mutation throw in strict mode. Do not `push`, splice, or\n// otherwise mutate a Messages array that came from one of these.\n\n/** Singleton `[DIRTY]` tuple — payload-free, interned. */\nexport const DIRTY_MSG: Message = Object.freeze([DIRTY]) as Message;\n/** Singleton `[RESOLVED]` tuple — payload-free, interned. */\nexport const RESOLVED_MSG: Message = Object.freeze([RESOLVED]) as Message;\n/** Singleton `[INVALIDATE]` tuple — payload-free, interned. */\nexport const INVALIDATE_MSG: Message = Object.freeze([INVALIDATE]) as Message;\n/** Singleton `[START]` tuple — payload-free, interned. */\nexport const START_MSG: Message = Object.freeze([START]) as Message;\n/** Singleton `[COMPLETE]` tuple — payload-free, interned. */\nexport const COMPLETE_MSG: Message = Object.freeze([COMPLETE]) as Message;\n/** Singleton `[TEARDOWN]` tuple — payload-free, interned. */\nexport const TEARDOWN_MSG: Message = Object.freeze([TEARDOWN]) as Message;\n\n/** Pre-wrapped `[[DIRTY]]` for `_emit([DIRTY_ONLY_BATCH])`-style callers. */\nexport const DIRTY_ONLY_BATCH: Messages = Object.freeze([DIRTY_MSG]) as Messages;\n/** Pre-wrapped `[[RESOLVED]]`. */\nexport const RESOLVED_ONLY_BATCH: Messages = Object.freeze([RESOLVED_MSG]) as Messages;\n/** Pre-wrapped `[[INVALIDATE]]`. */\nexport const INVALIDATE_ONLY_BATCH: Messages = Object.freeze([INVALIDATE_MSG]) as Messages;\n/** Pre-wrapped `[[COMPLETE]]`. */\nexport const COMPLETE_ONLY_BATCH: Messages = Object.freeze([COMPLETE_MSG]) as Messages;\n/** Pre-wrapped `[[TEARDOWN]]`. */\nexport const TEARDOWN_ONLY_BATCH: Messages = Object.freeze([TEARDOWN_MSG]) as Messages;\n\n// ---------------------------------------------------------------------------\n// Registry entry shape\n// ---------------------------------------------------------------------------\n\n/**\n * Per-type record stored in a {@link GraphReFlyConfig}'s registry.\n *\n * - `tier` — signal tier (0–5 built-in; custom tiers allowed but should fit\n * the phase model used by `batch.ts`).\n * - `wireCrossing` — when `true`, forwarded across SSE/WebSocket/worker\n * adapters. Defaults to `tier >= 3` if omitted in registration input.\n * - `metaPassthrough` — when `false`, this message type is filtered out of\n * `Graph.signal` deliveries to meta companion nodes (spec §2.3). Meta\n * companions still receive everything via their primary's own cascade.\n * Defaults to `true` (meta receives the message).\n */\nexport interface MessageTypeRegistration {\n\ttier: number;\n\twireCrossing: boolean;\n\tmetaPassthrough: boolean;\n}\n\n/**\n * Input accepted by {@link GraphReFlyConfig.registerMessageType}. Only `tier`\n * is required; `wireCrossing` defaults to `tier >= 3`; `metaPassthrough`\n * defaults to `true`.\n */\nexport interface MessageTypeRegistrationInput {\n\ttier: number;\n\twireCrossing?: boolean;\n\tmetaPassthrough?: boolean;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBO,IAAM,QAAQ,uBAAO,IAAI,kBAAkB;AAE3C,IAAM,OAAO,uBAAO,IAAI,iBAAiB;AAEzC,IAAM,QAAQ,uBAAO,IAAI,kBAAkB;AAE3C,IAAM,WAAW,uBAAO,IAAI,qBAAqB;AAEjD,IAAM,aAAa,uBAAO,IAAI,uBAAuB;AAErD,IAAM,QAAQ,uBAAO,IAAI,kBAAkB;AAE3C,IAAM,SAAS,uBAAO,IAAI,mBAAmB;AAE7C,IAAM,WAAW,uBAAO,IAAI,qBAAqB;AAEjD,IAAM,WAAW,uBAAO,IAAI,qBAAqB;AAEjD,IAAM,QAAQ,uBAAO,IAAI,kBAAkB;AAwB3C,IAAM,YAAqB,OAAO,OAAO,CAAC,KAAK,CAAC;AAEhD,IAAM,eAAwB,OAAO,OAAO,CAAC,QAAQ,CAAC;AAEtD,IAAM,iBAA0B,OAAO,OAAO,CAAC,UAAU,CAAC;AAE1D,IAAM,YAAqB,OAAO,OAAO,CAAC,KAAK,CAAC;AAEhD,IAAM,eAAwB,OAAO,OAAO,CAAC,QAAQ,CAAC;AAEtD,IAAM,eAAwB,OAAO,OAAO,CAAC,QAAQ,CAAC;AAGtD,IAAM,mBAA6B,OAAO,OAAO,CAAC,SAAS,CAAC;AAE5D,IAAM,sBAAgC,OAAO,OAAO,CAAC,YAAY,CAAC;AAElE,IAAM,wBAAkC,OAAO,OAAO,CAAC,cAAc,CAAC;AAEtE,IAAM,sBAAgC,OAAO,OAAO,CAAC,YAAY,CAAC;AAElE,IAAM,sBAAgC,OAAO,OAAO,CAAC,YAAY,CAAC;","names":[]}