@graphrefly/graphrefly 0.12.0 → 0.13.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.
- package/dist/{chunk-XWMTVV2D.js → chunk-5RN7NBNG.js} +5 -5
- package/dist/{chunk-4F2ZFD5L.js → chunk-6B2ZCCNN.js} +39 -39
- package/dist/chunk-6B2ZCCNN.js.map +1 -0
- package/dist/{chunk-BRPCN2HJ.js → chunk-H4UFM6WD.js} +3 -3
- package/dist/{chunk-NULSP7U4.js → chunk-HA6QMDKQ.js} +4 -4
- package/dist/{chunk-X732W3QA.js → chunk-KNGOJEYP.js} +2 -2
- package/dist/{chunk-6OLNYOGU.js → chunk-PFMXKG4Y.js} +2 -2
- package/dist/{chunk-IXTW3BIO.js → chunk-QOGWU5K7.js} +3 -3
- package/dist/{chunk-JYRHO63K.js → chunk-UPC5OEB5.js} +17 -17
- package/dist/chunk-UPC5OEB5.js.map +1 -0
- package/dist/{chunk-VQWLA6XQ.js → chunk-UQI4GAHD.js} +3 -3
- package/dist/compat/nestjs/index.cjs +37 -37
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +4 -4
- package/dist/compat/nestjs/index.d.ts +4 -4
- package/dist/compat/nestjs/index.js +7 -7
- package/dist/core/index.cjs +39 -39
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +5 -5
- package/dist/extra/index.cjs +37 -37
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +4 -4
- package/dist/extra/index.d.ts +4 -4
- package/dist/extra/index.js +3 -3
- package/dist/graph/index.cjs +37 -37
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +3 -3
- package/dist/graph/index.d.ts +3 -3
- package/dist/graph/index.js +4 -4
- package/dist/{graph-DXT95WZ3.d.ts → graph-BXIK5Dq5.d.ts} +1 -1
- package/dist/{graph-BE10ujU9.d.cts → graph-BhADtuFU.d.cts} +1 -1
- package/dist/{index-QfbXNW1N.d.cts → index-BNB0KjKe.d.ts} +24 -21
- package/dist/{index-C0_7g9sj.d.ts → index-BkToATim.d.ts} +1 -1
- package/dist/{index-CiAqgfFg.d.ts → index-CKyYg4IP.d.ts} +3 -3
- package/dist/{index-CCvzN5GB.d.cts → index-DANO9Gg7.d.cts} +2 -2
- package/dist/{index-CthwPnHQ.d.cts → index-DBhLjWSV.d.cts} +3 -3
- package/dist/{index-Dzdm20sx.d.ts → index-DKIyo4Bq.d.cts} +24 -21
- package/dist/{index-53cDGX7F.d.ts → index-DSp5R3Xq.d.ts} +3 -3
- package/dist/{index-aBZ2RoP0.d.cts → index-Dqemj9q0.d.cts} +3 -3
- package/dist/{index-nRulwTr-.d.cts → index-Wa8jXne6.d.cts} +1 -1
- package/dist/{index-B10Q0sQB.d.ts → index-fYObbpUw.d.ts} +2 -2
- package/dist/index.cjs +53 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -12
- package/dist/index.d.ts +12 -12
- package/dist/index.js +11 -11
- package/dist/{meta-BcuDhtwu.d.cts → meta-CrZUQAJ6.d.cts} +1 -1
- package/dist/{meta-BcuDhtwu.d.ts → meta-CrZUQAJ6.d.ts} +1 -1
- package/dist/patterns/reactive-layout/index.cjs +50 -50
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +3 -3
- package/dist/patterns/reactive-layout/index.d.ts +3 -3
- package/dist/patterns/reactive-layout/index.js +4 -4
- package/dist/{reactive-log-OULQssZg.d.cts → reactive-log-ChbpUrY2.d.cts} +2 -2
- package/dist/{reactive-log-Cu0VdqkT.d.ts → reactive-log-DV--7BWd.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/chunk-4F2ZFD5L.js.map +0 -1
- package/dist/chunk-JYRHO63K.js.map +0 -1
- /package/dist/{chunk-XWMTVV2D.js.map → chunk-5RN7NBNG.js.map} +0 -0
- /package/dist/{chunk-BRPCN2HJ.js.map → chunk-H4UFM6WD.js.map} +0 -0
- /package/dist/{chunk-NULSP7U4.js.map → chunk-HA6QMDKQ.js.map} +0 -0
- /package/dist/{chunk-X732W3QA.js.map → chunk-KNGOJEYP.js.map} +0 -0
- /package/dist/{chunk-6OLNYOGU.js.map → chunk-PFMXKG4Y.js.map} +0 -0
- /package/dist/{chunk-IXTW3BIO.js.map → chunk-QOGWU5K7.js.map} +0 -0
- /package/dist/{chunk-VQWLA6XQ.js.map → chunk-UQI4GAHD.js.map} +0 -0
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { B as BlockAdapters, C as CanvasMeasureAdapter, a as CanvasMeasureAdapterOptions, b as CanvasModule, c as CharPosition, d as CliMeasureAdapter, e as CliMeasureAdapterOptions, f as ContentBlock, I as ImageMeasurer, g as ImageSizeAdapter, L as LayoutLine, h as LineBreaksResult, j as MeasuredBlock, M as MeasurementAdapter, N as NodeCanvasMeasureAdapter, P as PositionedBlock, k as PrecomputedAdapter, l as PrecomputedAdapterOptions, m as PreparedSegment, R as ReactiveBlockLayoutBundle, n as ReactiveBlockLayoutOptions, o as ReactiveLayoutBundle, p as ReactiveLayoutOptions, S as SegmentBreakKind, q as SegmentMeasureStats, r as SvgBoundsAdapter, s as SvgMeasurer, t as analyzeAndMeasure, u as computeBlockFlow, v as computeCharPositions, w as computeLineBreaks, x as computeTotalHeight, y as measureBlock, z as measureBlocks, A as reactiveBlockLayout, D as reactiveLayout } from '../../index-
|
|
2
|
-
import '../../meta-
|
|
3
|
-
import '../../graph-
|
|
1
|
+
export { B as BlockAdapters, C as CanvasMeasureAdapter, a as CanvasMeasureAdapterOptions, b as CanvasModule, c as CharPosition, d as CliMeasureAdapter, e as CliMeasureAdapterOptions, f as ContentBlock, I as ImageMeasurer, g as ImageSizeAdapter, L as LayoutLine, h as LineBreaksResult, j as MeasuredBlock, M as MeasurementAdapter, N as NodeCanvasMeasureAdapter, P as PositionedBlock, k as PrecomputedAdapter, l as PrecomputedAdapterOptions, m as PreparedSegment, R as ReactiveBlockLayoutBundle, n as ReactiveBlockLayoutOptions, o as ReactiveLayoutBundle, p as ReactiveLayoutOptions, S as SegmentBreakKind, q as SegmentMeasureStats, r as SvgBoundsAdapter, s as SvgMeasurer, t as analyzeAndMeasure, u as computeBlockFlow, v as computeCharPositions, w as computeLineBreaks, x as computeTotalHeight, y as measureBlock, z as measureBlocks, A as reactiveBlockLayout, D as reactiveLayout } from '../../index-DANO9Gg7.cjs';
|
|
2
|
+
import '../../meta-CrZUQAJ6.cjs';
|
|
3
|
+
import '../../graph-BhADtuFU.cjs';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { B as BlockAdapters, C as CanvasMeasureAdapter, a as CanvasMeasureAdapterOptions, b as CanvasModule, c as CharPosition, d as CliMeasureAdapter, e as CliMeasureAdapterOptions, f as ContentBlock, I as ImageMeasurer, g as ImageSizeAdapter, L as LayoutLine, h as LineBreaksResult, j as MeasuredBlock, M as MeasurementAdapter, N as NodeCanvasMeasureAdapter, P as PositionedBlock, k as PrecomputedAdapter, l as PrecomputedAdapterOptions, m as PreparedSegment, R as ReactiveBlockLayoutBundle, n as ReactiveBlockLayoutOptions, o as ReactiveLayoutBundle, p as ReactiveLayoutOptions, S as SegmentBreakKind, q as SegmentMeasureStats, r as SvgBoundsAdapter, s as SvgMeasurer, t as analyzeAndMeasure, u as computeBlockFlow, v as computeCharPositions, w as computeLineBreaks, x as computeTotalHeight, y as measureBlock, z as measureBlocks, A as reactiveBlockLayout, D as reactiveLayout } from '../../index-
|
|
2
|
-
import '../../meta-
|
|
3
|
-
import '../../graph-
|
|
1
|
+
export { B as BlockAdapters, C as CanvasMeasureAdapter, a as CanvasMeasureAdapterOptions, b as CanvasModule, c as CharPosition, d as CliMeasureAdapter, e as CliMeasureAdapterOptions, f as ContentBlock, I as ImageMeasurer, g as ImageSizeAdapter, L as LayoutLine, h as LineBreaksResult, j as MeasuredBlock, M as MeasurementAdapter, N as NodeCanvasMeasureAdapter, P as PositionedBlock, k as PrecomputedAdapter, l as PrecomputedAdapterOptions, m as PreparedSegment, R as ReactiveBlockLayoutBundle, n as ReactiveBlockLayoutOptions, o as ReactiveLayoutBundle, p as ReactiveLayoutOptions, S as SegmentBreakKind, q as SegmentMeasureStats, r as SvgBoundsAdapter, s as SvgMeasurer, t as analyzeAndMeasure, u as computeBlockFlow, v as computeCharPositions, w as computeLineBreaks, x as computeTotalHeight, y as measureBlock, z as measureBlocks, A as reactiveBlockLayout, D as reactiveLayout } from '../../index-fYObbpUw.js';
|
|
2
|
+
import '../../meta-CrZUQAJ6.js';
|
|
3
|
+
import '../../graph-BXIK5Dq5.js';
|
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
measureBlocks,
|
|
15
15
|
reactiveBlockLayout,
|
|
16
16
|
reactiveLayout
|
|
17
|
-
} from "../../chunk-
|
|
18
|
-
import "../../chunk-
|
|
19
|
-
import "../../chunk-
|
|
20
|
-
import "../../chunk-
|
|
17
|
+
} from "../../chunk-UPC5OEB5.js";
|
|
18
|
+
import "../../chunk-UQI4GAHD.js";
|
|
19
|
+
import "../../chunk-PFMXKG4Y.js";
|
|
20
|
+
import "../../chunk-6B2ZCCNN.js";
|
|
21
21
|
export {
|
|
22
22
|
CanvasMeasureAdapter,
|
|
23
23
|
CliMeasureAdapter,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import { m as Messages, N as Node } from './meta-
|
|
3
|
-
import { G as Graph, x as ObserveOptions } from './graph-
|
|
2
|
+
import { m as Messages, N as Node } from './meta-CrZUQAJ6.cjs';
|
|
3
|
+
import { G as Graph, x as ObserveOptions } from './graph-BhADtuFU.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Bridge a `Node<T>` to an RxJS `Observable<T>`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import { m as Messages, N as Node } from './meta-
|
|
3
|
-
import { G as Graph, x as ObserveOptions } from './graph-
|
|
2
|
+
import { m as Messages, N as Node } from './meta-CrZUQAJ6.js';
|
|
3
|
+
import { G as Graph, x as ObserveOptions } from './graph-BXIK5Dq5.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Bridge a `Node<T>` to an RxJS `Observable<T>`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphrefly/graphrefly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be",
|
|
5
5
|
"description": "Reactive harness layer for agent workflows. Describe automations in plain language, trace every decision, enforce policies, persist checkpoints. Zero dependencies.",
|
|
6
6
|
"repository": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/actor.ts","../src/core/messages.ts","../src/core/batch.ts","../src/core/clock.ts","../src/core/guard.ts","../src/core/versioning.ts","../src/core/node.ts","../src/core/dynamic-node.ts","../src/core/sugar.ts"],"sourcesContent":["/**\n * Who is performing an operation (attribution + ABAC input).\n *\n * @see GRAPHREFLY-SPEC — roadmap Phase 1.5 (Actor & Guard).\n */\nexport type Actor = {\n\ttype: \"human\" | \"llm\" | \"wallet\" | \"system\" | string;\n\tid: string;\n} & Record<string, unknown>;\n\n/** Default actor when none is passed ({@link normalizeActor}). */\nexport const DEFAULT_ACTOR: Actor = { type: \"system\", id: \"\" };\n\n/**\n * Fills missing `type` / `id` on an actor and returns {@link DEFAULT_ACTOR} when input is undefined.\n *\n * @param actor - Optional partial actor from a transport hint.\n * @returns A normalized `Actor` safe to pass to guards and graph APIs.\n *\n * @example\n * ```ts\n * import { normalizeActor } from \"@graphrefly/graphrefly-ts\";\n *\n * normalizeActor({ type: \"human\", id: \"u1\" });\n * ```\n */\nexport function normalizeActor(actor?: Actor): Actor {\n\tif (actor == null) return DEFAULT_ACTOR;\n\tconst { type, id, ...rest } = actor;\n\treturn {\n\t\ttype: type ?? \"system\",\n\t\tid: id ?? \"\",\n\t\t...rest,\n\t} as Actor;\n}\n","/**\n * GraphReFly message protocol — §1 `~/src/graphrefly/GRAPHREFLY-SPEC.md`.\n * Emissions are always `[[Type, Data?], ...]` (no single-tuple shorthand).\n *\n * ## Canonical message ordering (within a composite batch)\n *\n * When multiple message types appear in a single `down()` call, the canonical\n * delivery order is determined by **signal tier**:\n *\n * | Tier | Signals | Role | Batch behavior |\n * |------|------------------------|-------------------|-------------------------------------|\n * | 0 | DIRTY, INVALIDATE | Notification | Immediate (never deferred) |\n * | 1 | PAUSE, RESUME | Flow control | Immediate (never deferred) |\n * | 2 | DATA, RESOLVED | Value settlement | Deferred inside `batch()` |\n * | 3 | COMPLETE, ERROR | Terminal lifecycle | Deferred to after phase-2 |\n * | 4 | TEARDOWN | Destruction | Immediate (usually sent alone) |\n *\n * **Rule:** Within `emitWithBatch`, messages are partitioned by tier and delivered\n * in tier order. This ensures phase-2 values (DATA/RESOLVED) reach sinks before\n * terminal signals (COMPLETE/ERROR) mark the node as done, preventing the\n * \"COMPLETE-before-DATA\" class of bugs. Sources that emit in canonical order\n * naturally partition correctly with zero overhead.\n *\n * Unknown message types (forward-compat) are tier 0 (immediate).\n *\n * ## Meta node bypass rules (centralized — GRAPHREFLY-SPEC §2.3)\n *\n * - **INVALIDATE** via `graph.signal()` — no-op on meta nodes (cached values preserved).\n * - **COMPLETE / ERROR** — not propagated from parent to meta (meta outlives terminal\n * state for post-mortem writes like setting `meta.error` after ERROR).\n * - **TEARDOWN** — propagated from parent to meta, releasing meta resources.\n */\n\n/** Value delivery (`DATA`, value). Tier 2 — deferred inside `batch()`. */\nexport const DATA = Symbol.for(\"graphrefly/DATA\");\n/** Phase 1: value about to change. Tier 0 — immediate. */\nexport const DIRTY = Symbol.for(\"graphrefly/DIRTY\");\n/** Phase 2: dirty pass completed, value unchanged. Tier 2 — deferred inside `batch()`. */\nexport const RESOLVED = Symbol.for(\"graphrefly/RESOLVED\");\n/** Clear cached state; do not auto-emit. Tier 0 — immediate. */\nexport const INVALIDATE = Symbol.for(\"graphrefly/INVALIDATE\");\n/** Suspend activity. Tier 1 — immediate. */\nexport const PAUSE = Symbol.for(\"graphrefly/PAUSE\");\n/** Resume after pause. Tier 1 — immediate. */\nexport const RESUME = Symbol.for(\"graphrefly/RESUME\");\n/** Permanent cleanup. Tier 4 — immediate (usually sent alone). */\nexport const TEARDOWN = Symbol.for(\"graphrefly/TEARDOWN\");\n/** Clean termination. Tier 3 — delivered after phase-2 in the same batch. */\nexport const COMPLETE = Symbol.for(\"graphrefly/COMPLETE\");\n/** Error termination. Tier 3 — delivered after phase-2 in the same batch. */\nexport const ERROR = Symbol.for(\"graphrefly/ERROR\");\n\n/** Known protocol type symbols (open set — other symbols are valid and forward). */\nexport const knownMessageTypes: readonly symbol[] = [\n\tDATA,\n\tDIRTY,\n\tRESOLVED,\n\tINVALIDATE,\n\tPAUSE,\n\tRESUME,\n\tTEARDOWN,\n\tCOMPLETE,\n\tERROR,\n];\n\n/** One protocol tuple: `[Type, optional payload]`. */\nexport type Message = readonly [symbol, unknown?];\n\n/**\n * A batch of tuples — the wire shape for `node.down()` / `node.up()`.\n */\nexport type Messages = readonly Message[];\n\n/**\n * Whether `t` is one of the built-in protocol symbols in this module.\n *\n * @param t — Message type symbol (unknown types are still valid; they must forward).\n * @returns `true` for `DATA`, `DIRTY`, `RESOLVED`, etc.\n *\n * @example\n * ```ts\n * import { DATA, DIRTY, isKnownMessageType } from \"@graphrefly/graphrefly-ts\";\n *\n * isKnownMessageType(DATA); // true\n * isKnownMessageType(Symbol(\"custom\")); // false\n * ```\n */\nexport function isKnownMessageType(t: symbol): boolean {\n\treturn knownMessageTypes.includes(t);\n}\n\n/**\n * Returns the signal tier for a message type (see module-level ordering table).\n *\n * - 0: notification (DIRTY, INVALIDATE) — immediate\n * - 1: flow control (PAUSE, RESUME) — immediate\n * - 2: value (DATA, RESOLVED) — deferred inside `batch()`\n * - 3: terminal (COMPLETE, ERROR) — delivered after phase-2\n * - 4: destruction (TEARDOWN) — immediate, usually alone\n * - 0 for unknown types (forward-compat: immediate)\n *\n * @param t — Message type symbol.\n * @returns Tier number (0–4).\n *\n * @example\n * ```ts\n * import { DATA, DIRTY, COMPLETE, TEARDOWN, messageTier } from \"@graphrefly/graphrefly-ts\";\n *\n * messageTier(DIRTY); // 0\n * messageTier(DATA); // 2\n * messageTier(COMPLETE); // 3\n * messageTier(TEARDOWN); // 4\n * ```\n */\nexport function messageTier(t: symbol): number {\n\tif (t === DIRTY || t === INVALIDATE) return 0;\n\tif (t === PAUSE || t === RESUME) return 1;\n\tif (t === DATA || t === RESOLVED) return 2;\n\tif (t === COMPLETE || t === ERROR) return 3;\n\tif (t === TEARDOWN) return 4;\n\treturn 0; // unknown → immediate\n}\n\n/**\n * Returns whether this tuple is deferred by `batch()` (phase 2: `DATA` or `RESOLVED`).\n *\n * @param msg — Single message tuple.\n * @returns `true` if `msg` is `DATA` or `RESOLVED`.\n *\n * @example\n * ```ts\n * import { DATA, RESOLVED, DIRTY, isPhase2Message } from \"@graphrefly/graphrefly-ts\";\n *\n * isPhase2Message([DATA, 42]); // true\n * isPhase2Message([RESOLVED]); // true\n * isPhase2Message([DIRTY]); // false\n * ```\n */\nexport function isPhase2Message(msg: Message): boolean {\n\tconst t = msg[0];\n\treturn t === DATA || t === RESOLVED;\n}\n\n/**\n * Returns whether this message type is terminal (COMPLETE or ERROR).\n * Terminal messages are delivered after phase-2 in the same batch to prevent\n * the node from becoming terminal before value messages reach sinks.\n *\n * @param t — Message type symbol.\n * @returns `true` for `COMPLETE` or `ERROR`.\n *\n * @example\n * ```ts\n * import { COMPLETE, ERROR, DATA, isTerminalMessage } from \"@graphrefly/graphrefly-ts\";\n *\n * isTerminalMessage(COMPLETE); // true\n * isTerminalMessage(ERROR); // true\n * isTerminalMessage(DATA); // false\n * ```\n */\nexport function isTerminalMessage(t: symbol): boolean {\n\treturn t === COMPLETE || t === ERROR;\n}\n\n/**\n * Whether `t` should be propagated from a parent node to its companion meta nodes.\n * Only TEARDOWN propagates; COMPLETE/ERROR/INVALIDATE do not (meta outlives parent\n * terminal state for post-mortem writes).\n *\n * @param t — Message type symbol.\n * @returns `true` if the signal should reach meta nodes.\n *\n * @example\n * ```ts\n * import { TEARDOWN, COMPLETE, ERROR, propagatesToMeta } from \"@graphrefly/graphrefly-ts\";\n *\n * propagatesToMeta(TEARDOWN); // true\n * propagatesToMeta(COMPLETE); // false\n * propagatesToMeta(ERROR); // false\n * ```\n */\nexport function propagatesToMeta(t: symbol): boolean {\n\treturn t === TEARDOWN;\n}\n","import {\n\tDATA,\n\tisPhase2Message,\n\tisTerminalMessage,\n\ttype Message,\n\ttype Messages,\n\tmessageTier,\n\tRESOLVED,\n} from \"./messages.js\";\n\n/**\n * §1.3.7 — Inside a batch, DIRTY propagates immediately; DATA and RESOLVED are\n * deferred until the outermost `batch()` callback returns. Terminal signals\n * (COMPLETE, ERROR) are delivered after phase-2 messages in the same batch\n * (see canonical ordering in `messages.ts`).\n */\n\nconst MAX_DRAIN_ITERATIONS = 1000;\n\nlet batchDepth = 0;\nlet flushInProgress = false;\nconst pendingPhase2: Array<() => void> = [];\nconst pendingPhase3: Array<() => void> = [];\n\n/**\n * Returns whether the current call stack is inside a batch scope **or** while\n * deferred phase-2 work is draining.\n *\n * Matching Python's `is_batching()` semantics: nested emissions during drain\n * are deferred until the current drain pass completes, preventing ordering\n * bugs when callbacks trigger further DATA/RESOLVED.\n *\n * @returns `true` while inside `batch()` or while the drain loop is running.\n *\n * @example\n * ```ts\n * import { batch, isBatching } from \"@graphrefly/graphrefly-ts\";\n *\n * batch(() => {\n * console.log(isBatching()); // true\n * });\n * ```\n *\n * @category core\n */\nexport function isBatching(): boolean {\n\treturn batchDepth > 0 || flushInProgress;\n}\n\n/**\n * Runs `fn` inside a batch scope. Nested `batch()` calls share one deferral queue.\n * If `fn` throws (including from a nested `batch`), deferred DATA/RESOLVED for\n * that **outer** `batch` frame are discarded — phase-2 is not flushed after an\n * error. While the drain loop is running (`flushInProgress`), a nested `batch`\n * that throws must **not** clear the global queue (cross-language decision A4).\n *\n * During the drain loop, `isBatching()` remains true so nested `emitWithBatch`\n * calls still defer phase-2 messages. The drain loop runs until the queue is\n * quiescent (no pending work remains). Per-emission try/catch ensures one\n * throwing callback does not orphan remaining emissions; the first error is\n * re-thrown after all emissions drain. Callbacks that ran before the throw may\n * have applied phase-2 — partial graph state is intentional (decision C1).\n *\n * @param fn — Synchronous work that may call `emitWithBatch` / `node.down()`.\n * @returns `void` — all side-effects happen through `emitWithBatch` and the\n * phase-2 drain that runs after `fn` returns.\n *\n * @example\n * ```ts\n * import { core } from \"@graphrefly/graphrefly-ts\";\n *\n * core.batch(() => {\n * core.emitWithBatch(sink, [[core.DATA, 1]]);\n * });\n * ```\n *\n * @category core\n */\nexport function batch(fn: () => void): void {\n\tbatchDepth += 1;\n\tlet threw = false;\n\ttry {\n\t\tfn();\n\t} catch (e) {\n\t\tthrew = true;\n\t\tthrow e;\n\t} finally {\n\t\tbatchDepth -= 1;\n\t\tif (batchDepth === 0) {\n\t\t\tif (threw) {\n\t\t\t\t// Do not wipe the outer drain's queue (decision A4).\n\t\t\t\tif (!flushInProgress) {\n\t\t\t\t\tpendingPhase2.length = 0;\n\t\t\t\t\tpendingPhase3.length = 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdrainPending();\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction drainPending(): void {\n\tconst ownsFlush = !flushInProgress;\n\tif (ownsFlush) {\n\t\tflushInProgress = true;\n\t}\n\tlet firstError: unknown;\n\tlet hasError = false;\n\ttry {\n\t\tlet iterations = 0;\n\t\t// Drain phase-2 first, then phase-3. If phase-3 callbacks enqueue new\n\t\t// phase-2 work, the outer loop catches it and drains phase-2 again\n\t\t// before re-entering phase-3.\n\t\twhile (pendingPhase2.length > 0 || pendingPhase3.length > 0) {\n\t\t\t// Phase-2 (DATA/RESOLVED) — parent node values settle here.\n\t\t\twhile (pendingPhase2.length > 0) {\n\t\t\t\titerations += 1;\n\t\t\t\tif (iterations > MAX_DRAIN_ITERATIONS) {\n\t\t\t\t\tpendingPhase2.length = 0;\n\t\t\t\t\tpendingPhase3.length = 0;\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`batch drain exceeded ${MAX_DRAIN_ITERATIONS} iterations — likely a reactive cycle`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst ops = pendingPhase2.splice(0);\n\t\t\t\tfor (const run of ops) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\trun();\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tif (!hasError) {\n\t\t\t\t\t\t\tfirstError = e;\n\t\t\t\t\t\t\thasError = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Phase-3 — meta companion emissions that must follow parent settlement.\n\t\t\tif (pendingPhase3.length > 0) {\n\t\t\t\titerations += 1;\n\t\t\t\tif (iterations > MAX_DRAIN_ITERATIONS) {\n\t\t\t\t\tpendingPhase2.length = 0;\n\t\t\t\t\tpendingPhase3.length = 0;\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`batch drain exceeded ${MAX_DRAIN_ITERATIONS} iterations — likely a reactive cycle`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst ops = pendingPhase3.splice(0);\n\t\t\t\tfor (const run of ops) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\trun();\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tif (!hasError) {\n\t\t\t\t\t\t\tfirstError = e;\n\t\t\t\t\t\t\thasError = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tif (ownsFlush) {\n\t\t\tflushInProgress = false;\n\t\t}\n\t}\n\tif (hasError) {\n\t\tthrow firstError;\n\t}\n}\n\n/**\n * Splits a message array into three groups by signal tier (see `messages.ts`):\n *\n * - **immediate** — tier 0–1: DIRTY, INVALIDATE, PAUSE, RESUME, TEARDOWN, unknown\n * - **deferred** — tier 2: DATA, RESOLVED (phase-2, deferred inside `batch()`)\n * - **terminal** — tier 3: COMPLETE, ERROR (delivered after phase-2)\n *\n * Order within each group is preserved.\n *\n * @param messages — One `down()` payload.\n * @returns Three groups in canonical delivery order.\n *\n * @example\n * ```ts\n * import { DATA, DIRTY, COMPLETE, partitionForBatch } from \"@graphrefly/graphrefly-ts\";\n *\n * partitionForBatch([[DIRTY], [DATA, 1], [COMPLETE]]);\n * // { immediate: [[DIRTY]], deferred: [[DATA, 1]], terminal: [[COMPLETE]] }\n * ```\n *\n * @category core\n */\nexport function partitionForBatch(messages: Messages): {\n\timmediate: Messages;\n\tdeferred: Messages;\n\tterminal: Messages;\n} {\n\tconst immediate: Message[] = [];\n\tconst deferred: Message[] = [];\n\tconst terminal: Message[] = [];\n\tfor (const m of messages) {\n\t\tif (isPhase2Message(m)) {\n\t\t\tdeferred.push(m);\n\t\t} else if (isTerminalMessage(m[0])) {\n\t\t\tterminal.push(m);\n\t\t} else {\n\t\t\timmediate.push(m);\n\t\t}\n\t}\n\treturn { immediate, deferred, terminal };\n}\n\n/**\n * Delivers messages through `emit`, applying batch semantics and canonical\n * tier-based ordering (see `messages.ts`):\n *\n * 1. **Immediate** (tier 0–1, 4): DIRTY, INVALIDATE, PAUSE, RESUME, TEARDOWN,\n * unknown — emitted synchronously.\n * 2. **Phase-2** (tier 2): DATA, RESOLVED — deferred while `isBatching()`.\n * 3. **Terminal** (tier 3): COMPLETE, ERROR — always delivered after phase-2.\n * When batching, terminal is queued after deferred phase-2 in the pending list.\n * When not batching, terminal is emitted after phase-2 synchronously.\n *\n * This ordering prevents the \"COMPLETE-before-DATA\" class of bugs: terminal\n * signals never make a node terminal before phase-2 values reach sinks,\n * regardless of how the source assembled the message array.\n *\n * @param emit — Sink callback. May be called up to three times per invocation\n * (immediate, deferred, terminal) when not batching.\n * @param messages — Full `[[Type, Data?], ...]` array for one emission.\n * @param phase — Starting delivery phase (`2` = data, `3` = terminal). Default `2`.\n * @param options - Optional configuration.\n * @option strategy | `\"partition\"` or `\"sequential\"` | `\"partition\"` | `\"partition\"` groups by tier; `\"sequential\"` preserves message order within each tier using `messageTier()` classification.\n * @returns `void` — delivery is performed through `emit` callbacks, synchronously\n * or deferred into the active batch queue.\n *\n * @example\n * ```ts\n * import { core } from \"@graphrefly/graphrefly-ts\";\n *\n * core.emitWithBatch((msgs) => console.log(msgs), [[core.DIRTY], [core.DATA, 42]]);\n * ```\n *\n * @category core\n */\nexport function emitWithBatch(\n\temit: (messages: Messages) => void,\n\tmessages: Messages,\n\tphase: 2 | 3 = 2,\n\toptions?: { strategy?: \"partition\" | \"sequential\" },\n): void {\n\tif (messages.length === 0) {\n\t\treturn;\n\t}\n\n\tif (options?.strategy === \"sequential\") {\n\t\t_emitSequential(emit, messages, phase);\n\t\treturn;\n\t}\n\n\tconst queue = phase === 3 ? pendingPhase3 : pendingPhase2;\n\n\t// Fast path: single-message batches (most common in graph-internal propagation)\n\t// skip partitionForBatch allocation entirely.\n\tif (messages.length === 1) {\n\t\tconst t = messages[0][0];\n\t\tif (t === DATA || t === RESOLVED) {\n\t\t\tif (isBatching()) {\n\t\t\t\tqueue.push(() => emit(messages));\n\t\t\t} else {\n\t\t\t\temit(messages);\n\t\t\t}\n\t\t} else if (isTerminalMessage(t)) {\n\t\t\t// Terminal single message: defer when batching so any preceding\n\t\t\t// phase-2 in the queue flushes first.\n\t\t\tif (isBatching()) {\n\t\t\t\tqueue.push(() => emit(messages));\n\t\t\t} else {\n\t\t\t\temit(messages);\n\t\t\t}\n\t\t} else {\n\t\t\t// Immediate: emit synchronously.\n\t\t\temit(messages);\n\t\t}\n\t\treturn;\n\t}\n\t// Multi-message: three-way partition by tier.\n\tconst { immediate, deferred, terminal } = partitionForBatch(messages);\n\n\t// 1. Immediate signals (tier 0–1, 4) — emit synchronously now.\n\tif (immediate.length > 0) {\n\t\temit(immediate);\n\t}\n\n\t// 2. Deferred (tier 2) + Terminal (tier 3) — canonical order preserved.\n\tif (isBatching()) {\n\t\tif (deferred.length > 0) {\n\t\t\tqueue.push(() => emit(deferred));\n\t\t}\n\t\tif (terminal.length > 0) {\n\t\t\tqueue.push(() => emit(terminal));\n\t\t}\n\t} else {\n\t\tif (deferred.length > 0) {\n\t\t\temit(deferred);\n\t\t}\n\t\tif (terminal.length > 0) {\n\t\t\temit(terminal);\n\t\t}\n\t}\n}\n\n/**\n * Sequential strategy: walk messages one at a time. Phase-2 (DATA/RESOLVED) and\n * terminal (COMPLETE/ERROR) messages are deferred while batching; immediate\n * messages emit synchronously. Matches graphrefly-py `_emit_sequential`.\n */\nfunction _emitSequential(\n\temit: (messages: Messages) => void,\n\tmessages: Messages,\n\tphase: 2 | 3 = 2,\n): void {\n\tconst dataQueue = phase === 3 ? pendingPhase3 : pendingPhase2;\n\tfor (const msg of messages) {\n\t\tconst tier = messageTier(msg[0]);\n\t\tif (tier === 2) {\n\t\t\t// Phase-2 (DATA/RESOLVED): defer while batching.\n\t\t\tif (isBatching()) {\n\t\t\t\tconst m = msg;\n\t\t\t\tdataQueue.push(() => emit([m]));\n\t\t\t} else {\n\t\t\t\temit([msg]);\n\t\t\t}\n\t\t} else if (tier >= 3) {\n\t\t\t// Terminal (COMPLETE/ERROR/TEARDOWN): always defer to phase-3\n\t\t\t// so all phase-2 work drains before terminals.\n\t\t\tif (isBatching()) {\n\t\t\t\tconst m = msg;\n\t\t\t\tpendingPhase3.push(() => emit([m]));\n\t\t\t} else {\n\t\t\t\temit([msg]);\n\t\t\t}\n\t\t} else {\n\t\t\t// Immediate (DIRTY, INVALIDATE, PAUSE, RESUME): emit synchronously.\n\t\t\temit([msg]);\n\t\t}\n\t}\n}\n","/**\n * Centralised timestamp utilities.\n *\n * Convention: all graphrefly-ts timestamps use nanoseconds (`_ns` suffix).\n *\n * - {@link monotonicNs} — monotonic clock (ordering, durations, timeline events).\n * - {@link wallClockNs} — wall-clock (mutation attribution, cron emission).\n *\n * **Precision limits (JS platform):**\n *\n * - `monotonicNs`: effective ~microsecond precision. `performance.now()` returns\n * milliseconds with ~5µs resolution; the last 3 digits of the nanosecond value\n * are always zero. Python's `time.monotonic_ns()` gives true nanoseconds.\n *\n * - `wallClockNs`: ~256ns precision loss at current epoch. `Date.now() * 1e6`\n * produces values around 1.8×10¹⁸ which exceed IEEE 754's 2⁵³ safe integer\n * limit. Python's `time.time_ns()` (arbitrary-precision `int`) has no loss.\n * In practice this is irrelevant — JS is single-threaded, so sub-microsecond\n * timestamp collisions cannot occur.\n */\n\n/** Monotonic nanosecond timestamp via `performance.now()`. */\nexport function monotonicNs(): number {\n\treturn Math.trunc(performance.now() * 1_000_000);\n}\n\n/** Wall-clock nanosecond timestamp via `Date.now()`. */\nexport function wallClockNs(): number {\n\treturn Date.now() * 1_000_000;\n}\n","import type { Actor } from \"./actor.js\";\n\n/**\n * Actions checked by {@link NodeGuard}. `write` covers both {@link Node.down} and\n * {@link Node.up} today; finer-grained strings may be added later (e.g. `\"write.data\"`).\n */\nexport type GuardAction = \"write\" | \"signal\" | \"observe\" | (string & {});\n\nexport type NodeGuard = (actor: Actor, action: GuardAction) => boolean;\n\nexport type GuardDeniedDetails = {\n\tactor: Actor;\n\taction: GuardAction;\n\t/** Registry or options name when known */\n\tnodeName?: string;\n};\n\n/**\n * Thrown when a {@link NodeGuard} denies an action for a given actor.\n *\n * Carries the rejected `actor`, `action`, and optional `nodeName` for diagnostic\n * messages and middleware error handling.\n *\n * @example\n * ```ts\n * import { GuardDenied, policy } from \"@graphrefly/graphrefly-ts\";\n *\n * const guard = policy((allow) => { allow(\"observe\"); });\n * try {\n * if (!guard({ type: \"llm\", id: \"agent-1\" }, \"write\")) {\n * throw new GuardDenied(\n * { actor: { type: \"llm\", id: \"agent-1\" }, action: \"write\", nodeName: \"userInput\" },\n * );\n * }\n * } catch (e) {\n * if (e instanceof GuardDenied) console.error(e.action, e.actor.type); // \"write\" \"llm\"\n * }\n * ```\n */\nexport class GuardDenied extends Error {\n\treadonly actor: Actor;\n\treadonly action: GuardAction;\n\treadonly nodeName?: string;\n\n\t/**\n\t * @param details - Actor, action, and optional node name for the denial.\n\t * @param message - Optional override for the default error message.\n\t */\n\tconstructor(details: GuardDeniedDetails, message?: string) {\n\t\tsuper(\n\t\t\tmessage ??\n\t\t\t\t`GuardDenied: action \"${String(details.action)}\" denied for actor type \"${String(details.actor.type)}\"`,\n\t\t);\n\t\tthis.name = \"GuardDenied\";\n\t\tthis.actor = details.actor;\n\t\tthis.action = details.action;\n\t\tthis.nodeName = details.nodeName;\n\t}\n\n\t/** Qualified registry path when known (roadmap diagnostics: same as {@link nodeName}). */\n\tget node(): string | undefined {\n\t\treturn this.nodeName;\n\t}\n}\n\ntype Where = (actor: Actor) => boolean;\n\ntype Rule = {\n\tkind: \"allow\" | \"deny\";\n\tactions: Set<GuardAction>;\n\twhere: Where;\n};\n\nfunction normalizeActions(action: GuardAction | readonly GuardAction[]): GuardAction[] {\n\tif (Array.isArray(action)) {\n\t\treturn [...action];\n\t}\n\treturn [action as GuardAction];\n}\n\nfunction matchesActions(set: Set<GuardAction>, action: GuardAction): boolean {\n\treturn set.has(action) || set.has(\"*\" as GuardAction);\n}\n\nexport type PolicyAllow = (\n\taction: GuardAction | readonly GuardAction[],\n\topts?: { where?: Where },\n) => void;\n\nexport type PolicyDeny = (\n\taction: GuardAction | readonly GuardAction[],\n\topts?: { where?: Where },\n) => void;\n\nexport type PolicyRuleData = {\n\teffect: \"allow\" | \"deny\";\n\taction: GuardAction | readonly GuardAction[];\n\tactorType?: string | readonly string[];\n\tactorId?: string | readonly string[];\n\tclaims?: Record<string, unknown>;\n};\n\n/**\n * Declarative guard builder. Precedence: any matching **deny** blocks even if an allow also matches.\n * If no rule matches, the guard returns `false` (deny-by-default). Aligned with graphrefly-py `policy()`.\n *\n * @param build - Callback that registers `allow(...)` / `deny(...)` rules in order.\n * @returns A `NodeGuard` for use as `node({ guard })`.\n *\n * @example\n * ```ts\n * const guard = policy((allow, deny) => {\n * allow(\"observe\");\n * deny(\"write\", { where: (a) => a.type === \"llm\" });\n * });\n * ```\n */\nexport function policy(build: (allow: PolicyAllow, deny: PolicyDeny) => void): NodeGuard {\n\tconst rules: Rule[] = [];\n\tconst allow: PolicyAllow = (action, opts) => {\n\t\trules.push({\n\t\t\tkind: \"allow\",\n\t\t\tactions: new Set(normalizeActions(action)),\n\t\t\twhere: opts?.where ?? (() => true),\n\t\t});\n\t};\n\tconst deny: PolicyDeny = (action, opts) => {\n\t\trules.push({\n\t\t\tkind: \"deny\",\n\t\t\tactions: new Set(normalizeActions(action)),\n\t\t\twhere: opts?.where ?? (() => true),\n\t\t});\n\t};\n\tbuild(allow, deny);\n\treturn (actor, action) => {\n\t\tlet denied = false;\n\t\tlet allowed = false;\n\t\tfor (const r of rules) {\n\t\t\tif (!matchesActions(r.actions, action)) continue;\n\t\t\tif (!r.where(actor)) continue;\n\t\t\tif (r.kind === \"deny\") {\n\t\t\t\tdenied = true;\n\t\t\t} else {\n\t\t\t\tallowed = true;\n\t\t\t}\n\t\t}\n\t\tif (denied) return false;\n\t\treturn allowed;\n\t};\n}\n\n/**\n * Rebuild a declarative guard from persisted policy data (snapshot-safe).\n *\n * Rules are deny-overrides, same semantics as {@link policy}.\n */\nexport function policyFromRules(rules: readonly PolicyRuleData[]): NodeGuard {\n\treturn policy((allow, deny) => {\n\t\tfor (const rule of rules) {\n\t\t\tconst actorTypes =\n\t\t\t\trule.actorType == null\n\t\t\t\t\t? null\n\t\t\t\t\t: new Set(Array.isArray(rule.actorType) ? rule.actorType : [rule.actorType]);\n\t\t\tconst actorIds =\n\t\t\t\trule.actorId == null\n\t\t\t\t\t? null\n\t\t\t\t\t: new Set(Array.isArray(rule.actorId) ? rule.actorId : [rule.actorId]);\n\t\t\tconst claimEntries = Object.entries(rule.claims ?? {});\n\t\t\tconst where: Where = (actor) => {\n\t\t\t\tif (actorTypes !== null && !actorTypes.has(String(actor.type))) return false;\n\t\t\t\tif (actorIds !== null && !actorIds.has(String(actor.id ?? \"\"))) return false;\n\t\t\t\tfor (const [key, value] of claimEntries) {\n\t\t\t\t\tif ((actor as Record<string, unknown>)[key] !== value) return false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t};\n\t\t\tif (rule.effect === \"deny\") {\n\t\t\t\tdeny(rule.action, { where });\n\t\t\t} else {\n\t\t\t\tallow(rule.action, { where });\n\t\t\t}\n\t\t}\n\t});\n}\n\nconst STANDARD_WRITE_TYPES = [\"human\", \"llm\", \"wallet\", \"system\"] as const;\n\n/**\n * Derives a best-effort `meta.access` hint string by probing `guard` with the\n * standard actor types `human`, `llm`, `wallet`, `system` for the `\"write\"` action\n * (roadmap 1.5). Aligned with graphrefly-py `access_hint_for_guard`.\n *\n * @param guard - Guard function to probe (typically from {@link policy}).\n * @returns `\"restricted\"` when no standard type is allowed; `\"both\"` when both\n * `human` and `llm` are allowed (plus optionally `system`); the single allowed\n * type name when only one passes; or a `\"+\"` joined list otherwise.\n *\n * @example\n * ```ts\n * import { policy, accessHintForGuard } from \"@graphrefly/graphrefly-ts\";\n *\n * const guardBoth = policy((allow) => { allow(\"write\"); });\n * accessHintForGuard(guardBoth); // \"both\"\n *\n * const guardHuman = policy((allow) => {\n * allow(\"write\", { where: (a) => a.type === \"human\" });\n * });\n * accessHintForGuard(guardHuman); // \"human\"\n * ```\n */\nexport function accessHintForGuard(guard: NodeGuard): string {\n\tconst allowed = STANDARD_WRITE_TYPES.filter((t) => guard({ type: t, id: \"\" }, \"write\"));\n\tif (allowed.length === 0) return \"restricted\";\n\tif (\n\t\tallowed.includes(\"human\") &&\n\t\tallowed.includes(\"llm\") &&\n\t\tallowed.every((t) => t === \"human\" || t === \"llm\" || t === \"system\")\n\t) {\n\t\treturn \"both\";\n\t}\n\tif (allowed.length === 1) return allowed[0];\n\treturn allowed.join(\"+\");\n}\n","/**\n * Node versioning — GRAPHREFLY-SPEC §7.\n *\n * Progressive, optional versioning for node identity and change tracking.\n *\n * - **V0**: `id` + `version` — identity & change detection (~16 bytes overhead)\n * - **V1**: + `cid` + `prev` — content addressing & linked history (~60 bytes overhead)\n *\n * **Lifecycle notes:**\n * - Version advances only on DATA (not RESOLVED, INVALIDATE, or TEARDOWN).\n * - `resetOnTeardown` clears the cached value but does NOT reset versioning state.\n * After teardown, `v.cid` still reflects the last DATA value, not the cleared cache.\n * The invariant `hash(node.get()) === v.cid` only holds in `settled`/`resolved` status.\n * - Resubscribable nodes preserve versioning across subscription lifetimes (monotonic counter).\n */\n\nimport { createHash, randomUUID } from \"node:crypto\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** V0: identity + monotonic version counter. */\nexport type V0 = {\n\treadonly id: string;\n\tversion: number;\n};\n\n/** V1: V0 + content-addressed identifier + previous cid link. */\nexport type V1 = V0 & {\n\tcid: string;\n\tprev: string | null;\n};\n\n/** Union of all versioning info shapes. */\nexport type NodeVersionInfo = V0 | V1;\n\n/** Supported versioning levels (extensible to 2, 3 later). */\nexport type VersioningLevel = 0 | 1;\n\n/** Function that hashes a value to a hex string (for V1 cid). */\nexport type HashFn = (value: unknown) => string;\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface VersioningOptions {\n\t/** Override auto-generated id. */\n\tid?: string;\n\t/** Custom hash function for V1 cid (default: SHA-256 truncated to 16 hex chars). */\n\thash?: HashFn;\n}\n\n// ---------------------------------------------------------------------------\n// Default hash\n// ---------------------------------------------------------------------------\n\n/**\n * Canonicalize a value for deterministic cross-language hashing.\n *\n * - Integer-valued floats normalize to integer strings (`1.0` → `1`).\n * - `NaN`, `Infinity`, `-Infinity` are rejected (no JSON equivalent).\n * - `undefined` normalizes to `null`.\n * - Object keys are sorted lexicographically.\n *\n * This ensures TS `JSON.stringify` and Python `json.dumps(sort_keys=True)`\n * produce identical output for the same logical value.\n */\nexport function canonicalizeForHash(value: unknown): unknown {\n\tif (value === undefined) return null;\n\tif (typeof value === \"number\") {\n\t\tif (!Number.isFinite(value)) {\n\t\t\tthrow new TypeError(`Cannot hash non-finite number: ${value}`);\n\t\t}\n\t\tif (Number.isInteger(value) && !Number.isSafeInteger(value)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`Cannot hash integer outside safe range (|n| > 2^53-1): ${value}. ` +\n\t\t\t\t\t\"Cross-language cid parity is not guaranteed for unsafe integers.\",\n\t\t\t);\n\t\t}\n\t\treturn value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"boolean\" || value === null) {\n\t\treturn value;\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map(canonicalizeForHash);\n\t}\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst sorted: Record<string, unknown> = {};\n\t\tfor (const k of Object.keys(value as Record<string, unknown>).sort()) {\n\t\t\tsorted[k] = canonicalizeForHash((value as Record<string, unknown>)[k]);\n\t\t}\n\t\treturn sorted;\n\t}\n\t// Fallback: coerce to null (bigint, symbol, function)\n\treturn null;\n}\n\n/**\n * Default content hash: SHA-256 of deterministic JSON, truncated to 16 hex chars (~64-bit).\n * Uses {@link canonicalizeForHash} for cross-language parity with Python `default_hash`.\n */\nexport function defaultHash(value: unknown): string {\n\tconst canonical = canonicalizeForHash(value ?? null);\n\tconst json = JSON.stringify(canonical);\n\treturn createHash(\"sha256\").update(json).digest(\"hex\").slice(0, 16);\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create initial versioning state for a node.\n *\n * @param level - 0 for V0, 1 for V1.\n * @param initialValue - The node's initial cached value (used for V1 cid).\n * @param opts - Optional overrides (id, hash).\n */\nexport function createVersioning(\n\tlevel: VersioningLevel,\n\tinitialValue: unknown,\n\topts?: VersioningOptions,\n): NodeVersionInfo {\n\tconst id = opts?.id ?? randomUUID();\n\tif (level === 0) {\n\t\treturn { id, version: 0 } satisfies V0;\n\t}\n\tconst hash = opts?.hash ?? defaultHash;\n\tconst cid = hash(initialValue);\n\treturn { id, version: 0, cid, prev: null } satisfies V1;\n}\n\n// ---------------------------------------------------------------------------\n// Advance\n// ---------------------------------------------------------------------------\n\n/**\n * Advance versioning state after a DATA emission (value changed).\n *\n * Mutates `info` in place for performance (called on every DATA).\n * Only call when the cached value has actually changed (not on RESOLVED).\n *\n * @param info - The node's current versioning state.\n * @param newValue - The new cached value.\n * @param hashFn - Hash function (only used for V1).\n */\nexport function advanceVersion(info: NodeVersionInfo, newValue: unknown, hashFn: HashFn): void {\n\tinfo.version += 1;\n\tif (\"cid\" in info) {\n\t\t(info as V1).prev = (info as V1).cid;\n\t\t(info as V1).cid = hashFn(newValue);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Guards\n// ---------------------------------------------------------------------------\n\n/** Type guard: is this V1 versioning info? */\nexport function isV1(info: NodeVersionInfo): info is V1 {\n\treturn \"cid\" in info;\n}\n","import type { Actor } from \"./actor.js\";\nimport { normalizeActor } from \"./actor.js\";\nimport { emitWithBatch } from \"./batch.js\";\nimport { wallClockNs } from \"./clock.js\";\nimport type { GuardAction, NodeGuard } from \"./guard.js\";\nimport { GuardDenied } from \"./guard.js\";\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tINVALIDATE,\n\ttype Message,\n\ttype Messages,\n\tPAUSE,\n\tpropagatesToMeta,\n\tRESOLVED,\n\tRESUME,\n\tTEARDOWN,\n} from \"./messages.js\";\nimport type { HashFn, NodeVersionInfo, VersioningLevel } from \"./versioning.js\";\nimport { advanceVersion, createVersioning, defaultHash } from \"./versioning.js\";\n\n/**\n * Internal sentinel value: \"no cached value has been set or emitted.\"\n * Used instead of `undefined` so that `undefined` can be a valid emitted value.\n */\nexport const NO_VALUE: unique symbol = Symbol.for(\"graphrefly/NO_VALUE\");\n\n/**\n * Branded symbol that marks a {@link CleanupResult} wrapper.\n * Used internally by {@link cleanupResult} — prevents duck-type collisions\n * with domain objects that happen to have a `cleanup` property.\n */\nexport const CLEANUP_RESULT: unique symbol = Symbol.for(\"graphrefly/CLEANUP_RESULT\");\n\n/** Lifecycle status of a node. */\nexport type NodeStatus =\n\t| \"disconnected\"\n\t| \"dirty\"\n\t| \"settled\"\n\t| \"resolved\"\n\t| \"completed\"\n\t| \"errored\";\n\n/** Callback that receives downstream message batches. */\nexport type NodeSink = (messages: Messages) => void;\n\n/**\n * Compute function passed to `node()`.\n *\n * @returns A value to emit, `undefined` to skip emission, or a cleanup\n * function invoked before the next run or on teardown.\n */\nexport type NodeFn<T = unknown> = (\n\tdeps: readonly unknown[],\n\tactions: NodeActions,\n) => T | undefined | (() => void);\n\n/** Imperative actions available inside a {@link NodeFn}. */\nexport interface NodeActions {\n\t/** Emit raw messages downstream. */\n\tdown(messages: Messages): void;\n\t/** Emit a single value (auto-wraps in DIRTY/DATA or DIRTY/RESOLVED). */\n\temit(value: unknown): void;\n\t/** Send messages upstream toward sources. */\n\tup(messages: Messages): void;\n}\n\n/**\n * Callback for intercepting messages before the default dispatch.\n *\n * Called for every message from every dep. Return `true` to consume the\n * message (skip default handling), or `false` to let default dispatch run.\n *\n * @param msg — The message tuple `[Type, Data?]`.\n * @param depIndex — Which dep sent it (index into the deps array).\n * @param actions — `{ down(), emit(), up() }` — same as `NodeFn` receives.\n */\nexport type OnMessageHandler = (msg: Message, depIndex: number, actions: NodeActions) => boolean;\n\n/**\n * Internal inspector hook (opt-in): emits dependency message and run events\n * for graph-level observability features (`observe(..., { causal|derived })`).\n */\nexport type NodeInspectorHookEvent =\n\t| { kind: \"dep_message\"; depIndex: number; message: Message }\n\t| { kind: \"run\"; depValues: readonly unknown[] };\n\nexport type NodeInspectorHook = (event: NodeInspectorHookEvent) => void;\n\n/** Explicit describe `type` for {@link Graph.describe} / {@link describeNode} (GRAPHREFLY-SPEC Appendix B). */\nexport type NodeDescribeKind = \"state\" | \"derived\" | \"producer\" | \"operator\" | \"effect\";\n\n/** Options for {@link node}. */\nexport interface NodeOptions {\n\tname?: string;\n\t/**\n\t * Overrides inferred `type` in describe output. Sugar constructors set this;\n\t * omit to infer from deps / fn / manual emit usage.\n\t */\n\tdescribeKind?: NodeDescribeKind;\n\t/** Equality check for RESOLVED detection. Defaults to `Object.is`. */\n\tequals?: (a: unknown, b: unknown) => boolean;\n\tinitial?: unknown;\n\t/**\n\t * Each key becomes an independently subscribable companion node.\n\t * Meta nodes outlive the parent's subscription lifecycle: when all sinks\n\t * unsubscribe the parent disconnects upstream but meta nodes stay alive.\n\t * Send `[[TEARDOWN]]` to the parent to release meta node resources.\n\t */\n\tmeta?: Record<string, unknown>;\n\t/** Allow fresh subscriptions after COMPLETE/ERROR. */\n\tresubscribable?: boolean;\n\t/**\n\t * Invoked when a new {@link Node.subscribe} clears a terminal state on a\n\t * resubscribable node — reset operator-local counters/accumulators here.\n\t */\n\tonResubscribe?: () => void;\n\t/** Clear cached value on TEARDOWN. */\n\tresetOnTeardown?: boolean;\n\t/**\n\t * When `true` (default), auto-emit `[[COMPLETE]]` when all deps complete\n\t * (spec §1.3.5). Set `false` for derived/operator nodes that should not\n\t * auto-complete.\n\t */\n\tcompleteWhenDepsComplete?: boolean;\n\t/**\n\t * Intercept messages before the default dispatch (spec §2.6).\n\t *\n\t * Return `true` to consume the message (skip default handling),\n\t * or `false` to let the default dispatch run.\n\t */\n\tonMessage?: OnMessageHandler;\n\t/**\n\t * ABAC: `(actor, action) => boolean`. `write` applies to both {@link Node.down} and {@link Node.up}.\n\t * Companion {@link NodeOptions.meta | meta} nodes inherit this guard from the primary.\n\t */\n\tguard?: NodeGuard;\n\t/**\n\t * Opt-in versioning level (GRAPHREFLY-SPEC §7).\n\t * - `0` (V0): `id` + `version` — identity & change detection.\n\t * - `1` (V1): + `cid` + `prev` — content addressing & linked history.\n\t */\n\tversioning?: VersioningLevel;\n\t/** Override auto-generated versioning id. */\n\tversioningId?: string;\n\t/** Custom hash function for V1 cid computation. */\n\tversioningHash?: HashFn;\n}\n\n/**\n * Options for {@link Node.down} / {@link Node.up} (actor context, graph delivery mode, internal bypass).\n */\nexport type NodeTransportOptions = {\n\tactor?: Actor;\n\t/**\n\t * When `true`, skips guard checks (reactive internals, graph lifecycle TEARDOWN, etc.).\n\t * Not for untrusted call sites.\n\t */\n\tinternal?: boolean;\n\t/**\n\t * `signal` for {@link Graph.signal} deliveries; default `write` for {@link Graph.set} and direct `down`.\n\t */\n\tdelivery?: \"write\" | \"signal\";\n};\n\n/**\n * Optional hints passed to {@link Node.subscribe} to enable per-sink\n * optimizations.\n */\nexport interface SubscribeHints {\n\t/**\n\t * Subscriber has exactly one dep with `fn` — the source may skip DIRTY\n\t * dispatch when this is the sole subscriber. The subscriber synthesizes\n\t * dirty state locally via `onDepSettled`.\n\t */\n\tsingleDep?: boolean;\n\t/**\n\t * Actor to check against the node's `observe` guard.\n\t * When set, `subscribe()` throws {@link GuardDenied} if the actor is not\n\t * permitted to observe this node. Aligned with graphrefly-py `subscribe(actor=)`.\n\t */\n\tactor?: Actor;\n}\n\n/** A reactive node in the GraphReFly protocol. */\nexport interface Node<T = unknown> {\n\treadonly name?: string;\n\treadonly status: NodeStatus;\n\treadonly meta: Record<string, Node>;\n\t/** Returns the current cached value. */\n\tget(): T | undefined;\n\t/** Push messages downstream. */\n\tdown(messages: Messages, options?: NodeTransportOptions): void;\n\t/**\n\t * Registers a sink to receive downstream messages.\n\t *\n\t * @param sink - Callback receiving message batches.\n\t * @param hints - Optional optimization hints (e.g. `{ singleDep: true }`).\n\t * @returns An unsubscribe function (idempotent).\n\t */\n\tsubscribe(sink: NodeSink, hints?: SubscribeHints): () => void;\n\t/** Send messages upstream (present on nodes with deps). */\n\tup?: (messages: Messages, options?: NodeTransportOptions) => void;\n\t/** Disconnect from upstream deps (present on nodes with deps). */\n\tunsubscribe?: () => void;\n\t/** Last successful guarded `down` / `up` (not set for `internal` deliveries). */\n\treadonly lastMutation?: Readonly<{ actor: Actor; timestamp_ns: number }>;\n\t/** Whether {@link NodeTransportOptions.actor | actor} may {@link Graph.observe | observe} this node. */\n\tallowsObserve(actor: Actor): boolean;\n\t/** Whether a {@link NodeOptions.guard | guard} is installed. */\n\thasGuard(): boolean;\n\t/** Versioning info (GRAPHREFLY-SPEC §7). `undefined` when versioning is not enabled. */\n\treadonly v: Readonly<NodeVersionInfo> | undefined;\n}\n\n// --- Bitmask helpers: integer for <=31 deps, Uint32Array for >31 ---\n\ninterface BitSet {\n\tset(index: number): void;\n\tclear(index: number): void;\n\thas(index: number): boolean;\n\t/**\n\t * True when all bits in `other` are also set in `this`.\n\t * IMPORTANT: `other` must be the same concrete type (both IntBitSet or both\n\t * ArrayBitSet). Cross-type calls will crash. Within `node()`, all masks for\n\t * a given node share the same `createBitSet(deps.length)` factory, so this\n\t * is always satisfied.\n\t */\n\tcovers(other: BitSet): boolean;\n\t/** True when at least one bit is set. */\n\tany(): boolean;\n\treset(): void;\n}\n\nfunction createIntBitSet(): BitSet {\n\tlet bits = 0;\n\treturn {\n\t\tset(i: number) {\n\t\t\tbits |= 1 << i;\n\t\t},\n\t\tclear(i: number) {\n\t\t\tbits &= ~(1 << i);\n\t\t},\n\t\thas(i: number) {\n\t\t\treturn (bits & (1 << i)) !== 0;\n\t\t},\n\t\tcovers(other: BitSet) {\n\t\t\treturn (\n\t\t\t\t(bits & (other as unknown as { _bits(): number })._bits()) ===\n\t\t\t\t(other as unknown as { _bits(): number })._bits()\n\t\t\t);\n\t\t},\n\t\tany() {\n\t\t\treturn bits !== 0;\n\t\t},\n\t\treset() {\n\t\t\tbits = 0;\n\t\t},\n\t\t_bits() {\n\t\t\treturn bits;\n\t\t},\n\t} as BitSet & { _bits(): number };\n}\n\nfunction createArrayBitSet(size: number): BitSet {\n\tconst words = new Uint32Array(Math.ceil(size / 32));\n\treturn {\n\t\tset(i: number) {\n\t\t\twords[i >>> 5] |= 1 << (i & 31);\n\t\t},\n\t\tclear(i: number) {\n\t\t\twords[i >>> 5] &= ~(1 << (i & 31));\n\t\t},\n\t\thas(i: number) {\n\t\t\treturn (words[i >>> 5] & (1 << (i & 31))) !== 0;\n\t\t},\n\t\tcovers(other: BitSet) {\n\t\t\tconst ow = (other as unknown as { _words: Uint32Array })._words;\n\t\t\tfor (let w = 0; w < words.length; w++) {\n\t\t\t\tif ((words[w] & ow[w]) >>> 0 !== ow[w]) return false;\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\tany() {\n\t\t\tfor (let w = 0; w < words.length; w++) {\n\t\t\t\tif (words[w] !== 0) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\treset() {\n\t\t\twords.fill(0);\n\t\t},\n\t\t_words: words,\n\t} as unknown as BitSet;\n}\n\nfunction createBitSet(size: number): BitSet {\n\treturn size <= 31 ? createIntBitSet() : createArrayBitSet(size);\n}\n\nconst isNodeArray = (value: unknown): value is readonly Node[] => Array.isArray(value);\n\nconst isNodeOptions = (value: unknown): value is NodeOptions =>\n\ttypeof value === \"object\" && value != null && !Array.isArray(value);\n\n/**\n * Explicit cleanup wrapper. When a node fn returns `{ cleanup, value? }`,\n * `cleanup` is registered as the teardown/recompute cleanup and `value`\n * (if present) is emitted as data. This avoids the ambiguity where returning\n * a plain function is silently consumed as cleanup instead of emitted as data.\n *\n * Use the {@link cleanupResult} factory to create instances — it stamps the\n * branded {@link CLEANUP_RESULT} symbol so that domain objects with a `cleanup`\n * property are never misinterpreted.\n *\n * Plain function returns are still treated as cleanup for backward compatibility.\n */\nexport type CleanupResult<T = unknown> = {\n\treadonly [CLEANUP_RESULT]: true;\n\tcleanup: () => void;\n\tvalue?: T;\n};\n\n/**\n * Create a branded {@link CleanupResult}.\n *\n * ```ts\n * node([dep], () => cleanupResult(() => release(), computedValue))\n * ```\n */\nexport function cleanupResult<T>(cleanup: () => void): CleanupResult<T>;\nexport function cleanupResult<T>(cleanup: () => void, value: T): CleanupResult<T>;\nexport function cleanupResult<T>(cleanup: () => void, ...args: [] | [T]): CleanupResult<T> {\n\tconst r: CleanupResult<T> = { [CLEANUP_RESULT]: true, cleanup };\n\tif (args.length > 0) r.value = args[0];\n\treturn r;\n}\n\nconst isCleanupResult = (value: unknown): value is CleanupResult =>\n\ttypeof value === \"object\" && value !== null && CLEANUP_RESULT in value;\n\nconst isCleanupFn = (value: unknown): value is () => void => typeof value === \"function\";\n\nconst statusAfterMessage = (status: NodeStatus, msg: Message): NodeStatus => {\n\tconst t = msg[0];\n\tif (t === DIRTY) return \"dirty\";\n\tif (t === DATA) return \"settled\";\n\tif (t === RESOLVED) return \"resolved\";\n\tif (t === COMPLETE) return \"completed\";\n\tif (t === ERROR) return \"errored\";\n\tif (t === INVALIDATE) return \"dirty\";\n\tif (t === TEARDOWN) return \"disconnected\";\n\treturn status;\n};\n\n// --- NodeImpl: class-based for V8 hidden class optimization and prototype method sharing ---\n\n/**\n * Class-based implementation of the {@link Node} interface.\n *\n * All internal state lives on instance fields (`_` prefix, private by convention)\n * so that introspection (e.g. {@link describeNode}) can read them directly via\n * `instanceof NodeImpl` — no side-channel registry needed.\n *\n * Follows callbag-recharge's `ProducerImpl` pattern: V8 hidden class stability,\n * prototype method sharing, selective binding for commonly detached methods.\n */\nexport class NodeImpl<T = unknown> implements Node<T> {\n\t// --- Configuration (set once, never reassigned) ---\n\tprivate readonly _optsName: string | undefined;\n\tprivate _registryName: string | undefined;\n\t/** @internal — read by {@link describeNode} before inference. */\n\treadonly _describeKind: NodeDescribeKind | undefined;\n\treadonly meta: Record<string, Node>;\n\t_deps: readonly Node[];\n\t_fn: NodeFn<T> | undefined;\n\t_opts: NodeOptions;\n\t_equals: (a: unknown, b: unknown) => boolean;\n\t_onMessage: OnMessageHandler | undefined;\n\t/** @internal — read by {@link describeNode} for `accessHintForGuard`. */\n\treadonly _guard: NodeGuard | undefined;\n\tprivate _lastMutation: { actor: Actor; timestamp_ns: number } | undefined;\n\t_hasDeps: boolean;\n\t_autoComplete: boolean;\n\t_isSingleDep: boolean;\n\n\t// --- Mutable state ---\n\t_cached: T | typeof NO_VALUE;\n\t_status: NodeStatus;\n\t_terminal = false;\n\t_connected = false;\n\t_producerStarted = false;\n\t_connecting = false;\n\t_manualEmitUsed = false;\n\t_sinkCount = 0;\n\t_singleDepSinkCount = 0;\n\n\t// --- Object/collection state ---\n\t_depDirtyMask: BitSet;\n\t_depSettledMask: BitSet;\n\t_depCompleteMask: BitSet;\n\t_allDepsCompleteMask: BitSet;\n\t_lastDepValues: readonly unknown[] | undefined;\n\t_cleanup: (() => void) | undefined;\n\t_sinks: NodeSink | Set<NodeSink> | null = null;\n\t_singleDepSinks = new WeakSet<NodeSink>();\n\t_upstreamUnsubs: Array<() => void> = [];\n\t_actions: NodeActions;\n\t_boundEmitToSinks: (messages: Messages) => void;\n\tprivate _inspectorHook: NodeInspectorHook | undefined;\n\tprivate _versioning: NodeVersionInfo | undefined;\n\tprivate _hashFn: HashFn;\n\n\tconstructor(deps: readonly Node[], fn: NodeFn<T> | undefined, opts: NodeOptions) {\n\t\tthis._deps = deps;\n\t\tthis._fn = fn;\n\t\tthis._opts = opts;\n\t\tthis._optsName = opts.name;\n\t\tthis._describeKind = opts.describeKind;\n\t\tthis._equals = opts.equals ?? Object.is;\n\t\tthis._onMessage = opts.onMessage;\n\t\tthis._guard = opts.guard;\n\t\tthis._hasDeps = deps.length > 0;\n\t\tthis._autoComplete = opts.completeWhenDepsComplete ?? true;\n\t\tthis._isSingleDep = deps.length === 1 && fn != null;\n\n\t\tthis._cached = \"initial\" in opts ? (opts.initial as T) : NO_VALUE;\n\t\tthis._status = this._hasDeps ? \"disconnected\" : \"settled\";\n\n\t\t// Versioning (GRAPHREFLY-SPEC §7)\n\t\tthis._hashFn = opts.versioningHash ?? defaultHash;\n\t\tthis._versioning =\n\t\t\topts.versioning != null\n\t\t\t\t? createVersioning(opts.versioning, this._cached === NO_VALUE ? undefined : this._cached, {\n\t\t\t\t\t\tid: opts.versioningId,\n\t\t\t\t\t\thash: this._hashFn,\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\n\t\tthis._depDirtyMask = createBitSet(deps.length);\n\t\tthis._depSettledMask = createBitSet(deps.length);\n\t\tthis._depCompleteMask = createBitSet(deps.length);\n\t\tthis._allDepsCompleteMask = createBitSet(deps.length);\n\t\tfor (let i = 0; i < deps.length; i++) this._allDepsCompleteMask.set(i);\n\n\t\t// Build companion meta nodes\n\t\tconst meta: Record<string, Node> = {};\n\t\tfor (const [k, v] of Object.entries(opts.meta ?? {})) {\n\t\t\tmeta[k] = node({\n\t\t\t\tinitial: v,\n\t\t\t\tname: `${opts.name ?? \"node\"}:meta:${k}`,\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\t...(opts.guard != null ? { guard: opts.guard } : {}),\n\t\t\t});\n\t\t}\n\t\tObject.freeze(meta);\n\t\tthis.meta = meta;\n\n\t\t// Actions object: created once, references `this` methods.\n\t\t// Captures `this` via arrow-in-object so manualEmitUsed is set on the instance.\n\t\tconst self = this;\n\t\tthis._actions = {\n\t\t\tdown(messages): void {\n\t\t\t\tself._manualEmitUsed = true;\n\t\t\t\tself._downInternal(messages);\n\t\t\t},\n\t\t\temit(value): void {\n\t\t\t\tself._manualEmitUsed = true;\n\t\t\t\tself._emitAutoValue(value);\n\t\t\t},\n\t\t\tup(messages): void {\n\t\t\t\tself._upInternal(messages);\n\t\t\t},\n\t\t};\n\n\t\t// Bind commonly detached protocol methods\n\t\tthis.down = this.down.bind(this);\n\t\tthis.up = this.up.bind(this);\n\t\tthis._boundEmitToSinks = this._emitToSinks.bind(this);\n\t}\n\n\tget name(): string | undefined {\n\t\treturn this._registryName ?? this._optsName;\n\t}\n\n\t/**\n\t * When a node is registered with {@link Graph.add} without an options `name`,\n\t * the graph assigns the registry local name for introspection (parity with graphrefly-py).\n\t */\n\t_assignRegistryName(localName: string): void {\n\t\tif (this._optsName !== undefined || this._registryName !== undefined) return;\n\t\tthis._registryName = localName;\n\t}\n\n\t/**\n\t * @internal Attach/remove inspector hook for graph-level observability.\n\t * Returns a disposer that restores the previous hook.\n\t */\n\t_setInspectorHook(hook?: NodeInspectorHook): () => void {\n\t\tconst prev = this._inspectorHook;\n\t\tthis._inspectorHook = hook;\n\t\treturn () => {\n\t\t\tif (this._inspectorHook === hook) {\n\t\t\t\tthis._inspectorHook = prev;\n\t\t\t}\n\t\t};\n\t}\n\n\t// --- Public interface (Node<T>) ---\n\n\tget status(): NodeStatus {\n\t\treturn this._status;\n\t}\n\n\tget lastMutation(): Readonly<{ actor: Actor; timestamp_ns: number }> | undefined {\n\t\treturn this._lastMutation;\n\t}\n\n\tget v(): Readonly<NodeVersionInfo> | undefined {\n\t\treturn this._versioning;\n\t}\n\n\t/**\n\t * Retroactively apply versioning to a node that was created without it.\n\t * No-op if versioning is already enabled.\n\t *\n\t * Version starts at 0 regardless of prior DATA emissions — it tracks\n\t * changes from the moment versioning is enabled, not historical ones.\n\t *\n\t * @internal — used by {@link Graph.setVersioning}.\n\t */\n\t_applyVersioning(level: VersioningLevel, opts?: { id?: string; hash?: HashFn }): void {\n\t\tif (this._versioning != null) return;\n\t\tthis._hashFn = opts?.hash ?? this._hashFn;\n\t\tthis._versioning = createVersioning(\n\t\t\tlevel,\n\t\t\tthis._cached === NO_VALUE ? undefined : this._cached,\n\t\t\t{\n\t\t\t\tid: opts?.id,\n\t\t\t\thash: this._hashFn,\n\t\t\t},\n\t\t);\n\t}\n\n\thasGuard(): boolean {\n\t\treturn this._guard != null;\n\t}\n\n\tallowsObserve(actor: Actor): boolean {\n\t\tif (this._guard == null) return true;\n\t\treturn this._guard(normalizeActor(actor), \"observe\");\n\t}\n\n\tget(): T | undefined {\n\t\treturn this._cached === NO_VALUE ? undefined : this._cached;\n\t}\n\n\tdown(messages: Messages, options?: NodeTransportOptions): void {\n\t\tif (messages.length === 0) return;\n\t\tif (!options?.internal && this._guard != null) {\n\t\t\tconst actor = normalizeActor(options?.actor);\n\t\t\tconst delivery = options?.delivery ?? \"write\";\n\t\t\tconst action: GuardAction = delivery === \"signal\" ? \"signal\" : \"write\";\n\t\t\tif (!this._guard(actor, action)) {\n\t\t\t\tthrow new GuardDenied({ actor, action, nodeName: this.name });\n\t\t\t}\n\t\t\tthis._lastMutation = { actor, timestamp_ns: wallClockNs() };\n\t\t}\n\t\tthis._downInternal(messages);\n\t}\n\n\tprivate _downInternal(messages: Messages): void {\n\t\tif (messages.length === 0) return;\n\t\tlet lifecycleMessages = messages;\n\t\tlet sinkMessages = messages;\n\t\tif (this._terminal && !this._opts.resubscribable) {\n\t\t\tconst terminalPassthrough = messages.filter((m) => m[0] === TEARDOWN || m[0] === INVALIDATE);\n\t\t\tif (terminalPassthrough.length === 0) return;\n\t\t\tlifecycleMessages = terminalPassthrough;\n\t\t\tsinkMessages = terminalPassthrough;\n\t\t}\n\t\tthis._handleLocalLifecycle(lifecycleMessages);\n\t\t// Single-dep optimization: skip DIRTY to sinks when sole subscriber is single-dep\n\t\t// AND the batch contains a phase-2 message (DATA/RESOLVED). Standalone DIRTY\n\t\t// (without follow-up) must pass through so downstream is notified.\n\t\tif (this._canSkipDirty()) {\n\t\t\t// Inline check: does the batch contain DATA or RESOLVED?\n\t\t\tlet hasPhase2 = false;\n\t\t\tfor (let i = 0; i < sinkMessages.length; i++) {\n\t\t\t\tconst t = sinkMessages[i][0];\n\t\t\t\tif (t === DATA || t === RESOLVED) {\n\t\t\t\t\thasPhase2 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (hasPhase2) {\n\t\t\t\t// Inline filter: remove DIRTY messages\n\t\t\t\tconst filtered: Message[] = [];\n\t\t\t\tfor (let i = 0; i < sinkMessages.length; i++) {\n\t\t\t\t\tif (sinkMessages[i][0] !== DIRTY) filtered.push(sinkMessages[i]);\n\t\t\t\t}\n\t\t\t\tif (filtered.length > 0) {\n\t\t\t\t\temitWithBatch(this._boundEmitToSinks, filtered);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\temitWithBatch(this._boundEmitToSinks, sinkMessages);\n\t}\n\n\tsubscribe(sink: NodeSink, hints?: SubscribeHints): () => void {\n\t\tif (hints?.actor != null && this._guard != null) {\n\t\t\tconst actor = normalizeActor(hints.actor);\n\t\t\tif (!this._guard(actor, \"observe\")) {\n\t\t\t\tthrow new GuardDenied({ actor, action: \"observe\", nodeName: this.name });\n\t\t\t}\n\t\t}\n\n\t\tif (this._terminal && this._opts.resubscribable) {\n\t\t\tthis._terminal = false;\n\t\t\tthis._cached = NO_VALUE;\n\t\t\tthis._status = this._hasDeps ? \"disconnected\" : \"settled\";\n\t\t\tthis._opts.onResubscribe?.();\n\t\t}\n\n\t\tthis._sinkCount += 1;\n\t\tif (hints?.singleDep) {\n\t\t\tthis._singleDepSinkCount += 1;\n\t\t\tthis._singleDepSinks.add(sink);\n\t\t}\n\n\t\tif (this._sinks == null) {\n\t\t\tthis._sinks = sink;\n\t\t} else if (typeof this._sinks === \"function\") {\n\t\t\tthis._sinks = new Set<NodeSink>([this._sinks, sink]);\n\t\t} else {\n\t\t\tthis._sinks.add(sink);\n\t\t}\n\n\t\tif (this._hasDeps) {\n\t\t\tthis._connectUpstream();\n\t\t} else if (this._fn) {\n\t\t\tthis._startProducer();\n\t\t}\n\n\t\tlet removed = false;\n\t\treturn () => {\n\t\t\tif (removed) return;\n\t\t\tremoved = true;\n\t\t\tthis._sinkCount -= 1;\n\t\t\tif (this._singleDepSinks.has(sink)) {\n\t\t\t\tthis._singleDepSinkCount -= 1;\n\t\t\t\tthis._singleDepSinks.delete(sink);\n\t\t\t}\n\t\t\tif (this._sinks == null) return;\n\t\t\tif (typeof this._sinks === \"function\") {\n\t\t\t\tif (this._sinks === sink) this._sinks = null;\n\t\t\t} else {\n\t\t\t\tthis._sinks.delete(sink);\n\t\t\t\tif (this._sinks.size === 1) {\n\t\t\t\t\tconst [only] = this._sinks;\n\t\t\t\t\tthis._sinks = only;\n\t\t\t\t} else if (this._sinks.size === 0) {\n\t\t\t\t\tthis._sinks = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._sinks == null) {\n\t\t\t\tthis._disconnectUpstream();\n\t\t\t\tthis._stopProducer();\n\t\t\t}\n\t\t};\n\t}\n\n\tup(messages: Messages, options?: NodeTransportOptions): void {\n\t\tif (!this._hasDeps) return;\n\t\tif (!options?.internal && this._guard != null) {\n\t\t\tconst actor = normalizeActor(options?.actor);\n\t\t\tif (!this._guard(actor, \"write\")) {\n\t\t\t\tthrow new GuardDenied({ actor, action: \"write\", nodeName: this.name });\n\t\t\t}\n\t\t\tthis._lastMutation = { actor, timestamp_ns: wallClockNs() };\n\t\t}\n\t\tfor (const dep of this._deps) {\n\t\t\tif (options === undefined) {\n\t\t\t\tdep.up?.(messages);\n\t\t\t} else {\n\t\t\t\tdep.up?.(messages, options);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _upInternal(messages: Messages): void {\n\t\tif (!this._hasDeps) return;\n\t\tfor (const dep of this._deps) {\n\t\t\tdep.up?.(messages, { internal: true });\n\t\t}\n\t}\n\n\tunsubscribe(): void {\n\t\tif (!this._hasDeps) return;\n\t\tthis._disconnectUpstream();\n\t}\n\n\t// --- Private methods (prototype, _ prefix) ---\n\n\t_emitToSinks(messages: Messages): void {\n\t\tif (this._sinks == null) return;\n\t\tif (typeof this._sinks === \"function\") {\n\t\t\tthis._sinks(messages);\n\t\t\treturn;\n\t\t}\n\t\t// Snapshot: a sink callback may unsubscribe itself or others mid-iteration.\n\t\t// Iterating the live Set would skip not-yet-visited sinks that were removed.\n\t\tconst snapshot = [...this._sinks];\n\t\tfor (const sink of snapshot) {\n\t\t\tsink(messages);\n\t\t}\n\t}\n\n\t_handleLocalLifecycle(messages: Messages): void {\n\t\tfor (const m of messages) {\n\t\t\tconst t = m[0];\n\t\t\tif (t === DATA) {\n\t\t\t\tthis._cached = m[1] as T;\n\t\t\t\tif (this._versioning != null) {\n\t\t\t\t\tadvanceVersion(this._versioning, m[1], this._hashFn);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (t === INVALIDATE) {\n\t\t\t\t// GRAPHREFLY-SPEC §1.2: clear cached state; do not auto-emit from here.\n\t\t\t\tconst cleanupFn = this._cleanup;\n\t\t\t\tthis._cleanup = undefined;\n\t\t\t\tcleanupFn?.();\n\t\t\t\tthis._cached = NO_VALUE;\n\t\t\t\tthis._lastDepValues = undefined;\n\t\t\t}\n\t\t\tthis._status = statusAfterMessage(this._status, m);\n\t\t\tif (t === COMPLETE || t === ERROR) {\n\t\t\t\tthis._terminal = true;\n\t\t\t}\n\t\t\tif (t === TEARDOWN) {\n\t\t\t\tif (this._opts.resetOnTeardown) {\n\t\t\t\t\tthis._cached = NO_VALUE;\n\t\t\t\t}\n\t\t\t\t// Invoke cleanup for compute nodes (deps+fn) — spec §2.4\n\t\t\t\t// requires cleanup on teardown, not just before next invocation.\n\t\t\t\t// _stopProducer handles cleanup for producer nodes separately.\n\t\t\t\tconst teardownCleanup = this._cleanup;\n\t\t\t\tthis._cleanup = undefined;\n\t\t\t\tteardownCleanup?.();\n\t\t\t\ttry {\n\t\t\t\t\tthis._propagateToMeta(t);\n\t\t\t\t} finally {\n\t\t\t\t\tthis._disconnectUpstream();\n\t\t\t\t\tthis._stopProducer();\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Propagate other meta-eligible signals (centralized in messages.ts).\n\t\t\tif (t !== TEARDOWN && propagatesToMeta(t)) {\n\t\t\t\tthis._propagateToMeta(t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Propagate a signal to all companion meta nodes (best-effort). */\n\t_propagateToMeta(t: symbol): void {\n\t\tfor (const metaNode of Object.values(this.meta)) {\n\t\t\ttry {\n\t\t\t\t(metaNode as NodeImpl)._downInternal([[t]]);\n\t\t\t} catch {\n\t\t\t\t/* best-effort: other meta nodes still receive the signal */\n\t\t\t}\n\t\t}\n\t}\n\n\t_canSkipDirty(): boolean {\n\t\treturn this._sinkCount === 1 && this._singleDepSinkCount === 1;\n\t}\n\n\t_emitAutoValue(value: unknown): void {\n\t\tconst wasDirty = this._status === \"dirty\";\n\t\t// §2.5: equals() only compares two real values. NO_VALUE sentinel means\n\t\t// \"never emitted / cache cleared\" — first emission always treated as changed.\n\t\tlet unchanged: boolean;\n\t\ttry {\n\t\t\tunchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);\n\t\t} catch (eqErr) {\n\t\t\tconst eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);\n\t\t\tconst wrapped = new Error(`Node \"${this.name}\": equals threw: ${eqMsg}`, { cause: eqErr });\n\t\t\tthis._downInternal([[ERROR, wrapped]]);\n\t\t\treturn;\n\t\t}\n\t\tif (unchanged) {\n\t\t\tthis._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);\n\t\t\treturn;\n\t\t}\n\t\tthis._cached = value as T;\n\t\tthis._downInternal(wasDirty ? [[DATA, value]] : [[DIRTY], [DATA, value]]);\n\t}\n\n\t_runFn(): void {\n\t\tif (!this._fn) return;\n\t\tif (this._terminal && !this._opts.resubscribable) return;\n\t\tif (this._connecting) return;\n\n\t\ttry {\n\t\t\tconst n = this._deps.length;\n\t\t\tconst depValues = new Array(n);\n\t\t\tfor (let i = 0; i < n; i++) depValues[i] = this._deps[i].get();\n\t\t\t// Identity check BEFORE cleanup: if all dep values are unchanged,\n\t\t\t// skip cleanup+fn entirely so effect nodes don't teardown/restart on no-op.\n\t\t\tconst prev = this._lastDepValues;\n\t\t\tif (n > 0 && prev != null && prev.length === n) {\n\t\t\t\tlet allSame = true;\n\t\t\t\tfor (let i = 0; i < n; i++) {\n\t\t\t\t\tif (!Object.is(depValues[i], prev[i])) {\n\t\t\t\t\t\tallSame = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (allSame) {\n\t\t\t\t\tif (this._status === \"dirty\") {\n\t\t\t\t\t\tthis._downInternal([[RESOLVED]]);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst prevCleanup = this._cleanup;\n\t\t\tthis._cleanup = undefined;\n\t\t\tprevCleanup?.();\n\t\t\tthis._manualEmitUsed = false;\n\t\t\tthis._lastDepValues = depValues;\n\t\t\tthis._inspectorHook?.({ kind: \"run\", depValues });\n\t\t\tconst out = this._fn(depValues, this._actions);\n\t\t\t// Explicit cleanup wrapper: { cleanup, value? }\n\t\t\tif (isCleanupResult(out)) {\n\t\t\t\tthis._cleanup = out.cleanup;\n\t\t\t\tif (this._manualEmitUsed) return;\n\t\t\t\tif (\"value\" in out) {\n\t\t\t\t\tthis._emitAutoValue(out.value);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Legacy: plain function return → cleanup (backward compat)\n\t\t\tif (isCleanupFn(out)) {\n\t\t\t\tthis._cleanup = out;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this._manualEmitUsed) return;\n\t\t\tif (out === undefined) return;\n\t\t\tthis._emitAutoValue(out);\n\t\t} catch (err) {\n\t\t\tconst errMsg = err instanceof Error ? err.message : String(err);\n\t\t\tconst wrapped = new Error(`Node \"${this.name}\": fn threw: ${errMsg}`, { cause: err });\n\t\t\tthis._downInternal([[ERROR, wrapped]]);\n\t\t}\n\t}\n\n\t_onDepDirty(index: number): void {\n\t\tconst wasDirty = this._depDirtyMask.has(index);\n\t\tthis._depDirtyMask.set(index);\n\t\tthis._depSettledMask.clear(index);\n\t\tif (!wasDirty) {\n\t\t\tthis._downInternal([[DIRTY]]);\n\t\t}\n\t}\n\n\t_onDepSettled(index: number): void {\n\t\tif (!this._depDirtyMask.has(index)) {\n\t\t\tthis._onDepDirty(index);\n\t\t}\n\t\tthis._depSettledMask.set(index);\n\t\tif (this._depDirtyMask.any() && this._depSettledMask.covers(this._depDirtyMask)) {\n\t\t\tthis._depDirtyMask.reset();\n\t\t\tthis._depSettledMask.reset();\n\t\t\tthis._runFn();\n\t\t}\n\t}\n\n\t_maybeCompleteFromDeps(): void {\n\t\tif (\n\t\t\tthis._autoComplete &&\n\t\t\tthis._deps.length > 0 &&\n\t\t\tthis._depCompleteMask.covers(this._allDepsCompleteMask)\n\t\t) {\n\t\t\tthis._downInternal([[COMPLETE]]);\n\t\t}\n\t}\n\n\t_handleDepMessages(index: number, messages: Messages): void {\n\t\tfor (const msg of messages) {\n\t\t\tthis._inspectorHook?.({ kind: \"dep_message\", depIndex: index, message: msg });\n\t\t\tconst t = msg[0];\n\t\t\t// User-defined message handler gets first look (spec §2.6).\n\t\t\tif (this._onMessage) {\n\t\t\t\ttry {\n\t\t\t\t\tif (this._onMessage(msg, index, this._actions)) continue;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst errMsg = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst wrapped = new Error(`Node \"${this.name}\": onMessage threw: ${errMsg}`, {\n\t\t\t\t\t\tcause: err,\n\t\t\t\t\t});\n\t\t\t\t\tthis._downInternal([[ERROR, wrapped]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!this._fn) {\n\t\t\t\t// Passthrough: forward all messages except COMPLETE when multi-dep.\n\t\t\t\t// Multi-dep passthrough must wait for ALL deps to complete (§1.3.5).\n\t\t\t\tif (t === COMPLETE && this._deps.length > 1) {\n\t\t\t\t\tthis._depCompleteMask.set(index);\n\t\t\t\t\tthis._maybeCompleteFromDeps();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis._downInternal([msg]);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === DIRTY) {\n\t\t\t\tthis._onDepDirty(index);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === DATA || t === RESOLVED) {\n\t\t\t\tthis._onDepSettled(index);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === COMPLETE) {\n\t\t\t\tthis._depCompleteMask.set(index);\n\t\t\t\t// Complete implies no longer pending — clear dirty/settled bits\n\t\t\t\t// so a preceding DIRTY from this dep doesn't block settlement.\n\t\t\t\tthis._depDirtyMask.clear(index);\n\t\t\t\tthis._depSettledMask.clear(index);\n\t\t\t\tif (this._depDirtyMask.any() && this._depSettledMask.covers(this._depDirtyMask)) {\n\t\t\t\t\tthis._depDirtyMask.reset();\n\t\t\t\t\tthis._depSettledMask.reset();\n\t\t\t\t\tthis._runFn();\n\t\t\t\t} else if (!this._depDirtyMask.any() && this._status === \"dirty\") {\n\t\t\t\t\t// D2: dep went DIRTY→COMPLETE without DATA — node was marked\n\t\t\t\t\t// dirty but no settlement came. Recompute so downstream\n\t\t\t\t\t// gets RESOLVED (value unchanged) or DATA (value changed).\n\t\t\t\t\tthis._depSettledMask.reset();\n\t\t\t\t\tthis._runFn();\n\t\t\t\t}\n\t\t\t\tthis._maybeCompleteFromDeps();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === ERROR) {\n\t\t\t\tthis._downInternal([msg]);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === INVALIDATE || t === TEARDOWN || t === PAUSE || t === RESUME) {\n\t\t\t\tthis._downInternal([msg]);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Forward unknown message types\n\t\t\tthis._downInternal([msg]);\n\t\t}\n\t}\n\n\t_connectUpstream(): void {\n\t\tif (!this._hasDeps || this._connected) return;\n\t\tthis._connected = true;\n\t\tthis._depDirtyMask.reset();\n\t\tthis._depSettledMask.reset();\n\t\tthis._depCompleteMask.reset();\n\t\tthis._status = \"settled\";\n\t\tconst subHints: SubscribeHints | undefined = this._isSingleDep\n\t\t\t? { singleDep: true }\n\t\t\t: undefined;\n\t\tthis._connecting = true;\n\t\ttry {\n\t\t\tfor (let i = 0; i < this._deps.length; i += 1) {\n\t\t\t\tconst dep = this._deps[i];\n\t\t\t\tthis._upstreamUnsubs.push(\n\t\t\t\t\tdep.subscribe((msgs) => this._handleDepMessages(i, msgs), subHints),\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._connecting = false;\n\t\t}\n\t\tif (this._fn) {\n\t\t\tthis._runFn();\n\t\t}\n\t}\n\n\t_stopProducer(): void {\n\t\tif (!this._producerStarted) return;\n\t\tthis._producerStarted = false;\n\t\tconst producerCleanup = this._cleanup;\n\t\tthis._cleanup = undefined;\n\t\tproducerCleanup?.();\n\t}\n\n\t_startProducer(): void {\n\t\tif (this._deps.length !== 0 || !this._fn || this._producerStarted) return;\n\t\tthis._producerStarted = true;\n\t\tthis._runFn();\n\t}\n\n\t_disconnectUpstream(): void {\n\t\tif (!this._connected) return;\n\t\tfor (const unsub of this._upstreamUnsubs.splice(0)) {\n\t\t\tunsub();\n\t\t}\n\t\tthis._connected = false;\n\t\tthis._depDirtyMask.reset();\n\t\tthis._depSettledMask.reset();\n\t\tthis._depCompleteMask.reset();\n\t\tthis._status = \"disconnected\";\n\t}\n}\n\n/**\n * Creates a reactive {@link Node} — the single GraphReFly primitive (GRAPHREFLY-SPEC §2).\n *\n * Typical shapes: `node([])` / `node([], opts)` for a manual source; `node(producerFn, opts)` for a\n * producer; `node(deps, computeFn, opts)` for derived nodes and operators.\n *\n * @param depsOrFn - Dependency nodes, a {@link NodeFn} (producer), or {@link NodeOptions} alone.\n * @param fnOrOpts - With deps: compute function or options. Omitted for producer-only form.\n * @param optsArg - Options when both `deps` and `fn` are provided.\n * @returns `Node<T>` - Configured node instance (lazy until subscribed).\n *\n * @remarks\n * **Protocol:** DIRTY / DATA / RESOLVED ordering, completion, and batch deferral follow `~/src/graphrefly/GRAPHREFLY-SPEC.md`.\n *\n * @example\n * ```ts\n * import { node, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const a = state(1);\n * const b = node([a], ([x]) => (x as number) + 1);\n * ```\n *\n * @seeAlso [Specification](/spec)\n *\n * @category core\n */\nexport function node<T = unknown>(\n\tdepsOrFn?: readonly Node[] | NodeFn<T> | NodeOptions,\n\tfnOrOpts?: NodeFn<T> | NodeOptions,\n\toptsArg?: NodeOptions,\n): Node<T> {\n\tconst deps: readonly Node[] = isNodeArray(depsOrFn) ? depsOrFn : [];\n\tconst fn: NodeFn<T> | undefined =\n\t\ttypeof depsOrFn === \"function\"\n\t\t\t? depsOrFn\n\t\t\t: typeof fnOrOpts === \"function\"\n\t\t\t\t? fnOrOpts\n\t\t\t\t: undefined;\n\tlet opts: NodeOptions = {};\n\tif (isNodeArray(depsOrFn)) {\n\t\topts = (isNodeOptions(fnOrOpts) ? fnOrOpts : optsArg) ?? {};\n\t} else if (isNodeOptions(depsOrFn)) {\n\t\topts = depsOrFn;\n\t} else {\n\t\topts = (isNodeOptions(fnOrOpts) ? fnOrOpts : optsArg) ?? {};\n\t}\n\n\treturn new NodeImpl<T>(deps, fn, opts);\n}\n","/**\n * `dynamicNode` — runtime dep tracking with diamond resolution (Phase 0.3b).\n *\n * Unlike `node()` where deps are fixed at construction, `dynamicNode` discovers\n * deps at runtime via a tracking `get()` proxy. After each recompute, deps are\n * diffed: new deps are connected, removed deps are disconnected, and bitmasks\n * are rebuilt. Kept deps retain their subscriptions (no teardown/reconnect churn).\n *\n * This ports callbag-recharge's `dynamicDerived` pattern to GraphReFly's protocol.\n */\nimport type { Actor } from \"./actor.js\";\nimport { normalizeActor } from \"./actor.js\";\nimport { emitWithBatch } from \"./batch.js\";\nimport { wallClockNs } from \"./clock.js\";\nimport type { GuardAction, NodeGuard } from \"./guard.js\";\nimport { GuardDenied } from \"./guard.js\";\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tINVALIDATE,\n\ttype Message,\n\ttype Messages,\n\tPAUSE,\n\tpropagatesToMeta,\n\tRESOLVED,\n\tRESUME,\n\tTEARDOWN,\n} from \"./messages.js\";\nimport {\n\tnode as createNode,\n\tNO_VALUE,\n\ttype Node,\n\ttype NodeActions,\n\ttype NodeDescribeKind,\n\ttype NodeInspectorHook,\n\ttype NodeOptions,\n\ttype NodeSink,\n\ttype NodeStatus,\n\ttype NodeTransportOptions,\n\ttype OnMessageHandler,\n\ttype SubscribeHints,\n} from \"./node.js\";\n\n/**\n * The tracking `get` function passed to `dynamicNode`'s compute function.\n * Each call to `get(dep)` reads the dep's current value and records it as a dependency.\n */\nexport type DynGet = <V>(dep: Node<V>) => V | undefined;\n\n/**\n * Compute function for `dynamicNode`. Receives a tracking `get` proxy.\n * Deps are discovered by which nodes are passed to `get()` during execution.\n */\nexport type DynamicNodeFn<T> = (get: DynGet) => T;\n\n/** Options for `dynamicNode`. */\nexport type DynamicNodeOptions = Pick<\n\tNodeOptions,\n\t| \"name\"\n\t| \"equals\"\n\t| \"meta\"\n\t| \"resubscribable\"\n\t| \"resetOnTeardown\"\n\t| \"guard\"\n\t| \"onMessage\"\n\t| \"onResubscribe\"\n\t| \"completeWhenDepsComplete\"\n\t| \"describeKind\"\n>;\n\n/**\n * Creates a node with runtime dep tracking. Deps are discovered each time the\n * compute function runs by tracking which nodes are passed to the `get()` proxy.\n *\n * After each recompute:\n * - New deps (not in previous set) are subscribed\n * - Removed deps (not in current set) are unsubscribed\n * - Kept deps retain their existing subscriptions\n * - Bitmasks are rebuilt to match the new dep set\n *\n * The node participates fully in diamond resolution via the standard two-phase\n * DIRTY/RESOLVED protocol across all dynamically-tracked deps.\n *\n * @param fn - Compute function receiving a tracking `get` proxy.\n * @param opts - Optional configuration.\n * @returns `Node<T>` with dynamic dep tracking.\n *\n * @example\n * ```ts\n * import { dynamicNode, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const cond = state(true);\n * const a = state(1);\n * const b = state(2);\n *\n * // Deps change based on cond's value\n * const d = dynamicNode((get) => {\n * const useA = get(cond);\n * return useA ? get(a) : get(b);\n * });\n * ```\n *\n * @category core\n */\nexport function dynamicNode<T = unknown>(fn: DynamicNodeFn<T>, opts?: DynamicNodeOptions): Node<T> {\n\treturn new DynamicNodeImpl<T>(fn, opts ?? {});\n}\n\n/** @internal — exported for {@link describeNode} `instanceof` check. */\nexport class DynamicNodeImpl<T = unknown> implements Node<T> {\n\tprivate readonly _optsName: string | undefined;\n\tprivate _registryName: string | undefined;\n\treadonly _describeKind: NodeDescribeKind | undefined;\n\treadonly meta: Record<string, Node>;\n\tprivate readonly _fn: DynamicNodeFn<T>;\n\tprivate readonly _equals: (a: unknown, b: unknown) => boolean;\n\tprivate readonly _resubscribable: boolean;\n\tprivate readonly _resetOnTeardown: boolean;\n\tprivate readonly _autoComplete: boolean;\n\tprivate readonly _onMessage: OnMessageHandler | undefined;\n\tprivate readonly _onResubscribe: (() => void) | undefined;\n\t/** @internal — read by {@link describeNode} for `accessHintForGuard`. */\n\treadonly _guard: NodeGuard | undefined;\n\tprivate _lastMutation: { actor: Actor; timestamp_ns: number } | undefined;\n\tprivate _inspectorHook: NodeInspectorHook | undefined;\n\n\t// Sink tracking\n\tprivate _sinkCount = 0;\n\tprivate _singleDepSinkCount = 0;\n\tprivate _singleDepSinks = new WeakSet<NodeSink>();\n\n\t// Actions object (for onMessage handler)\n\tprivate readonly _actions: NodeActions;\n\tprivate readonly _boundEmitToSinks: (messages: Messages) => void;\n\n\t// Mutable state\n\tprivate _cached: T | typeof NO_VALUE = NO_VALUE;\n\tprivate _status: NodeStatus = \"disconnected\";\n\tprivate _terminal = false;\n\tprivate _connected = false;\n\tprivate _rewiring = false; // re-entrancy guard\n\n\t// Dynamic deps tracking\n\tprivate _deps: Node[] = [];\n\tprivate _depUnsubs: Array<() => void> = [];\n\tprivate _depIndexMap = new Map<Node, number>(); // node → index in _deps\n\tprivate _dirtyBits = new Set<number>();\n\tprivate _settledBits = new Set<number>();\n\tprivate _completeBits = new Set<number>();\n\n\t// Sinks\n\tprivate _sinks: NodeSink | Set<NodeSink> | null = null;\n\n\tconstructor(fn: DynamicNodeFn<T>, opts: DynamicNodeOptions) {\n\t\tthis._fn = fn;\n\t\tthis._optsName = opts.name;\n\t\tthis._describeKind = opts.describeKind;\n\t\tthis._equals = opts.equals ?? Object.is;\n\t\tthis._resubscribable = opts.resubscribable ?? false;\n\t\tthis._resetOnTeardown = opts.resetOnTeardown ?? false;\n\t\tthis._autoComplete = opts.completeWhenDepsComplete ?? true;\n\t\tthis._onMessage = opts.onMessage;\n\t\tthis._onResubscribe = opts.onResubscribe;\n\t\tthis._guard = opts.guard;\n\t\tthis._inspectorHook = undefined;\n\n\t\t// Build companion meta nodes (same pattern as NodeImpl)\n\t\tconst meta: Record<string, Node> = {};\n\t\tfor (const [k, v] of Object.entries(opts.meta ?? {})) {\n\t\t\tmeta[k] = createNode({\n\t\t\t\tinitial: v,\n\t\t\t\tname: `${opts.name ?? \"dynamicNode\"}:meta:${k}`,\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\t...(opts.guard != null ? { guard: opts.guard } : {}),\n\t\t\t});\n\t\t}\n\t\tObject.freeze(meta);\n\t\tthis.meta = meta;\n\n\t\t// Actions object: created once, references `this` methods.\n\t\tconst self = this;\n\t\tthis._actions = {\n\t\t\tdown(messages): void {\n\t\t\t\tself._downInternal(messages);\n\t\t\t},\n\t\t\temit(value): void {\n\t\t\t\tself._emitAutoValue(value);\n\t\t\t},\n\t\t\tup(messages): void {\n\t\t\t\tfor (const dep of self._deps) {\n\t\t\t\t\tdep.up?.(messages, { internal: true });\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\t// Bind commonly detached protocol methods\n\t\tthis._boundEmitToSinks = this._emitToSinks.bind(this);\n\t}\n\n\tget name(): string | undefined {\n\t\treturn this._registryName ?? this._optsName;\n\t}\n\n\t/** @internal */\n\t_assignRegistryName(localName: string): void {\n\t\tif (this._optsName !== undefined || this._registryName !== undefined) return;\n\t\tthis._registryName = localName;\n\t}\n\n\t/**\n\t * @internal Attach/remove inspector hook for graph-level observability.\n\t * Returns a disposer that restores the previous hook.\n\t */\n\t_setInspectorHook(hook?: NodeInspectorHook): () => void {\n\t\tconst prev = this._inspectorHook;\n\t\tthis._inspectorHook = hook;\n\t\treturn () => {\n\t\t\tif (this._inspectorHook === hook) {\n\t\t\t\tthis._inspectorHook = prev;\n\t\t\t}\n\t\t};\n\t}\n\n\tget status(): NodeStatus {\n\t\treturn this._status;\n\t}\n\n\tget lastMutation(): Readonly<{ actor: Actor; timestamp_ns: number }> | undefined {\n\t\treturn this._lastMutation;\n\t}\n\n\t/** Versioning not yet supported on DynamicNodeImpl. */\n\tget v(): undefined {\n\t\treturn undefined;\n\t}\n\n\thasGuard(): boolean {\n\t\treturn this._guard != null;\n\t}\n\n\tallowsObserve(actor: Actor): boolean {\n\t\tif (this._guard == null) return true;\n\t\treturn this._guard(normalizeActor(actor), \"observe\");\n\t}\n\n\tget(): T | undefined {\n\t\treturn this._cached === NO_VALUE ? undefined : this._cached;\n\t}\n\n\tdown(messages: Messages, options?: NodeTransportOptions): void {\n\t\tif (messages.length === 0) return;\n\t\tif (!options?.internal && this._guard != null) {\n\t\t\tconst actor = normalizeActor(options?.actor);\n\t\t\tconst delivery = options?.delivery ?? \"write\";\n\t\t\tconst action: GuardAction = delivery === \"signal\" ? \"signal\" : \"write\";\n\t\t\tif (!this._guard(actor, action)) {\n\t\t\t\tthrow new GuardDenied({ actor, action, nodeName: this.name });\n\t\t\t}\n\t\t\tthis._lastMutation = { actor, timestamp_ns: wallClockNs() };\n\t\t}\n\t\tthis._downInternal(messages);\n\t}\n\n\tprivate _downInternal(messages: Messages): void {\n\t\tif (messages.length === 0) return;\n\t\tlet sinkMessages = messages;\n\t\tif (this._terminal && !this._resubscribable) {\n\t\t\tconst pass = messages.filter((m) => m[0] === TEARDOWN || m[0] === INVALIDATE);\n\t\t\tif (pass.length === 0) return;\n\t\t\tsinkMessages = pass as Messages;\n\t\t}\n\t\tthis._handleLocalLifecycle(sinkMessages);\n\t\t// Single-dep optimization: skip DIRTY to sinks when sole subscriber is single-dep\n\t\t// AND the batch contains a phase-2 message (DATA/RESOLVED). Standalone DIRTY\n\t\t// (without follow-up) must pass through so downstream is notified.\n\t\tif (this._canSkipDirty()) {\n\t\t\t// Inline check: does the batch contain DATA or RESOLVED?\n\t\t\tlet hasPhase2 = false;\n\t\t\tfor (let i = 0; i < sinkMessages.length; i++) {\n\t\t\t\tconst t = sinkMessages[i][0];\n\t\t\t\tif (t === DATA || t === RESOLVED) {\n\t\t\t\t\thasPhase2 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (hasPhase2) {\n\t\t\t\t// Inline filter: remove DIRTY messages\n\t\t\t\tconst filtered: Message[] = [];\n\t\t\t\tfor (let i = 0; i < sinkMessages.length; i++) {\n\t\t\t\t\tif (sinkMessages[i][0] !== DIRTY) filtered.push(sinkMessages[i]);\n\t\t\t\t}\n\t\t\t\tif (filtered.length > 0) {\n\t\t\t\t\temitWithBatch(this._boundEmitToSinks, filtered);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\temitWithBatch(this._boundEmitToSinks, sinkMessages);\n\t}\n\n\tprivate _canSkipDirty(): boolean {\n\t\treturn this._sinkCount === 1 && this._singleDepSinkCount === 1;\n\t}\n\n\tsubscribe(sink: NodeSink, hints?: SubscribeHints): () => void {\n\t\tif (hints?.actor != null && this._guard != null) {\n\t\t\tconst actor = normalizeActor(hints.actor);\n\t\t\tif (!this._guard(actor, \"observe\")) {\n\t\t\t\tthrow new GuardDenied({ actor, action: \"observe\", nodeName: this.name });\n\t\t\t}\n\t\t}\n\n\t\tif (this._terminal && this._resubscribable) {\n\t\t\tthis._terminal = false;\n\t\t\tthis._cached = NO_VALUE;\n\t\t\tthis._status = \"disconnected\";\n\t\t\tthis._onResubscribe?.();\n\t\t}\n\n\t\tthis._sinkCount += 1;\n\t\tif (hints?.singleDep) {\n\t\t\tthis._singleDepSinkCount += 1;\n\t\t\tthis._singleDepSinks.add(sink);\n\t\t}\n\n\t\tif (this._sinks == null) {\n\t\t\tthis._sinks = sink;\n\t\t} else if (typeof this._sinks === \"function\") {\n\t\t\tthis._sinks = new Set<NodeSink>([this._sinks, sink]);\n\t\t} else {\n\t\t\tthis._sinks.add(sink);\n\t\t}\n\n\t\tif (!this._connected) {\n\t\t\tthis._connect();\n\t\t}\n\n\t\tlet removed = false;\n\t\treturn () => {\n\t\t\tif (removed) return;\n\t\t\tremoved = true;\n\t\t\tthis._sinkCount -= 1;\n\t\t\tif (this._singleDepSinks.has(sink)) {\n\t\t\t\tthis._singleDepSinkCount -= 1;\n\t\t\t\tthis._singleDepSinks.delete(sink);\n\t\t\t}\n\t\t\tif (this._sinks == null) return;\n\t\t\tif (typeof this._sinks === \"function\") {\n\t\t\t\tif (this._sinks === sink) this._sinks = null;\n\t\t\t} else {\n\t\t\t\tthis._sinks.delete(sink);\n\t\t\t\tif (this._sinks.size === 1) {\n\t\t\t\t\tconst [only] = this._sinks;\n\t\t\t\t\tthis._sinks = only;\n\t\t\t\t} else if (this._sinks.size === 0) {\n\t\t\t\t\tthis._sinks = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._sinks == null) {\n\t\t\t\tthis._disconnect();\n\t\t\t}\n\t\t};\n\t}\n\n\tup(messages: Messages, options?: NodeTransportOptions): void {\n\t\tif (this._deps.length === 0) return;\n\t\tif (!options?.internal && this._guard != null) {\n\t\t\tconst actor = normalizeActor(options?.actor);\n\t\t\tif (!this._guard(actor, \"write\")) {\n\t\t\t\tthrow new GuardDenied({ actor, action: \"write\", nodeName: this.name });\n\t\t\t}\n\t\t\tthis._lastMutation = { actor, timestamp_ns: wallClockNs() };\n\t\t}\n\t\tfor (const dep of this._deps) {\n\t\t\tdep.up?.(messages, options);\n\t\t}\n\t}\n\n\tunsubscribe(): void {\n\t\tthis._disconnect();\n\t}\n\n\t// --- Private methods ---\n\n\tprivate _emitToSinks(messages: Messages): void {\n\t\tif (this._sinks == null) return;\n\t\tif (typeof this._sinks === \"function\") {\n\t\t\tthis._sinks(messages);\n\t\t\treturn;\n\t\t}\n\t\tconst snapshot = [...this._sinks];\n\t\tfor (const sink of snapshot) {\n\t\t\tsink(messages);\n\t\t}\n\t}\n\n\tprivate _handleLocalLifecycle(messages: Messages): void {\n\t\tfor (const m of messages) {\n\t\t\tconst t = m[0];\n\t\t\tif (t === DATA) this._cached = m[1] as T;\n\t\t\tif (t === INVALIDATE) {\n\t\t\t\tthis._cached = NO_VALUE;\n\t\t\t\tthis._status = \"dirty\";\n\t\t\t}\n\t\t\tif (t === DATA) {\n\t\t\t\tthis._status = \"settled\";\n\t\t\t} else if (t === RESOLVED) {\n\t\t\t\tthis._status = \"resolved\";\n\t\t\t} else if (t === DIRTY) {\n\t\t\t\tthis._status = \"dirty\";\n\t\t\t} else if (t === COMPLETE) {\n\t\t\t\tthis._status = \"completed\";\n\t\t\t\tthis._terminal = true;\n\t\t\t} else if (t === ERROR) {\n\t\t\t\tthis._status = \"errored\";\n\t\t\t\tthis._terminal = true;\n\t\t\t}\n\t\t\tif (t === TEARDOWN) {\n\t\t\t\tif (this._resetOnTeardown) this._cached = NO_VALUE;\n\t\t\t\ttry {\n\t\t\t\t\tthis._propagateToMeta(t);\n\t\t\t\t} finally {\n\t\t\t\t\tthis._disconnect();\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Propagate other meta-eligible signals (centralized in messages.ts).\n\t\t\tif (t !== TEARDOWN && propagatesToMeta(t)) {\n\t\t\t\tthis._propagateToMeta(t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Propagate a signal to all companion meta nodes (best-effort). */\n\tprivate _propagateToMeta(t: symbol): void {\n\t\tfor (const metaNode of Object.values(this.meta)) {\n\t\t\ttry {\n\t\t\t\tmetaNode.down([[t]], { internal: true });\n\t\t\t} catch {\n\t\t\t\t/* best-effort: other meta nodes still receive the signal */\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _emitAutoValue(value: unknown): void {\n\t\tconst wasDirty = this._status === \"dirty\";\n\t\tlet unchanged: boolean;\n\t\ttry {\n\t\t\tunchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);\n\t\t} catch (eqErr) {\n\t\t\tconst eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);\n\t\t\tconst wrapped = new Error(`Node \"${this.name}\": equals threw: ${eqMsg}`, { cause: eqErr });\n\t\t\tthis._downInternal([[ERROR, wrapped]]);\n\t\t\treturn;\n\t\t}\n\t\tif (unchanged) {\n\t\t\tthis._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);\n\t\t\treturn;\n\t\t}\n\t\tthis._cached = value as T;\n\t\tthis._downInternal(wasDirty ? [[DATA, value]] : [[DIRTY], [DATA, value]]);\n\t}\n\n\tprivate _connect(): void {\n\t\tif (this._connected) return;\n\t\tthis._connected = true;\n\t\tthis._status = \"settled\";\n\t\tthis._dirtyBits.clear();\n\t\tthis._settledBits.clear();\n\t\tthis._completeBits.clear();\n\t\tthis._runFn();\n\t}\n\n\tprivate _disconnect(): void {\n\t\tif (!this._connected) return;\n\t\tfor (const unsub of this._depUnsubs) unsub();\n\t\tthis._depUnsubs = [];\n\t\tthis._deps = [];\n\t\tthis._depIndexMap.clear();\n\t\tthis._dirtyBits.clear();\n\t\tthis._settledBits.clear();\n\t\tthis._completeBits.clear();\n\t\tthis._connected = false;\n\t\tthis._status = \"disconnected\";\n\t}\n\n\tprivate _runFn(): void {\n\t\tif (this._terminal && !this._resubscribable) return;\n\t\tif (this._rewiring) return;\n\n\t\t// Track deps during fn execution\n\t\tconst trackedDeps: Node[] = [];\n\t\tconst trackedSet = new Set<Node>();\n\n\t\tconst get: DynGet = <V>(dep: Node<V>): V | undefined => {\n\t\t\tif (!trackedSet.has(dep)) {\n\t\t\t\ttrackedSet.add(dep);\n\t\t\t\ttrackedDeps.push(dep);\n\t\t\t}\n\t\t\treturn dep.get();\n\t\t};\n\n\t\ttry {\n\t\t\t// Collect dep values for inspector hook\n\t\t\tconst depValues: unknown[] = [];\n\t\t\tfor (const dep of this._deps) {\n\t\t\t\tdepValues.push(dep.get());\n\t\t\t}\n\t\t\tthis._inspectorHook?.({ kind: \"run\", depValues });\n\n\t\t\tconst result = this._fn(get);\n\t\t\tthis._rewire(trackedDeps);\n\t\t\tif (result === undefined) return;\n\t\t\tthis._emitAutoValue(result);\n\t\t} catch (err) {\n\t\t\tthis._downInternal([[ERROR, err]]);\n\t\t}\n\t}\n\n\tprivate _rewire(newDeps: Node[]): void {\n\t\tthis._rewiring = true;\n\t\ttry {\n\t\t\tconst oldMap = this._depIndexMap;\n\t\t\tconst newMap = new Map<Node, number>();\n\t\t\tconst newUnsubs: Array<() => void> = [];\n\n\t\t\t// Reuse or create subscriptions\n\t\t\tfor (let i = 0; i < newDeps.length; i++) {\n\t\t\t\tconst dep = newDeps[i];\n\t\t\t\tnewMap.set(dep, i);\n\t\t\t\tconst oldIdx = oldMap.get(dep);\n\t\t\t\tif (oldIdx !== undefined) {\n\t\t\t\t\t// Kept dep — reuse subscription but update index\n\t\t\t\t\tnewUnsubs.push(this._depUnsubs[oldIdx]);\n\t\t\t\t\t// Mark old unsub as consumed\n\t\t\t\t\tthis._depUnsubs[oldIdx] = () => {};\n\t\t\t\t} else {\n\t\t\t\t\t// New dep — subscribe\n\t\t\t\t\tconst idx = i;\n\t\t\t\t\tconst unsub = dep.subscribe((msgs) => this._handleDepMessages(idx, msgs));\n\t\t\t\t\tnewUnsubs.push(unsub);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Disconnect removed deps\n\t\t\tfor (const [dep, oldIdx] of oldMap) {\n\t\t\t\tif (!newMap.has(dep)) {\n\t\t\t\t\tthis._depUnsubs[oldIdx]();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._deps = newDeps;\n\t\t\tthis._depUnsubs = newUnsubs;\n\t\t\tthis._depIndexMap = newMap;\n\t\t\tthis._dirtyBits.clear();\n\t\t\tthis._settledBits.clear();\n\t\t\t// Preserve complete bits for deps that are still present\n\t\t\tconst newCompleteBits = new Set<number>();\n\t\t\tfor (const oldIdx of this._completeBits) {\n\t\t\t\tconst dep = [...oldMap.entries()].find(([, idx]) => idx === oldIdx)?.[0];\n\t\t\t\tif (dep && newMap.has(dep)) {\n\t\t\t\t\tnewCompleteBits.add(newMap.get(dep)!);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._completeBits = newCompleteBits;\n\t\t} finally {\n\t\t\tthis._rewiring = false;\n\t\t}\n\t}\n\n\tprivate _handleDepMessages(index: number, messages: Messages): void {\n\t\tif (this._rewiring) return; // suppress signals during rewire\n\n\t\tfor (const msg of messages) {\n\t\t\tthis._inspectorHook?.({ kind: \"dep_message\", depIndex: index, message: msg });\n\t\t\tconst t = msg[0];\n\t\t\t// User-defined message handler gets first look (spec §2.6).\n\t\t\tif (this._onMessage) {\n\t\t\t\ttry {\n\t\t\t\t\tif (this._onMessage(msg, index, this._actions)) continue;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tthis._downInternal([[ERROR, err]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (t === DIRTY) {\n\t\t\t\tthis._dirtyBits.add(index);\n\t\t\t\tthis._settledBits.delete(index);\n\t\t\t\tif (this._dirtyBits.size === 1) {\n\t\t\t\t\t// First dirty — propagate\n\t\t\t\t\temitWithBatch(this._boundEmitToSinks, [[DIRTY]]);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === DATA || t === RESOLVED) {\n\t\t\t\tif (!this._dirtyBits.has(index)) {\n\t\t\t\t\tthis._dirtyBits.add(index);\n\t\t\t\t\temitWithBatch(this._boundEmitToSinks, [[DIRTY]]);\n\t\t\t\t}\n\t\t\t\tthis._settledBits.add(index);\n\t\t\t\tif (this._allDirtySettled()) {\n\t\t\t\t\tthis._dirtyBits.clear();\n\t\t\t\t\tthis._settledBits.clear();\n\t\t\t\t\tthis._runFn();\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === COMPLETE) {\n\t\t\t\tthis._completeBits.add(index);\n\t\t\t\tthis._dirtyBits.delete(index);\n\t\t\t\tthis._settledBits.delete(index);\n\t\t\t\tif (this._allDirtySettled()) {\n\t\t\t\t\tthis._dirtyBits.clear();\n\t\t\t\t\tthis._settledBits.clear();\n\t\t\t\t\tthis._runFn();\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tthis._autoComplete &&\n\t\t\t\t\tthis._completeBits.size >= this._deps.length &&\n\t\t\t\t\tthis._deps.length > 0\n\t\t\t\t) {\n\t\t\t\t\tthis._downInternal([[COMPLETE]]);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === ERROR) {\n\t\t\t\tthis._downInternal([msg]);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (t === INVALIDATE || t === TEARDOWN || t === PAUSE || t === RESUME) {\n\t\t\t\tthis._downInternal([msg]);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._downInternal([msg]);\n\t\t}\n\t}\n\n\tprivate _allDirtySettled(): boolean {\n\t\tif (this._dirtyBits.size === 0) return false;\n\t\tfor (const idx of this._dirtyBits) {\n\t\t\tif (!this._settledBits.has(idx)) return false;\n\t\t}\n\t\treturn true;\n\t}\n}\n","import { type Node, type NodeFn, type NodeOptions, node } from \"./node.js\";\n\n/**\n * Creates a manual source with no upstream deps. Emit values with {@link Node.down}.\n *\n * Spec: `state(initial, opts?)` is `node([], { initial, ...opts })` (GRAPHREFLY-SPEC §2.7).\n *\n * @param initial - Initial cached value. Because `initial` is provided, `equals` is\n * called on the first {@link Node.down | down()} emission — if the value matches\n * `initial`, the node emits `RESOLVED` instead of `DATA` (spec §2.5).\n * @param opts - Optional {@link NodeOptions} (excluding `initial`).\n * @returns `Node<T>` - Stateful node you drive imperatively.\n *\n * @example\n * ```ts\n * import { DATA, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const n = state(0);\n * n.down([[DATA, 1]]);\n * ```\n *\n * @category core\n */\nexport function state<T>(initial: T, opts?: Omit<NodeOptions, \"initial\">): Node<T> {\n\treturn node<T>([], { ...opts, initial });\n}\n\n/**\n * Creates a producer node with no deps; `fn` runs when the first subscriber connects.\n *\n * @param fn - Receives deps (empty) and {@link NodeActions}; use `emit` / `down` to push.\n * @param opts - Optional {@link NodeOptions}.\n * @returns `Node<T>` - Producer node.\n *\n * @example\n * ```ts\n * import { producer } from \"@graphrefly/graphrefly-ts\";\n *\n * const tick = producer((_d, a) => {\n * a.emit(1);\n * });\n * ```\n *\n * @category core\n */\nexport function producer<T = unknown>(fn: NodeFn<T>, opts?: NodeOptions): Node<T> {\n\treturn node<T>(fn, { describeKind: \"producer\", ...opts });\n}\n\n/**\n * Creates a derived node from dependencies and a compute function (same primitive as operators).\n *\n * @param deps - Upstream nodes.\n * @param fn - Compute function; return value is emitted, or use `actions` explicitly.\n * @param opts - Optional {@link NodeOptions}.\n * @returns `Node<T>` - Derived node.\n *\n * @example\n * ```ts\n * import { derived, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const a = state(1);\n * const b = derived([a], ([x]) => (x as number) * 2);\n * ```\n *\n * @category core\n */\nexport function derived<T = unknown>(\n\tdeps: readonly Node[],\n\tfn: NodeFn<T>,\n\topts?: NodeOptions,\n): Node<T> {\n\treturn node<T>(deps, fn, { describeKind: \"derived\", ...opts });\n}\n\n/**\n * Runs a side-effect when deps settle; return value is not auto-emitted.\n *\n * @param deps - Nodes to watch.\n * @param fn - Side-effect body.\n * @returns `Node<unknown>` - Effect node.\n *\n * @example\n * ```ts\n * import { effect, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const n = state(1);\n * effect([n], ([v]) => {\n * console.log(v);\n * });\n * ```\n *\n * @category core\n */\nexport function effect(deps: readonly Node[], fn: NodeFn<unknown>): Node<unknown> {\n\treturn node(deps, fn, { describeKind: \"effect\" });\n}\n\n/** Unary transform used by {@link pipe} (typically returns a new node wrapping `n`). */\nexport type PipeOperator = (n: Node) => Node;\n\n/**\n * Composes unary operators left-to-right; returns the final node. Does not register a {@link Graph}.\n *\n * @param source - Starting node.\n * @param ops - Each operator maps `Node` to `Node` (curried operators from `extra` use a factory pattern — wrap or use direct calls).\n * @returns `Node` - Result of the last operator.\n *\n * @example\n * ```ts\n * import { filter, map, pipe, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const src = state(1);\n * const out = pipe(\n * src,\n * (n) => map(n, (x) => x + 1),\n * (n) => filter(n, (x) => x > 0),\n * );\n * ```\n *\n * @category core\n */\nexport function pipe(source: Node, ...ops: PipeOperator[]): Node {\n\tlet current = source;\n\tfor (const op of ops) {\n\t\tcurrent = op(current);\n\t}\n\treturn current;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/patterns/reactive-layout/index.ts","../src/patterns/reactive-layout/measurement-adapters.ts","../src/patterns/reactive-layout/reactive-layout.ts","../src/patterns/reactive-layout/reactive-block-layout.ts"],"sourcesContent":["/**\n * Reactive layout pattern — standalone subpath export.\n *\n * ```ts\n * import { reactiveLayout, CliMeasureAdapter } from \"@graphrefly/graphrefly-ts/reactive-layout\";\n * ```\n */\n\nexport * from \"./measurement-adapters.js\";\nexport * from \"./reactive-block-layout.js\";\nexport * from \"./reactive-layout.js\";\n","/**\n * MeasurementAdapter implementations (roadmap §7.1 — pluggable backends).\n *\n * All adapters implement {@link MeasurementAdapter} from `reactive-layout.ts`.\n * Sync constructors, sync `measureSegment()` — no async, no polling.\n */\n\nimport type { MeasurementAdapter } from \"./reactive-layout.js\";\n\n// ---------------------------------------------------------------------------\n// Shared: East Asian Width detection for CLI adapter\n// ---------------------------------------------------------------------------\n\n/**\n * Return the display-cell width of a single codepoint in a monospace terminal.\n * Fullwidth / wide CJK → 2 cells; combining marks → 0 cells; everything else → 1 cell.\n *\n * Approximates UAX #11 East_Asian_Width (W/F → 2). Not a full EAW table —\n * covers CJK, Hangul, fullwidth forms, common emoji, and Extensions B-G.\n * Python's `unicodedata.east_asian_width()` is authoritative; this tracks it\n * closely but may diverge on rare/ambiguous codepoints.\n */\nfunction cellWidth(code: number): 0 | 1 | 2 {\n\t// Combining marks (Mn, Mc, Me) → 0 cells\n\tif (\n\t\t(code >= 0x0300 && code <= 0x036f) || // Combining Diacritical Marks\n\t\t(code >= 0x0483 && code <= 0x0489) || // Cyrillic combining marks\n\t\t(code >= 0x0591 && code <= 0x05bd) || // Hebrew combining marks\n\t\t(code >= 0x0610 && code <= 0x061a) || // Arabic combining marks\n\t\t(code >= 0x064b && code <= 0x065f) || // Arabic combining marks\n\t\t(code >= 0x0670 && code === 0x0670) || // Arabic superscript alef\n\t\t(code >= 0x06d6 && code <= 0x06dc) || // Arabic combining marks\n\t\t(code >= 0x06df && code <= 0x06e4) || // Arabic combining marks\n\t\t(code >= 0x06e7 && code <= 0x06e8) || // Arabic combining marks\n\t\t(code >= 0x06ea && code <= 0x06ed) || // Arabic combining marks\n\t\t(code >= 0x0730 && code <= 0x074a) || // Syriac combining marks\n\t\t(code >= 0x07a6 && code <= 0x07b0) || // Thaana combining marks\n\t\t(code >= 0x0900 && code <= 0x0903) || // Devanagari combining marks\n\t\t(code >= 0x093a && code <= 0x094f) || // Devanagari combining marks\n\t\t(code >= 0x0951 && code <= 0x0957) || // Devanagari combining marks\n\t\t(code >= 0x0962 && code <= 0x0963) || // Devanagari combining marks\n\t\t(code >= 0x0981 && code <= 0x0983) || // Bengali combining marks\n\t\t(code >= 0x09bc && code <= 0x09cd) || // Bengali combining marks\n\t\t(code >= 0x0a01 && code <= 0x0a03) || // Gurmukhi combining marks\n\t\t(code >= 0x0a3c && code <= 0x0a51) || // Gurmukhi combining marks\n\t\t(code >= 0x0a70 && code <= 0x0a71) || // Gurmukhi combining marks\n\t\t(code >= 0x0a75 && code === 0x0a75) || // Gurmukhi combining mark\n\t\t(code >= 0x0e31 && code === 0x0e31) || // Thai combining mark\n\t\t(code >= 0x0e34 && code <= 0x0e3a) || // Thai combining marks\n\t\t(code >= 0x0e47 && code <= 0x0e4e) || // Thai combining marks\n\t\t(code >= 0x0eb1 && code === 0x0eb1) || // Lao combining mark\n\t\t(code >= 0x0eb4 && code <= 0x0ebc) || // Lao combining marks\n\t\t(code >= 0x0ec8 && code <= 0x0ece) || // Lao combining marks\n\t\t(code >= 0x1dc0 && code <= 0x1dff) || // Combining Diacritical Marks Supplement\n\t\t(code >= 0x20d0 && code <= 0x20ff) || // Combining Diacritical Marks for Symbols\n\t\t(code >= 0xfe00 && code <= 0xfe0f) || // Variation Selectors\n\t\t(code >= 0xfe20 && code <= 0xfe2f) || // Combining Half Marks\n\t\tcode === 0x200d // Zero Width Joiner\n\t) {\n\t\treturn 0;\n\t}\n\t// Wide / fullwidth → 2 cells\n\tif (\n\t\t(code >= 0x1100 && code <= 0x115f) || // Hangul Jamo\n\t\t(code >= 0x231a && code <= 0x231b) || // Watch, Hourglass\n\t\t(code >= 0x2329 && code <= 0x232a) || // Angle brackets\n\t\t(code >= 0x23e9 && code <= 0x23f3) || // Media control symbols\n\t\t(code >= 0x23f8 && code <= 0x23fa) || // Media control symbols\n\t\t(code >= 0x25fd && code <= 0x25fe) || // Medium squares\n\t\t(code >= 0x2614 && code <= 0x2615) || // Umbrella, Hot Beverage\n\t\t(code >= 0x2648 && code <= 0x2653) || // Zodiac symbols\n\t\tcode === 0x267f || // Wheelchair\n\t\tcode === 0x2693 || // Anchor\n\t\tcode === 0x26a1 || // High Voltage\n\t\t(code >= 0x26aa && code <= 0x26ab) || // Medium circles\n\t\t(code >= 0x26bd && code <= 0x26be) || // Soccer, Baseball\n\t\t(code >= 0x26c4 && code <= 0x26c5) || // Snowman, Sun behind cloud\n\t\tcode === 0x26ce || // Ophiuchus\n\t\tcode === 0x26d4 || // No Entry\n\t\tcode === 0x26ea || // Church\n\t\t(code >= 0x26f2 && code <= 0x26f3) || // Fountain, Golf\n\t\tcode === 0x26f5 || // Sailboat\n\t\tcode === 0x26fa || // Tent\n\t\tcode === 0x26fd || // Fuel Pump\n\t\tcode === 0x2702 || // Scissors\n\t\tcode === 0x2705 || // Check Mark\n\t\t(code >= 0x2708 && code <= 0x270d) || // Airplane...Writing Hand\n\t\tcode === 0x270f || // Pencil\n\t\t(code >= 0x2753 && code <= 0x2755) || // Question marks\n\t\tcode === 0x2757 || // Exclamation\n\t\t(code >= 0x2795 && code <= 0x2797) || // Plus, Minus, Divide\n\t\tcode === 0x27b0 || // Curly Loop\n\t\tcode === 0x27bf || // Double Curly Loop\n\t\t(code >= 0x2934 && code <= 0x2935) || // Arrows\n\t\t(code >= 0x2b05 && code <= 0x2b07) || // Arrows\n\t\t(code >= 0x2b1b && code <= 0x2b1c) || // Squares\n\t\tcode === 0x2b50 || // Star\n\t\tcode === 0x2b55 || // Circle\n\t\t(code >= 0x2e80 && code <= 0x303e) || // CJK Radicals, Symbols, Punctuation\n\t\t(code >= 0x3040 && code <= 0x309f) || // Hiragana\n\t\t(code >= 0x30a0 && code <= 0x30ff) || // Katakana\n\t\t(code >= 0x3105 && code <= 0x312f) || // Bopomofo\n\t\t(code >= 0x3131 && code <= 0x318e) || // Hangul Compatibility Jamo\n\t\t(code >= 0x3190 && code <= 0x31e3) || // Kanbun, CJK Strokes\n\t\t(code >= 0x31f0 && code <= 0x321e) || // Katakana Phonetic Extensions\n\t\t(code >= 0x3220 && code <= 0x3247) || // Enclosed CJK\n\t\t(code >= 0x3250 && code <= 0x4dbf) || // CJK Extensions + Unified block\n\t\t(code >= 0x4e00 && code <= 0x9fff) || // CJK Unified Ideographs\n\t\t(code >= 0xa960 && code <= 0xa97c) || // Hangul Jamo Extended-A\n\t\t(code >= 0xac00 && code <= 0xd7a3) || // Hangul Syllables\n\t\t(code >= 0xf900 && code <= 0xfaff) || // CJK Compatibility Ideographs\n\t\t(code >= 0xfe10 && code <= 0xfe19) || // Vertical forms\n\t\t(code >= 0xfe30 && code <= 0xfe6b) || // CJK Compatibility Forms\n\t\t(code >= 0xff01 && code <= 0xff60) || // Fullwidth Forms (excl. halfwidth)\n\t\t(code >= 0xffe0 && code <= 0xffe6) || // Fullwidth Signs\n\t\t(code >= 0x1f004 && code === 0x1f004) || // Mahjong Red Dragon\n\t\tcode === 0x1f0cf || // Joker\n\t\t(code >= 0x1f170 && code <= 0x1f171) || // A/B buttons\n\t\tcode === 0x1f17e || // O button\n\t\tcode === 0x1f17f || // P button\n\t\tcode === 0x1f18e || // AB button\n\t\t(code >= 0x1f191 && code <= 0x1f19a) || // Squared symbols\n\t\t(code >= 0x1f1e0 && code <= 0x1f1ff) || // Regional Indicator Symbols\n\t\t(code >= 0x1f200 && code <= 0x1f202) || // Enclosed ideographic\n\t\tcode === 0x1f21a || // Squared CJK\n\t\tcode === 0x1f22f || // Squared CJK\n\t\t(code >= 0x1f232 && code <= 0x1f23a) || // Squared CJK\n\t\t(code >= 0x1f250 && code <= 0x1f251) || // Circled ideographic\n\t\t(code >= 0x1f300 && code <= 0x1f9ff) || // Misc Symbols / Emoticons / Emoji\n\t\t(code >= 0x1fa00 && code <= 0x1faff) || // Chess, Symbols Extended-A\n\t\t(code >= 0x1fb00 && code <= 0x1fbff) || // Symbols for Legacy Computing\n\t\t(code >= 0x20000 && code <= 0x2fffd) || // CJK Extension B-F (excl. nonchars)\n\t\t(code >= 0x30000 && code <= 0x3fffd) // CJK Extension G+ (excl. nonchars)\n\t) {\n\t\treturn 2;\n\t}\n\treturn 1;\n}\n\n/**\n * Count total display cells for a string in a monospace terminal.\n *\n * Combining marks contribute 0 cells; CJK/fullwidth contribute 2.\n * Does not handle ZWJ emoji sequences (multi-codepoint clusters that\n * render as a single glyph) — terminal support for these varies widely.\n */\nfunction countCells(text: string): number {\n\tlet cells = 0;\n\tfor (const ch of text) {\n\t\tcells += cellWidth(ch.codePointAt(0)!);\n\t}\n\treturn cells;\n}\n\n// ---------------------------------------------------------------------------\n// CliMeasureAdapter\n// ---------------------------------------------------------------------------\n\nexport type CliMeasureAdapterOptions = {\n\t/** Pixel width per terminal cell (default: 8). */\n\tcellPx?: number;\n};\n\n/**\n * Monospace terminal measurement adapter.\n *\n * Width = cell count × `cellPx`. CJK / fullwidth characters count as 2 cells.\n * No external dependencies. Works in any JS environment.\n */\nexport class CliMeasureAdapter implements MeasurementAdapter {\n\tprivate readonly cellPx: number;\n\n\tconstructor(opts?: CliMeasureAdapterOptions) {\n\t\tthis.cellPx = opts?.cellPx ?? 8;\n\t}\n\n\tmeasureSegment(text: string, _font: string): { width: number } {\n\t\treturn { width: countCells(text) * this.cellPx };\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// PrecomputedAdapter\n// ---------------------------------------------------------------------------\n\nexport type PrecomputedAdapterOptions = {\n\t/**\n\t * Pre-computed metrics: `{ font: { segment: widthPx } }`.\n\t * Outer key is the CSS font string; inner key is the text segment.\n\t */\n\tmetrics: Record<string, Record<string, number>>;\n\t/**\n\t * Fallback when a segment is not found in the metrics map.\n\t * - `\"per-char\"`: sum individual character widths from the same font map (default)\n\t * - `\"error\"`: throw an error for unknown segments\n\t */\n\tfallback?: \"per-char\" | \"error\";\n};\n\nclass PrecomputedAdapterKeyError extends Error {\n\tname = \"KeyError\";\n}\n\n/**\n * Pre-computed measurement adapter for SSR / snapshot replay.\n *\n * Reads from a static metrics object — zero measurement at runtime.\n * Ideal for server-side rendering or replaying snapshotted layouts.\n */\nexport class PrecomputedAdapter implements MeasurementAdapter {\n\tprivate readonly metrics: Record<string, Record<string, number>>;\n\tprivate readonly fallback: \"per-char\" | \"error\";\n\n\tconstructor(opts: PrecomputedAdapterOptions) {\n\t\tthis.metrics = opts.metrics;\n\t\tconst fb = opts.fallback ?? \"per-char\";\n\t\tif (fb !== \"per-char\" && fb !== \"error\") {\n\t\t\t// Keep parity with Python: validate at runtime.\n\t\t\tthrow new Error(\n\t\t\t\t`fallback must be 'per-char' or 'error', got ${JSON.stringify(opts.fallback)}`,\n\t\t\t);\n\t\t}\n\t\tthis.fallback = fb;\n\t}\n\n\tmeasureSegment(text: string, font: string): { width: number } {\n\t\tconst fontMap = this.metrics[font];\n\t\tif (fontMap) {\n\t\t\tconst w = fontMap[text];\n\t\t\tif (w !== undefined) return { width: w };\n\t\t}\n\n\t\tif (this.fallback === \"error\") {\n\t\t\tthrow new PrecomputedAdapterKeyError(\n\t\t\t\t`PrecomputedAdapter: no metrics for segment ${JSON.stringify(text)} in font ${JSON.stringify(font)}`,\n\t\t\t);\n\t\t}\n\n\t\t// per-char fallback: sum individual character widths\n\t\tlet total = 0;\n\t\tif (fontMap) {\n\t\t\tfor (const ch of text) {\n\t\t\t\tconst cw = fontMap[ch];\n\t\t\t\tif (cw !== undefined) {\n\t\t\t\t\ttotal += cw;\n\t\t\t\t}\n\t\t\t\t// unknown char contributes 0 (best-effort)\n\t\t\t}\n\t\t}\n\t\treturn { width: total };\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// CanvasMeasureAdapter (browser)\n// ---------------------------------------------------------------------------\n\nexport type CanvasMeasureAdapterOptions = {\n\t/** Emoji width correction factor (default: 1, no correction). */\n\temojiCorrection?: number;\n};\n\n/**\n * Browser measurement adapter using `OffscreenCanvas.measureText()`.\n *\n * Lazily creates an OffscreenCanvas and 2D context on first call.\n * Requires a browser environment with OffscreenCanvas support.\n */\nexport class CanvasMeasureAdapter implements MeasurementAdapter {\n\tprivate ctx: OffscreenCanvasRenderingContext2D | null = null;\n\tprivate currentFont = \"\";\n\tprivate readonly emojiCorrection: number;\n\n\tconstructor(opts?: CanvasMeasureAdapterOptions) {\n\t\tthis.emojiCorrection = opts?.emojiCorrection ?? 1;\n\t}\n\n\tprivate getContext(): OffscreenCanvasRenderingContext2D {\n\t\tif (!this.ctx) {\n\t\t\tif (typeof OffscreenCanvas === \"undefined\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"CanvasMeasureAdapter requires a browser environment with OffscreenCanvas support. \" +\n\t\t\t\t\t\t\"Use CliMeasureAdapter or NodeCanvasMeasureAdapter for Node.js.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst canvas = new OffscreenCanvas(0, 0);\n\t\t\tconst ctx = canvas.getContext(\"2d\");\n\t\t\tif (!ctx) throw new Error(\"CanvasMeasureAdapter: failed to get 2d context\");\n\t\t\tthis.ctx = ctx;\n\t\t}\n\t\treturn this.ctx;\n\t}\n\n\tmeasureSegment(text: string, font: string): { width: number } {\n\t\tconst ctx = this.getContext();\n\t\tif (font !== this.currentFont) {\n\t\t\tctx.font = font;\n\t\t\tthis.currentFont = font;\n\t\t}\n\t\tlet width = ctx.measureText(text).width;\n\t\t// Apply emoji correction if configured\n\t\tif (this.emojiCorrection !== 1 && /\\p{Emoji_Presentation}/u.test(text)) {\n\t\t\twidth *= this.emojiCorrection;\n\t\t}\n\t\treturn { width };\n\t}\n\n\tclearCache(): void {\n\t\t// No segment cache; context font is the only state.\n\t\tthis.currentFont = \"\";\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// NodeCanvasMeasureAdapter (Node.js / CLI with canvas package)\n// ---------------------------------------------------------------------------\n\n/**\n * Canvas API subset expected from `@napi-rs/canvas` or `skia-canvas`.\n * Passed via dependency injection — no dynamic import, no polling.\n */\nexport type CanvasModule = {\n\tcreateCanvas(\n\t\twidth: number,\n\t\theight: number,\n\t): {\n\t\tgetContext(type: \"2d\"): {\n\t\t\tfont: string;\n\t\t\tmeasureText(text: string): { width: number };\n\t\t};\n\t};\n};\n\n/**\n * Node.js measurement adapter using an injected canvas module.\n *\n * ```ts\n * import * as canvas from \"@napi-rs/canvas\";\n * const adapter = new NodeCanvasMeasureAdapter(canvas);\n * ```\n *\n * Works with `@napi-rs/canvas`, `skia-canvas`, or any module exposing\n * `createCanvas(w, h).getContext(\"2d\").measureText(text)`.\n */\nexport class NodeCanvasMeasureAdapter implements MeasurementAdapter {\n\tprivate ctx: { font: string; measureText(text: string): { width: number } } | null = null;\n\tprivate currentFont = \"\";\n\tprivate readonly canvasModule: CanvasModule;\n\n\tconstructor(canvasModule: CanvasModule) {\n\t\tthis.canvasModule = canvasModule;\n\t}\n\n\tprivate getContext(): { font: string; measureText(text: string): { width: number } } {\n\t\tif (!this.ctx) {\n\t\t\tconst canvas = this.canvasModule.createCanvas(0, 0);\n\t\t\tconst ctx = canvas.getContext(\"2d\");\n\t\t\tif (!ctx) throw new Error(\"NodeCanvasMeasureAdapter: failed to get 2d context\");\n\t\t\tthis.ctx = ctx;\n\t\t}\n\t\treturn this.ctx;\n\t}\n\n\tmeasureSegment(text: string, font: string): { width: number } {\n\t\tconst ctx = this.getContext();\n\t\tif (font !== this.currentFont) {\n\t\t\tctx.font = font;\n\t\t\tthis.currentFont = font;\n\t\t}\n\t\treturn { width: ctx.measureText(text).width };\n\t}\n\n\tclearCache(): void {\n\t\tthis.currentFont = \"\";\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// SvgBoundsAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * SVG measurement adapter — extracts dimensions from `viewBox` attribute\n * or explicit `width`/`height` attributes in the SVG string.\n *\n * Pure arithmetic: parses the SVG string for dimension attributes.\n * No DOM required. Works in any JS environment.\n *\n * Browser users who need `getBBox()` should pre-measure and pass explicit\n * `viewBox` on the content block instead.\n */\nexport class SvgBoundsAdapter {\n\tmeasureSvg(content: string): { width: number; height: number } {\n\t\t// Try viewBox first: viewBox=\"minX minY width height\"\n\t\tconst viewBoxMatch = content.match(/viewBox\\s*=\\s*[\"']([^\"']+)[\"']/);\n\t\tif (viewBoxMatch) {\n\t\t\tconst parts = viewBoxMatch[1]!.trim().split(/[\\s,]+/);\n\t\t\tif (parts.length >= 4) {\n\t\t\t\tconst w = Number.parseFloat(parts[2]!);\n\t\t\t\tconst h = Number.parseFloat(parts[3]!);\n\t\t\t\tif (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {\n\t\t\t\t\treturn { width: w, height: h };\n\t\t\t\t}\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"SvgBoundsAdapter: viewBox width/height are missing, non-finite, or not positive\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to explicit width/height attributes\n\t\tconst widthMatch = content.match(/<svg[^>]*\\bwidth\\s*=\\s*[\"']?([\\d.]+)/);\n\t\tconst heightMatch = content.match(/<svg[^>]*\\bheight\\s*=\\s*[\"']?([\\d.]+)/);\n\t\tif (widthMatch && heightMatch) {\n\t\t\tconst w = Number.parseFloat(widthMatch[1]!);\n\t\t\tconst h = Number.parseFloat(heightMatch[1]!);\n\t\t\tif (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {\n\t\t\t\treturn { width: w, height: h };\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t\"SvgBoundsAdapter: svg width/height attributes are non-finite or not positive\",\n\t\t\t);\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t\"SvgBoundsAdapter: cannot determine dimensions — SVG has no viewBox or width/height attributes\",\n\t\t);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// ImageSizeAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * Image measurement adapter — returns pre-registered dimensions by src key.\n *\n * Sync-only: dimensions must be provided upfront via the `sizes` map.\n * No I/O, no polling, no async. For browser use, pre-measure via\n * `Image.onload` and pass natural dimensions on the content block directly,\n * or register them here.\n *\n * ```ts\n * const adapter = new ImageSizeAdapter({\n * \"hero.png\": { width: 1200, height: 630 },\n * \"logo.svg\": { width: 120, height: 40 },\n * });\n * ```\n */\nexport class ImageSizeAdapter {\n\tprivate readonly sizes: Map<string, { width: number; height: number }>;\n\n\tconstructor(sizes: Record<string, { width: number; height: number }>) {\n\t\tthis.sizes = new Map(Object.entries(sizes));\n\t}\n\n\tmeasureImage(src: string): { width: number; height: number } {\n\t\tconst dims = this.sizes.get(src);\n\t\tif (!dims) {\n\t\t\tthrow new Error(`ImageSizeAdapter: no dimensions registered for ${JSON.stringify(src)}`);\n\t\t}\n\t\treturn { width: dims.width, height: dims.height };\n\t}\n}\n","/**\n * Reactive text layout engine (roadmap §7.1 — Pretext parity).\n *\n * Pure-arithmetic text measurement and line breaking without DOM thrashing.\n * Inspired by [Pretext](https://github.com/chenglou/pretext), rebuilt as a\n * GraphReFly graph — inspectable via `describe()`, snapshotable, debuggable.\n *\n * Two-tier DX:\n * - `reactiveLayout({ adapter, text?, font?, lineHeight?, maxWidth?, name? })` — convenience factory\n * - `MeasurementAdapter` — pluggable backends (`measureSegment`; optional `clearCache`)\n */\nimport { emitWithBatch } from \"../../core/batch.js\";\nimport { monotonicNs } from \"../../core/clock.js\";\nimport { DATA, INVALIDATE, TEARDOWN } from \"../../core/messages.js\";\nimport type { Node } from \"../../core/node.js\";\nimport { derived, state } from \"../../core/sugar.js\";\nimport { Graph } from \"../../graph/graph.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Pluggable measurement backend. */\nexport interface MeasurementAdapter {\n\tmeasureSegment(text: string, font: string): { width: number };\n\t/** Optional; adapters may omit for read-only / stateless measurement. */\n\tclearCache?(): void;\n}\n\n/** Mutable counters for `analyzeAndMeasure` cache hit ratio (hits / (hits + misses)). */\nexport type SegmentMeasureStats = { hits: number; misses: number };\n\n/** Break kind for each segment (ported from Pretext analysis.ts). */\nexport type SegmentBreakKind = \"text\" | \"space\" | \"zero-width-break\" | \"soft-hyphen\" | \"hard-break\";\n\n/** A measured text segment ready for line breaking. */\nexport type PreparedSegment = {\n\ttext: string;\n\twidth: number;\n\tkind: SegmentBreakKind;\n\t/** Grapheme widths for overflow-wrap: break-word (null if single grapheme). */\n\tgraphemeWidths: number[] | null;\n};\n\n/** A laid-out line with start/end cursors. */\nexport type LayoutLine = {\n\ttext: string;\n\twidth: number;\n\tstartSegment: number;\n\tstartGrapheme: number;\n\tendSegment: number;\n\tendGrapheme: number;\n};\n\n/** Per-character position for hit testing. */\nexport type CharPosition = {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n\tline: number;\n};\n\n/** Full layout result from the line-breaks derived node. */\nexport type LineBreaksResult = {\n\tlines: LayoutLine[];\n\tlineCount: number;\n};\n\n/** Result of the reactive layout graph's describe-accessible state. */\nexport type ReactiveLayoutBundle = {\n\tgraph: Graph;\n\t/** Set input text. */\n\tsetText: (text: string) => void;\n\t/** Set CSS font string. */\n\tsetFont: (font: string) => void;\n\t/** Set line height (px). */\n\tsetLineHeight: (lineHeight: number) => void;\n\t/** Set max width constraint (px). */\n\tsetMaxWidth: (maxWidth: number) => void;\n\t/** Segments node. */\n\tsegments: Node<PreparedSegment[]>;\n\t/** Line breaks node. */\n\tlineBreaks: Node<LineBreaksResult>;\n\t/** Total height node. */\n\theight: Node<number>;\n\t/** Per-character positions node. */\n\tcharPositions: Node<CharPosition[]>;\n};\n\n// ---------------------------------------------------------------------------\n// Text analysis (ported from Pretext analysis.ts — core subset)\n// ---------------------------------------------------------------------------\n\n// CJK detection (Unicode CJK Unified Ideographs + common ranges)\nfunction isCJK(s: string): boolean {\n\tfor (const ch of s) {\n\t\tconst c = ch.codePointAt(0)!;\n\t\tif (\n\t\t\t(c >= 0x4e00 && c <= 0x9fff) || // CJK Unified Ideographs\n\t\t\t(c >= 0x3400 && c <= 0x4dbf) || // CJK Extension A\n\t\t\t(c >= 0x3000 && c <= 0x303f) || // CJK Symbols and Punctuation\n\t\t\t(c >= 0x3040 && c <= 0x309f) || // Hiragana\n\t\t\t(c >= 0x30a0 && c <= 0x30ff) || // Katakana\n\t\t\t(c >= 0xac00 && c <= 0xd7af) || // Hangul\n\t\t\t(c >= 0xff00 && c <= 0xffef) // Fullwidth Forms\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n// Kinsoku: characters that cannot start a line (CJK punctuation)\nconst kinsokuStart = new Set([\n\t\"\\uff0c\",\n\t\"\\uff0e\",\n\t\"\\uff01\",\n\t\"\\uff1a\",\n\t\"\\uff1b\",\n\t\"\\uff1f\",\n\t\"\\u3001\",\n\t\"\\u3002\",\n\t\"\\u30fb\",\n\t\"\\uff09\",\n\t\"\\u3015\",\n\t\"\\u3009\",\n\t\"\\u300b\",\n\t\"\\u300d\",\n\t\"\\u300f\",\n\t\"\\u3011\",\n]);\n\n// Left-sticky punctuation (merges into preceding segment)\nconst leftStickyPunctuation = new Set([\n\t\".\",\n\t\",\",\n\t\"!\",\n\t\"?\",\n\t\":\",\n\t\";\",\n\t\")\",\n\t\"]\",\n\t\"}\",\n\t\"%\",\n\t'\"',\n\t\"\\u201d\",\n\t\"\\u2019\",\n\t\"\\u00bb\",\n\t\"\\u203a\",\n\t\"\\u2026\",\n]);\n\n/** Normalize collapsible whitespace (CSS white-space: normal). */\nfunction normalizeWhitespace(text: string): string {\n\treturn text.replace(/[\\t\\n\\r\\f ]+/g, \" \").replace(/^ | $/g, \"\");\n}\n\n/**\n * Segment text using Intl.Segmenter (word granularity) and classify break kinds.\n * Returns raw segmentation pieces before merging.\n */\nfunction segmentText(normalized: string): {\n\ttexts: string[];\n\tisWordLike: boolean[];\n\tkinds: SegmentBreakKind[];\n}[] {\n\tconst wordSegmenter = new Intl.Segmenter(undefined, { granularity: \"word\" });\n\tconst pieces: {\n\t\ttexts: string[];\n\t\tisWordLike: boolean[];\n\t\tkinds: SegmentBreakKind[];\n\t}[] = [];\n\n\tfor (const s of wordSegmenter.segment(normalized)) {\n\t\tconst text = s.segment;\n\t\tconst isWordLike = s.isWordLike ?? false;\n\n\t\t// Split segment by break-relevant characters\n\t\tconst texts: string[] = [];\n\t\tconst wordLikes: boolean[] = [];\n\t\tconst kinds: SegmentBreakKind[] = [];\n\n\t\tlet currentText = \"\";\n\t\tlet currentKind: SegmentBreakKind | null = null;\n\n\t\tfor (const ch of text) {\n\t\t\tlet kind: SegmentBreakKind;\n\t\t\tif (ch === \" \") kind = \"space\";\n\t\t\telse if (ch === \"\\u200b\") kind = \"zero-width-break\";\n\t\t\telse if (ch === \"\\u00ad\") kind = \"soft-hyphen\";\n\t\t\telse if (ch === \"\\n\") kind = \"hard-break\";\n\t\t\telse kind = \"text\";\n\n\t\t\tif (currentKind !== null && kind === currentKind) {\n\t\t\t\tcurrentText += ch;\n\t\t\t} else {\n\t\t\t\tif (currentKind !== null) {\n\t\t\t\t\ttexts.push(currentText);\n\t\t\t\t\twordLikes.push(currentKind === \"text\" && isWordLike);\n\t\t\t\t\tkinds.push(currentKind);\n\t\t\t\t}\n\t\t\t\tcurrentText = ch;\n\t\t\t\tcurrentKind = kind;\n\t\t\t}\n\t\t}\n\n\t\tif (currentKind !== null) {\n\t\t\ttexts.push(currentText);\n\t\t\twordLikes.push(currentKind === \"text\" && isWordLike);\n\t\t\tkinds.push(currentKind);\n\t\t}\n\n\t\tpieces.push({ texts, isWordLike: wordLikes, kinds });\n\t}\n\treturn pieces;\n}\n\n/**\n * Merge segmentation pieces: sticky punctuation, CJK per-grapheme splitting,\n * and produce the final measured segment list.\n */\nexport function analyzeAndMeasure(\n\ttext: string,\n\tfont: string,\n\tadapter: MeasurementAdapter,\n\tcache: Map<string, Map<string, number>>,\n\tstats?: SegmentMeasureStats,\n): PreparedSegment[] {\n\tconst normalized = normalizeWhitespace(text);\n\tif (normalized.length === 0) return [];\n\n\tconst pieces = segmentText(normalized);\n\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\tgranularity: \"grapheme\",\n\t});\n\n\t// Flatten pieces into a single segment list with merging\n\tconst rawTexts: string[] = [];\n\tconst rawKinds: SegmentBreakKind[] = [];\n\tconst rawWordLike: boolean[] = [];\n\n\tfor (const piece of pieces) {\n\t\tfor (let i = 0; i < piece.texts.length; i++) {\n\t\t\trawTexts.push(piece.texts[i]!);\n\t\t\trawKinds.push(piece.kinds[i]!);\n\t\t\trawWordLike.push(piece.isWordLike[i]!);\n\t\t}\n\t}\n\n\t// Merge: left-sticky punctuation and kinsoku-start into preceding text segment\n\tconst mergedTexts: string[] = [];\n\tconst mergedKinds: SegmentBreakKind[] = [];\n\tconst mergedWordLike: boolean[] = [];\n\n\tfor (let i = 0; i < rawTexts.length; i++) {\n\t\tconst t = rawTexts[i]!;\n\t\tconst k = rawKinds[i]!;\n\t\tconst wl = rawWordLike[i]!;\n\n\t\t// Merge left-sticky punctuation into preceding text\n\t\tif (\n\t\t\tk === \"text\" &&\n\t\t\t!wl &&\n\t\t\tmergedTexts.length > 0 &&\n\t\t\tmergedKinds[mergedKinds.length - 1] === \"text\"\n\t\t) {\n\t\t\tconst isSticky = t.length === 1 && (leftStickyPunctuation.has(t) || kinsokuStart.has(t));\n\t\t\tif (isSticky) {\n\t\t\t\tmergedTexts[mergedTexts.length - 1] += t;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Merge hyphen after word into preceding text (\"well-known\" stays together)\n\t\tif (\n\t\t\tt === \"-\" &&\n\t\t\tmergedTexts.length > 0 &&\n\t\t\tmergedKinds[mergedKinds.length - 1] === \"text\" &&\n\t\t\tmergedWordLike[mergedWordLike.length - 1]\n\t\t) {\n\t\t\tmergedTexts[mergedTexts.length - 1] += t;\n\t\t\tcontinue;\n\t\t}\n\n\t\tmergedTexts.push(t);\n\t\tmergedKinds.push(k);\n\t\tmergedWordLike.push(wl);\n\t}\n\n\t// Get or create font-specific cache\n\tlet fontCache = cache.get(font);\n\tif (!fontCache) {\n\t\tfontCache = new Map<string, number>();\n\t\tcache.set(font, fontCache);\n\t}\n\n\tfunction measureCached(seg: string): number {\n\t\tlet w = fontCache!.get(seg);\n\t\tif (w === undefined) {\n\t\t\tif (stats) stats.misses += 1;\n\t\t\tw = adapter.measureSegment(seg, font).width;\n\t\t\tfontCache!.set(seg, w);\n\t\t} else if (stats) {\n\t\t\tstats.hits += 1;\n\t\t}\n\t\treturn w;\n\t}\n\n\t// Build final prepared segments, splitting CJK into per-grapheme\n\tconst segments: PreparedSegment[] = [];\n\n\tfor (let i = 0; i < mergedTexts.length; i++) {\n\t\tconst t = mergedTexts[i]!;\n\t\tconst k = mergedKinds[i]!;\n\n\t\tif (k !== \"text\") {\n\t\t\t// Non-text segments: space, hard-break, soft-hyphen, zero-width-break\n\t\t\tsegments.push({\n\t\t\t\ttext: t,\n\t\t\t\twidth: k === \"space\" ? measureCached(\" \") * t.length : 0,\n\t\t\t\tkind: k,\n\t\t\t\tgraphemeWidths: null,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// CJK text: split into per-grapheme segments for line breaking\n\t\tif (isCJK(t)) {\n\t\t\tlet unitText = \"\";\n\t\t\tfor (const gs of graphemeSegmenter.segment(t)) {\n\t\t\t\tconst grapheme = gs.segment;\n\n\t\t\t\t// Kinsoku: line-start-prohibited chars stick to preceding unit\n\t\t\t\tif (unitText.length > 0 && kinsokuStart.has(grapheme)) {\n\t\t\t\t\tunitText += grapheme;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (unitText.length > 0) {\n\t\t\t\t\tconst w = measureCached(unitText);\n\t\t\t\t\tsegments.push({\n\t\t\t\t\t\ttext: unitText,\n\t\t\t\t\t\twidth: w,\n\t\t\t\t\t\tkind: \"text\",\n\t\t\t\t\t\tgraphemeWidths: null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tunitText = grapheme;\n\t\t\t}\n\t\t\tif (unitText.length > 0) {\n\t\t\t\tconst w = measureCached(unitText);\n\t\t\t\tsegments.push({\n\t\t\t\t\ttext: unitText,\n\t\t\t\t\twidth: w,\n\t\t\t\t\tkind: \"text\",\n\t\t\t\t\tgraphemeWidths: null,\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Non-CJK text: measure whole segment, pre-compute grapheme widths for break-word\n\t\tconst w = measureCached(t);\n\t\tlet graphemeWidths: number[] | null = null;\n\n\t\tif (mergedWordLike[i] && t.length > 1) {\n\t\t\tconst gWidths: number[] = [];\n\t\t\tfor (const gs of graphemeSegmenter.segment(t)) {\n\t\t\t\tgWidths.push(measureCached(gs.segment));\n\t\t\t}\n\t\t\tif (gWidths.length > 1) {\n\t\t\t\tgraphemeWidths = gWidths;\n\t\t\t}\n\t\t}\n\n\t\tsegments.push({ text: t, width: w, kind: \"text\", graphemeWidths });\n\t}\n\n\treturn segments;\n}\n\n// ---------------------------------------------------------------------------\n// Line breaking (greedy, ported from Pretext line-break.ts — core subset)\n// ---------------------------------------------------------------------------\n\n/**\n * Greedy line-breaking algorithm.\n *\n * Walks segments left to right, accumulating width. Breaks when a segment would\n * overflow maxWidth. Supports:\n * - Trailing space hang (spaces don't trigger breaks)\n * - overflow-wrap: break-word via grapheme widths\n * - Soft hyphens (break opportunity, adds visible hyphen width)\n * - Hard breaks (forced newline)\n */\nexport function computeLineBreaks(\n\tsegments: PreparedSegment[],\n\tmaxWidth: number,\n\tadapter: MeasurementAdapter,\n\tfont: string,\n\tcache: Map<string, Map<string, number>>,\n): LineBreaksResult {\n\tif (segments.length === 0) {\n\t\treturn { lines: [], lineCount: 0 };\n\t}\n\n\tconst lines: LayoutLine[] = [];\n\tlet lineW = 0;\n\tlet hasContent = false;\n\tlet lineStartSeg = 0;\n\tlet lineStartGrapheme = 0;\n\tlet lineEndSeg = 0;\n\tlet lineEndGrapheme = 0;\n\tlet pendingBreakSeg = -1;\n\tlet pendingBreakWidth = 0;\n\n\t// Measure hyphen for soft-hyphen support\n\tlet fontCache = cache.get(font);\n\tif (!fontCache) {\n\t\tfontCache = new Map<string, number>();\n\t\tcache.set(font, fontCache);\n\t}\n\tlet hyphenWidth = fontCache.get(\"-\");\n\tif (hyphenWidth === undefined) {\n\t\thyphenWidth = adapter.measureSegment(\"-\", font).width;\n\t\tfontCache.set(\"-\", hyphenWidth);\n\t}\n\n\tfunction emitLine(endSeg = lineEndSeg, endGrapheme = lineEndGrapheme, width = lineW) {\n\t\t// Build line text\n\t\tlet text = \"\";\n\t\tfor (let i = lineStartSeg; i < endSeg; i++) {\n\t\t\tconst seg = segments[i]!;\n\t\t\tif (seg.kind === \"soft-hyphen\" || seg.kind === \"hard-break\") continue;\n\t\t\tif (i === lineStartSeg && lineStartGrapheme > 0 && seg.graphemeWidths) {\n\t\t\t\t// Partial segment from grapheme break\n\t\t\t\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\t\t\t\tgranularity: \"grapheme\",\n\t\t\t\t});\n\t\t\t\tconst graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);\n\t\t\t\ttext += graphemes.slice(lineStartGrapheme).join(\"\");\n\t\t\t} else {\n\t\t\t\ttext += seg.text;\n\t\t\t}\n\t\t}\n\t\t// Handle partial end segment\n\t\tif (endGrapheme > 0 && endSeg < segments.length) {\n\t\t\tconst seg = segments[endSeg]!;\n\t\t\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\t\t\tgranularity: \"grapheme\",\n\t\t\t});\n\t\t\tconst graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);\n\t\t\tconst startG = lineStartSeg === endSeg ? lineStartGrapheme : 0;\n\t\t\ttext += graphemes.slice(startG, endGrapheme).join(\"\");\n\t\t}\n\t\t// Add visible hyphen if line ends at soft-hyphen\n\t\tif (\n\t\t\tendSeg > 0 &&\n\t\t\tsegments[endSeg - 1]?.kind === \"soft-hyphen\" &&\n\t\t\t!(lineStartSeg === endSeg && lineStartGrapheme > 0)\n\t\t) {\n\t\t\ttext += \"-\";\n\t\t}\n\n\t\tlines.push({\n\t\t\ttext,\n\t\t\twidth,\n\t\t\tstartSegment: lineStartSeg,\n\t\t\tstartGrapheme: lineStartGrapheme,\n\t\t\tendSegment: endSeg,\n\t\t\tendGrapheme,\n\t\t});\n\t\tlineW = 0;\n\t\thasContent = false;\n\t\tpendingBreakSeg = -1;\n\t\tpendingBreakWidth = 0;\n\t}\n\n\tfunction canBreakAfter(kind: SegmentBreakKind): boolean {\n\t\treturn kind === \"space\" || kind === \"zero-width-break\" || kind === \"soft-hyphen\";\n\t}\n\n\tfunction startLine(segIdx: number, graphemeIdx: number, width: number) {\n\t\thasContent = true;\n\t\tlineStartSeg = segIdx;\n\t\tlineStartGrapheme = graphemeIdx;\n\t\tlineEndSeg = segIdx + 1;\n\t\tlineEndGrapheme = 0;\n\t\tlineW = width;\n\t}\n\n\tfunction startLineAtGrapheme(segIdx: number, graphemeIdx: number, width: number) {\n\t\thasContent = true;\n\t\tlineStartSeg = segIdx;\n\t\tlineStartGrapheme = graphemeIdx;\n\t\tlineEndSeg = segIdx;\n\t\tlineEndGrapheme = graphemeIdx + 1;\n\t\tlineW = width;\n\t}\n\n\tfor (let i = 0; i < segments.length; i++) {\n\t\tconst seg = segments[i]!;\n\n\t\t// Hard break: emit current line, start fresh\n\t\tif (seg.kind === \"hard-break\") {\n\t\t\tif (hasContent) {\n\t\t\t\temitLine();\n\t\t\t} else {\n\t\t\t\t// Empty line\n\t\t\t\tlines.push({\n\t\t\t\t\ttext: \"\",\n\t\t\t\t\twidth: 0,\n\t\t\t\t\tstartSegment: i,\n\t\t\t\t\tstartGrapheme: 0,\n\t\t\t\t\tendSegment: i,\n\t\t\t\t\tendGrapheme: 0,\n\t\t\t\t});\n\t\t\t}\n\t\t\tlineStartSeg = i + 1;\n\t\t\tlineStartGrapheme = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst w = seg.width;\n\n\t\tif (!hasContent) {\n\t\t\t// First content on a new line\n\t\t\tif (w > maxWidth && seg.graphemeWidths) {\n\t\t\t\t// Word wider than maxWidth: break at grapheme level\n\t\t\t\tappendBreakableSegment(i, 0, seg.graphemeWidths);\n\t\t\t} else {\n\t\t\t\tstartLine(i, 0, w);\n\t\t\t}\n\t\t\tif (canBreakAfter(seg.kind)) {\n\t\t\t\tpendingBreakSeg = i + 1;\n\t\t\t\tpendingBreakWidth = seg.kind === \"space\" ? lineW - w : lineW;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst newW = lineW + w;\n\n\t\tif (newW > maxWidth + 0.005) {\n\t\t\t// Overflow\n\t\t\tif (canBreakAfter(seg.kind)) {\n\t\t\t\t// Trailing space: hang past edge, then break\n\t\t\t\tlineW += w;\n\t\t\t\tlineEndSeg = i + 1;\n\t\t\t\tlineEndGrapheme = 0;\n\t\t\t\temitLine(i + 1, 0, seg.kind === \"space\" ? lineW - w : lineW);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (pendingBreakSeg >= 0) {\n\t\t\t\t// Break at last break opportunity\n\t\t\t\temitLine(pendingBreakSeg, 0, pendingBreakWidth);\n\t\t\t\t// Don't advance i — re-process current segment on new line\n\t\t\t\ti--;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (w > maxWidth && seg.graphemeWidths) {\n\t\t\t\t// Break-word: split at grapheme level\n\t\t\t\temitLine();\n\t\t\t\tappendBreakableSegment(i, 0, seg.graphemeWidths);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// No break opportunity: force break before this segment\n\t\t\temitLine();\n\t\t\ti--;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Fits on current line\n\t\tlineW = newW;\n\t\tlineEndSeg = i + 1;\n\t\tlineEndGrapheme = 0;\n\n\t\tif (canBreakAfter(seg.kind)) {\n\t\t\tpendingBreakSeg = i + 1;\n\t\t\tpendingBreakWidth = seg.kind === \"space\" ? lineW - w : lineW;\n\t\t}\n\t}\n\n\tif (hasContent) {\n\t\temitLine();\n\t}\n\n\treturn { lines, lineCount: lines.length };\n\n\tfunction appendBreakableSegment(segIdx: number, startG: number, gWidths: number[]) {\n\t\tfor (let g = startG; g < gWidths.length; g++) {\n\t\t\tconst gw = gWidths[g]!;\n\t\t\tif (!hasContent) {\n\t\t\t\tstartLineAtGrapheme(segIdx, g, gw);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (lineW + gw > maxWidth + 0.005) {\n\t\t\t\temitLine();\n\t\t\t\tstartLineAtGrapheme(segIdx, g, gw);\n\t\t\t} else {\n\t\t\t\tlineW += gw;\n\t\t\t\tlineEndSeg = segIdx;\n\t\t\t\tlineEndGrapheme = g + 1;\n\t\t\t}\n\t\t}\n\t\t// If we consumed the whole segment, advance end past it\n\t\tif (hasContent && lineEndSeg === segIdx && lineEndGrapheme === gWidths.length) {\n\t\t\tlineEndSeg = segIdx + 1;\n\t\t\tlineEndGrapheme = 0;\n\t\t}\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Character positions\n// ---------------------------------------------------------------------------\n\n/** Compute per-character x,y positions from line breaks and segments. */\nexport function computeCharPositions(\n\tlineBreaks: LineBreaksResult,\n\tsegments: PreparedSegment[],\n\tlineHeight: number,\n): CharPosition[] {\n\tconst positions: CharPosition[] = [];\n\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\tgranularity: \"grapheme\",\n\t});\n\n\tfor (let lineIdx = 0; lineIdx < lineBreaks.lines.length; lineIdx++) {\n\t\tconst line = lineBreaks.lines[lineIdx]!;\n\t\tconst y = lineIdx * lineHeight;\n\t\tlet x = 0;\n\n\t\tfor (let si = line.startSegment; si < segments.length; si++) {\n\t\t\tconst seg = segments[si]!;\n\t\t\tif (seg.kind === \"soft-hyphen\" || seg.kind === \"hard-break\") {\n\t\t\t\t// Skip non-visual segments but stop if past the line\n\t\t\t\tif (si >= line.endSegment && line.endGrapheme === 0) break;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);\n\t\t\tif (graphemes.length === 0) continue;\n\t\t\tconst startG = si === line.startSegment ? line.startGrapheme : 0;\n\n\t\t\t// Determine how many graphemes of this segment belong to this line\n\t\t\tlet endG: number;\n\t\t\tif (si < line.endSegment) {\n\t\t\t\t// Full segment is on this line\n\t\t\t\tendG = graphemes.length;\n\t\t\t} else if (si === line.endSegment && line.endGrapheme > 0) {\n\t\t\t\t// Partial segment (grapheme-level break)\n\t\t\t\tendG = line.endGrapheme;\n\t\t\t} else {\n\t\t\t\t// Past the line's content\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tfor (let g = startG; g < endG; g++) {\n\t\t\t\tconst gWidth = seg.graphemeWidths ? seg.graphemeWidths[g]! : seg.width / graphemes.length;\n\t\t\t\tpositions.push({ x, y, width: gWidth, height: lineHeight, line: lineIdx });\n\t\t\t\tx += gWidth;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn positions;\n}\n\n// ---------------------------------------------------------------------------\n// Reactive graph factory\n// ---------------------------------------------------------------------------\n\nexport type ReactiveLayoutOptions = {\n\t/** Measurement backend (required). */\n\tadapter: MeasurementAdapter;\n\t/** Graph name (default: \"reactive-layout\"). */\n\tname?: string;\n\t/** Initial text. */\n\ttext?: string;\n\t/** Initial CSS font string. */\n\tfont?: string;\n\t/** Initial line height in px. */\n\tlineHeight?: number;\n\t/** Initial max width in px (clamped to ≥ 0). */\n\tmaxWidth?: number;\n};\n\n/**\n * Create a reactive text layout graph.\n *\n * ```\n * Graph(\"reactive-layout\")\n * ├── state(\"text\")\n * ├── state(\"font\")\n * ├── state(\"line-height\")\n * ├── state(\"max-width\")\n * ├── derived(\"segments\") — text + font → PreparedSegment[]\n * ├── derived(\"line-breaks\") — segments + max-width → LineBreaksResult\n * ├── derived(\"height\") — line-breaks → number\n * └── derived(\"char-positions\") — line-breaks + segments → CharPosition[]\n * ```\n */\nexport function reactiveLayout(opts: ReactiveLayoutOptions): ReactiveLayoutBundle {\n\tconst { adapter, name = \"reactive-layout\" } = opts;\n\tconst g = new Graph(name);\n\n\t// Shared measurement cache: Map<font, Map<segment, width>>\n\tconst measureCache = new Map<string, Map<string, number>>();\n\n\t// --- State nodes ---\n\tconst textNode = state<string>(opts.text ?? \"\", { name: \"text\" });\n\tconst fontNode = state<string>(opts.font ?? \"16px sans-serif\", {\n\t\tname: \"font\",\n\t});\n\tconst lineHeightNode = state<number>(opts.lineHeight ?? 20, {\n\t\tname: \"line-height\",\n\t});\n\tconst maxWidthNode = state<number>(Math.max(0, opts.maxWidth ?? 800), {\n\t\tname: \"max-width\",\n\t});\n\n\t// --- Derived: segments (text + font → PreparedSegment[]) ---\n\tfunction graphemeWidthsEqual(a: number[] | null, b: number[] | null): boolean {\n\t\tif (a === null || b === null) return a === b;\n\t\tif (a.length !== b.length) return false;\n\t\tfor (let i = 0; i < a.length; i++) {\n\t\t\tif (a[i] !== b[i]!) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tconst segmentsNode = derived<PreparedSegment[]>(\n\t\t[textNode, fontNode],\n\t\t([textVal, fontVal]) => {\n\t\t\tconst t0 = monotonicNs();\n\t\t\tconst measureStats: SegmentMeasureStats = { hits: 0, misses: 0 };\n\t\t\tconst result = analyzeAndMeasure(\n\t\t\t\ttextVal as string,\n\t\t\t\tfontVal as string,\n\t\t\t\tadapter,\n\t\t\t\tmeasureCache,\n\t\t\t\tmeasureStats,\n\t\t\t);\n\t\t\tconst elapsed = monotonicNs() - t0;\n\n\t\t\tconst lookups = measureStats.hits + measureStats.misses;\n\t\t\tconst hitRate = lookups === 0 ? 1 : measureStats.hits / lookups;\n\n\t\t\t// After parent `segments` auto-emits DATA/RESOLVED, deliver metrics\n\t\t\t// via phase-3 deferral so observers see the parent value first.\n\t\t\t// Phase-3 drains after all phase-2 work (parent settlements) completes\n\t\t\t// (parity with Python `defer_down` → `emit_with_batch_phase3`).\n\t\t\tconst meta = segmentsNode.meta;\n\t\t\tif (meta) {\n\t\t\t\tconst hr = hitRate;\n\t\t\t\tconst len = result.length;\n\t\t\t\tconst el = elapsed;\n\t\t\t\temitWithBatch((msgs) => meta[\"cache-hit-rate\"]?.down(msgs), [[DATA, hr]], 3);\n\t\t\t\temitWithBatch((msgs) => meta[\"segment-count\"]?.down(msgs), [[DATA, len]], 3);\n\t\t\t\temitWithBatch((msgs) => meta[\"layout-time-ns\"]?.down(msgs), [[DATA, el]], 3);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\t\t{\n\t\t\tname: \"segments\",\n\t\t\tmeta: {\n\t\t\t\t\"cache-hit-rate\": 0,\n\t\t\t\t\"segment-count\": 0,\n\t\t\t\t\"layout-time-ns\": 0,\n\t\t\t},\n\t\t\tonMessage(msg) {\n\t\t\t\tif (msg[0] === INVALIDATE || msg[0] === TEARDOWN) {\n\t\t\t\t\t// Local side-effect: clear closure-held cache that the node\n\t\t\t\t\t// cannot reach via its normal lifecycle. Return false so the\n\t\t\t\t\t// message still propagates via default dispatch (TEARDOWN\n\t\t\t\t\t// forwarding to meta/downstream, INVALIDATE clearing _cached).\n\t\t\t\t\tmeasureCache.clear();\n\t\t\t\t\tadapter.clearCache?.();\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst sa = a as PreparedSegment[] | null;\n\t\t\t\tconst sb = b as PreparedSegment[] | null;\n\t\t\t\tif (sa == null || sb == null) return sa === sb;\n\t\t\t\tif (sa.length !== sb.length) return false;\n\t\t\t\tfor (let i = 0; i < sa.length; i++) {\n\t\t\t\t\tconst pa = sa[i]!;\n\t\t\t\t\tconst pb = sb[i]!;\n\t\t\t\t\tif (\n\t\t\t\t\t\tpa.text !== pb.text ||\n\t\t\t\t\t\tpa.width !== pb.width ||\n\t\t\t\t\t\tpa.kind !== pb.kind ||\n\t\t\t\t\t\t!graphemeWidthsEqual(pa.graphemeWidths ?? null, pb.graphemeWidths ?? null)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: line-breaks (segments + max-width + font → LineBreaksResult) ---\n\tconst lineBreaksNode = derived<LineBreaksResult>(\n\t\t[segmentsNode, maxWidthNode, fontNode],\n\t\t([segs, mw, font]) => {\n\t\t\treturn computeLineBreaks(\n\t\t\t\tsegs as PreparedSegment[],\n\t\t\t\tmw as number,\n\t\t\t\tadapter,\n\t\t\t\tfont as string,\n\t\t\t\tmeasureCache,\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tname: \"line-breaks\",\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst la = a as LineBreaksResult | null;\n\t\t\t\tconst lb = b as LineBreaksResult | null;\n\t\t\t\tif (la == null || lb == null) return la === lb;\n\t\t\t\tif (la.lineCount !== lb.lineCount) return false;\n\t\t\t\tfor (let i = 0; i < la.lines.length; i++) {\n\t\t\t\t\tconst lineA = la.lines[i]!;\n\t\t\t\t\tconst lineB = lb.lines[i]!;\n\t\t\t\t\tif (\n\t\t\t\t\t\tlineA.text !== lineB.text ||\n\t\t\t\t\t\tlineA.width !== lineB.width ||\n\t\t\t\t\t\tlineA.startSegment !== lineB.startSegment ||\n\t\t\t\t\t\tlineA.startGrapheme !== lineB.startGrapheme ||\n\t\t\t\t\t\tlineA.endSegment !== lineB.endSegment ||\n\t\t\t\t\t\tlineA.endGrapheme !== lineB.endGrapheme\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: height ---\n\tconst heightNode = derived<number>(\n\t\t[lineBreaksNode, lineHeightNode],\n\t\t([lb, lh]) => (lb as LineBreaksResult).lineCount * (lh as number),\n\t\t{ name: \"height\" },\n\t);\n\n\t// --- Derived: char-positions ---\n\tconst charPositionsNode = derived<CharPosition[]>(\n\t\t[lineBreaksNode, segmentsNode, lineHeightNode],\n\t\t([lb, segs, lh]) => {\n\t\t\treturn computeCharPositions(lb as LineBreaksResult, segs as PreparedSegment[], lh as number);\n\t\t},\n\t\t{\n\t\t\tname: \"char-positions\",\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst ca = a as CharPosition[] | null;\n\t\t\t\tconst cb = b as CharPosition[] | null;\n\t\t\t\tif (ca == null || cb == null) return ca === cb;\n\t\t\t\tif (ca.length !== cb.length) return false;\n\t\t\t\tfor (let i = 0; i < ca.length; i++) {\n\t\t\t\t\tif (ca[i]!.x !== cb[i]!.x || ca[i]!.y !== cb[i]!.y || ca[i]!.width !== cb[i]!.width)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Register in graph ---\n\tg.add(\"text\", textNode);\n\tg.add(\"font\", fontNode);\n\tg.add(\"line-height\", lineHeightNode);\n\tg.add(\"max-width\", maxWidthNode);\n\tg.add(\"segments\", segmentsNode);\n\tg.add(\"line-breaks\", lineBreaksNode);\n\tg.add(\"height\", heightNode);\n\tg.add(\"char-positions\", charPositionsNode);\n\n\t// --- Edges (for describe() visibility) ---\n\tg.connect(\"text\", \"segments\");\n\tg.connect(\"font\", \"segments\");\n\tg.connect(\"segments\", \"line-breaks\");\n\tg.connect(\"max-width\", \"line-breaks\");\n\tg.connect(\"font\", \"line-breaks\");\n\tg.connect(\"line-breaks\", \"height\");\n\tg.connect(\"line-height\", \"height\");\n\tg.connect(\"line-breaks\", \"char-positions\");\n\tg.connect(\"segments\", \"char-positions\");\n\tg.connect(\"line-height\", \"char-positions\");\n\n\treturn {\n\t\tgraph: g,\n\t\tsetText: (text: string) => g.set(\"text\", text),\n\t\tsetFont: (font: string) => g.set(\"font\", font),\n\t\tsetLineHeight: (lh: number) => g.set(\"line-height\", lh),\n\t\tsetMaxWidth: (mw: number) => g.set(\"max-width\", Math.max(0, mw)),\n\t\tsegments: segmentsNode,\n\t\tlineBreaks: lineBreaksNode,\n\t\theight: heightNode,\n\t\tcharPositions: charPositionsNode,\n\t};\n}\n","/**\n * Reactive multi-content block layout engine (roadmap §7.1 — mixed content).\n *\n * Extends the text-only `reactiveLayout` with support for image and SVG blocks.\n * Pure-arithmetic layout over measured child sizes — no DOM, no async.\n *\n * Graph shape:\n * ```\n * Graph(\"reactive-block-layout\")\n * ├── state(\"blocks\") — ContentBlock[] input\n * ├── state(\"max-width\") — container constraint\n * ├── state(\"gap\") — vertical gap between blocks (px)\n * ├── derived(\"measured-blocks\") — blocks → MeasuredBlock[] (per-type measurement)\n * ├── derived(\"block-flow\") — measured-blocks + max-width + gap → PositionedBlock[]\n * ├── derived(\"total-height\") — block-flow → total height\n * └── meta: { block-count, layout-time-ns }\n * ```\n */\nimport { emitWithBatch } from \"../../core/batch.js\";\nimport { monotonicNs } from \"../../core/clock.js\";\nimport { DATA, INVALIDATE, TEARDOWN } from \"../../core/messages.js\";\nimport type { Node } from \"../../core/node.js\";\nimport { derived, state } from \"../../core/sugar.js\";\nimport { Graph } from \"../../graph/graph.js\";\nimport {\n\tanalyzeAndMeasure,\n\ttype CharPosition,\n\tcomputeCharPositions,\n\tcomputeLineBreaks,\n\ttype LineBreaksResult,\n\ttype MeasurementAdapter,\n\ttype PreparedSegment,\n} from \"./reactive-layout.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Pluggable measurement backend for SVG content. */\nexport interface SvgMeasurer {\n\tmeasureSvg(content: string): { width: number; height: number };\n}\n\n/** Pluggable measurement backend for image content. */\nexport interface ImageMeasurer {\n\tmeasureImage(src: string): { width: number; height: number };\n}\n\n/** Adapters map for `reactiveBlockLayout`. */\nexport type BlockAdapters = {\n\t/** Text measurement adapter (required — delegates to `reactiveLayout` internals). */\n\ttext: MeasurementAdapter;\n\t/** SVG measurement (optional — required only if SVG blocks are present). */\n\tsvg?: SvgMeasurer;\n\t/** Image measurement (optional — required only if image blocks without explicit dimensions are present). */\n\timage?: ImageMeasurer;\n};\n\n/** A content block — text, image, or SVG. */\nexport type ContentBlock =\n\t| {\n\t\t\ttype: \"text\";\n\t\t\ttext: string;\n\t\t\tfont?: string;\n\t\t\tlineHeight?: number;\n\t }\n\t| {\n\t\t\ttype: \"image\";\n\t\t\tsrc: string;\n\t\t\t/** Natural width in px. Required if no ImageMeasurer adapter is provided. */\n\t\t\tnaturalWidth?: number;\n\t\t\t/** Natural height in px. Required if no ImageMeasurer adapter is provided. */\n\t\t\tnaturalHeight?: number;\n\t }\n\t| {\n\t\t\ttype: \"svg\";\n\t\t\tcontent: string;\n\t\t\t/** Explicit viewBox dimensions. Required if no SvgMeasurer adapter is provided. */\n\t\t\tviewBox?: { width: number; height: number };\n\t };\n\n/**\n * A block after measurement — knows its natural dimensions.\n *\n * **Equality note:** The reactive `measured-blocks` node uses dimension-only equality\n * (`type`, `width`, `height`, `index`). Inner text layout data (`textSegments`,\n * `textLineBreaks`, `textCharPositions`) is NOT compared for change detection.\n * If you need text-level reactivity, use `reactiveLayout()` directly per text block.\n */\nexport type MeasuredBlock = {\n\tindex: number;\n\ttype: \"text\" | \"image\" | \"svg\";\n\twidth: number;\n\theight: number;\n\t/** For text blocks: the inner layout results. */\n\ttextSegments?: PreparedSegment[];\n\ttextLineBreaks?: LineBreaksResult;\n\ttextCharPositions?: CharPosition[];\n};\n\n/** A block after flow — positioned in the container. */\nexport type PositionedBlock = MeasuredBlock & {\n\tx: number;\n\ty: number;\n};\n\n/** Options for `reactiveBlockLayout`. */\nexport type ReactiveBlockLayoutOptions = {\n\tadapters: BlockAdapters;\n\tname?: string;\n\tblocks?: ContentBlock[];\n\t/** Container max width in px (clamped to ≥ 0 on init and `setMaxWidth`). */\n\tmaxWidth?: number;\n\t/** Vertical gap between blocks in px (default 0). */\n\tgap?: number;\n\t/** Default font for text blocks that don't specify one. */\n\tdefaultFont?: string;\n\t/** Default line height for text blocks that don't specify one. */\n\tdefaultLineHeight?: number;\n};\n\n/** Result bundle from `reactiveBlockLayout`. */\nexport type ReactiveBlockLayoutBundle = {\n\tgraph: Graph;\n\tsetBlocks: (blocks: ContentBlock[]) => void;\n\tsetMaxWidth: (maxWidth: number) => void;\n\tsetGap: (gap: number) => void;\n\tmeasuredBlocks: Node<MeasuredBlock[]>;\n\tblockFlow: Node<PositionedBlock[]>;\n\ttotalHeight: Node<number>;\n};\n\n// ---------------------------------------------------------------------------\n// Block measurement (pure functions)\n// ---------------------------------------------------------------------------\n\n/**\n * Measure a single content block, returning natural (unconstrained) dimensions.\n * Text blocks use the text layout pipeline; image/SVG use adapters or explicit dims.\n */\nexport function measureBlock(\n\tblock: ContentBlock,\n\tmaxWidth: number,\n\tadapters: BlockAdapters,\n\tmeasureCache: Map<string, Map<string, number>>,\n\tdefaultFont: string,\n\tdefaultLineHeight: number,\n\tindex: number,\n): MeasuredBlock {\n\tswitch (block.type) {\n\t\tcase \"text\": {\n\t\t\tconst font = block.font ?? defaultFont;\n\t\t\tconst lineHeight = block.lineHeight ?? defaultLineHeight;\n\t\t\tconst segments = analyzeAndMeasure(block.text, font, adapters.text, measureCache);\n\t\t\tconst lineBreaks = computeLineBreaks(segments, maxWidth, adapters.text, font, measureCache);\n\t\t\tconst charPositions = computeCharPositions(lineBreaks, segments, lineHeight);\n\t\t\tconst height = lineBreaks.lineCount * lineHeight;\n\t\t\t// Width is the max line width (clamped to maxWidth)\n\t\t\tlet width = 0;\n\t\t\tfor (const line of lineBreaks.lines) {\n\t\t\t\tif (line.width > width) width = line.width;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tindex,\n\t\t\t\ttype: \"text\",\n\t\t\t\twidth: Math.min(width, maxWidth),\n\t\t\t\theight,\n\t\t\t\ttextSegments: segments,\n\t\t\t\ttextLineBreaks: lineBreaks,\n\t\t\t\ttextCharPositions: charPositions,\n\t\t\t};\n\t\t}\n\t\tcase \"image\": {\n\t\t\tlet w: number;\n\t\t\tlet h: number;\n\t\t\tif (block.naturalWidth != null && block.naturalHeight != null) {\n\t\t\t\tw = block.naturalWidth;\n\t\t\t\th = block.naturalHeight;\n\t\t\t} else if (adapters.image) {\n\t\t\t\tconst dims = adapters.image.measureImage(block.src);\n\t\t\t\tw = dims.width;\n\t\t\t\th = dims.height;\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Image block at index ${index} has no naturalWidth/naturalHeight and no ImageMeasurer adapter`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Scale proportionally to fit maxWidth\n\t\t\tif (w > maxWidth) {\n\t\t\t\th = (h * maxWidth) / w;\n\t\t\t\tw = maxWidth;\n\t\t\t}\n\t\t\treturn { index, type: \"image\", width: w, height: h };\n\t\t}\n\t\tcase \"svg\": {\n\t\t\tlet w: number;\n\t\t\tlet h: number;\n\t\t\tif (block.viewBox) {\n\t\t\t\tw = block.viewBox.width;\n\t\t\t\th = block.viewBox.height;\n\t\t\t} else if (adapters.svg) {\n\t\t\t\tconst dims = adapters.svg.measureSvg(block.content);\n\t\t\t\tw = dims.width;\n\t\t\t\th = dims.height;\n\t\t\t} else {\n\t\t\t\tthrow new Error(`SVG block at index ${index} has no viewBox and no SvgMeasurer adapter`);\n\t\t\t}\n\t\t\t// Scale proportionally to fit maxWidth\n\t\t\tif (w > maxWidth) {\n\t\t\t\th = (h * maxWidth) / w;\n\t\t\t\tw = maxWidth;\n\t\t\t}\n\t\t\treturn { index, type: \"svg\", width: w, height: h };\n\t\t}\n\t}\n}\n\n/**\n * Measure all blocks in a content array.\n */\nexport function measureBlocks(\n\tblocks: ContentBlock[],\n\tmaxWidth: number,\n\tadapters: BlockAdapters,\n\tmeasureCache: Map<string, Map<string, number>>,\n\tdefaultFont: string,\n\tdefaultLineHeight: number,\n): MeasuredBlock[] {\n\treturn blocks.map((block, i) =>\n\t\tmeasureBlock(block, maxWidth, adapters, measureCache, defaultFont, defaultLineHeight, i),\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Block flow (pure function)\n// ---------------------------------------------------------------------------\n\n/**\n * Vertical stacking flow: blocks are placed top-to-bottom, left-aligned,\n * separated by `gap` pixels. Pure arithmetic over measured sizes.\n */\nexport function computeBlockFlow(measured: MeasuredBlock[], gap: number): PositionedBlock[] {\n\tconst result: PositionedBlock[] = [];\n\tlet y = 0;\n\tfor (let i = 0; i < measured.length; i++) {\n\t\tconst m = measured[i]!;\n\t\tresult.push({ ...m, x: 0, y });\n\t\ty += m.height + (i < measured.length - 1 ? gap : 0);\n\t}\n\treturn result;\n}\n\n/**\n * Compute total height from positioned blocks.\n */\nexport function computeTotalHeight(flow: PositionedBlock[]): number {\n\tif (flow.length === 0) return 0;\n\tconst last = flow[flow.length - 1]!;\n\treturn last.y + last.height;\n}\n\n// ---------------------------------------------------------------------------\n// Reactive graph factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a reactive block layout graph for mixed content (text + image + SVG).\n *\n * ```\n * Graph(\"reactive-block-layout\")\n * ├── state(\"blocks\") — ContentBlock[] input\n * ├── state(\"max-width\") — container constraint\n * ├── state(\"gap\") — vertical gap (px)\n * ├── derived(\"measured-blocks\") — blocks + max-width → MeasuredBlock[]\n * ├── derived(\"block-flow\") — measured-blocks + gap → PositionedBlock[]\n * ├── derived(\"total-height\") — block-flow → number\n * └── meta: { block-count, layout-time-ns }\n * ```\n */\nexport function reactiveBlockLayout(opts: ReactiveBlockLayoutOptions): ReactiveBlockLayoutBundle {\n\tconst {\n\t\tadapters,\n\t\tname = \"reactive-block-layout\",\n\t\tdefaultFont = \"16px sans-serif\",\n\t\tdefaultLineHeight = 20,\n\t} = opts;\n\tconst g = new Graph(name);\n\n\t// Shared text measurement cache (same structure as reactiveLayout)\n\tconst measureCache = new Map<string, Map<string, number>>();\n\n\t// --- State nodes ---\n\tconst blocksNode = state<ContentBlock[]>(opts.blocks ?? [], { name: \"blocks\" });\n\tconst maxWidthNode = state<number>(Math.max(0, opts.maxWidth ?? 800), { name: \"max-width\" });\n\tconst gapNode = state<number>(opts.gap ?? 0, { name: \"gap\" });\n\n\t// --- Derived: measured-blocks ---\n\tconst measuredBlocksNode = derived<MeasuredBlock[]>(\n\t\t[blocksNode, maxWidthNode],\n\t\t([blocksVal, mwVal]) => {\n\t\t\tconst t0 = monotonicNs();\n\t\t\tconst result = measureBlocks(\n\t\t\t\tblocksVal as ContentBlock[],\n\t\t\t\tmwVal as number,\n\t\t\t\tadapters,\n\t\t\t\tmeasureCache,\n\t\t\t\tdefaultFont,\n\t\t\t\tdefaultLineHeight,\n\t\t\t);\n\t\t\tconst elapsed = monotonicNs() - t0;\n\n\t\t\t// Phase-3 meta deferral (parity with reactiveLayout)\n\t\t\tconst meta = measuredBlocksNode.meta;\n\t\t\tif (meta) {\n\t\t\t\temitWithBatch((msgs) => meta[\"block-count\"]?.down(msgs), [[DATA, result.length]], 3);\n\t\t\t\temitWithBatch((msgs) => meta[\"layout-time-ns\"]?.down(msgs), [[DATA, elapsed]], 3);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\t\t{\n\t\t\tname: \"measured-blocks\",\n\t\t\tmeta: { \"block-count\": 0, \"layout-time-ns\": 0 },\n\t\t\tonMessage(msg, _depIndex, _actions) {\n\t\t\t\tif (msg[0] === INVALIDATE || msg[0] === TEARDOWN) {\n\t\t\t\t\t// Local side-effect only; return false so default dispatch\n\t\t\t\t\t// still propagates the message (TEARDOWN → meta/downstream).\n\t\t\t\t\tmeasureCache.clear();\n\t\t\t\t\tadapters.text.clearCache?.();\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst ma = a as MeasuredBlock[] | null;\n\t\t\t\tconst mb = b as MeasuredBlock[] | null;\n\t\t\t\tif (ma == null || mb == null) return ma === mb;\n\t\t\t\tif (ma.length !== mb.length) return false;\n\t\t\t\tfor (let i = 0; i < ma.length; i++) {\n\t\t\t\t\tconst ba = ma[i]!;\n\t\t\t\t\tconst bb = mb[i]!;\n\t\t\t\t\tif (\n\t\t\t\t\t\tba.type !== bb.type ||\n\t\t\t\t\t\tba.width !== bb.width ||\n\t\t\t\t\t\tba.height !== bb.height ||\n\t\t\t\t\t\tba.index !== bb.index\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: block-flow ---\n\tconst blockFlowNode = derived<PositionedBlock[]>(\n\t\t[measuredBlocksNode, gapNode],\n\t\t([measured, gapVal]) => {\n\t\t\treturn computeBlockFlow(measured as MeasuredBlock[], gapVal as number);\n\t\t},\n\t\t{\n\t\t\tname: \"block-flow\",\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst fa = a as PositionedBlock[] | null;\n\t\t\t\tconst fb = b as PositionedBlock[] | null;\n\t\t\t\tif (fa == null || fb == null) return fa === fb;\n\t\t\t\tif (fa.length !== fb.length) return false;\n\t\t\t\tfor (let i = 0; i < fa.length; i++) {\n\t\t\t\t\tconst pa = fa[i]!;\n\t\t\t\t\tconst pb = fb[i]!;\n\t\t\t\t\tif (pa.x !== pb.x || pa.y !== pb.y || pa.width !== pb.width || pa.height !== pb.height)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: total-height ---\n\tconst totalHeightNode = derived<number>(\n\t\t[blockFlowNode],\n\t\t([flow]) => computeTotalHeight(flow as PositionedBlock[]),\n\t\t{ name: \"total-height\" },\n\t);\n\n\t// --- Register in graph ---\n\tg.add(\"blocks\", blocksNode);\n\tg.add(\"max-width\", maxWidthNode);\n\tg.add(\"gap\", gapNode);\n\tg.add(\"measured-blocks\", measuredBlocksNode);\n\tg.add(\"block-flow\", blockFlowNode);\n\tg.add(\"total-height\", totalHeightNode);\n\n\t// --- Edges (for describe() visibility) ---\n\tg.connect(\"blocks\", \"measured-blocks\");\n\tg.connect(\"max-width\", \"measured-blocks\");\n\tg.connect(\"measured-blocks\", \"block-flow\");\n\tg.connect(\"gap\", \"block-flow\");\n\tg.connect(\"block-flow\", \"total-height\");\n\n\treturn {\n\t\tgraph: g,\n\t\tsetBlocks: (blocks: ContentBlock[]) => g.set(\"blocks\", blocks),\n\t\tsetMaxWidth: (mw: number) => g.set(\"max-width\", Math.max(0, mw)),\n\t\tsetGap: (gap: number) => g.set(\"gap\", gap),\n\t\tmeasuredBlocks: measuredBlocksNode,\n\t\tblockFlow: blockFlowNode,\n\t\ttotalHeight: totalHeightNode,\n\t};\n}\n"],"mappings":"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","names":["w"]}
|