@graphrefly/graphrefly 0.47.2 → 0.48.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/base/composition/index.cjs +4 -3
- package/dist/base/composition/index.cjs.map +1 -1
- package/dist/base/composition/index.d.cts +14 -5
- package/dist/base/composition/index.d.ts +14 -5
- package/dist/base/composition/index.js +8 -8
- package/dist/base/index.cjs +152 -78
- package/dist/base/index.cjs.map +1 -1
- package/dist/base/index.d.cts +2 -2
- package/dist/base/index.d.ts +2 -2
- package/dist/base/index.js +75 -70
- package/dist/base/io/index.cjs +31 -17
- package/dist/base/io/index.cjs.map +1 -1
- package/dist/base/io/index.d.cts +32 -5
- package/dist/base/io/index.d.ts +32 -5
- package/dist/base/io/index.js +1 -1
- package/dist/base/mutation/index.cjs +21 -0
- package/dist/base/mutation/index.cjs.map +1 -1
- package/dist/base/mutation/index.d.cts +23 -1
- package/dist/base/mutation/index.d.ts +23 -1
- package/dist/base/mutation/index.js +3 -1
- package/dist/base/sources/browser/index.cjs +5 -3
- package/dist/base/sources/browser/index.cjs.map +1 -1
- package/dist/base/sources/browser/index.d.cts +20 -2
- package/dist/base/sources/browser/index.d.ts +20 -2
- package/dist/base/sources/browser/index.js +5 -3
- package/dist/base/sources/browser/index.js.map +1 -1
- package/dist/base/sources/event/index.cjs +28 -0
- package/dist/base/sources/event/index.cjs.map +1 -1
- package/dist/base/sources/event/index.d.cts +67 -3
- package/dist/base/sources/event/index.d.ts +67 -3
- package/dist/base/sources/event/index.js +4 -1
- package/dist/base/sources/index.cjs +75 -37
- package/dist/base/sources/index.cjs.map +1 -1
- package/dist/base/sources/index.d.cts +1 -1
- package/dist/base/sources/index.d.ts +1 -1
- package/dist/base/sources/index.js +5 -2
- package/dist/{chunk-R6ZCSXKX.js → chunk-23MAWVOJ.js} +3 -3
- package/dist/{chunk-MS3WPRJR.js → chunk-3REMCHSS.js} +6 -6
- package/dist/chunk-3REMCHSS.js.map +1 -0
- package/dist/{chunk-CEVNQ74M.js → chunk-3YGXPUHW.js} +2 -2
- package/dist/{chunk-CEVNQ74M.js.map → chunk-3YGXPUHW.js.map} +1 -1
- package/dist/{chunk-6ZLCPUXS.js → chunk-46X2EFQH.js} +15 -4
- package/dist/chunk-46X2EFQH.js.map +1 -0
- package/dist/{chunk-NY2PYHNC.js → chunk-5UY3PNFY.js} +12 -5
- package/dist/chunk-5UY3PNFY.js.map +1 -0
- package/dist/{chunk-FQSQONOU.js → chunk-65OM4XLQ.js} +49 -3
- package/dist/chunk-65OM4XLQ.js.map +1 -0
- package/dist/{chunk-3PSLNJDU.js → chunk-6DQYBIHW.js} +314 -49
- package/dist/chunk-6DQYBIHW.js.map +1 -0
- package/dist/{chunk-LDCSZ72P.js → chunk-6YBER5UP.js} +3 -3
- package/dist/{chunk-LDCSZ72P.js.map → chunk-6YBER5UP.js.map} +1 -1
- package/dist/{chunk-3O3NKZJW.js → chunk-7T7WLEPM.js} +24 -3
- package/dist/chunk-7T7WLEPM.js.map +1 -0
- package/dist/{chunk-PKPO3JTZ.js → chunk-AQAKDE7F.js} +29 -11
- package/dist/chunk-AQAKDE7F.js.map +1 -0
- package/dist/{chunk-6MRSX3YK.js → chunk-B5Y5GPD5.js} +2 -2
- package/dist/{chunk-BXGZFGZ4.js → chunk-C5QD5DQX.js} +22 -1
- package/dist/chunk-C5QD5DQX.js.map +1 -0
- package/dist/{chunk-4XCHZRUJ.js → chunk-D5YGR4TP.js} +58 -7
- package/dist/chunk-D5YGR4TP.js.map +1 -0
- package/dist/{chunk-NPRP3MCV.js → chunk-DHDCOOJU.js} +2 -2
- package/dist/chunk-DHDCOOJU.js.map +1 -0
- package/dist/{chunk-VP3TIUDF.js → chunk-DVTDF5OI.js} +2 -2
- package/dist/{chunk-OXD5LFQP.js → chunk-G7H6PN7P.js} +2 -2
- package/dist/{chunk-EL5VHUGK.js → chunk-GGKHHG5Y.js} +32 -18
- package/dist/chunk-GGKHHG5Y.js.map +1 -0
- package/dist/{chunk-446I4EGD.js → chunk-J5TBZFBD.js} +2 -2
- package/dist/{chunk-7AVQIGF6.js → chunk-K4ZYJ4EM.js} +554 -460
- package/dist/chunk-K4ZYJ4EM.js.map +1 -0
- package/dist/{chunk-QFE5BQH7.js → chunk-LTSI7ULC.js} +2 -2
- package/dist/{chunk-5GVURVIG.js → chunk-MMHGYX44.js} +12 -2
- package/dist/{chunk-5GVURVIG.js.map → chunk-MMHGYX44.js.map} +1 -1
- package/dist/{chunk-KRFGO5QH.js → chunk-MQMTRKY3.js} +118 -43
- package/dist/chunk-MQMTRKY3.js.map +1 -0
- package/dist/{chunk-42FQ27MQ.js → chunk-MTODGQBR.js} +44 -179
- package/dist/chunk-MTODGQBR.js.map +1 -0
- package/dist/{chunk-FVINAAKA.js → chunk-NBK6QQMG.js} +14 -13
- package/dist/{chunk-FVINAAKA.js.map → chunk-NBK6QQMG.js.map} +1 -1
- package/dist/{chunk-KNU73RZW.js → chunk-NSA5K5G2.js} +2 -2
- package/dist/{chunk-MLTPJMH6.js → chunk-QQYULEZL.js} +2 -2
- package/dist/chunk-QSW4DFKE.js +31 -0
- package/dist/chunk-QSW4DFKE.js.map +1 -0
- package/dist/{chunk-VAZXUK6G.js → chunk-SUNCHMML.js} +2 -2
- package/dist/{chunk-EP4WVQLX.js → chunk-T2U6N3FV.js} +6 -6
- package/dist/{chunk-T7SP3EYR.js → chunk-T5URUIIY.js} +33 -24
- package/dist/chunk-T5URUIIY.js.map +1 -0
- package/dist/{chunk-VNXAF2KE.js → chunk-TPTZZV25.js} +6 -6
- package/dist/chunk-TPTZZV25.js.map +1 -0
- package/dist/{chunk-IOJDYUA7.js → chunk-V46JWFGV.js} +6 -5
- package/dist/chunk-V46JWFGV.js.map +1 -0
- package/dist/{chunk-WGDEBIP4.js → chunk-X6ESZDR6.js} +5 -6
- package/dist/chunk-X6ESZDR6.js.map +1 -0
- package/dist/{chunk-N65E26UL.js → chunk-XEWV254I.js} +2 -2
- package/dist/{chunk-N65E26UL.js.map → chunk-XEWV254I.js.map} +1 -1
- package/dist/{chunk-PTWADEH3.js → chunk-YBJVKMTM.js} +34 -14
- package/dist/chunk-YBJVKMTM.js.map +1 -0
- package/dist/{chunk-DDTS7F5O.js → chunk-ZW32BPXV.js} +12 -3
- package/dist/chunk-ZW32BPXV.js.map +1 -0
- package/dist/compat/index.cjs +51 -4
- package/dist/compat/index.cjs.map +1 -1
- package/dist/compat/index.d.cts +1 -1
- package/dist/compat/index.d.ts +1 -1
- package/dist/compat/index.js +6 -6
- package/dist/compat/nestjs/index.cjs +51 -4
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +1 -1
- package/dist/compat/nestjs/index.d.ts +1 -1
- package/dist/compat/nestjs/index.js +3 -3
- package/dist/{fallback-Bx46zqky.d.cts → fallback-BROR6ZhO.d.cts} +1 -1
- package/dist/{fallback-pIWW8A2d.d.ts → fallback-DO80aM_3.d.ts} +1 -1
- package/dist/{index-B_p8tnvf.d.cts → index-D1z3XcF9.d.cts} +1 -0
- package/dist/{index-_HDSmPyp.d.ts → index-DZ6yua0Q.d.ts} +1 -0
- package/dist/index.cjs +2215 -1676
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +169 -146
- package/dist/index.js.map +1 -1
- package/dist/presets/ai/index.cjs +46 -0
- package/dist/presets/ai/index.cjs.map +1 -1
- package/dist/presets/ai/index.js +12 -12
- package/dist/presets/harness/index.cjs +130 -18
- package/dist/presets/harness/index.cjs.map +1 -1
- package/dist/presets/harness/index.d.cts +15 -5
- package/dist/presets/harness/index.d.ts +15 -5
- package/dist/presets/harness/index.js +22 -22
- package/dist/presets/index.cjs +222 -53
- package/dist/presets/index.cjs.map +1 -1
- package/dist/presets/index.d.cts +2 -2
- package/dist/presets/index.d.ts +2 -2
- package/dist/presets/index.js +45 -45
- package/dist/presets/inspect/index.cjs +63 -14
- package/dist/presets/inspect/index.cjs.map +1 -1
- package/dist/presets/inspect/index.d.cts +1 -1
- package/dist/presets/inspect/index.d.ts +1 -1
- package/dist/presets/inspect/index.js +6 -6
- package/dist/presets/resilience/index.cjs +29 -21
- package/dist/presets/resilience/index.cjs.map +1 -1
- package/dist/presets/resilience/index.d.cts +12 -8
- package/dist/presets/resilience/index.d.ts +12 -8
- package/dist/presets/resilience/index.js +3 -3
- package/dist/{rate-limiter-DpVbSYdH.d.cts → rate-limiter-DC26FM8J.d.cts} +10 -1
- package/dist/{rate-limiter-CEALq4N1.d.ts → rate-limiter-DyWpwpQP.d.ts} +10 -1
- package/dist/{reactive-layout-fswlBUvX.d.ts → reactive-layout-BBBWH0V_.d.cts} +85 -4
- package/dist/{reactive-layout-fswlBUvX.d.cts → reactive-layout-BBBWH0V_.d.ts} +85 -4
- package/dist/solutions/index.cjs +168 -47
- package/dist/solutions/index.cjs.map +1 -1
- package/dist/solutions/index.d.cts +2 -2
- package/dist/solutions/index.d.ts +2 -2
- package/dist/solutions/index.js +28 -28
- package/dist/{spawnable-5mDY501F.d.cts → spawnable-B2IlW60f.d.cts} +23 -2
- package/dist/{spawnable-D3lR0oQu.d.ts → spawnable-tttFz2Nh.d.ts} +23 -2
- package/dist/testing/index.cjs +94 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +59 -0
- package/dist/testing/index.d.ts +59 -0
- package/dist/testing/index.js +73 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/utils/ai/browser.cjs.map +1 -1
- package/dist/utils/ai/browser.d.cts +2 -2
- package/dist/utils/ai/browser.d.ts +2 -2
- package/dist/utils/ai/browser.js +6 -6
- package/dist/utils/ai/browser.js.map +1 -1
- package/dist/utils/ai/index.cjs +250 -166
- package/dist/utils/ai/index.cjs.map +1 -1
- package/dist/utils/ai/index.d.cts +108 -12
- package/dist/utils/ai/index.d.ts +108 -12
- package/dist/utils/ai/index.js +21 -19
- package/dist/utils/ai/node.cjs.map +1 -1
- package/dist/utils/ai/node.d.cts +5 -5
- package/dist/utils/ai/node.d.ts +5 -5
- package/dist/utils/ai/node.js +2 -2
- package/dist/utils/ai/node.js.map +1 -1
- package/dist/utils/cqrs/index.cjs +29 -3
- package/dist/utils/cqrs/index.cjs.map +1 -1
- package/dist/utils/cqrs/index.d.cts +12 -7
- package/dist/utils/cqrs/index.d.ts +12 -7
- package/dist/utils/cqrs/index.js +2 -2
- package/dist/utils/demo-shell/index.cjs +45 -19
- package/dist/utils/demo-shell/index.cjs.map +1 -1
- package/dist/utils/demo-shell/index.d.cts +1 -1
- package/dist/utils/demo-shell/index.d.ts +1 -1
- package/dist/utils/demo-shell/index.js +2 -2
- package/dist/utils/domain-templates/index.cjs.map +1 -1
- package/dist/utils/domain-templates/index.js +3 -3
- package/dist/utils/graphspec/index.cjs.map +1 -1
- package/dist/utils/graphspec/index.js +3 -3
- package/dist/utils/index.cjs +1642 -1225
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +7 -7
- package/dist/utils/index.d.ts +7 -7
- package/dist/utils/index.js +72 -54
- package/dist/utils/inspect/index.cjs +52 -4
- package/dist/utils/inspect/index.cjs.map +1 -1
- package/dist/utils/inspect/index.d.cts +32 -3
- package/dist/utils/inspect/index.d.ts +32 -3
- package/dist/utils/inspect/index.js +4 -4
- package/dist/utils/job-queue/index.cjs +46 -9
- package/dist/utils/job-queue/index.cjs.map +1 -1
- package/dist/utils/job-queue/index.d.cts +33 -3
- package/dist/utils/job-queue/index.d.ts +33 -3
- package/dist/utils/job-queue/index.js +2 -2
- package/dist/utils/memory/index.cjs +556 -462
- package/dist/utils/memory/index.cjs.map +1 -1
- package/dist/utils/memory/index.d.cts +203 -24
- package/dist/utils/memory/index.d.ts +203 -24
- package/dist/utils/memory/index.js +10 -2
- package/dist/utils/messaging/index.cjs.map +1 -1
- package/dist/utils/messaging/index.d.cts +4 -3
- package/dist/utils/messaging/index.d.ts +4 -3
- package/dist/utils/messaging/index.js +2 -2
- package/dist/utils/orchestration/index.cjs +9 -0
- package/dist/utils/orchestration/index.cjs.map +1 -1
- package/dist/utils/orchestration/index.js +3 -3
- package/dist/utils/process/index.cjs +32 -2
- package/dist/utils/process/index.cjs.map +1 -1
- package/dist/utils/process/index.d.cts +4 -3
- package/dist/utils/process/index.d.ts +4 -3
- package/dist/utils/process/index.js +2 -2
- package/dist/utils/reactive-layout/index.cjs +184 -55
- package/dist/utils/reactive-layout/index.cjs.map +1 -1
- package/dist/utils/reactive-layout/index.d.cts +128 -3
- package/dist/utils/reactive-layout/index.d.ts +128 -3
- package/dist/utils/reactive-layout/index.js +16 -8
- package/dist/utils/reduction/index.cjs.map +1 -1
- package/dist/utils/reduction/index.js +2 -2
- package/dist/utils/resilience/index.cjs +29 -20
- package/dist/utils/resilience/index.cjs.map +1 -1
- package/dist/utils/resilience/index.d.cts +1 -1
- package/dist/utils/resilience/index.d.ts +1 -1
- package/dist/utils/resilience/index.js +2 -2
- package/dist/utils/surface/index.cjs.map +1 -1
- package/dist/utils/surface/index.js +4 -4
- package/package.json +15 -3
- package/dist/chunk-3O3NKZJW.js.map +0 -1
- package/dist/chunk-3PSLNJDU.js.map +0 -1
- package/dist/chunk-42FQ27MQ.js.map +0 -1
- package/dist/chunk-4XCHZRUJ.js.map +0 -1
- package/dist/chunk-6ZLCPUXS.js.map +0 -1
- package/dist/chunk-7AVQIGF6.js.map +0 -1
- package/dist/chunk-BXGZFGZ4.js.map +0 -1
- package/dist/chunk-DDTS7F5O.js.map +0 -1
- package/dist/chunk-EL5VHUGK.js.map +0 -1
- package/dist/chunk-FQSQONOU.js.map +0 -1
- package/dist/chunk-IOJDYUA7.js.map +0 -1
- package/dist/chunk-KRFGO5QH.js.map +0 -1
- package/dist/chunk-MS3WPRJR.js.map +0 -1
- package/dist/chunk-NPRP3MCV.js.map +0 -1
- package/dist/chunk-NY2PYHNC.js.map +0 -1
- package/dist/chunk-PKPO3JTZ.js.map +0 -1
- package/dist/chunk-PTWADEH3.js.map +0 -1
- package/dist/chunk-T7SP3EYR.js.map +0 -1
- package/dist/chunk-VNXAF2KE.js.map +0 -1
- package/dist/chunk-W2BOPXTI.js +0 -1
- package/dist/chunk-W2BOPXTI.js.map +0 -1
- package/dist/chunk-WGDEBIP4.js.map +0 -1
- /package/dist/{chunk-R6ZCSXKX.js.map → chunk-23MAWVOJ.js.map} +0 -0
- /package/dist/{chunk-6MRSX3YK.js.map → chunk-B5Y5GPD5.js.map} +0 -0
- /package/dist/{chunk-VP3TIUDF.js.map → chunk-DVTDF5OI.js.map} +0 -0
- /package/dist/{chunk-OXD5LFQP.js.map → chunk-G7H6PN7P.js.map} +0 -0
- /package/dist/{chunk-446I4EGD.js.map → chunk-J5TBZFBD.js.map} +0 -0
- /package/dist/{chunk-QFE5BQH7.js.map → chunk-LTSI7ULC.js.map} +0 -0
- /package/dist/{chunk-KNU73RZW.js.map → chunk-NSA5K5G2.js.map} +0 -0
- /package/dist/{chunk-MLTPJMH6.js.map → chunk-QQYULEZL.js.map} +0 -0
- /package/dist/{chunk-VAZXUK6G.js.map → chunk-SUNCHMML.js.map} +0 -0
- /package/dist/{chunk-EP4WVQLX.js.map → chunk-T2U6N3FV.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/inspect/lens.ts"],"sourcesContent":["/**\n * Reactive graph observability preset (Tier 5.3 reshape — Session A.4 lock).\n *\n * `graphLens(target)` is a thin compositor (~30 LOC of glue) over two\n * already-shipped reactive primitives:\n *\n * - `target.describe({ reactive: true })` — live topology snapshot.\n * - `target.observe({ reactive: true, tiers: [\"data\"] })` — coalesced data\n * changesets per outermost batch flush.\n *\n * It returns three Nodes plus a dispose function:\n *\n * - `topology: Node<GraphDescribeOutput>` — the live describe snapshot,\n * re-emitting on every settle of the target tree (structural change,\n * error/complete/teardown transition).\n * - `health: Node<HealthReport>` — `{ok, problems[]}` aggregated from the\n * live describe; `ok=false` when any node enters `\"errored\"` status,\n * with `upstreamCause` walked backward through deps.\n * - `flow: Node<ReadonlyMap<string, FlowEntry>>` — per-path DATA counters\n * accumulating as `target.observe({reactive: true, tiers: [\"data\"]})`\n * delivers changesets. The map is reconciled against `topology` on each\n * topology change so removed nodes drop their entries.\n *\n * Pre-Tier-5.3 shipped a `LensGraph` class with `stats` / `health` / `flow`\n * (as a `ReactiveMapBundle`) / `why(from, to)` / `flowEntryNode(...)`. The\n * surface collapsed because every concern was already a one-liner over\n * `describe({reactive:true})` + `observe({reactive:true, tiers})` once those\n * landed in Tier 1.5.1 / 1.5.2 — the class added no protocol-level concept,\n * just glue. Callers who need topology stats compose a derived over\n * `topology` directly; callers who need a causal chain call\n * `target.describe({ explain: { from, to }, reactive: true })`.\n *\n * The transitive topology-subscription helper {@link watchTopologyTree} is\n * re-exported here for downstream factories that need full-tree dynamic\n * coverage without taking a dep on `graph/`.\n *\n * @module\n */\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { keepalive } from \"@graphrefly/pure-ts/extra\";\nimport {\n\ttype Graph,\n\ttype GraphDescribeOutput,\n\ttype ObserveChangeset,\n\ttype ObserveEvent,\n\treachable,\n} from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\n\nexport { watchTopologyTree } from \"@graphrefly/pure-ts/graph\";\n\n// ---------------------------------------------------------------------------\n// Payload types\n// ---------------------------------------------------------------------------\n\n/** A single health problem entry. */\nexport interface HealthProblem {\n\tpath: string;\n\t/** V1 only reports `\"errored\"`. Future versions may add `\"completed\"`, `\"disconnected\"`. */\n\tstatus: \"errored\";\n\t/** First errored upstream ancestor along the dep chain, when one exists and is distinct from `path`. */\n\tupstreamCause?: string;\n}\n\n/** Aggregate health snapshot. `ok=true` iff `problems.length === 0`. */\nexport interface HealthReport {\n\tok: boolean;\n\tproblems: readonly HealthProblem[];\n}\n\n/** Per-path flow entry stored in the {@link GraphLensView.flow} map. */\nexport interface FlowEntry {\n\tpath: string;\n\t/** Cumulative DATA emissions observed since the lens activated. */\n\tcount: number;\n\t/** Monotonic ns at the most recent DATA emission for this path, or `null` if none yet. */\n\tlastUpdate_ns: number | null;\n}\n\n/** Output of {@link graphLens}. */\nexport interface GraphLensView {\n\t/** Live describe snapshot. Re-emits on structural change AND status transitions. */\n\ttopology: Node<GraphDescribeOutput>;\n\t/** Live `{ok, problems[]}`. Aggregated from `topology`; equality-deduped. */\n\thealth: Node<HealthReport>;\n\t/** Per-path DATA counter map. Re-emits per outermost batch flush. */\n\tflow: Node<ReadonlyMap<string, FlowEntry>>;\n\t/**\n\t * Tear down the underlying `describe({reactive:true})` subscription.\n\t * The `flow` node activates lazily; subscribing-then-unsubscribing reclaims\n\t * its observe stream automatically. Call `dispose()` once when finished.\n\t */\n\tdispose(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers (exported for testing / composition)\n// ---------------------------------------------------------------------------\n\n/** Build a `HealthReport` from a fresh `GraphDescribeOutput`. */\nexport function computeHealthReport(described: GraphDescribeOutput): HealthReport {\n\tconst problems: HealthProblem[] = [];\n\tfor (const [path, desc] of Object.entries(described.nodes)) {\n\t\tif (desc.status !== \"errored\") continue;\n\t\tconst entry: HealthProblem = { path, status: \"errored\" };\n\t\t// Walk upstream to find the first errored ancestor (if any) distinct from `path`.\n\t\t// Explicit empty options disambiguates the overload (otherwise both match\n\t\t// and TS picks the `withDetail:true` signature first).\n\t\tconst upstream = reachable(described, path, \"upstream\", {});\n\t\tfor (const p of upstream) {\n\t\t\tif (p === path) continue;\n\t\t\tif (described.nodes[p]?.status === \"errored\") {\n\t\t\t\tentry.upstreamCause = p;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tproblems.push(entry);\n\t}\n\tproblems.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n\treturn { ok: problems.length === 0, problems };\n}\n\n/** Structural equality for {@link HealthReport} — used as the `health` derived's `equals`. */\nexport function healthReportEqual(a: HealthReport, b: HealthReport): boolean {\n\tif (a.ok !== b.ok) return false;\n\tif (a.problems.length !== b.problems.length) return false;\n\tfor (let i = 0; i < a.problems.length; i++) {\n\t\tconst x = a.problems[i]!;\n\t\tconst y = b.problems[i]!;\n\t\tif (x.path !== y.path) return false;\n\t\tif (x.status !== y.status) return false;\n\t\tif (x.upstreamCause !== y.upstreamCause) return false;\n\t}\n\treturn true;\n}\n\n// ---------------------------------------------------------------------------\n// graphLens preset\n// ---------------------------------------------------------------------------\n\n/**\n * Reactive observability preset over a target {@link Graph}.\n *\n * @param target - The graph to observe.\n *\n * @example\n * ```ts\n * const g = new Graph(\"app\");\n * g.add(state(0, { name: \"counter\" }), { name: \"counter\" });\n *\n * const lens = graphLens(g);\n * lens.topology.subscribe((msgs) => console.log(\"topology:\", msgs));\n * lens.health.subscribe((msgs) => console.log(\"health:\", msgs));\n * lens.flow.subscribe((msgs) => {\n * for (const [type, payload] of msgs) {\n * if (type === DATA) console.log(\"flow map size:\", (payload as ReadonlyMap<string, FlowEntry>).size);\n * }\n * });\n *\n * // Causal chains: use the underlying primitive directly — `graphLens` no\n * // longer wraps it, since `graph.describe({ explain: {...}, reactive: true })`\n * // already provides everything the old `lens.why()` did.\n * const why = g.describe({\n * explain: { from: \"counter\", to: \"consumer\" },\n * reactive: true,\n * });\n *\n * // Tear down when done.\n * lens.dispose();\n * ```\n *\n * @category observability\n */\nexport function graphLens(target: Graph): GraphLensView {\n\tconst topologyHandle = target.describe({\n\t\treactive: true,\n\t\tdetail: \"standard\",\n\t\treactiveName: \"graphLens.topology\",\n\t});\n\tconst topology = topologyHandle.node;\n\n\tconst health = node<HealthReport>(\n\t\t[topology],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tactions.emit(computeHealthReport(data[0] as GraphDescribeOutput));\n\t\t},\n\t\t{\n\t\t\tname: \"graphLens.health\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tequals: healthReportEqual,\n\t\t\tmeta: domainMeta(\"lens\", \"health\"),\n\t\t},\n\t);\n\t// `topology` is already kept alive by `_describeReactive`'s internal\n\t// keepalive; `health` needs its own so the derived stays warm even if\n\t// the consumer subscribes lazily.\n\tconst stopHealthKeep = keepalive(health);\n\n\t// `flow` accumulates per-path counters across emissions. Closure-mirror\n\t// (COMPOSITION-GUIDE §28) holds the canonical map; the derived returns a\n\t// fresh ReadonlyMap projection per emit so consumers never observe an\n\t// in-place mutation. Topology drives reconciliation: paths that disappear\n\t// from the describe drop their counter entry.\n\t//\n\t// `lastAppliedFlush_ns` guards against double-applying the same changeset\n\t// when topology re-emits without a new dataFlow event (e.g. a node remove\n\t// re-fires `topology` while `dataFlow.cache` still holds the previous\n\t// changeset by reference). Using the monotonic `flushedAt_ns` cursor (qa\n\t// G2A — EC4 fix) is more robust than ref-comparison: an empty changeset\n\t// re-emitted with a fresh object identity but the same `flushedAt_ns`\n\t// won't trigger a stale-events replay, and a genuinely-new changeset\n\t// always advances the cursor.\n\tconst flowMap = new Map<string, FlowEntry>();\n\tlet lastAppliedFlush_ns = -1;\n\tconst dataFlow = target.observe({ reactive: true, tiers: [\"data\"] });\n\tconst flow = node<ReadonlyMap<string, FlowEntry>>(\n\t\t[dataFlow, topology],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst changeset = data[0];\n\t\t\tconst described = data[1];\n\t\t\tconst c = changeset as ObserveChangeset | undefined;\n\t\t\tconst desc = described as GraphDescribeOutput | undefined;\n\n\t\t\t// Apply NEW changeset events first so a freshly-emitted node-remove\n\t\t\t// observed below cleanly drops the entry. (If we reconciled first\n\t\t\t// then applied, an event referencing a path the topology had already\n\t\t\t// dropped would re-create the entry only to be wiped on the next\n\t\t\t// topology re-emit — order events-then-topology to avoid that.)\n\t\t\t//\n\t\t\t// Skip when `events.length === 0`: an empty changeset has no work\n\t\t\t// to do. The cursor advances anyway so a future identical-content\n\t\t\t// changeset (different ref, same flushedAt_ns) is also skipped.\n\t\t\tif (c != null && c.flushedAt_ns > lastAppliedFlush_ns) {\n\t\t\t\tlastAppliedFlush_ns = c.flushedAt_ns;\n\t\t\t\tfor (const event of c.events as readonly ObserveEvent[]) {\n\t\t\t\t\tif (event.type !== \"data\") continue;\n\t\t\t\t\tconst path = event.path;\n\t\t\t\t\tif (path == null || path === \"\") continue;\n\t\t\t\t\tconst prior = flowMap.get(path);\n\t\t\t\t\tflowMap.set(path, {\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tcount: (prior?.count ?? 0) + 1,\n\t\t\t\t\t\tlastUpdate_ns: c.flushedAt_ns,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Reconcile against current topology — drop entries whose paths\n\t\t\t// no longer exist in the describe.\n\t\t\tif (desc != null && flowMap.size > 0) {\n\t\t\t\tconst valid = new Set(Object.keys(desc.nodes));\n\t\t\t\tfor (const k of [...flowMap.keys()]) {\n\t\t\t\t\tif (!valid.has(k)) flowMap.delete(k);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Snapshot — consumers receive a frozen view.\n\t\t\tactions.emit(new Map(flowMap) as ReadonlyMap<string, FlowEntry>);\n\t\t},\n\t\t{\n\t\t\tname: \"graphLens.flow\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: domainMeta(\"lens\", \"flow\"),\n\t\t},\n\t);\n\tconst stopFlowKeep = keepalive(flow);\n\n\tlet disposed = false;\n\treturn {\n\t\ttopology,\n\t\thealth,\n\t\tflow,\n\t\tdispose() {\n\t\t\tif (disposed) return;\n\t\t\tdisposed = true;\n\t\t\tstopFlowKeep();\n\t\t\tstopHealthKeep();\n\t\t\ttopologyHandle.dispose();\n\t\t},\n\t};\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/process/index.ts"],"sourcesContent":["/**\n * Process Manager pattern (Phase 7 — roadmap §4.6, Audit 3 — locked 2026-04-24).\n *\n * Reactive long-running workflow primitive over CQRS event nodes.\n * Correlates events across aggregates, tracks per-instance state, supports\n * retries with backoff, and runs compensation on failure or explicit cancel.\n *\n * ## Architecture\n *\n * - Per-instance state lives in a `Map<correlationId, TState>` closure (in-memory).\n * The `_process_<name>_started` synthetic event is dispatched per `start()`\n * for an event-sourced audit trail using `correlationId` as `aggregateId`.\n * Cross-restart state recovery is opt-in via\n * `opts.persistence.stateStorage` (kv-tier per-correlationId snapshot,\n * Tier 6.5 3.5) plus an explicit `restore()` call after construction.\n * - Watched-event subscriptions are imperative (coordinator role) — each\n * watched CQRS event type is subscribed to via `entries.subscribe(...)`.\n * These are NOT reactive node edges; the process manager is intentionally\n * a coordinator that bridges reactive CQRS events into imperative instance logic.\n * - Step execution uses `fromAny` to uniformly handle sync and async handlers.\n * - Retry delays use `setTimeout` (same sanctioned pattern as `extra/resilience.ts`\n * retry helper — this primitive is a coordinator, not a reactive pipeline stage).\n * - Timer scheduling uses `fromTimer` from `extra/sources.ts` per spec §5.8.\n * - Audit log uses `createAuditLog` per Audit 2.\n *\n * @module\n */\n\nimport {\n\tbatch,\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Messages,\n\ttype Node,\n\tnode,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport type {\n\tAppendLogStorageTier,\n\tKvStorageTier,\n\tReactiveLogBundle,\n} from \"@graphrefly/pure-ts/extra\";\nimport {\n\tfromAny,\n\tfromIter,\n\tfromTimer,\n\tmergeMap,\n\ttype NodeInput,\n\tvalve,\n} from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype BaseAuditRecord,\n\tcreateAuditLog,\n\tmutate,\n\tregisterCursor,\n} from \"../../base/mutation/index.js\";\nimport type { StatusValue } from \"../../base/resilience/status.js\";\nimport { firstWhere } from \"../../base/sources/settled.js\";\nimport type { CqrsEvent, CqrsEventMap, CqrsGraph } from \"../cqrs/index.js\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Discriminated union returned by each step handler.\n *\n * - `\"success\"` — step ran cleanly; update state, optionally emit\n * side-effect events and schedule a future synthetic event. The process\n * instance stays `\"running\"`.\n * - `\"terminate\"` — workflow complete; instance moves to `\"completed\"`.\n * Process-specific extension to the canonical outcome enum.\n * - `\"failure\"` — triggers compensation; instance moves to `\"cancelled\"` /\n * `\"errored\"`.\n *\n * Field name is `outcome` (matching `cqrs.DispatchRecord.outcome` and the\n * canonical Tier 1.6.2 / 2.3 enum). `\"success\"` and `\"failure\"` are the\n * canonical values; `\"terminate\"` is the process-specific extension for\n * \"early-return success\".\n */\nexport type ProcessStepResult<TState> =\n\t| {\n\t\t\toutcome: \"success\";\n\t\t\tstate: TState;\n\t\t\temit?: readonly { type: string; payload: unknown }[];\n\t\t\tschedule?: ProcessSchedule;\n\t }\n\t| {\n\t\t\toutcome: \"terminate\";\n\t\t\tstate: TState;\n\t\t\temit?: readonly { type: string; payload: unknown }[];\n\t\t\treason?: string;\n\t }\n\t| { outcome: \"failure\"; error: unknown };\n\n/**\n * Schedule a synthetic timer event after `afterMs` milliseconds.\n * When the timer fires, the synthetic event of `eventType` is routed to the\n * matching step (if one is registered) for this correlationId.\n */\nexport type ProcessSchedule = { afterMs: number; eventType: string };\n\n/**\n * Step handler signature.\n *\n * Receives the current instance state and the triggering CQRS event.\n * Returns a {@link ProcessStepResult} — sync value, Promise, or any\n * {@link NodeInput} consumed via `fromAny`.\n */\nexport type ProcessStep<TState, EM extends CqrsEventMap, K extends keyof EM & string> = (\n\tstate: TState,\n\tevent: CqrsEvent<EM[K]>,\n) => NodeInput<ProcessStepResult<TState>>;\n\n/**\n * Compensation handler. Runs when a step returns `outcome: \"failure\"`, throws, or\n * when `cancel(correlationId)` is called on a running instance.\n *\n * Should undo any side effects performed by prior steps (refund, cancel\n * reservation, etc.). Errors thrown inside compensate are swallowed and\n * recorded in the audit log with `status: \"errored\"` to prevent cascading\n * failure loops.\n */\nexport type ProcessCompensate<TState> = (state: TState, error: unknown) => NodeInput<void>;\n\n/**\n * Audit record for a single process instance state transition.\n *\n * Every status change (start → running → completed / errored / cancelled)\n * appends one record. `correlationId` is the stable process key.\n *\n * Extends {@link BaseAuditRecord} so records carry `t_ns` / `seq` /\n * `handlerVersion` from the cross-cutting Audit 2 schema.\n */\nexport interface ProcessInstance<TState> extends BaseAuditRecord {\n\t/** Stable correlation key that identifies this process instance. */\n\treadonly correlationId: string;\n\t/** Most-recent instance state at this transition. */\n\treadonly state: TState;\n\t/** Current lifecycle status after this transition. */\n\treadonly status: \"running\" | \"completed\" | \"errored\" | \"cancelled\";\n\t/** Wall-clock nanoseconds when `start()` was called. */\n\treadonly startedAt: number;\n\t/** Wall-clock nanoseconds of this transition. */\n\treadonly updatedAt: number;\n\t/** Handler version stamped at transition time (Audit 5). */\n\treadonly handlerVersion?: { id: string; version: string | number };\n\t/** Optional human-readable reason for cancellation. Present only on `\"cancelled\"` records produced by `cancel()`. */\n\treadonly reason?: string;\n}\n\n/**\n * Recommended `keyOf` for storage tiers keyed by correlationId (Audit 2).\n */\nexport const processInstanceKeyOf = <TState>(i: ProcessInstance<TState>): string => i.correlationId;\n\n/**\n * Per-correlationId state snapshot persisted via\n * {@link ProcessManagerOpts.persistence.stateStorage} (Tier 6.5 3.5,\n * 2026-04-29). Captures the running instance's current state plus\n * lifecycle metadata so a fresh `processManager` can resume in-flight\n * workflows after restart via {@link ProcessManagerResult.restore}.\n *\n * Terminal records (`status` ∈ `\"completed\" | \"errored\" | \"cancelled\"`)\n * are deleted from the kv tier on transition — only running instances\n * persist between restarts.\n */\nexport interface ProcessStateSnapshot<TState> {\n\treadonly correlationId: string;\n\treadonly state: TState;\n\treadonly status: \"running\" | \"completed\" | \"errored\" | \"cancelled\";\n\treadonly startedAt: number;\n\treadonly updatedAt: number;\n\treadonly handlerVersion?: { id: string; version: string | number };\n}\n\n/** Recommended `keyOf` for `KvStorageTier<ProcessStateSnapshot<...>>`. */\nexport const processStateKeyOf = <TState>(s: ProcessStateSnapshot<TState>): string =>\n\ts.correlationId;\n\n/**\n * Options for {@link processManager}.\n */\nexport interface ProcessManagerOpts<TState, EM extends CqrsEventMap> {\n\t/** Initial state value for every new process instance. */\n\treadonly initial: TState;\n\t/** CQRS event types to watch for correlation routing. */\n\treadonly watching: readonly (keyof EM & string)[];\n\t/**\n\t * Per-event-type step handlers. A step is invoked when a watched event's\n\t * `correlationId` matches a running instance and the event type is in\n\t * `steps`. Events with no matching step are silently ignored.\n\t */\n\treadonly steps: { [K in keyof EM & string]?: ProcessStep<TState, EM, K> };\n\t/**\n\t * Optional compensation handler. Runs on step `outcome: \"failure\"` / step throw\n\t * and on explicit `cancel()`. If omitted, instances fail silently with\n\t * status `\"errored\"` instead of `\"cancelled\"`.\n\t */\n\treadonly compensate?: ProcessCompensate<TState>;\n\t/**\n\t * Optional predicate called after each `\"success\"` step. When it returns\n\t * `true`, the instance is moved to `\"completed\"` immediately without\n\t * waiting for a `\"terminate\"` step result.\n\t */\n\treadonly isTerminal?: (state: TState) => boolean;\n\t/**\n\t * Maximum number of retry attempts after a step throws (not counting the\n\t * first attempt). Default: `0` (no retry — fail immediately on throw).\n\t */\n\treadonly retryMax?: number;\n\t/**\n\t * Per-retry backoff delays in milliseconds. `backoffMs[i]` is the delay\n\t * before attempt `i + 1`. If fewer entries than `retryMax`, the last entry\n\t * is repeated. Default: `[0]` (no delay).\n\t *\n\t * **Implementation note:** retry delays are implemented with `setTimeout`\n\t * (same sanctioned exception as `extra/resilience.ts`). This is a\n\t * coordinator-layer primitive — `fromTimer` would require subscribing to\n\t * an additional node per attempt, which would leak timer nodes without a\n\t * clear disposal scope.\n\t */\n\treadonly backoffMs?: readonly number[];\n\t/** Handler version tag stamped onto audit records (Audit 5). */\n\treadonly handlerVersion?: { id: string; version: string | number };\n\t/**\n\t * When `true`, do NOT auto-restore on construction. The caller must invoke\n\t * {@link ProcessManagerResult.restore} explicitly to load persisted\n\t * snapshots and arm watch dispatch.\n\t *\n\t * **Default `false`:** the factory kicks off restoration immediately so\n\t * watch dispatch arms as soon as snapshots have loaded (or instantly when\n\t * no `stateStorage` tier is configured). Until restoration completes,\n\t * watched events accumulate at the source but are valve-blocked from\n\t * reaching the per-instance step pipeline (B5 — locked 2026-05-01).\n\t */\n\treadonly deferRestore?: boolean;\n\t/**\n\t * Maximum number of concurrent `tier.load(key)` calls during restore.\n\t *\n\t * The restore pipeline streams keys from `tier.list()` through\n\t * `mergeMap`, which by default subscribes to inner sources unbounded\n\t * (parallel up to the number of keys). For storage tiers with large\n\t * persisted-instance counts (10K+), unbounded concurrency can exhaust\n\t * file handles, connection pools, or the backend's concurrent-request\n\t * budget. This option caps the in-flight load count.\n\t *\n\t * **Default `8`** (D2 lock 2026-05-01). Set higher for backends with\n\t * generous concurrency budgets; set to `Number.POSITIVE_INFINITY` for\n\t * the prior unbounded behavior.\n\t */\n\treadonly restoreConcurrency?: number;\n\t/** Optional persistence wiring (Audit 4). */\n\treadonly persistence?: {\n\t\t/**\n\t\t * Wire the per-process synthetic state event stream to append-log tiers.\n\t\t * Reuses `CqrsGraph.attachEventStorage` so events persist across restarts.\n\t\t */\n\t\teventStorage?: readonly AppendLogStorageTier<CqrsEvent>[];\n\t\t/**\n\t\t * Wire per-correlationId state snapshots to kv tiers (Tier 6.5 3.5,\n\t\t * 2026-04-29). Each `start()` and step transition writes the running\n\t\t * instance's state under its `correlationId`; terminal transitions\n\t\t * (`completed` / `errored` / `cancelled`) `delete` the key. After\n\t\t * restart, callers invoke {@link ProcessManagerResult.restore} to\n\t\t * reload running instances from the first tier.\n\t\t *\n\t\t * Uses {@link KvStorageTier} (not snapshot tier) because per-instance\n\t\t * state is N records keyed by correlationId, not a single global\n\t\t * snapshot. {@link processStateKeyOf} is the recommended `keyOf`\n\t\t * (already aligned with the kv tier's `save(key, value)` shape).\n\t\t *\n\t\t * Terminal records are NOT preserved — historical lifecycle is the\n\t\t * audit log's job. State persistence covers crash-recovery only.\n\t\t */\n\t\tstateStorage?: readonly KvStorageTier<ProcessStateSnapshot<TState>>[];\n\t};\n}\n\n/**\n * Result handle returned by {@link processManager}.\n */\nexport interface ProcessManagerResult<TState> {\n\t/**\n\t * Reactive audit log of every process instance state transition.\n\t * Every `start()`, step result, retry, cancellation, and compensation\n\t * appends a {@link ProcessInstance} record.\n\t */\n\treadonly instances: ReactiveLogBundle<ProcessInstance<TState>>;\n\t/**\n\t * Alias for {@link instances} (Audit 2 `.audit` duplication convention).\n\t */\n\treadonly audit: ReactiveLogBundle<ProcessInstance<TState>>;\n\t/**\n\t * Start a new process instance identified by `correlationId`.\n\t *\n\t * Emits a synthetic `_process_<name>_started` event into the CQRS graph\n\t * with `correlationId` as `aggregateId` so per-aggregate streams record\n\t * the process lifecycle. If the correlationId already has an active\n\t * (running) instance, this call is a no-op (idempotent).\n\t *\n\t * @param correlationId - Stable key for this workflow instance.\n\t * @param initialPayload - Optional payload carried on the start event.\n\t */\n\tstart(correlationId: string, initialPayload?: unknown): void;\n\t/**\n\t * Cancel a running instance by correlationId.\n\t *\n\t * Triggers the `compensate` handler (if configured), then marks the\n\t * instance as `\"cancelled\"`. If the instance is not running, this is\n\t * a no-op.\n\t *\n\t * @param correlationId - Instance to cancel.\n\t * @param reason - Optional human-readable reason recorded in the audit log.\n\t */\n\tcancel(correlationId: string, reason?: string): void;\n\t/**\n\t * Synchronous read of the current in-memory state for a correlationId.\n\t * Returns `undefined` if the instance does not exist or has terminated.\n\t */\n\tgetState(correlationId: string): TState | undefined;\n\t/**\n\t * Reactive lifecycle of the restore pipeline. Typed as the central\n\t * {@link StatusValue} enum (`\"pending\" | \"running\" | \"completed\" | \"errored\"`);\n\t * the process-manager restore state machine currently emits the `\"pending\"`\n\t * and `\"completed\"` literals only — `\"running\"` / `\"errored\"` reserved\n\t * for future fine-grained restore observability. Starts at `\"pending\"`,\n\t * flips to `\"completed\"` once snapshot loads complete (or immediately when\n\t * no `stateStorage` is configured). On {@link dispose}, the node receives\n\t * TEARDOWN via the standard subgraph teardown cascade — there is no\n\t * `\"disposed\"` literal; consumers detect tear-down via subscription\n\t * COMPLETE on {@link dispose}. Watched events are valve-gated on this\n\t * node: dispatch is blocked while `restoreState !== \"completed\"`.\n\t *\n\t * Exposed for observability and tests. Subscribers can compose\n\t * `derived([restoreState], …)` to build their own gates / readouts.\n\t */\n\treadonly restoreState: Node<StatusValue>;\n\t/**\n\t * Trigger restoration of running instances from the first\n\t * {@link ProcessManagerOpts.persistence.stateStorage} tier (Tier 6.5\n\t * 3.5, 2026-04-29). Loads every record in the tier reactively and\n\t * re-hydrates `instanceStates` / `activeInstances` / `startedAt` for\n\t * any record whose `status === \"running\"`. Terminal records, if any\n\t * persisted before delete fired, are silently skipped.\n\t *\n\t * **Reactive composition (B5 — locked 2026-05-01):** internally,\n\t * `tier.list()` and `tier.load()` are wrapped in `fromAny` sources\n\t * (handles sync values, Promises, async iterables, and existing Nodes\n\t * uniformly per `~/src/graphrefly/COMPOSITION-GUIDE.md` §3 source\n\t * bridging); a `mergeMap` flattens per-key load results; an `effect`\n\t * populates closure state and flips {@link restoreState} to\n\t * `\"completed\"` on the `COMPLETE` boundary. No `await` inside the\n\t * reactive interior — the single async boundary is the returned\n\t * `Promise<void>`, which resolves when {@link restoreState} transitions\n\t * to `\"completed\"` OR when {@link dispose} tears down the restore node\n\t * (in which case `firstWhere`'s COMPLETE-rejection is swallowed and\n\t * the promise resolves to `undefined`).\n\t *\n\t * Idempotent — calling twice subscribes to the same restore pipeline\n\t * and resolves on the same gate flip. No-op when no `stateStorage`\n\t * tier is configured OR the first tier lacks a `list?` method:\n\t * `restoreState` flips to `\"completed\"` immediately so watches can arm.\n\t *\n\t * **Auto-restore default.** With `deferRestore: false` (the default),\n\t * the factory invokes `restore()` once at construction so callers do\n\t * not need to remember to wire it. Pass `deferRestore: true` to\n\t * suppress auto-restore and call `restore()` manually.\n\t */\n\trestore(): Promise<void>;\n\t/**\n\t * Release all watched-event subscriptions and stop processing new events.\n\t *\n\t * After `dispose()`, subsequent `start()` and `cancel()` calls are no-ops.\n\t * In-flight async steps complete naturally; no new steps are dispatched.\n\t *\n\t * Tears down the {@link restoreState} node via the standard subgraph\n\t * teardown cascade. Any pending `restore()` Promise resolves (the\n\t * COMPLETE-rejection from `firstWhere` is swallowed at the API edge);\n\t * the watch valve closes via TEARDOWN propagation; no further dispatch\n\t * even if a `fromAny(tier.load…)` would resolve later (the per-key\n\t * load source's cleanup sets `settled = true`, dropping the late DATA).\n\t */\n\tdispose(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Materialise a `NodeInput<T>` into a Promise.\n * Uses `fromAny` to normalise Node / Promise / iterable / scalar, then\n * collects the first DATA message.\n *\n * - If `input` is `null` or `undefined`, resolves immediately with `undefined`\n * (skips constructing a `fromAny` source).\n * - On COMPLETE without prior DATA, resolves with `undefined` (supports `void`\n * compensate handlers whose `NodeInput<void>` delivers COMPLETE only).\n *\n * Implementation note: `fromAny` over a scalar (e.g. `void` / `undefined`) or\n * sync iterable delivers DATA synchronously inside `n.subscribe()`, BEFORE the\n * `subscribe()` call returns. We therefore use `let unsub` (not `const`) and\n * avoid calling `unsub()` until after `subscribe()` has returned — deferring\n * the cleanup to a microtask via `Promise.resolve().then(unsub)` to sidestep\n * the Temporal Dead Zone.\n */\nfunction toPromise<T>(input: NodeInput<T>): Promise<T> {\n\t// Short-circuit: null/undefined input resolves immediately.\n\tif (input == null) return Promise.resolve(undefined as T);\n\n\tconst n = fromAny<T>(input);\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\t// `let` instead of `const` so that synchronous DATA delivery during\n\t\t// n.subscribe() (before the assignment completes) doesn't hit TDZ.\n\t\tlet unsub: (() => void) | undefined;\n\t\tconst cleanup = () => {\n\t\t\tif (unsub) {\n\t\t\t\tunsub();\n\t\t\t}\n\t\t};\n\t\tunsub = n.subscribe((msgs) => {\n\t\t\tif (settled) return;\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\t// Defer cleanup to after the subscribe() call returns (TDZ-safe).\n\t\t\t\t\tPromise.resolve().then(cleanup);\n\t\t\t\t\tresolve(m[1] as T);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tPromise.resolve().then(cleanup);\n\t\t\t\t\treject(m[1] as unknown);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\t// COMPLETE without prior DATA — resolve with undefined.\n\t\t\t\t\t// Supports void compensate handlers that return without emitting DATA.\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tPromise.resolve().then(cleanup);\n\t\t\t\t\tresolve(undefined as T);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/** Run `step(state, event)` with retry logic. Returns the step result. */\nasync function runWithRetry<TState>(\n\tstep: (state: TState, event: CqrsEvent) => NodeInput<ProcessStepResult<TState>>,\n\tstate: TState,\n\tevent: CqrsEvent,\n\tretryMax: number,\n\tbackoffMs: readonly number[],\n): Promise<ProcessStepResult<TState>> {\n\tlet lastError: unknown;\n\tfor (let attempt = 0; attempt <= retryMax; attempt++) {\n\t\tif (attempt > 0) {\n\t\t\t// Sanctioned setTimeout for retry backoff in coordinator primitives.\n\t\t\t// Same pattern as extra/resilience.ts retry implementation.\n\t\t\tconst delayMs = backoffMs[Math.min(attempt - 1, backoffMs.length - 1)] ?? 0;\n\t\t\tif (delayMs > 0) {\n\t\t\t\tawait new Promise<void>((r) => setTimeout(r, delayMs));\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tconst result = await toPromise(step(state, event));\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tlastError = err;\n\t\t\t// If we've exhausted retries, fall through to return a fail result.\n\t\t}\n\t}\n\treturn { outcome: \"failure\", error: lastError };\n}\n\n// ---------------------------------------------------------------------------\n// processManager factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a process manager that coordinates long-running reactive workflows\n * over a {@link CqrsGraph}.\n *\n * Process instances are identified by `correlationId`. Events from the watched\n * event types are routed to per-instance step handlers when the event's\n * `correlationId` matches a running instance.\n *\n * ```ts\n * const app = cqrs<{ orderPlaced: { orderId: string }; paymentReceived: { amount: number } }>(\"orders\");\n *\n * const pm = processManager(app, \"fulfillment\", {\n * initial: { step: \"awaiting-payment\", total: 0 },\n * watching: [\"orderPlaced\", \"paymentReceived\"],\n * steps: {\n * orderPlaced(state, event) {\n * return { outcome: \"success\", state: { ...state, orderId: event.payload.orderId } };\n * },\n * paymentReceived(state, event) {\n * return { outcome: \"terminate\", state: { ...state, total: event.payload.amount } };\n * },\n * },\n * compensate(state, _error) {\n * // undo reservation, issue refund, etc.\n * },\n * retryMax: 2,\n * backoffMs: [100, 500],\n * });\n *\n * pm.start(\"order-123\");\n * app.dispatch(\"orderPlaced\", { orderId: \"order-123\" }, { correlationId: \"order-123\" });\n * ```\n *\n * @param cqrsGraph - The CQRS graph whose event streams the manager watches.\n * @param name - Stable identifier for this process type; used for the\n * synthetic event-type prefix `_process_<name>_*`. Currently emits\n * `_process_<name>_started` per `start()`; the prefix is reserved for\n * future `_state` / `_timer` channels.\n * @param opts - Configuration: initial state, watched events, steps, retry,\n * compensation, and optional persistence.\n * @returns {@link ProcessManagerResult} with `instances` audit log and\n * `start`, `cancel`, `getState` imperative controls.\n *\n * @category patterns\n */\nexport function processManager<TState, EM extends CqrsEventMap = Record<string, unknown>>(\n\tcqrsGraph: CqrsGraph<EM>,\n\tname: string,\n\topts: ProcessManagerOpts<TState, EM>,\n): ProcessManagerResult<TState> {\n\tconst retryMax = opts.retryMax ?? 0;\n\tconst backoffMs: readonly number[] = opts.backoffMs ?? [0];\n\tconst retainedLimit = 1024;\n\n\t// ── Per-instance in-memory state ──────────────────────────────────────\n\t// Map from correlationId → current TState for running instances.\n\t// Imperative coordinator state — documented pattern for this primitive.\n\tconst instanceStates = new Map<string, TState>();\n\t// Track which instances are \"active\" (running) to prevent double-start\n\t// and to gate step delivery.\n\tconst activeInstances = new Set<string>();\n\t// Track startedAt per instance.\n\tconst startedAt = new Map<string, number>();\n\n\t// ── Audit log + seq cursor ────────────────────────────────────────────\n\t// EH-16 (Tier 6.5 3.3, 2026-04-29): the audit log + seq cursor are\n\t// mounted under a per-instance child Graph (`__processManagers__/<name>`)\n\t// rather than directly under `cqrsGraph._nodes`. `dispose()` then calls\n\t// `cqrsGraph.remove(...)` to unmount the subgraph cleanly via the\n\t// existing mount/removeMount lifecycle — no leaked nodes after repeated\n\t// create/dispose cycles. Pre-1.0 path-schema change: paths shift from\n\t// `${name}_process_instances` / `${name}_process_seq` (top-level) to\n\t// `__processManagers__/${name}::instances` / `::seq` (mounted).\n\tconst mountName = `__processManagers__/${name}`;\n\tconst subgraph = new Graph(name);\n\ttry {\n\t\tcqrsGraph.mount(mountName, subgraph);\n\t} catch (err) {\n\t\t// `Graph.mount` throws if the mount name is in use; surface a\n\t\t// processManager-specific message so callers see actionable context.\n\t\tconst detail = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(\n\t\t\t`processManager: name \"${name}\" is already in use on this CQRS graph ` +\n\t\t\t\t`(mount path \"${mountName}\" collides). Call .dispose() on the prior ` +\n\t\t\t\t`manager OR pick a different name before re-creating. (${detail})`,\n\t\t);\n\t}\n\n\tconst instances = createAuditLog<ProcessInstance<TState>>({\n\t\tname: \"instances\",\n\t\tretainedLimit,\n\t\tgraph: subgraph,\n\t});\n\n\t// Tier 8 γ-7-A (2026-04-28): seq cursor promoted from `let seq = 0` closure\n\t// to a `state(0)` node mounted on the per-process subgraph (visible in\n\t// `describe()` at `__processManagers__/<name>::seq`). The audit-record\n\t// stamping routes through `mutate` for centralized freeze + seq\n\t// advance + `handlerVersion` stamping + batch-frame rollback. The batch\n\t// frame closes EH-17 (re-entrancy hazard).\n\tconst seqCursor = registerCursor(subgraph, \"seq\", 0);\n\n\t// D4 (qa lock): `freeze: true` so step-handler-supplied state values\n\t// captured into audit records cannot be mutated post-record. Process\n\t// states are typically small workflow records (an order ID + a few\n\t// flags), so the `deepFreeze` tax is negligible — the safety vs. mutation\n\t// trade-off favors freeze. (The 768-dim-vector concern that motivates\n\t// `freeze: false` in memory primitives doesn't apply here.)\n\tconst appendRecord = mutate<\n\t\t[string, TState, ProcessInstance<TState>[\"status\"], string | undefined],\n\t\tvoid,\n\t\tProcessInstance<TState>\n\t>(\n\t\t// No closure-state mutation in the action — the audit-record append IS\n\t\t// the effect, performed by the framework via `onSuccessRecord`.\n\t\t() => undefined,\n\t\t{\n\t\t\tframe: \"transactional\",\n\t\t\tlog: instances,\n\t\t\tseq: seqCursor,\n\t\t\tfreeze: true,\n\t\t\t...(opts.handlerVersion !== undefined ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\tonSuccessRecord: ([correlationId, state, status, reason], _r, { t_ns, seq }) => ({\n\t\t\t\tcorrelationId,\n\t\t\t\tstate,\n\t\t\t\tstatus,\n\t\t\t\tstartedAt: startedAt.get(correlationId) ?? t_ns,\n\t\t\t\tupdatedAt: t_ns,\n\t\t\t\tt_ns,\n\t\t\t\tseq: seq ?? 0,\n\t\t\t\t...(reason !== undefined ? { reason } : {}),\n\t\t\t}),\n\t\t},\n\t);\n\n\t// ── State-snapshot persistence (Tier 6.5 3.5) ─────────────────────────\n\tconst stateStorageTiers = opts.persistence?.stateStorage ?? [];\n\n\t/**\n\t * Build the snapshot payload + iterate tiers. Returns the iterator over\n\t * tiers so the caller decides whether sync throws propagate (B4 — start\n\t * path inside mutate) or are swallowed (step path, fire-and-forget).\n\t */\n\tconst buildSnapshot = (\n\t\tcorrelationId: string,\n\t\tstatus: ProcessStateSnapshot<TState>[\"status\"],\n\t): ProcessStateSnapshot<TState> | undefined => {\n\t\tconst stateValue = instanceStates.get(correlationId);\n\t\tif (stateValue === undefined) return undefined;\n\t\treturn {\n\t\t\tcorrelationId,\n\t\t\tstate: stateValue,\n\t\t\tstatus,\n\t\t\tstartedAt: startedAt.get(correlationId) ?? wallClockNs(),\n\t\t\tupdatedAt: wallClockNs(),\n\t\t\t...(opts.handlerVersion !== undefined ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t};\n\t};\n\n\t/**\n\t * Best-effort persistence (used by step transitions). Sync throws are\n\t * swallowed so persistence failures do NOT poison reactive step dispatch.\n\t * Async rejections are caught at the Promise boundary.\n\t */\n\tconst persistState = (\n\t\tcorrelationId: string,\n\t\tstatus: ProcessStateSnapshot<TState>[\"status\"],\n\t): void => {\n\t\tif (stateStorageTiers.length === 0) return;\n\t\tconst snapshot = buildSnapshot(correlationId, status);\n\t\tif (snapshot === undefined) return;\n\t\tfor (const tier of stateStorageTiers) {\n\t\t\ttry {\n\t\t\t\tconst r = tier.save(correlationId, snapshot);\n\t\t\t\t// Tier may return Promise — fire-and-forget. Storage errors\n\t\t\t\t// surface via the tier's own onError plumbing (Tier 4 storage).\n\t\t\t\tif (r != null && typeof (r as Promise<void>).then === \"function\") {\n\t\t\t\t\t(r as Promise<void>).catch(() => undefined);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// best-effort; persistence failures don't block step execution\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Throwing variant (B4 — used inside `startInternal`'s mutate\n\t * action body so a sync-throwing tier rolls back the audit-log append +\n\t * seq cursor advance). Async rejections from `tier.save()` still cannot\n\t * unwind the synchronous batch frame — that's a known limitation of\n\t * Promise-returning storage; sync-throwing tiers (the actual D2 hazard)\n\t * are fully covered.\n\t */\n\tconst persistStateThrowing = (\n\t\tcorrelationId: string,\n\t\tstatus: ProcessStateSnapshot<TState>[\"status\"],\n\t): void => {\n\t\tif (stateStorageTiers.length === 0) return;\n\t\tconst snapshot = buildSnapshot(correlationId, status);\n\t\tif (snapshot === undefined) return;\n\t\tfor (const tier of stateStorageTiers) {\n\t\t\tconst r = tier.save(correlationId, snapshot);\n\t\t\tif (r != null && typeof (r as Promise<void>).then === \"function\") {\n\t\t\t\t(r as Promise<void>).catch(() => undefined);\n\t\t\t}\n\t\t}\n\t};\n\tconst removeState = (correlationId: string): void => {\n\t\tif (stateStorageTiers.length === 0) return;\n\t\tfor (const tier of stateStorageTiers) {\n\t\t\tif (!tier.delete) continue;\n\t\t\ttry {\n\t\t\t\tconst r = tier.delete(correlationId);\n\t\t\t\tif (r != null && typeof (r as Promise<void>).then === \"function\") {\n\t\t\t\t\t(r as Promise<void>).catch(() => undefined);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// best-effort\n\t\t\t}\n\t\t}\n\t};\n\n\t// ── Synthetic event helpers ───────────────────────────────────────────\n\tconst startedEventType = `_process_${name}_started`;\n\n\t// Pre-register the started event stream so it appears in describe().\n\t// Side-effect events (result.emit) dispatch using their own declared event type\n\t// via _appendEvent directly — no separate state event stream needed.\n\tcqrsGraph.event(startedEventType);\n\n\t// Wire persistence: event storage for synthetic state stream.\n\tif (opts.persistence?.eventStorage) {\n\t\tcqrsGraph.attachEventStorage(opts.persistence.eventStorage);\n\t}\n\n\t// ── Compensation helper ───────────────────────────────────────────────\n\tasync function runCompensate(\n\t\tcorrelationId: string,\n\t\tstate: TState,\n\t\terror: unknown,\n\t\treason?: string,\n\t): Promise<void> {\n\t\t// Eagerly remove from active state BEFORE any await so that concurrent\n\t\t// cancel() calls or in-flight step completions that arrive while we are\n\t\t// awaiting the compensate handler find the instance already gone and\n\t\t// exit early (C1 — double-compensation race fix).\n\t\tactiveInstances.delete(correlationId);\n\t\tinstanceStates.delete(correlationId);\n\t\tstartedAt.delete(correlationId);\n\n\t\tif (opts.compensate) {\n\t\t\ttry {\n\t\t\t\tawait toPromise(opts.compensate(state, error) as NodeInput<void>);\n\t\t\t\tappendRecord(correlationId, state, \"cancelled\", reason);\n\t\t\t\tremoveState(correlationId);\n\t\t\t} catch (_compErr) {\n\t\t\t\t// Compensation itself failed — still mark as errored so instance\n\t\t\t\t// doesn't stay in limbo. Swallow error to prevent cascading.\n\t\t\t\tappendRecord(correlationId, state, \"errored\", undefined);\n\t\t\t\tremoveState(correlationId);\n\t\t\t}\n\t\t} else {\n\t\t\tappendRecord(correlationId, state, \"errored\", undefined);\n\t\t\tremoveState(correlationId);\n\t\t}\n\t}\n\n\t// ── Step result handler ───────────────────────────────────────────────\n\tasync function handleStepResult(\n\t\tcorrelationId: string,\n\t\tresult: ProcessStepResult<TState>,\n\t): Promise<void> {\n\t\tif (!activeInstances.has(correlationId)) return; // cancelled during async step\n\n\t\tif (result.outcome === \"failure\") {\n\t\t\t// Capture state before eager delete (C1 — step-fail eager-delete).\n\t\t\tconst state = instanceStates.get(correlationId) ?? opts.initial;\n\t\t\t// runCompensate handles the eager delete; the early-exit guard above\n\t\t\t// ensures we won't double-compensate for an already-inactive instance.\n\t\t\tawait runCompensate(correlationId, state, result.error);\n\t\t\treturn;\n\t\t}\n\n\t\tif (result.outcome === \"success\") {\n\t\t\tinstanceStates.set(correlationId, result.state);\n\n\t\t\t// Emit side-effect CQRS events.\n\t\t\tif (result.emit) {\n\t\t\t\tfor (const ev of result.emit) {\n\t\t\t\t\t// Dispatch via _appendEvent is internal. Use a synthetic command\n\t\t\t\t\t// channel via the public `dispatch` API by pre-registering a\n\t\t\t\t\t// passthrough command, OR emit directly via an internal event.\n\t\t\t\t\t// Strategy: use event stream directly — the process manager is\n\t\t\t\t\t// an internal coordinator allowed to call internal CQRS APIs.\n\t\t\t\t\t// We use the synthetic stateEventType to carry side-effect events\n\t\t\t\t\t// so they appear in the aggregate stream.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Emit side-effect events using the process state event stream with\n\t\t\t\t\t\t// the correlationId as aggregateId, but use the declared event type\n\t\t\t\t\t\t// as the type field for downstream sagas/projections to react to.\n\t\t\t\t\t\t// We do this by directly dispatching into the CQRS graph via the\n\t\t\t\t\t\t// dedicated per-process synthetic event channel.\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tcqrsGraph as unknown as {\n\t\t\t\t\t\t\t\t_appendEvent(\n\t\t\t\t\t\t\t\t\tname: string,\n\t\t\t\t\t\t\t\t\tpayload: unknown,\n\t\t\t\t\t\t\t\t\textra?: { correlationId?: string; aggregateId?: string },\n\t\t\t\t\t\t\t\t): void;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)._appendEvent(ev.type, ev.payload, {\n\t\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\t\taggregateId: correlationId,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (_emitErr) {\n\t\t\t\t\t\t// Non-fatal: side-effect event emission failures are not\n\t\t\t\t\t\t// step-fatal (they are fire-and-forget coordination signals).\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tappendRecord(correlationId, result.state, \"running\", undefined);\n\t\t\tpersistState(correlationId, \"running\");\n\n\t\t\t// Check isTerminal predicate.\n\t\t\tif (opts.isTerminal?.(result.state)) {\n\t\t\t\tactiveInstances.delete(correlationId);\n\t\t\t\tinstanceStates.delete(correlationId);\n\t\t\t\tstartedAt.delete(correlationId); // M3 — cleanup startedAt on isTerminal terminate\n\t\t\t\tappendRecord(correlationId, result.state, \"completed\", undefined);\n\t\t\t\tremoveState(correlationId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Handle schedule: fire synthetic event after delay via fromTimer.\n\t\t\tif (result.schedule) {\n\t\t\t\tconst { afterMs, eventType } = result.schedule;\n\t\t\t\t// fromTimer per spec §5.8 — reactive timer source.\n\t\t\t\t// Subscribe to fire once and deliver the synthetic event.\n\t\t\t\t// M6: use `let timerUnsub` + TDZ guard to avoid referencing the\n\t\t\t\t// variable before its assignment if the callback fires synchronously.\n\t\t\t\tlet timerUnsub: (() => void) | undefined;\n\t\t\t\tconst timerNode = fromTimer(afterMs);\n\t\t\t\tconst timerCb: Parameters<typeof timerNode.subscribe>[0] = (msgs) => {\n\t\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\t\t\t// TDZ guard: if subscribe() hasn't returned yet, defer cleanup.\n\t\t\t\t\t\t\tif (timerUnsub) {\n\t\t\t\t\t\t\t\ttimerUnsub();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// fromTimer is async (setTimeout-backed) so this path is\n\t\t\t\t\t\t\t\t// never hit in practice, but guard for safety.\n\t\t\t\t\t\t\t\tqueueMicrotask(() => timerUnsub?.());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!activeInstances.has(correlationId)) return;\n\t\t\t\t\t\t\tconst currentState = instanceStates.get(correlationId);\n\t\t\t\t\t\t\tif (currentState === undefined) return;\n\t\t\t\t\t\t\tconst step = (\n\t\t\t\t\t\t\t\topts.steps as unknown as Record<string, ProcessStep<TState, EM, string>>\n\t\t\t\t\t\t\t)[eventType];\n\t\t\t\t\t\t\tif (!step) return;\n\t\t\t\t\t\t\tconst syntheticEvent: CqrsEvent = {\n\t\t\t\t\t\t\t\ttype: eventType,\n\t\t\t\t\t\t\t\t// m5: null payload (not undefined) to avoid soft §1.2 risk.\n\t\t\t\t\t\t\t\t// seq: Number.NaN — sentinel for synthetic events that do not\n\t\t\t\t\t\t\t\t// participate in cross-event ordering.\n\t\t\t\t\t\t\t\tpayload: null,\n\t\t\t\t\t\t\t\ttimestampNs: wallClockNs(),\n\t\t\t\t\t\t\t\tseq: Number.NaN,\n\t\t\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\t\t\taggregateId: correlationId,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tdispatchStep(correlationId, step, currentState, syntheticEvent);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\ttimerUnsub = timerNode.subscribe(timerCb);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (result.outcome === \"terminate\") {\n\t\t\tinstanceStates.set(correlationId, result.state);\n\t\t\t// Emit side-effect events.\n\t\t\tif (result.emit) {\n\t\t\t\tfor (const ev of result.emit) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tcqrsGraph as unknown as {\n\t\t\t\t\t\t\t\t_appendEvent(\n\t\t\t\t\t\t\t\t\tname: string,\n\t\t\t\t\t\t\t\t\tpayload: unknown,\n\t\t\t\t\t\t\t\t\textra?: { correlationId?: string; aggregateId?: string },\n\t\t\t\t\t\t\t\t): void;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)._appendEvent(ev.type, ev.payload, {\n\t\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\t\taggregateId: correlationId,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (_emitErr) {\n\t\t\t\t\t\t// non-fatal\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tactiveInstances.delete(correlationId);\n\t\t\tinstanceStates.delete(correlationId);\n\t\t\tstartedAt.delete(correlationId); // M3 — cleanup startedAt on terminate\n\t\t\tappendRecord(correlationId, result.state, \"completed\", undefined);\n\t\t\tremoveState(correlationId);\n\t\t}\n\t}\n\n\t// ── Step dispatch ─────────────────────────────────────────────────────\n\t// C2: Per-correlationId in-flight serialization map.\n\t// Multiple events for the same correlationId in one DATA wave both read the\n\t// same instanceStates snapshot if dispatched concurrently. Serializing via a\n\t// promise chain ensures the second step sees the first step's written state.\n\t// Cross-correlationId events still parallelize (separate map entries).\n\tconst inFlight = new Map<string, Promise<void>>();\n\n\tfunction dispatchStep(\n\t\tcorrelationId: string,\n\t\tstep: ProcessStep<TState, EM, string>,\n\t\t_state: TState, // C2: state is re-read inside the serialized closure; this param is kept for call-site clarity\n\t\tevent: CqrsEvent,\n\t): void {\n\t\tconst prior = inFlight.get(correlationId) ?? Promise.resolve();\n\t\tconst next = prior.then(async () => {\n\t\t\t// Re-read current state at execution time (prior steps may have updated it).\n\t\t\tconst currentState = instanceStates.get(correlationId);\n\t\t\tif (currentState === undefined) return; // instance was cancelled/terminated in prior step\n\t\t\tif (!activeInstances.has(correlationId)) return;\n\t\t\tlet result: ProcessStepResult<TState>;\n\t\t\ttry {\n\t\t\t\tresult = await runWithRetry(\n\t\t\t\t\tstep as (s: TState, e: CqrsEvent) => NodeInput<ProcessStepResult<TState>>,\n\t\t\t\t\tcurrentState,\n\t\t\t\t\tevent,\n\t\t\t\t\tretryMax,\n\t\t\t\t\tbackoffMs,\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\t// runWithRetry itself should not throw (it returns fail on exhaustion),\n\t\t\t\t// but guard against unexpected errors.\n\t\t\t\tawait runCompensate(correlationId, instanceStates.get(correlationId) ?? opts.initial, err);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait handleStepResult(correlationId, result);\n\t\t});\n\t\tinFlight.set(correlationId, next);\n\t\tnext.finally(() => {\n\t\t\tif (inFlight.get(correlationId) === next) inFlight.delete(correlationId);\n\t\t});\n\t}\n\n\t// C3: disposal flag — set true by dispose(); gates start() and cancel().\n\t// Synchronous liveness check used by start() / cancel() to avoid\n\t// reaching into the reactive layer (and to short-circuit before the\n\t// teardown cascade has propagated through restoreState).\n\tlet _disposed = false;\n\n\t// ── Restore lifecycle state (B5 — locked 2026-05-01; post-fix using\n\t// central StatusValue enum 2026-05-01) ───────────────────────────────\n\t// Reactive lifecycle node typed as the central StatusValue enum\n\t// (`\"pending\" | \"running\" | \"completed\" | \"errored\"`). Currently emits\n\t// the \"pending\" → \"completed\" subset only:\n\t// \"pending\" → constructed; restore not yet finished. Watched events\n\t// arrive at the source but are valve-blocked from\n\t// reaching step dispatch.\n\t// \"completed\" → restoration complete. Watch valve is open; events\n\t// accumulated during \"pending\" are delivered as the\n\t// latest cumulative cqrs log array; the per-watch\n\t// cursor catches up to that array in one step.\n\t// (\"running\" / \"errored\" reserved for future fine-grained restore\n\t// observability; not emitted today.)\n\t// Disposal: no \"disposed\" literal — dispose() unmounts the subgraph\n\t// which TEARDOWNs restoreState; the gateOpen valve closes via standard\n\t// cascade; pending restore() Promise resolves via the .catch at the\n\t// public API edge.\n\tconst restoreState = node<StatusValue>([], {\n\t\tinitial: \"pending\",\n\t\tname: \"restoreState\",\n\t\tdescribeKind: \"state\",\n\t});\n\tsubgraph.add(restoreState, { name: \"restoreState\" });\n\n\t// `gateOpen` is the valve control: true only while\n\t// restoreState === \"completed\". Lazy: activates when the first valve\n\t// subscribes.\n\tconst gateOpen = node<boolean>(\n\t\t[restoreState as Node],\n\t\t(data, a, ctx) => {\n\t\t\tconst batch0 = data[0];\n\t\t\tconst v = (batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0]) as\n\t\t\t\t| StatusValue\n\t\t\t\t| undefined;\n\t\t\ta.emit(v === \"completed\");\n\t\t},\n\t\t{ name: \"gateOpen\", describeKind: \"derived\" },\n\t);\n\tsubgraph.add(gateOpen, { name: \"gateOpen\" });\n\n\t// ── Watched event subscriptions (valve-gated) ────────────────────────\n\t// COMPOSITION-GUIDE §28 cursor pattern + valve(eventNode, gateOpen):\n\t// per watched event type, subscribe to a valve over the cqrs event\n\t// stream. While restoreState !== \"completed\", valve emits RESOLVED so\n\t// no DATA reaches the cursor — events are NOT lost; the cqrs event\n\t// log retains them. When the gate flips open, valve re-emits the\n\t// latest cumulative event array (control-only wave path inside\n\t// `valve`); the cursor processes everything from `lastCount` (still\n\t// 0 at that point) in one shot.\n\tconst watchDisposers: Array<() => void> = [];\n\n\tfor (const eventType of opts.watching) {\n\t\tconst eventNode = cqrsGraph.event(eventType as string);\n\t\tconst gated = valve(eventNode, gateOpen, { name: `gatedEvent:${eventType as string}` });\n\n\t\t// Cursor starts at 0 — pre-restore events are NOT pre-counted because\n\t\t// they may be pre-restart events that the persisted snapshot already\n\t\t// consumed. The restore pipeline's job is to seed instanceStates /\n\t\t// activeInstances; events for instances NOT in activeInstances after\n\t\t// restore drop on the floor (the per-event activeInstances.has guard).\n\t\tlet lastCount = 0;\n\n\t\tconst unsub = gated.subscribe((msgs: Messages) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tconst events = m[1] as readonly CqrsEvent[];\n\t\t\t\tif (events.length <= lastCount) continue;\n\t\t\t\tconst newEvents = events.slice(lastCount);\n\t\t\t\tlastCount = events.length;\n\n\t\t\t\tfor (const ev of newEvents) {\n\t\t\t\t\tconst corrId = ev.correlationId;\n\t\t\t\t\tif (corrId === undefined) continue;\n\t\t\t\t\tif (!activeInstances.has(corrId)) continue;\n\n\t\t\t\t\tconst step = (opts.steps as unknown as Record<string, ProcessStep<TState, EM, string>>)[\n\t\t\t\t\t\teventType as string\n\t\t\t\t\t];\n\t\t\t\t\tif (!step) continue;\n\n\t\t\t\t\tconst state = instanceStates.get(corrId);\n\t\t\t\t\tif (state === undefined) continue;\n\n\t\t\t\t\tdispatchStep(corrId, step, state, ev);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\twatchDisposers.push(unsub);\n\t}\n\n\t// ── Public API ────────────────────────────────────────────────────────\n\n\t// Tier 8 γ-7-A (2026-04-28): `start()` body is mutate-wrapped so the\n\t// synthetic-start-event emit + the running audit record commit in one\n\t// batch frame. If `_appendEvent` throws (e.g. event stream terminated),\n\t// mutate rolls back the in-band batch (audit append discarded, seq\n\t// cursor advance discarded) and re-throws to the caller. Pre-1.0 behavior\n\t// change vs. γ-7-B: the previous form silently swallowed `_appendEvent`\n\t// failures and still appended the running record. Per COMPOSITION-GUIDE\n\t// §35, closure mutations are NOT rolled back — so they are deferred to\n\t// after `_appendEvent` succeeds inside the action body.\n\t//\n\t// B4 (D2 — locked 2026-05-01): `persistState(...)` lives INSIDE the action\n\t// body (after the closure mutations that seed `instanceStates`) so a\n\t// sync-throwing `stateStorage` tier rolls back the in-band batch the same\n\t// way `_appendEvent` failures do — neither the audit log entry nor the\n\t// state snapshot ends up in the \"running\" record store. Per §35 the\n\t// closure mutations stay (instanceStates / activeInstances / startedAt\n\t// are already set), but the audit-log + persisted-snapshot are coherent\n\t// with each other: both absent on throw, both present on success.\n\tconst startInternal = mutate<[string, unknown], void, ProcessInstance<TState>>(\n\t\t(correlationId, initialPayload) => {\n\t\t\t// Synthetic start event first (potentially throws). Closure\n\t\t\t// mutations below only run if this call succeeds — per §35,\n\t\t\t// rollback does not undo them, so they must come after the\n\t\t\t// throwing work.\n\t\t\t(\n\t\t\t\tcqrsGraph as unknown as {\n\t\t\t\t\t_appendEvent(\n\t\t\t\t\t\tname: string,\n\t\t\t\t\t\tpayload: unknown,\n\t\t\t\t\t\textra?: { correlationId?: string; aggregateId?: string },\n\t\t\t\t\t): void;\n\t\t\t\t}\n\t\t\t)._appendEvent(startedEventType, initialPayload ?? null, {\n\t\t\t\tcorrelationId,\n\t\t\t\taggregateId: correlationId,\n\t\t\t});\n\t\t\tstartedAt.set(correlationId, wallClockNs());\n\t\t\tinstanceStates.set(correlationId, opts.initial);\n\t\t\tactiveInstances.add(correlationId);\n\t\t\t// B4: inside the rollback boundary so a sync-throwing tier\n\t\t\t// discards the audit-log append + seq cursor advance.\n\t\t\tpersistStateThrowing(correlationId, \"running\");\n\t\t},\n\t\t{\n\t\t\tframe: \"transactional\",\n\t\t\tlog: instances,\n\t\t\tseq: seqCursor,\n\t\t\tfreeze: true,\n\t\t\t...(opts.handlerVersion !== undefined ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\tonSuccessRecord: ([correlationId], _r, { t_ns, seq }) => ({\n\t\t\t\tcorrelationId,\n\t\t\t\tstate: opts.initial,\n\t\t\t\tstatus: \"running\",\n\t\t\t\tstartedAt: startedAt.get(correlationId) ?? t_ns,\n\t\t\t\tupdatedAt: t_ns,\n\t\t\t\tt_ns,\n\t\t\t\tseq: seq ?? 0,\n\t\t\t}),\n\t\t},\n\t);\n\n\t/**\n\t * Start a new process instance.\n\t *\n\t * Idempotent: if a running instance with the same `correlationId` already\n\t * exists, the call is a no-op. Also a no-op after `dispose()`.\n\t *\n\t * **Throws** if the synthetic `_process_<name>_started` event stream is\n\t * terminated (γ-7-A, 2026-04-28). The audit log is not appended in that\n\t * case — the in-band batch rolls back so the seq cursor and audit log\n\t * stay consistent with the pre-call state.\n\t */\n\tfunction start(correlationId: string, initialPayload?: unknown): void {\n\t\tif (_disposed) return;\n\t\tif (activeInstances.has(correlationId)) return;\n\t\t// B4 (D2): persistState now lives INSIDE `startInternal`'s mutate\n\t\t// action body so sync-throwing tiers roll back the audit-log entry too.\n\t\tstartInternal(correlationId, initialPayload);\n\t}\n\n\t/**\n\t * Cancel a running instance and trigger compensation.\n\t *\n\t * No-op if the instance is not currently running (or after `dispose()`).\n\t */\n\tfunction cancel(correlationId: string, reason?: string): void {\n\t\tif (_disposed) return;\n\t\tif (!activeInstances.has(correlationId)) return;\n\n\t\t// Capture state before the async compensate path.\n\t\tconst state = instanceStates.get(correlationId) ?? opts.initial;\n\t\t// Run compensation asynchronously (fire-and-forget from caller perspective).\n\t\t// C1: runCompensate does the eager activeInstances.delete before any await,\n\t\t// so concurrent calls or in-flight steps that complete concurrently find the\n\t\t// instance already removed and exit early.\n\t\t// M4: pass reason through so it lands on the audit record.\n\t\trunCompensate(\n\t\t\tcorrelationId,\n\t\t\tstate,\n\t\t\tnew Error(`cancelled: ${reason ?? \"no reason given\"}`),\n\t\t\treason,\n\t\t);\n\t}\n\n\t/**\n\t * Read the current in-memory state for a correlationId.\n\t *\n\t * Returns `undefined` if the instance does not exist or has terminated.\n\t */\n\tfunction getState(correlationId: string): TState | undefined {\n\t\treturn instanceStates.get(correlationId);\n\t}\n\n\t/**\n\t * Reactive restore pipeline (B5 — locked 2026-05-01; post-fix using\n\t * fromAny + StatusValue 2026-05-01).\n\t *\n\t * `restoreSubscription` is the single keepalive over the snapshot-load\n\t * effect. Set on first `restore()` call (or on construction when\n\t * `deferRestore !== true`). The effect:\n\t *\n\t * 1. Subscribes to `mergeMap(fromAny(tier.list()), keys =>\n\t * mergeMap(fromIter(keys), key => fromAny(tier.load(key))))` —\n\t * a fully reactive chain whose only async boundaries are the source\n\t * `fromAny` nodes (spec §5.10). `fromAny` accepts sync values,\n\t * Promises, async iterables, and existing Nodes — future-proof\n\t * against tier impls that decide to expose paginated/streaming\n\t * `list()` or batched `load()`.\n\t * 2. On each per-key load DATA, populates `instanceStates` /\n\t * `activeInstances` / `startedAt` for `status === \"running\"` records.\n\t * 3. On `COMPLETE` (all loads finished), flips `restoreState` to\n\t * `\"completed\"` — the watch valve opens, queued cqrs events become\n\t * deliverable, and any `firstWhere(restoreState …)` awaiter resolves.\n\t *\n\t * Idempotent: subsequent calls reuse the same subscription and resolve\n\t * on the same gate flip.\n\t */\n\tlet restoreSubscription: (() => void) | undefined;\n\n\tfunction startRestorePipeline(): void {\n\t\tif (restoreSubscription !== undefined) return;\n\t\tconst tier = stateStorageTiers[0];\n\t\tif (tier == null || tier.list == null || tier.load == null) {\n\t\t\t// No snapshot tier — flip immediately so watches can arm.\n\t\t\t// `restoreState` is a state node so write directly.\n\t\t\tif (!_disposed) restoreState.emit(\"completed\");\n\t\t\trestoreSubscription = () => undefined;\n\t\t\treturn;\n\t\t}\n\t\tconst tierLoad = tier.load.bind(tier);\n\t\tconst tierList = tier.list.bind(tier);\n\n\t\t// Reactive source chain. `tier.list()` and `tier.load(key)` are the\n\t\t// only async boundaries. Bridged via `fromAny`, which (post DS-13.5\n\t\t// follow-up, 2026-05-01) treats sync iterables as single DATA values\n\t\t// by default — `tier.list()`'s `readonly string[]` flows through as\n\t\t// ONE DATA carrying the whole list, not as a per-key stream. Sync\n\t\t// tier returns emit immediately at subscribe time; async tier\n\t\t// returns emit on resolve.\n\t\tconst listSource = fromAny<readonly string[]>(tierList());\n\t\tconst flattened = mergeMap(listSource, (keys: readonly string[]) => {\n\t\t\tif (keys.length === 0) {\n\t\t\t\t// fromIter([]) emits no DATA, only COMPLETE — which\n\t\t\t\t// propagates up through mergeMap so the effect sees its\n\t\t\t\t// own COMPLETE.\n\t\t\t\treturn fromIter<ProcessStateSnapshot<TState> | undefined>([]);\n\t\t\t}\n\t\t\t// Inner: per-key load via fromAny, flattened across keys.\n\t\t\t// Outer fromIter(keys) DOES want per-element emission here —\n\t\t\t// each key triggers a fresh load via mergeMap.\n\t\t\treturn mergeMap(\n\t\t\t\tfromIter(keys),\n\t\t\t\t(key: string) => fromAny(tierLoad(key)) as Node<ProcessStateSnapshot<TState> | undefined>,\n\t\t\t\t// Bound concurrent in-flight loads (D2, 2026-05-01) so a\n\t\t\t\t// large persisted-instance count doesn't exhaust file\n\t\t\t\t// handles / connection pools on the storage backend.\n\t\t\t\t{ concurrent: opts.restoreConcurrency ?? 8 },\n\t\t\t);\n\t\t});\n\n\t\t// Effect node: populate closure state on each load, flip the gate on\n\t\t// COMPLETE. Reactive — no awaits.\n\t\t//\n\t\t// Re-entrancy guard (A3, 2026-05-01): wrap the closure-mutation loop\n\t\t// + the gate flip in a single `batch()`. Without it, the synchronous\n\t\t// `restoreState.emit(\"completed\")` mid-fn-body would cascade through\n\t\t// gateOpen → valves → cqrs cursors → step dispatch BEFORE the\n\t\t// snapshot loop returns — external observers would see a half-\n\t\t// populated `instanceStates` map.\n\t\t//\n\t\t// Mid-iteration dispose hoisting (A4, 2026-05-01): the `_disposed`\n\t\t// check is hoisted to BEFORE the snapshot loop. The previous per-\n\t\t// snapshot check leaked state when `dispose()` fired between\n\t\t// snapshots N and N+1: snapshots 0..N populated `instanceStates`,\n\t\t// then dispose flipped `_disposed`, the terminalDeps branch\n\t\t// short-circuited the gate flip, and the cleanup path tore down the\n\t\t// watch valve — leaving orphan entries that subsequent `start()`\n\t\t// calls would treat as \"already active\" via `activeInstances.has`.\n\t\tconst restoreEffect = node(\n\t\t\t[flattened as Node],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tif (_disposed) return;\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst hasSnapshots = batch0 != null && batch0.length > 0;\n\t\t\t\tconst allDone = ctx.terminalDeps[0] === true;\n\t\t\t\tif (!hasSnapshots && !allDone) return;\n\t\t\t\tbatch(() => {\n\t\t\t\t\tif (hasSnapshots) {\n\t\t\t\t\t\tfor (const snap of batch0 as readonly (ProcessStateSnapshot<TState> | undefined)[]) {\n\t\t\t\t\t\t\tif (snap == null) continue;\n\t\t\t\t\t\t\tif (snap.status !== \"running\") continue;\n\t\t\t\t\t\t\tinstanceStates.set(snap.correlationId, snap.state);\n\t\t\t\t\t\t\tactiveInstances.add(snap.correlationId);\n\t\t\t\t\t\t\tstartedAt.set(snap.correlationId, snap.startedAt);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (allDone) restoreState.emit(\"completed\");\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ name: \"restoreEffect\", describeKind: \"effect\" },\n\t\t);\n\t\tsubgraph.add(restoreEffect, { name: \"restoreEffect\" });\n\t\trestoreSubscription = restoreEffect.subscribe(() => undefined);\n\t}\n\n\t/**\n\t * Trigger restoration (idempotent) and return a Promise that resolves\n\t * when `restoreState` transitions to `\"completed\"` OR when {@link dispose}\n\t * tears down the restore node (firstWhere's COMPLETE-rejection is\n\t * swallowed at the API edge so the caller's promise settles cleanly).\n\t */\n\tfunction restore(): Promise<void> {\n\t\tstartRestorePipeline();\n\t\tif (_disposed) return Promise.resolve();\n\t\tif (restoreState.cache === \"completed\") return Promise.resolve();\n\t\t// firstWhere is the canonical reactive→Promise bridge (spec §5.10);\n\t\t// async boundary lives at the public API edge, not in the graph.\n\t\t// .catch distinguishes the COMPLETE-without-match shape (which is\n\t\t// the dispose-tears-down case — swallow + resolve undefined) from\n\t\t// any other rejection (re-throw — caller sees a real failure).\n\t\treturn firstWhere(restoreState, (s) => s === \"completed\")\n\t\t\t.then(() => undefined)\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tif (err instanceof Error && err.message === \"completed without matching value\") {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t});\n\t}\n\n\tfunction dispose(): void {\n\t\tif (_disposed) return;\n\t\t_disposed = true;\n\t\t// Pending `firstWhere(restoreState, ...)` awaiters (i.e. a `restore()`\n\t\t// Promise still waiting on the gate flip) settle via the framework's\n\t\t// DS-13.5.A Q16 auto-precede rule: TEARDOWN delivery on a non-terminal\n\t\t// node automatically prepends [COMPLETE] in `_frameBatch`, so sinks\n\t\t// see [[COMPLETE], [TEARDOWN]] in order. firstWhere rejects on\n\t\t// COMPLETE-without-match; the .catch in `restore()` swallows that\n\t\t// rejection and the public Promise resolves cleanly.\n\t\t// Tear down the restore pipeline keepalive. fromAny.cleanup sets\n\t\t// `settled = true`, so when the underlying tier.list/load promises\n\t\t// finally resolve, the DATA never propagates — the closure mutations\n\t\t// in `restoreEffect` are never invoked (D5 belt + suspenders).\n\t\tif (restoreSubscription) {\n\t\t\ttry {\n\t\t\t\trestoreSubscription();\n\t\t\t} catch {\n\t\t\t\t// non-fatal\n\t\t\t}\n\t\t\trestoreSubscription = undefined;\n\t\t}\n\t\t// Release all watched-event subscriptions (C3 — watchDisposers leak fix).\n\t\tfor (const unsub of watchDisposers) {\n\t\t\ttry {\n\t\t\t\tunsub();\n\t\t\t} catch (_err) {\n\t\t\t\t// non-fatal: best-effort teardown\n\t\t\t}\n\t\t}\n\t\twatchDisposers.length = 0;\n\t\t// EH-16 (Tier 6.5 3.3): unmount the per-instance subgraph so the\n\t\t// audit log + seq cursor nodes are removed from the CQRS graph and\n\t\t// don't leak across repeated create/dispose cycles. `Graph.remove`\n\t\t// fires TEARDOWN through the subtree.\n\t\ttry {\n\t\t\tcqrsGraph.remove(mountName);\n\t\t} catch (_err) {\n\t\t\t// non-fatal: best-effort teardown (e.g. cqrsGraph already destroyed)\n\t\t}\n\t}\n\n\t// Auto-restore on construction unless explicitly deferred (B5).\n\tif (opts.deferRestore !== true) {\n\t\tstartRestorePipeline();\n\t}\n\n\treturn {\n\t\tinstances,\n\t\taudit: instances,\n\t\trestoreState,\n\t\tstart,\n\t\tcancel,\n\t\tgetState,\n\t\trestore,\n\t\tdispose,\n\t};\n}\n"],"mappings":"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","names":[]}
|