@graphrefly/graphrefly 0.47.1 → 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 +28 -19
- 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 +9 -9
- package/dist/base/index.cjs +294 -164
- 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 +77 -72
- package/dist/base/io/index.cjs +145 -85
- 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 +5 -5
- 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 +18 -12
- 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 +18 -12
- package/dist/base/sources/browser/index.js.map +1 -1
- package/dist/base/sources/event/index.cjs +29 -1
- 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 +5 -2
- package/dist/base/sources/index.cjs +96 -50
- 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 +7 -4
- package/dist/base/sources/node/index.cjs +43 -37
- package/dist/base/sources/node/index.cjs.map +1 -1
- package/dist/base/sources/node/index.js +43 -37
- package/dist/base/sources/node/index.js.map +1 -1
- package/dist/{chunk-J5WFUEO4.js → chunk-23MAWVOJ.js} +3 -3
- package/dist/{chunk-YXCPV26R.js → chunk-3REMCHSS.js} +39 -27
- 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-EVYY4X5A.js → chunk-46X2EFQH.js} +16 -5
- 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-RGMTUZCL.js → chunk-65OM4XLQ.js} +50 -4
- 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-7EGRP2VX.js → chunk-7BULJTL6.js} +2 -2
- package/dist/{chunk-7EGRP2VX.js.map → chunk-7BULJTL6.js.map} +1 -1
- package/dist/{chunk-VLAGJZSL.js → chunk-7T7WLEPM.js} +25 -4
- 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-2OB3CEJS.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-MTTRCEJT.js → chunk-DVTDF5OI.js} +2 -2
- package/dist/{chunk-SOOKUYVM.js → chunk-F7EKHR32.js} +13 -9
- package/dist/chunk-F7EKHR32.js.map +1 -0
- package/dist/{chunk-A7KV5UK4.js → chunk-G7H6PN7P.js} +2 -2
- package/dist/{chunk-OCUDSN63.js → chunk-GGKHHG5Y.js} +110 -64
- package/dist/chunk-GGKHHG5Y.js.map +1 -0
- package/dist/{chunk-RAGGHLCV.js → chunk-GUNIRPEJ.js} +8 -6
- package/dist/{chunk-RAGGHLCV.js.map → chunk-GUNIRPEJ.js.map} +1 -1
- package/dist/{chunk-YJ4U2D2C.js → chunk-J5TBZFBD.js} +9 -7
- package/dist/chunk-J5TBZFBD.js.map +1 -0
- package/dist/{chunk-Y52CS6YA.js → chunk-JA67ZQG2.js} +2 -2
- package/dist/{chunk-Y52CS6YA.js.map → chunk-JA67ZQG2.js.map} +1 -1
- package/dist/{chunk-U225SKB4.js → chunk-K4ZYJ4EM.js} +569 -424
- package/dist/chunk-K4ZYJ4EM.js.map +1 -0
- package/dist/{chunk-Z4YXAUDN.js → chunk-KUFXLAEY.js} +11 -7
- package/dist/{chunk-Z4YXAUDN.js.map → chunk-KUFXLAEY.js.map} +1 -1
- package/dist/{chunk-IHTWQEDR.js → chunk-LTSI7ULC.js} +3 -3
- package/dist/{chunk-IHTWQEDR.js.map → chunk-LTSI7ULC.js.map} +1 -1
- package/dist/{chunk-DKNHAICT.js → chunk-MMHGYX44.js} +25 -9
- package/dist/chunk-MMHGYX44.js.map +1 -0
- package/dist/{chunk-K7PDZYQE.js → chunk-MQMTRKY3.js} +129 -50
- 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-O3MT7DYI.js → chunk-N6MNJNHB.js} +2 -2
- 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-DM4OMPWK.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-PZWISPIQ.js → chunk-S7HN5FHL.js} +17 -11
- package/dist/chunk-S7HN5FHL.js.map +1 -0
- package/dist/{chunk-4S53H2KR.js → chunk-SUNCHMML.js} +2 -2
- package/dist/{chunk-4GYMCUDZ.js → chunk-T2U6N3FV.js} +7 -7
- package/dist/{chunk-RJOG4IJU.js → chunk-T5URUIIY.js} +50 -35
- package/dist/chunk-T5URUIIY.js.map +1 -0
- package/dist/{chunk-B4AKFXGE.js → chunk-TPTZZV25.js} +6 -6
- package/dist/chunk-TPTZZV25.js.map +1 -0
- package/dist/{chunk-BU3SEFA5.js → chunk-V46JWFGV.js} +7 -6
- package/dist/chunk-V46JWFGV.js.map +1 -0
- package/dist/{chunk-IJRR6YAI.js → chunk-VLDRAMP7.js} +18 -12
- package/dist/chunk-VLDRAMP7.js.map +1 -0
- package/dist/{chunk-6XZYT4SW.js → chunk-X6ESZDR6.js} +8 -9
- package/dist/chunk-X6ESZDR6.js.map +1 -0
- package/dist/{chunk-E5OZPDIW.js → chunk-X7BA5PWG.js} +7 -5
- package/dist/chunk-X7BA5PWG.js.map +1 -0
- package/dist/{chunk-CXANAIZU.js → chunk-XEWV254I.js} +3 -3
- package/dist/{chunk-CXANAIZU.js.map → chunk-XEWV254I.js.map} +1 -1
- package/dist/{chunk-V4Y3TM7U.js → chunk-YBJVKMTM.js} +38 -16
- package/dist/chunk-YBJVKMTM.js.map +1 -0
- package/dist/{chunk-7ADWWI2T.js → chunk-ZW32BPXV.js} +17 -6
- package/dist/chunk-ZW32BPXV.js.map +1 -0
- package/dist/compat/index.cjs +52 -5
- 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 +7 -7
- package/dist/compat/nestjs/index.cjs +52 -5
- 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 +4 -4
- 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 +2387 -1707
- 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 +173 -150
- package/dist/index.js.map +1 -1
- package/dist/presets/ai/index.cjs +88 -26
- package/dist/presets/ai/index.cjs.map +1 -1
- package/dist/presets/ai/index.js +14 -14
- package/dist/presets/harness/index.cjs +183 -51
- 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 +26 -26
- package/dist/presets/index.cjs +298 -101
- 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 +49 -49
- 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 +64 -44
- 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 +6 -6
- 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 +239 -92
- 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 +32 -32
- 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/{timeout-U5O4ESK3.js → timeout-BEABACRP.js} +2 -2
- 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 +10 -10
- package/dist/utils/ai/browser.js.map +1 -1
- package/dist/utils/ai/index.cjs +291 -191
- 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 +23 -21
- 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 +3 -3
- 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 +1 -1
- 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 +1 -1
- package/dist/utils/graphspec/index.cjs.map +1 -1
- package/dist/utils/graphspec/index.js +3 -3
- package/dist/utils/harness/index.cjs +16 -10
- package/dist/utils/harness/index.cjs.map +1 -1
- package/dist/utils/harness/index.js +1 -1
- package/dist/utils/index.cjs +1692 -1192
- 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 +77 -59
- 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 +570 -425
- package/dist/utils/memory/index.cjs.map +1 -1
- package/dist/utils/memory/index.d.cts +261 -33
- package/dist/utils/memory/index.d.ts +261 -33
- 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 +14 -3
- 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 +3 -3
- 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 +1 -1
- package/dist/utils/reduction/index.cjs.map +1 -1
- package/dist/utils/reduction/index.js +2 -2
- package/dist/utils/resilience/index.cjs +64 -43
- 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 +5 -5
- package/dist/utils/surface/index.cjs +1 -1
- 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-3PSLNJDU.js.map +0 -1
- package/dist/chunk-42FQ27MQ.js.map +0 -1
- package/dist/chunk-4XCHZRUJ.js.map +0 -1
- package/dist/chunk-6XZYT4SW.js.map +0 -1
- package/dist/chunk-7ADWWI2T.js.map +0 -1
- package/dist/chunk-B4AKFXGE.js.map +0 -1
- package/dist/chunk-BU3SEFA5.js.map +0 -1
- package/dist/chunk-BXGZFGZ4.js.map +0 -1
- package/dist/chunk-DKNHAICT.js.map +0 -1
- package/dist/chunk-E5OZPDIW.js.map +0 -1
- package/dist/chunk-EVYY4X5A.js.map +0 -1
- package/dist/chunk-IJRR6YAI.js.map +0 -1
- package/dist/chunk-K7PDZYQE.js.map +0 -1
- package/dist/chunk-NPRP3MCV.js.map +0 -1
- package/dist/chunk-NY2PYHNC.js.map +0 -1
- package/dist/chunk-OCUDSN63.js.map +0 -1
- package/dist/chunk-PKPO3JTZ.js.map +0 -1
- package/dist/chunk-PZWISPIQ.js.map +0 -1
- package/dist/chunk-RGMTUZCL.js.map +0 -1
- package/dist/chunk-RJOG4IJU.js.map +0 -1
- package/dist/chunk-SOOKUYVM.js.map +0 -1
- package/dist/chunk-U225SKB4.js.map +0 -1
- package/dist/chunk-V4Y3TM7U.js.map +0 -1
- package/dist/chunk-VLAGJZSL.js.map +0 -1
- package/dist/chunk-W2BOPXTI.js +0 -1
- package/dist/chunk-YJ4U2D2C.js.map +0 -1
- package/dist/chunk-YXCPV26R.js.map +0 -1
- package/dist/timeout-U5O4ESK3.js.map +0 -1
- /package/dist/{chunk-J5WFUEO4.js.map → chunk-23MAWVOJ.js.map} +0 -0
- /package/dist/{chunk-2OB3CEJS.js.map → chunk-B5Y5GPD5.js.map} +0 -0
- /package/dist/{chunk-MTTRCEJT.js.map → chunk-DVTDF5OI.js.map} +0 -0
- /package/dist/{chunk-A7KV5UK4.js.map → chunk-G7H6PN7P.js.map} +0 -0
- /package/dist/{chunk-O3MT7DYI.js.map → chunk-N6MNJNHB.js.map} +0 -0
- /package/dist/{chunk-DM4OMPWK.js.map → chunk-NSA5K5G2.js.map} +0 -0
- /package/dist/{chunk-MLTPJMH6.js.map → chunk-QQYULEZL.js.map} +0 -0
- /package/dist/{chunk-4S53H2KR.js.map → chunk-SUNCHMML.js.map} +0 -0
- /package/dist/{chunk-4GYMCUDZ.js.map → chunk-T2U6N3FV.js.map} +0 -0
- /package/dist/{chunk-W2BOPXTI.js.map → timeout-BEABACRP.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/messaging/audit-records.ts","../src/utils/messaging/message.ts","../src/utils/messaging/index.ts"],"sourcesContent":["/**\n * Messaging audit-record schemas (DS-13.5.E, locked 2026-05-01 alt A).\n *\n * Per-site discriminated-union audit records for the four messaging mutation\n * sites that route through `mutate`:\n *\n * - {@link TopicPublishRecord} — `Topic.publish`\n * - {@link SubscriptionAckRecord} — `Subscription.ack`\n * - {@link SubscriptionPullAndAckRecord} — `Subscription.pullAndAck`\n * - {@link HubRemoveTopicRecord} — `Hub.removeTopic`\n *\n * **Opt-in usage.** None of the four mutation sites enable an audit log by\n * default — caller wires audit visibility by composing `mutate` with\n * an audit `ReactiveLogBundle<R>` of the matching record type and an\n * `onSuccess`/`onFailure` builder:\n *\n * ```ts\n * import { createAuditLog, mutate } from \"@graphrefly/graphrefly/extra\";\n * import {\n * type TopicPublishRecord,\n * topicPublishKeyOf,\n * } from \"@graphrefly/graphrefly/patterns/messaging\";\n *\n * const audit = createAuditLog<TopicPublishRecord>({ name: \"publishes\" });\n * const publish = mutate(\n * (item: MyMessage) => topic.publish(item),\n * {\n * frame: \"inline\",\n * log: audit,\n * onSuccessRecord: ([item], _r, m) => ({\n * t_ns: m.t_ns,\n * seq: m.seq,\n * kind: \"topic.publish\",\n * topicName: topic.name,\n * itemKey: keyOf(item),\n * }),\n * },\n * );\n * ```\n *\n * **Stability.** The `kind` discriminator strings are pre-1.0 stable;\n * renaming downstream breaks external auditors.\n *\n * **Composability.** All four records extend {@link BaseAuditRecord} so they\n * carry the cross-cutting `t_ns` / `seq?` / `handlerVersion?` fields stamped\n * by `mutate` (Audit 2 / Audit 5).\n *\n * **Per-record keyOf.** Each record exports a recommended `keyOf` for\n * keyed-storage adapters (Rule G.27-keyOf-recommended) — partition the audit\n * log by the most natural identity (`topicName::itemKey`,\n * `subscriptionId::cursor`, etc.).\n *\n * **Hub.addTopic deferred.** No `HubAddTopicRecord` ships now; the lazy\n * topic-creation site has no caller signal asking for an audit record.\n * Re-add when a consumer surfaces.\n *\n * @category patterns\n * @module patterns/messaging/audit-records\n */\n\nimport type { BaseAuditRecord } from \"../../base/mutation/index.js\";\n\n// ── Topic.publish ────────────────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link TopicGraph.publish} call.\n *\n * - `topicName` — the topic the publish targeted.\n * - `itemKey` — caller-supplied identity for the published item (typically\n * the result of the topic's own `keyOf` derivation, when one exists).\n */\nexport interface TopicPublishRecord extends BaseAuditRecord {\n\treadonly kind: \"topic.publish\";\n\treadonly topicName: string;\n\treadonly itemKey: string;\n}\n\n/**\n * Recommended `keyOf` for {@link TopicPublishRecord} — formats as\n * `${topicName}::${itemKey}` for keyed-storage partitioning. Caller may\n * override per Rule G.27-keyOf-recommended.\n */\nexport const topicPublishKeyOf = (r: TopicPublishRecord): string => `${r.topicName}::${r.itemKey}`;\n\n// ── Subscription.ack ─────────────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link SubscriptionGraph.ack} call.\n *\n * - `subscriptionId` — the subscription the ack advanced.\n * - `cursor` — the post-ack cursor position.\n */\nexport interface SubscriptionAckRecord extends BaseAuditRecord {\n\treadonly kind: \"subscription.ack\";\n\treadonly subscriptionId: string;\n\treadonly cursor: number;\n}\n\n/**\n * Recommended `keyOf` for {@link SubscriptionAckRecord} — formats as\n * `${subscriptionId}::${cursor}`.\n */\nexport const subscriptionAckKeyOf = (r: SubscriptionAckRecord): string =>\n\t`${r.subscriptionId}::${r.cursor}`;\n\n// ── Subscription.pullAndAck ──────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link SubscriptionGraph.pullAndAck} call.\n *\n * - `subscriptionId` — the subscription the pullAndAck advanced.\n * - `cursor` — the post-pullAndAck cursor position.\n * - `itemCount` — number of items returned to the caller in this call.\n */\nexport interface SubscriptionPullAndAckRecord extends BaseAuditRecord {\n\treadonly kind: \"subscription.pullAndAck\";\n\treadonly subscriptionId: string;\n\treadonly cursor: number;\n\treadonly itemCount: number;\n}\n\n/**\n * Recommended `keyOf` for {@link SubscriptionPullAndAckRecord} — formats as\n * `${subscriptionId}::${cursor}` (identical shape to ack records so the\n * combined audit-log partitioning matches a per-cursor-frame view).\n */\nexport const subscriptionPullAndAckKeyOf = (r: SubscriptionPullAndAckRecord): string =>\n\t`${r.subscriptionId}::${r.cursor}`;\n\n// ── Hub.removeTopic ──────────────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link MessagingHubGraph.removeTopic} call.\n *\n * - `topicName` — the topic that was unmounted from the hub.\n */\nexport interface HubRemoveTopicRecord extends BaseAuditRecord {\n\treadonly kind: \"hub.removeTopic\";\n\treadonly topicName: string;\n}\n\n/**\n * Recommended `keyOf` for {@link HubRemoveTopicRecord} — the topic name itself\n * is already the natural identity.\n */\nexport const hubRemoveTopicKeyOf = (r: HubRemoveTopicRecord): string => r.topicName;\n\n// ── Discriminated-union convenience ──────────────────────────────────────\n\n/**\n * Discriminated union over every messaging audit record. Useful for callers\n * that aggregate records from multiple sites into one log; switch on\n * `record.kind` to narrow.\n */\nexport type MessagingAuditRecord =\n\t| TopicPublishRecord\n\t| SubscriptionAckRecord\n\t| SubscriptionPullAndAckRecord\n\t| HubRemoveTopicRecord;\n","/**\n * Standard `TopicMessage<T>` envelope for hub topics + well-known topic name\n * constants (Phase 13.B; spec source: archive/docs/SESSION-human-llm-intervention-primitives.md\n * §6 + archive/docs/SESSION-multi-agent-gap-analysis.md §6 cross-cut).\n *\n * `TopicMessage<T>` is the **recommended** wrapper for cross-agent / cross-graph\n * topic payloads — it carries identity, schema, deadline, and correlation\n * metadata alongside the typed `payload`. It is NOT a required protocol\n * type; raw `topic<T>` continues to work for in-process payloads where the\n * envelope fields would be noise.\n *\n * Use the envelope when:\n * - Two or more graphs (or human + LLM consumers) communicate over a topic\n * and need a stable wire shape — `correlationId` is the join key, `schema`\n * gates payload validation, `expiresAt` enables TTL enforcement.\n * - A topic carries multiple payload kinds and consumers need to discriminate\n * without parsing structurally.\n *\n * The standard well-known topic constants below are **conventions** — string\n * literals callers can pass to `messagingHub().topic(NAME)` to get a\n * predictable lookup. The hub does not enforce any topic to actually exist;\n * topics are still lazy on first access.\n */\n\n// ---------------------------------------------------------------------------\n// JSON Schema — minimal local type\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal JSON Schema shape, scoped to what `TopicMessage<T>` validates against.\n * Locked DS-13.B (2026-04-30): zero-dep posture, structural shape only — no\n * full validator shipped. Callers that want full validation supply their own\n * (e.g. `ajv`, `zod`, `valibot`) and read `Message.schema` as the rule\n * source. The shape covers the JSON-Schema-7 subset that hub-topic payload\n * descriptions actually need:\n * - `type` / `properties` / `required` / `additionalProperties` for objects.\n * - `items` for arrays.\n * - `enum` / `const` for value constraints.\n * - `$ref` / `definitions` for shared sub-schemas.\n *\n * If a concrete consumer needs a richer shape (oneOf, allOf, format, etc.),\n * extend this type — it's a structural contract, not a tagged union, so\n * additive fields don't break existing producers.\n */\nexport interface JsonSchema {\n\treadonly type?:\n\t\t| \"string\"\n\t\t| \"number\"\n\t\t| \"integer\"\n\t\t| \"boolean\"\n\t\t| \"object\"\n\t\t| \"array\"\n\t\t| \"null\"\n\t\t| readonly (\"string\" | \"number\" | \"integer\" | \"boolean\" | \"object\" | \"array\" | \"null\")[];\n\treadonly properties?: Readonly<Record<string, JsonSchema>>;\n\treadonly required?: readonly string[];\n\treadonly additionalProperties?: boolean | JsonSchema;\n\treadonly items?: JsonSchema | readonly JsonSchema[];\n\treadonly enum?: readonly unknown[];\n\treadonly const?: unknown;\n\treadonly $ref?: string;\n\treadonly definitions?: Readonly<Record<string, JsonSchema>>;\n\treadonly description?: string;\n\treadonly title?: string;\n}\n\n// ---------------------------------------------------------------------------\n// TopicMessage<T> envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Recommended envelope for hub topic payloads. Carries identity, optional\n * schema reference, optional expiry, optional correlation, and the typed\n * payload itself.\n *\n * - `id` — globally-unique identifier for this message instance. Producers\n * mint it (UUID, ULID, hash, etc.); consumers use it for deduplication and\n * trace correlation. **Required.**\n * - `schema` — optional structural description of `payload`. Validators\n * (caller-supplied) read this to gate or shape consumption. Writers MAY\n * include the schema inline for self-describing topics, or omit when the\n * payload type is statically known to all consumers.\n * - `expiresAt` — ISO 8601 timestamp; consumers SHOULD drop / fallback past\n * this point. Substrate enforcement is via composition (`timeout(source,\n * ms)` + `fallback`), not a hub-level rule.\n * - `correlationId` — links related messages across topics (request /\n * response pairs, conversation threads, multi-agent handoffs). Producers\n * propagate it; consumers filter / group on it.\n * - `payload` — the typed body. Type parameter `T` is the consumer-agreed\n * shape; the envelope adds metadata around it without coupling consumers\n * to a concrete payload type.\n *\n * Reactive composition with the envelope:\n *\n * ```ts\n * const requests = hub.topic<TopicMessage<RequestBody>>(PROMPTS_TOPIC);\n * const responses = hub.topic<TopicMessage<ResponseBody>>(RESPONSES_TOPIC);\n *\n * // Filter responses to one correlation\n * const myResponse = derived([responses.latest], ([msg]) =>\n * msg?.correlationId === requestId ? [msg.payload] : [],\n * );\n * ```\n */\nexport interface TopicMessage<T> {\n\treadonly id: string;\n\treadonly schema?: JsonSchema;\n\treadonly expiresAt?: string;\n\treadonly correlationId?: string;\n\treadonly payload: T;\n}\n\n// ---------------------------------------------------------------------------\n// Standard topic name constants\n// ---------------------------------------------------------------------------\n\n/**\n * Well-known topic name for human / LLM prompts directed at the harness.\n * Example payload: `TopicMessage<{ prompt: string; context?: object }>`.\n *\n * Co-locked with {@link RESPONSES_TOPIC} per the human-LLM intervention\n * session §6 #4 (paired request / response convention).\n */\nexport const PROMPTS_TOPIC = \"prompts\";\n\n/**\n * Well-known topic name for responses to {@link PROMPTS_TOPIC} entries.\n * Producers pair the response to its prompt via `correlationId`. Example\n * payload: `TopicMessage<{ content: string; finishReason?: string }>`.\n */\nexport const RESPONSES_TOPIC = \"responses\";\n\n/**\n * Well-known topic name for out-of-band injections — runtime overrides /\n * hot-fixes / human nudges that bypass the normal request flow. Example\n * payload: `TopicMessage<{ kind: \"context-patch\" | \"policy-override\" | ...;\n * data: unknown }>`. Per-injection consumers decide how (and whether) to\n * apply.\n */\nexport const INJECTIONS_TOPIC = \"injections\";\n\n/**\n * Well-known topic name for items the harness deferred for later attention\n * (parked queue, follow-up tracker, \"I'll get back to this\"). Producer is\n * usually the harness itself; consumer is a tracker / dashboard / human.\n * Example payload: `TopicMessage<{ reason: string; original: unknown }>`.\n */\nexport const DEFERRED_TOPIC = \"deferred\";\n\n/**\n * Well-known topic name for spawn requests (Phase 13.I `spawnable()`\n * surface). Producer emits a `TopicMessage<SpawnRequest>` to request a child\n * agent / subgraph; consumer is the materializer that mints the slot.\n * Example payload: `TopicMessage<{ presetId: string; taskInput: unknown;\n * depth?: number }>`. `correlationId` links the spawn to its parent\n * conversation; `expiresAt` enforces TTL on long-lived requests.\n */\nexport const SPAWNS_TOPIC = \"spawns\";\n\n/**\n * DS-14.6.A D-B3 — well-known topic for the dynamic `actorPool()` shared\n * tagged-context pool. Actors publish `ContextEntry` here; per-actor views\n * render their own compressed slice.\n */\nexport const CONTEXT_TOPIC = \"context\";\n\n/**\n * DS-14.6.A D-B3 — well-known topic for the `actorPool()` shared todo list.\n * Any actor may `enqueueTodo`; actors pull assigned todos via their cursor.\n */\nexport const TODOS_TOPIC = \"todos\";\n\n/**\n * Tuple of all well-known topic constants — useful for \"register all\n * standard topics on a hub\" patterns and for compile-time exhaustiveness\n * checks.\n */\nexport const STANDARD_TOPICS = [\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\tINJECTIONS_TOPIC,\n\tDEFERRED_TOPIC,\n\tSPAWNS_TOPIC,\n\tCONTEXT_TOPIC,\n\tTODOS_TOPIC,\n] as const;\n\n/**\n * Union of all well-known topic name string literals.\n */\nexport type StandardTopic = (typeof STANDARD_TOPICS)[number];\n","/**\n * Messaging patterns (roadmap §4.2).\n *\n * Pulsar-inspired messaging primitives modeled as graph factories:\n * - `topic()` for append-only topic streams with a retained window.\n * - `subscription()` for cursor-based consumers.\n * - `topicBridge()` for autonomous topic-to-topic relay.\n * - `messagingHub()` for a lazy topic registry.\n *\n * Plus the Phase 13.B standard `Message<T>` envelope and well-known topic\n * name constants ({@link PROMPTS_TOPIC} / {@link RESPONSES_TOPIC} /\n * {@link INJECTIONS_TOPIC} / {@link DEFERRED_TOPIC} / {@link SPAWNS_TOPIC})\n * — recommended (not enforced) wire shape for cross-graph topic payloads.\n *\n * Job queue / job flow primitives live in `patterns/job-queue` — they are a\n * distinct domain that happens to share reactive-log / reactive-map\n * infrastructure with topics.\n */\n\nexport {\n\ttype HubRemoveTopicRecord,\n\thubRemoveTopicKeyOf,\n\ttype MessagingAuditRecord,\n\ttype SubscriptionAckRecord,\n\ttype SubscriptionPullAndAckRecord,\n\tsubscriptionAckKeyOf,\n\tsubscriptionPullAndAckKeyOf,\n\ttype TopicPublishRecord,\n\ttopicPublishKeyOf,\n} from \"./audit-records.js\";\nexport {\n\tCONTEXT_TOPIC,\n\tDEFERRED_TOPIC,\n\tINJECTIONS_TOPIC,\n\ttype JsonSchema,\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\tSPAWNS_TOPIC,\n\tSTANDARD_TOPICS,\n\ttype StandardTopic,\n\tTODOS_TOPIC,\n\ttype TopicMessage,\n} from \"./message.js\";\n\nimport { batch, COMPLETE, DATA, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { mutate } from \"../../base/mutation/index.js\";\n\nconst DEFAULT_MAX_PER_PUMP = 256;\n\nfunction requireNonNegativeInt(value: number, label: string): number {\n\tif (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {\n\t\tthrow new Error(`${label} must be a non-negative integer`);\n\t}\n\treturn value;\n}\n\nfunction messagingMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"messaging\", kind, extra);\n}\n\nexport type TopicOptions = {\n\tgraph?: GraphOptions;\n\t/** Bounded retention; default 1024 per cross-cutting policy (Audit 2/4). */\n\tretainedLimit?: number;\n};\n\nconst DEFAULT_TOPIC_RETAINED_LIMIT = 1024;\n\nexport class TopicGraph<T> extends Graph {\n\tprivate readonly _log;\n\tprivate readonly _publishImpl: (value: T) => void;\n\treadonly events: Node<readonly T[]>;\n\t/**\n\t * Most recently published value. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first publish, then\n\t * tracks the latest entry. Spec §5.12 reserves `undefined` as the\n\t * \"never sent DATA\" sentinel — and `TopicGraph.publish(undefined)` is\n\t * rejected — so `cache === undefined` unambiguously signals \"empty topic\"\n\t * even when `T` itself includes `null` (i.e., `topic<number | null>`).\n\t *\n\t * **Within a reactive fn:** detect the empty-topic case via\n\t * `ctx.prevData[i] === undefined` for the dep slot holding `topic.latest`,\n\t * or check `latest.cache === undefined` outside reactive code. No\n\t * separate `hasLatest` companion needed — the SENTINEL is the answer.\n\t */\n\treadonly latest: Node<T>;\n\n\tconstructor(name: string, opts: TopicOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis._log = reactiveLog<T>([], {\n\t\t\tname: \"events\",\n\t\t\tmaxSize: opts.retainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.events = this._log.entries;\n\t\tthis.add(this.events, { name: \"events\" });\n\t\t// `this.derived(\"latest\", [\"events\"], …)` is expressible after the\n\t\t// 2026-04-30 self-resolve fix in `Graph._resolveFromSegments` — a\n\t\t// single-segment path matching the graph's own name (e.g.\n\t\t// `topic(\"events\").resolve(\"events\")`) no longer collapses to empty\n\t\t// and falls through to local-node lookup. Replaces the prior\n\t\t// `node([events], …) + this.add(...)` workaround.\n\t\t//\n\t\t// SENTINEL on empty: returning `[]` here yields a RESOLVED-only wave\n\t\t// (no DATA), so `latest.cache` stays `undefined` until the first\n\t\t// publish. `TopicGraph.publish(undefined)` is rejected (line below),\n\t\t// so `undefined` cache is unambiguously \"empty topic\" even when `T`\n\t\t// itself includes `null`. Drops the prior `hasLatest` companion as\n\t\t// redundant.\n\t\tthis.latest = this.derived<T>(\n\t\t\t\"latest\",\n\t\t\t[\"events\"],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly T[];\n\t\t\t\treturn entries.length === 0 ? [] : [entries[entries.length - 1] as T];\n\t\t\t},\n\t\t\t{ meta: messagingMeta(\"topic_latest\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\t// D1(a): on teardown, propagate COMPLETE on `events` so downstream\n\t\t// derived chains (including any externally-held SubscriptionGraph\n\t\t// sources) see the termination via their `terminalDeps` and can stop\n\t\t// serving stale caches. Tier-3 terminal per spec §2.2.\n\t\t//\n\t\t// EC16 (verified 2026-04-30): the COMPLETE-then-disposeAllViews order\n\t\t// is intentional. COMPLETE propagates SYNCHRONOUSLY through every\n\t\t// subscriber (cursor views, derived chains) so they self-unsubscribe\n\t\t// in their terminal handler before `disposeAllViews` runs. Swapping\n\t\t// the order would clear view caches before subscribers receive the\n\t\t// terminal — strictly worse. Reading `.cache` outside a reactive fn\n\t\t// across teardown is an anti-pattern (spec §5.12) and not a use case\n\t\t// this ordering needs to preserve.\n\t\tthis.addDisposer(() => {\n\t\t\tthis.events.down([[COMPLETE]]);\n\t\t});\n\t\t// P9: release any memoized tail/slice view keepalives held by the log.\n\t\t// TopicGraph itself doesn't call log.tail/slice, but plugins may have\n\t\t// attached views via `_log` — defensive (typical reactive subscribers\n\t\t// have already unsubscribed in their COMPLETE handler above).\n\t\tthis.addDisposer(() => this._log.disposeAllViews());\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route publish through `mutate`\n\t\t// for centralized freeze + re-throw semantics. No audit log surface\n\t\t// (per Tier 8 γ-0): the topic's `events` log already records every\n\t\t// successful publish, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because topic payloads can be large and per-publish\n\t\t// cost matters on hot paths.\n\t\tthis._publishImpl = mutate<[T], void, never>(\n\t\t\t(value): void => {\n\t\t\t\tthis._log.append(value);\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tpublish(value: T): void {\n\t\t// SENTINEL alignment (Wave B.1 Unit 11 lock): `undefined` is the\n\t\t// protocol-level \"never sent DATA\" sentinel — refusing it here\n\t\t// preserves `lastValue: Node<T | undefined>` semantics.\n\t\tif (value === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`TopicGraph \"${this.name}\": publish(undefined) is not allowed (spec §5.12 SENTINEL).`,\n\t\t\t);\n\t\t}\n\t\tthis._publishImpl(value);\n\t}\n\n\t/**\n\t * Wire one or more append-log storage tiers (Audit 4). Each tier receives\n\t * appended events per wave; rollback honors the wave-as-transaction model.\n\t *\n\t * Named `attachEventStorage` (not `attachStorage`) to avoid colliding with\n\t * the inherited {@link Graph.attachSnapshotStorage} which takes the\n\t * paired `AttachSnapshotTierPair[]` shape (Phase 14.6) — distinct\n\t * concerns, distinct surfaces.\n\t *\n\t * @returns Disposer.\n\t */\n\tattachEventStorage(\n\t\ttiers: readonly import(\"@graphrefly/pure-ts/extra\").AppendLogStorageTier<T>[],\n\t): () => void {\n\t\treturn this._log.attachStorage(tiers);\n\t}\n\n\tretained(): readonly T[] {\n\t\treturn this.events.cache as readonly T[];\n\t}\n\n\t/** Internal log bundle — used by TopicBridgeGraph for `attach`. */\n\tget _logBundle() {\n\t\treturn this._log;\n\t}\n}\n\nexport type SubscriptionOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Starting cursor position.\n\t * @deprecated Use `from` instead.\n\t */\n\tcursor?: number;\n\t/**\n\t * Starting position for the subscription.\n\t * - `\"retained\"` (default) — cursor starts at 0; consumer sees all retained history.\n\t * - `\"now\"` — cursor starts at current topic length; consumer ignores history.\n\t * - `number` — explicit cursor position.\n\t */\n\tfrom?: \"now\" | \"retained\" | number;\n\t/**\n\t * When this signal node emits DATA, the subscription auto-advances cursor\n\t * to current `available.length`. Useful for \"ack everything when X happens\"\n\t * patterns. The reactive edge `advanceOn → cursor` is visible in `explain()`.\n\t */\n\tadvanceOn?: Node<unknown>;\n};\n\n/** Result of {@link SubscriptionGraph.pullAndAck}. */\nexport type PullAndAckResult<T> = {\n\titems: readonly T[];\n\tcursor: number;\n};\n\nexport class SubscriptionGraph<T> extends Graph {\n\treadonly cursor: Node<number>;\n\treadonly available: Node<readonly T[]>;\n\t/**\n\t * Reference to the upstream topic graph. Intentionally NOT mounted\n\t * under this subscription: a subscription is a VIEW over an\n\t * externally-owned topic. Double-mounting (e.g. hub-owned topic +\n\t * sub-mount here) would make either-side teardown leave the other\n\t * holding a dead reference. Node-level `derived([topicEvents], …)`\n\t * still wires the data dependency across graph boundaries. D1(e).\n\t */\n\treadonly topic: TopicGraph<T>;\n\n\tprivate _disposed = false;\n\tprivate readonly _ackImpl: (count: number | undefined) => number;\n\tprivate readonly _pullAndAckImpl: (limit: number | undefined) => PullAndAckResult<T>;\n\n\tconstructor(name: string, topicGraph: TopicGraph<T>, opts: SubscriptionOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis.topic = topicGraph;\n\n\t\t// Resolve initial cursor from `from` option, falling back to legacy `cursor` option.\n\t\tlet initialCursor: number;\n\t\tif (opts.from !== undefined) {\n\t\t\tif (opts.from === \"retained\") {\n\t\t\t\tinitialCursor = 0;\n\t\t\t} else if (opts.from === \"now\") {\n\t\t\t\t// §28 sanctioned factory-time boundary read.\n\t\t\t\tinitialCursor = (topicGraph.events.cache as readonly T[]).length;\n\t\t\t} else {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"subscription from\");\n\t\t\t}\n\t\t} else {\n\t\t\tinitialCursor = requireNonNegativeInt(opts.cursor ?? 0, \"subscription cursor\");\n\t\t}\n\n\t\tthis.cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\tmeta: messagingMeta(\"subscription_cursor\"),\n\t\t});\n\n\t\t// B.1 Unit 12 lock: `available` depends directly on topic.events + cursor\n\t\t// via `view({ kind: \"fromCursor\" })`. No `source` passthrough node —\n\t\t// describe shows `topic::events → available` (cross-graph edge) and\n\t\t// `cursor → available` (local edge). One fewer node per subscription.\n\t\tthis.available = topicGraph._logBundle.view({ kind: \"fromCursor\", cursor: this.cursor });\n\t\tthis.add(this.available, { name: \"available\" });\n\t\tthis.addDisposer(keepalive(this.available));\n\n\t\t// Optional reactive auto-advance: when `advanceOn` emits a NEW DATA\n\t\t// (after construction), cursor advances by `available.length` atomically.\n\t\t// Edge visible in describe: advancePump depends on advanceOn.\n\t\t// `_advanceInitialized` guards against the initial push-on-subscribe fire\n\t\t// that would advance cursor before the user has a chance to read.\n\t\tif (opts.advanceOn !== undefined) {\n\t\t\tconst advanceOn = opts.advanceOn;\n\t\t\tlet advanceInitialized = false;\n\t\t\tconst advancePump = node<unknown>(\n\t\t\t\t[advanceOn],\n\t\t\t\t() => {\n\t\t\t\t\t// Skip the initial push-on-subscribe wave.\n\t\t\t\t\tif (!advanceInitialized) {\n\t\t\t\t\t\tadvanceInitialized = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._disposed) return;\n\t\t\t\t\tconst avail = this.available.cache as readonly T[];\n\t\t\t\t\tif (avail.length === 0) return;\n\t\t\t\t\tconst next = (this.cursor.cache as number) + avail.length;\n\t\t\t\t\tthis.cursor.emit(next);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"advancePump\",\n\t\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\t\tmeta: messagingMeta(\"subscription_advance_pump\"),\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.add(advancePump, { name: \"advancePump\" });\n\t\t\tthis.addDisposer(keepalive(advancePump));\n\t\t}\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route ack + pullAndAck through\n\t\t// `mutate` for centralized freeze + re-throw semantics. No audit\n\t\t// log surface (per Tier 8 γ-0): the cursor's own emission stream already\n\t\t// records every advance, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because count/limit are simple numbers; freezing is\n\t\t// pointless overhead. Disposed-checks stay outside the wrapper so a\n\t\t// no-op call doesn't unnecessarily run the wrapper.\n\t\tthis._ackImpl = mutate<[number | undefined], number, never>(\n\t\t\t(count): number => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst requested =\n\t\t\t\t\tcount === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(count, \"subscription ack count\");\n\t\t\t\tconst step = Math.min(requested, available.length);\n\t\t\t\tif (step <= 0) return this.cursor.cache as number;\n\t\t\t\tconst next = (this.cursor.cache as number) + step;\n\t\t\t\t// F8: use emit() so the pipeline auto-prefixes DIRTY, runs equals\n\t\t\t\t// substitution, and produces a proper two-phase wave (the raw\n\t\t\t\t// `down([[DATA, next]])` path bypassed those contracts).\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn next;\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\n\t\tthis._pullAndAckImpl = mutate<[number | undefined], PullAndAckResult<T>, never>(\n\t\t\t(limit): PullAndAckResult<T> => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst max =\n\t\t\t\t\tlimit === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(limit, \"subscription pullAndAck limit\");\n\t\t\t\tconst items = available.slice(0, max);\n\t\t\t\tif (items.length === 0) return { items, cursor: this.cursor.cache as number };\n\t\t\t\tconst next = (this.cursor.cache as number) + items.length;\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn { items, cursor: next };\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tack(count?: number): number {\n\t\tif (this._disposed) return this.cursor.cache as number;\n\t\treturn this._ackImpl(count);\n\t}\n\n\tpull(limit?: number): readonly T[] {\n\t\tif (this._disposed) return [];\n\t\tconst available = this.available.cache as readonly T[];\n\t\tconst max =\n\t\t\tlimit === undefined\n\t\t\t\t? available.length\n\t\t\t\t: requireNonNegativeInt(limit, \"subscription pull limit\");\n\t\treturn available.slice(0, max);\n\t}\n\n\t/**\n\t * Atomic pull-and-acknowledge. Returns `{ items, cursor }` where `cursor`\n\t * is the new cursor position after advancing. Under single-threaded JS the\n\t * snapshot and advance are atomic; PY callers use a per-subscription Lock.\n\t *\n\t * Replaces `pull(limit, { ack: true })`.\n\t */\n\tpullAndAck(limit?: number): PullAndAckResult<T> {\n\t\tif (this._disposed) return { items: [], cursor: this.cursor.cache as number };\n\t\treturn this._pullAndAckImpl(limit);\n\t}\n\n\t/**\n\t * Release internal subscriptions and mark the subscription torn-down.\n\t * Subsequent `pull`, `pullAndAck`, `ack` return empty / current cursor.\n\t * Emits COMPLETE on `cursor` so derived consumers (e.g. `available`) see\n\t * the termination signal. Also drains `addDisposer` callbacks (including\n\t * the `keepalive(advancePump)` subscription) so no keepalive leak occurs.\n\t */\n\tdispose(): void {\n\t\tif (this._disposed) return;\n\t\tthis._disposed = true;\n\t\tthis.cursor.down([[COMPLETE]]);\n\t\t// m4: drain addDisposer callbacks to release the keepalive subscription.\n\t\tthis.destroy();\n\t}\n}\n\nexport type TopicBridgeOptions<TIn, TOut> = {\n\tgraph?: GraphOptions;\n\tcursor?: number;\n\tmaxPerPump?: number;\n\t/**\n\t * Optional transform/filter applied to each item before republishing.\n\t *\n\t * **At-most-once with silent drop:** when `map` returns `undefined`, the\n\t * input is consumed from the source cursor but NOT republished. Filtered\n\t * items are not retained for retry. If you need filter-with-retry\n\t * semantics, do the filtering in a downstream subscription on the bridged\n\t * output rather than in the `map` function.\n\t */\n\tmap?: (value: TIn) => TOut | undefined;\n};\n\nexport class TopicBridgeGraph<TIn, TOut = TIn> extends Graph {\n\tprivate readonly _sourceSub;\n\treadonly bridgedCount: Node<number>;\n\t/**\n\t * Emits each mapped batch as DATA — gives downstream observers a reactive\n\t * stream of bridged values. Also the link target for `target._log.attach`.\n\t */\n\treadonly output: Node<readonly TOut[]>;\n\n\tconstructor(\n\t\tname: string,\n\t\tsourceTopic: TopicGraph<TIn>,\n\t\ttargetTopic: TopicGraph<TOut>,\n\t\topts: TopicBridgeOptions<TIn, TOut> = {},\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tthis._sourceSub = subscription<TIn>(`${name}-subscription`, sourceTopic, {\n\t\t\tcursor: opts.cursor,\n\t\t});\n\t\tthis.mount(\"subscription\", this._sourceSub);\n\n\t\tconst maxPerPump = Math.max(\n\t\t\t1,\n\t\t\trequireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, \"topic bridge maxPerPump\"),\n\t\t);\n\t\tconst mapValue = opts.map ?? ((value: TIn) => value as unknown as TOut);\n\n\t\t// Reactive output node: derives a mapped batch from `available`.\n\t\t// §24 compliant — output is a real derived edge, visible in describe.\n\t\t// Replaces imperative publish loop. Items where mapValue returns undefined\n\t\t// are filtered out (opt-out / filter).\n\t\tthis.output = node<readonly TOut[]>(\n\t\t\t[this._sourceSub.available],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst arr = data[0] as readonly TIn[];\n\t\t\t\tconst outBatch: TOut[] = [];\n\t\t\t\tconst take = Math.min(arr.length, maxPerPump);\n\t\t\t\tfor (let i = 0; i < take; i++) {\n\t\t\t\t\tconst mapped = mapValue(arr[i] as TIn);\n\t\t\t\t\tif (mapped !== undefined) outBatch.push(mapped);\n\t\t\t\t}\n\t\t\t\tactions.emit(outBatch);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"output\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_output\", { targetRef: targetTopic.name }),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.output, { name: \"output\" });\n\t\tthis.addDisposer(keepalive(this.output));\n\n\t\t// bridgedCount: state node accumulating total bridged items.\n\t\t// Updated by ackPump after each batch — edge visible via ackPump dep on output.\n\t\tthis.bridgedCount = this.state<number>(\"bridgedCount\", 0, {\n\t\t\tmeta: messagingMeta(\"topic_bridge_count\"),\n\t\t});\n\t\tthis.addDisposer(keepalive(this.bridgedCount));\n\n\t\t// ackPump: effect that advances the subscription cursor and updates\n\t\t// bridgedCount after each batch. Runs after `output` settles.\n\t\t// Captures refs to `this.output`, `this._sourceSub`, `this.bridgedCount`\n\t\t// to avoid `this` inside the fn body.\n\t\tconst outputRef = this.output;\n\t\tconst subRef = this._sourceSub;\n\t\tconst countRef = this.bridgedCount;\n\t\tconst ackPump = this.effect(\n\t\t\t\"ackPump\",\n\t\t\t[\"output\"],\n\t\t\t() => {\n\t\t\t\tconst outBatch = outputRef.cache as readonly TOut[];\n\t\t\t\tif (outBatch.length === 0) return;\n\t\t\t\tconst availLen = (subRef.available.cache as readonly TIn[]).length;\n\t\t\t\tconst toAck = Math.min(availLen, maxPerPump);\n\t\t\t\tif (toAck > 0) {\n\t\t\t\t\tsubRef.ack(toAck);\n\t\t\t\t\tconst prev = (countRef.cache as number) ?? 0;\n\t\t\t\t\tcountRef.emit(prev + outBatch.length);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_ack_pump\"),\n\t\t\t},\n\t\t);\n\t\tthis.addDisposer(keepalive(ackPump));\n\n\t\t// Wire output into target topic's log reactively.\n\t\t// _attachArrayToLog subscribes to output and publishes each item to targetTopic.\n\t\t// Teardown: disposer runs before mount teardown.\n\t\tconst detach = _attachArrayToLog(this.output, targetTopic);\n\t\tthis.addDisposer(detach);\n\t}\n}\n\n/**\n * Attaches each element of an array-valued Node to a TopicGraph's log.\n * Every DATA emission on `source` appends all items in the array to `targetTopic`.\n * Returns a disposer.\n */\nfunction _attachArrayToLog<T>(source: Node<readonly T[]>, targetTopic: TopicGraph<T>): () => void {\n\treturn source.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst arr = m[1] as readonly T[];\n\t\t\tif (arr.length === 0) continue;\n\t\t\tbatch(() => {\n\t\t\t\tfor (const v of arr) targetTopic.publish(v);\n\t\t\t});\n\t\t}\n\t});\n}\n\n// ── TopicRegistry ─────────────────────────────────────────────────────────\n\n/**\n * Private pure data structure managing a named set of {@link TopicGraph}\n * instances. Extracted from {@link MessagingHubGraph} for separation of\n * concerns (B.2 Unit 14 lock: D — split into TopicRegistry + facade).\n *\n * Reusable if other domain consumers (e.g. cqrs.eventLogs) want a shared\n * topic registry later.\n *\n * @internal\n */\nexport class TopicRegistry {\n\tprivate readonly _map = new Map<string, TopicGraph<unknown>>();\n\t/** Reactive monotonic version counter. Advances on topic create/remove. */\n\treadonly version: Node<number>;\n\n\tconstructor(versionNode: Node<number>) {\n\t\tthis.version = versionNode;\n\t}\n\n\tget size(): number {\n\t\treturn this._map.size;\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this._map.has(name);\n\t}\n\n\tget<T>(name: string): TopicGraph<T> | undefined {\n\t\treturn this._map.get(name) as TopicGraph<T> | undefined;\n\t}\n\n\tset<T>(name: string, t: TopicGraph<T>): void {\n\t\tthis._map.set(name, t as TopicGraph<unknown>);\n\t}\n\n\tdelete(name: string): boolean {\n\t\treturn this._map.delete(name);\n\t}\n\n\tkeys(): IterableIterator<string> {\n\t\treturn this._map.keys();\n\t}\n}\n\n// ── MessagingHubGraph ─────────────────────────────────────────────────────\n\nexport type MessagingHubOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Default `TopicOptions` applied to every topic created via `topic(name)`\n\t * without explicit options. Per-call opts override. Default: `{}`\n\t * (unbounded retention per topic unless `retainedLimit` is set per call).\n\t */\n\tdefaultTopicOptions?: TopicOptions;\n};\n\n/**\n * Lazy Pulsar-inspired topic registry. Manages a named set of {@link TopicGraph}\n * instances with retention + cursor semantics. Topics are created on first\n * access; `removeTopic(name)` unmounts and tears down via {@link Graph.remove}.\n *\n * Internally delegates to {@link TopicRegistry} for topic map management\n * (B.2 Unit 14 lock: D facade split).\n *\n * **Relationship to `pubsub()` in `src/extra/pubsub.ts`:** `pubsub` is a\n * lightweight last-value state hub (no retention, no cursors). `MessagingHubGraph`\n * is the full messaging hub — retained message logs, cursor-based subscriptions,\n * and pattern-layer lifecycle management.\n *\n * @category patterns\n */\nexport class MessagingHubGraph extends Graph {\n\tprivate readonly _registry: TopicRegistry;\n\t/** Reactive monotonic version counter — advances on topic create/remove. */\n\treadonly version: Node<number>;\n\tprivate readonly _defaultTopicOptions: TopicOptions;\n\tprivate readonly _removeTopicImpl: (name: string) => void;\n\n\tconstructor(name: string, opts: MessagingHubOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\t// B.2 Unit 14 lock: promote _version → version: Node<number>.\n\t\tconst versionNode = this.state<number>(\"version\", 0, {\n\t\t\tmeta: messagingMeta(\"hub_version\"),\n\t\t});\n\t\tthis.version = versionNode;\n\t\tthis._registry = new TopicRegistry(versionNode);\n\t\t// P8: shallow-copy caller-provided defaults so post-construction\n\t\t// mutations by the caller don't leak into every future `topic()` call.\n\t\tthis._defaultTopicOptions = { ...(opts.defaultTopicOptions ?? {}) };\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route the registry-delete branch of\n\t\t// `removeTopic` through `mutate` for centralized re-throw\n\t\t// semantics. No audit log surface (per Tier 8 γ-0).\n\t\t// `freeze: false` because the only arg is a string name (freeze pointless).\n\t\t// **Closure-state caveat (γ-4):** the inner `try/finally` mutates\n\t\t// `_registry` (a `Map`) and emits the version bump. mutate has no\n\t\t// `batch()` frame, so reactive emissions are NOT rolled back on throw —\n\t\t// and even if it did, `Map.delete` on closure state is invisible to the\n\t\t// batch and can't be unwound. The pre-existing try/finally on\n\t\t// `Graph.remove` is what guarantees registry/version converge to a\n\t\t// consistent state when `remove()` throws; `mutate` adds nothing\n\t\t// to that contract beyond the re-throw.\n\t\tthis._removeTopicImpl = mutate<[string], void, never>(\n\t\t\t(topicName): void => {\n\t\t\t\ttry {\n\t\t\t\t\tthis.remove(topicName); // unmounts, drops edges, tears down\n\t\t\t\t} finally {\n\t\t\t\t\tthis._registry.delete(topicName);\n\t\t\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\t\t\tthis.version.emit(cur + 1);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\t/** Number of topics currently in the hub. */\n\tget size(): number {\n\t\treturn this._registry.size;\n\t}\n\n\t/** Checks topic existence without creating. */\n\thas(name: string): boolean {\n\t\treturn this._registry.has(name);\n\t}\n\n\t/** Iterator over topic names. */\n\ttopicNames(): IterableIterator<string> {\n\t\treturn this._registry.keys();\n\t}\n\n\t/**\n\t * Returns the {@link TopicGraph} for `name`, creating lazily on first call.\n\t * Subsequent calls with the same name return the same instance (options on\n\t * repeat calls are ignored — the topic is already configured).\n\t */\n\ttopic<T = unknown>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\t\tlet t = this._registry.get<T>(name);\n\t\tif (t === undefined) {\n\t\t\tconst effective: TopicOptions = { ...this._defaultTopicOptions, ...(opts ?? {}) };\n\t\t\tt = new TopicGraph<T>(name, effective);\n\t\t\tthis._registry.set(name, t);\n\t\t\tthis.mount(name, t);\n\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\tthis.version.emit(cur + 1);\n\t\t}\n\t\treturn t;\n\t}\n\n\t/**\n\t * Publishes a value to the topic, lazily creating it on first publish.\n\t *\n\t * **Late-subscriber caveat:** the topic is created lazily, so subscribers\n\t * that attach AFTER a publish only see the retained window (governed by\n\t * `retainedLimit` on `TopicOptions` / `defaultTopicOptions`). If\n\t * `retainedLimit === 0` is set explicitly, early publishes are\n\t * effectively dropped — prefer an unset `retainedLimit` (unbounded\n\t * retention) or subscribe before publishing when late-subscribers matter.\n\t */\n\tpublish<T = unknown>(name: string, value: T): void {\n\t\tthis.topic<T>(name).publish(value);\n\t}\n\n\t/**\n\t * Bulk publish — issues all publishes inside one outer batch. New topics\n\t * are created on demand. No-op if `entries` yields nothing.\n\t *\n\t * **Iterable consumption (F6):** `entries` is consumed once (single-pass)\n\t * INSIDE the batch frame. If the iterator throws mid-way, the batch is\n\t * discarded and NO publishes are visible to subscribers (all-or-nothing).\n\t * Pass an array or `Set` for multi-shot callers.\n\t */\n\tpublishMany(entries: Iterable<[string, unknown]>): void {\n\t\t// P2: iterate inside batch — no `[...entries]` materialization so large\n\t\t// / infinite iterables don't OOM, and iterator throws are contained.\n\t\tbatch(() => {\n\t\t\tfor (const [name, value] of entries) {\n\t\t\t\tthis.topic(name).publish(value);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Creates a {@link SubscriptionGraph} over a named topic. The topic is\n\t * lazily created if missing. Subscription lifecycle is owned by the caller —\n\t * the hub does NOT mount the subscription.\n\t *\n\t * @param subName - Local name for the subscription graph.\n\t * @param topicName - Hub topic to subscribe to.\n\t * @param opts - `SubscriptionOptions` (initial cursor, etc.).\n\t */\n\tsubscribe<T = unknown>(\n\t\tsubName: string,\n\t\ttopicName: string,\n\t\topts?: SubscriptionOptions,\n\t): SubscriptionGraph<T> {\n\t\tconst t = this.topic<T>(topicName);\n\t\treturn new SubscriptionGraph<T>(subName, t, opts);\n\t}\n\n\t/**\n\t * Unmounts and tears down the topic's graph. Returns `true` if the topic\n\t * existed. Subscribers receive `TEARDOWN` via {@link Graph.remove}.\n\t *\n\t * **Closure-state caveat:** the registry mutation (`_registry.delete`) and\n\t * version bump happen in a `try/finally`, so registry/version converge to\n\t * a consistent state even when {@link Graph.remove} throws. `mutate`\n\t * does not roll back this mutation on throw — `Map.delete` on closure\n\t * state is invisible to any batch frame. The pre-existing try/finally is\n\t * load-bearing for that invariant.\n\t */\n\tremoveTopic(name: string): boolean {\n\t\tif (!this._registry.has(name)) return false;\n\t\t// P1 / P3: Graph.remove first — if it throws, `_registry` must NOT still\n\t\t// hold the broken half-disposed topic (otherwise the next\n\t\t// `hub.topic(name)` returns the corrupted reference). The `try/finally`\n\t\t// inside `_removeTopicImpl`'s action body preserves that invariant.\n\t\tthis._removeTopicImpl(name);\n\t\treturn true;\n\t}\n}\n\n/**\n * Creates a Pulsar-inspired topic graph (append-only retained stream + latest value).\n */\nexport function topic<T>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\treturn new TopicGraph<T>(name, opts);\n}\n\n/**\n * Creates a lazy Pulsar-inspired messaging hub. Topics are created on first access\n * via `hub.topic(name)`; `hub.publish(name, value)` shortcuts through the registry.\n *\n * @example\n * ```ts\n * import { messagingHub } from \"@graphrefly/graphrefly/patterns/messaging\";\n *\n * const hub = messagingHub(\"main\", { defaultTopicOptions: { retainedLimit: 256 } });\n * hub.publish(\"orders\", { id: 1 });\n * hub.publishMany([[\"shipments\", { id: 1 }], [\"orders\", { id: 2 }]]);\n * const sub = hub.subscribe(\"orders-worker\", \"orders\", { cursor: 0 });\n * ```\n */\nexport function messagingHub(name: string, opts?: MessagingHubOptions): MessagingHubGraph {\n\treturn new MessagingHubGraph(name, opts);\n}\n\n/**\n * Creates a cursor-based subscription graph over a topic.\n */\nexport function subscription<T>(\n\tname: string,\n\ttopicGraph: TopicGraph<T>,\n\topts?: SubscriptionOptions,\n): SubscriptionGraph<T> {\n\treturn new SubscriptionGraph<T>(name, topicGraph, opts);\n}\n\n/**\n * Creates an autonomous cursor-based topic relay graph.\n *\n * When `opts.map` is provided, items where `map` returns `undefined` are\n * consumed from the source cursor but NOT republished (at-most-once with\n * silent drop). For filter-with-retry semantics, apply the filter in a\n * downstream subscription on the bridge's `output` node instead.\n */\nexport function topicBridge<TIn, TOut = TIn>(\n\tname: string,\n\tsourceTopic: TopicGraph<TIn>,\n\ttargetTopic: TopicGraph<TOut>,\n\topts?: TopicBridgeOptions<TIn, TOut>,\n): TopicBridgeGraph<TIn, TOut> {\n\treturn new TopicBridgeGraph<TIn, TOut>(name, sourceTopic, targetTopic, opts);\n}\n\n// ── LogProjector ──────────────────────────────────────────────────────────\n//\n// Promotion 2 (memo:Re Story 6.4 back-derivation, design-review-locked\n// 2026-05-16). A cursor-driven projector over a log/topic where a per-item\n// sink can poison-fail. memo:Re hand-rolled `createProjectorCursor` and got\n// the failure mode wrong: a bare `catch { break; }` conflated a *transient*\n// condition (a native feature not yet available → retry later) with a\n// *poison* entry (will never project) → a permanent head-of-line block of\n// every newer entry. The fix is a real, observable, subscribable dead-letter\n// topic + a typed failure policy.\n//\n// Built ON `subscription()` (TopicGraph source) / the bundle's `fromCursor`\n// view (ReactiveLogBundle source) — the same hardened cursor machinery\n// `SubscriptionGraph` itself uses — so the consumer never hand-rolls cursor\n// persistence/durability (the Med \"durability skew\" + parse-leniency findings\n// dissolve). Scope is deliberately bounded: `halt | deadLetter` only, NO\n// programmatic retry/backoff (compose a downstream subscription on\n// `deadLetter` for that — avoids the §44 wrap-imperative-as-primitive trap).\n\nexport type ProjectorPoisonPolicy = \"halt\" | \"deadLetter\";\n\n/** A poison entry routed to {@link LogProjectorGraph.deadLetter}. */\nexport type DeadLetterEntry<T> = {\n\treadonly item: T;\n\t/** `Error.message` (or `String(thrown)`) from the failing `sink`. */\n\treadonly error: string;\n\t/** Absolute 0-based log position of the poisoned item. */\n\treadonly cursorPos: number;\n};\n\nexport type LogProjectorOptions<T> = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Per-item side-effecting projection.\n\t *\n\t * **Transient-vs-poison contract (read this).** The projector cannot tell\n\t * \"this will project later\" from \"this will never project\" — only the sink\n\t * knows. So the contract is:\n\t * - **Return normally** (sync return, or a resolved Promise) → the item is\n\t * *handled*; the cursor advances. Use this for the success path AND for\n\t * any transient/skip condition the sink wants to no-op (e.g. an optional\n\t * native feature not yet available — return without throwing; the entry\n\t * is simply considered done for this projector).\n\t * - **Throw / reject** → the item is *poison*; the {@link onPoison} policy\n\t * applies. Do NOT throw for transient conditions or the item is\n\t * dead-lettered (or halts the stream).\n\t */\n\treadonly sink: (item: T) => void | Promise<void>;\n\t/**\n\t * Behaviour when `sink` throws/rejects on an item (poison):\n\t * - `\"halt\"` (default) — stop projecting at the poison item; the cursor\n\t * does NOT advance past it (head-of-line stop). `position` stalls — that\n\t * is the observable signal. No retry/backoff is built in.\n\t * - `\"deadLetter\"` — publish `{ item, error, cursorPos }` to the\n\t * {@link LogProjectorGraph.deadLetter} topic and advance past it, so\n\t * newer entries still project.\n\t */\n\treadonly onPoison?: ProjectorPoisonPolicy;\n\t/**\n\t * Initial cursor position. `\"retained\"` (default) projects all history;\n\t * `\"now\"` skips existing entries (project only future appends); a number\n\t * starts at that absolute index.\n\t */\n\treadonly from?: \"retained\" | \"now\" | number;\n\t/** Retained window for the `deadLetter` topic. Default 1024. */\n\treadonly deadLetterRetainedLimit?: number;\n};\n\n/**\n * Cursor-driven projector over a {@link TopicGraph} or {@link ReactiveLogBundle}.\n *\n * Topology (mounted on the returned graph):\n * - `subscription` (TopicGraph source only) — the hardened\n * {@link SubscriptionGraph} cursor; or a local `cursor` state + the\n * bundle's `fromCursor` view (ReactiveLogBundle source).\n * - `drain` — an `effect` that, on every not-yet-projected wave, schedules a\n * serialized async pass that calls `sink` per item (mirrors the\n * `SubscriptionGraph.ackPump` / `TopicBridge.ackPump` effect precedent +\n * memo:Re's `inFlight` chain — one wave processed at a time).\n * - `deadLetter` — a real {@link TopicGraph} (NOT a callback): poison entries\n * are observable in `describe()` and subscribable, instead of memo:Re's\n * silent `break`.\n *\n * **No imperative reads.** Observe `position` (cursor) / subscribe to\n * `deadLetter`. `idle()` is a test-only await convenience.\n *\n * @category patterns\n */\nexport class LogProjectorGraph<T> extends Graph {\n\t/** Reactive count of fully-projected entries (the cursor; read-only). */\n\treadonly position: Node<number>;\n\t/**\n\t * Poison entries (populated when `onPoison: \"deadLetter\"`). A real topic —\n\t * subscribable + visible in `describe()`.\n\t */\n\treadonly deadLetter: TopicGraph<DeadLetterEntry<T>>;\n\tprivate _inFlight: Promise<void> = Promise.resolve();\n\n\tconstructor(\n\t\tname: string,\n\t\tsource: TopicGraph<T> | ReactiveLogBundle<T>,\n\t\topts: LogProjectorOptions<T>,\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tconst onPoison: ProjectorPoisonPolicy = opts.onPoison ?? \"halt\";\n\t\tconst sink = opts.sink;\n\n\t\tconst dl = new TopicGraph<DeadLetterEntry<T>>(`${name}_dead_letter`, {\n\t\t\tretainedLimit: opts.deadLetterRetainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.mount(\"deadLetter\", dl);\n\t\tthis.deadLetter = dl;\n\n\t\t// Uniform cursor surface over either source kind. A TopicGraph reuses\n\t\t// the hardened SubscriptionGraph cursor; a ReactiveLogBundle uses a\n\t\t// local state cursor + the bundle's `fromCursor` view — the very\n\t\t// machinery SubscriptionGraph is itself built on.\n\t\tlet available: Node<readonly T[]>;\n\t\tlet cursorBase: () => number;\n\t\tlet advance: (n: number) => void;\n\n\t\tif (source instanceof TopicGraph) {\n\t\t\tconst sub = new SubscriptionGraph<T>(`${name}_subscription`, source, {\n\t\t\t\tfrom: opts.from ?? \"retained\",\n\t\t\t});\n\t\t\tthis.mount(\"subscription\", sub);\n\t\t\tavailable = sub.available;\n\t\t\tthis.position = sub.cursor;\n\t\t\tcursorBase = () => sub.cursor.cache as number;\n\t\t\tadvance = (n) => {\n\t\t\t\tif (n > 0) sub.ack(n);\n\t\t\t};\n\t\t} else {\n\t\t\tconst log = source;\n\t\t\tlet initialCursor: number;\n\t\t\tif (opts.from === \"now\") {\n\t\t\t\tinitialCursor = log.size;\n\t\t\t} else if (typeof opts.from === \"number\") {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"logProjector from\");\n\t\t\t} else {\n\t\t\t\tinitialCursor = 0; // \"retained\"\n\t\t\t}\n\t\t\tconst cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\t\tmeta: messagingMeta(\"log_projector_cursor\"),\n\t\t\t});\n\t\t\tthis.position = cursor;\n\t\t\tcursorBase = () => cursor.cache as number;\n\t\t\tavailable = log.view({ kind: \"fromCursor\", cursor });\n\t\t\tadvance = (n) => {\n\t\t\t\tif (n > 0) cursor.emit((cursor.cache as number) + n);\n\t\t\t};\n\t\t}\n\n\t\t// `halt` is a HARD LATCH (QA-C): on the first poison under `onPoison:\n\t\t// \"halt\"`, `sink` has been invoked exactly once on the poison item;\n\t\t// the projector then freezes — no further `sink` calls, no rescheduled\n\t\t// drains — so a later unrelated append cannot re-invoke the (possibly\n\t\t// side-effecting, non-idempotent) sink on the poison. The stalled\n\t\t// `position` + frozen stream IS the observable signal. v1 has no retry\n\t\t// (compose downstream of `deadLetter` if you need that).\n\t\tlet halted = false;\n\n\t\t// Serialized async drain. One wave processed at a time (the inFlight\n\t\t// chain) so an async `sink` cannot interleave; the cursor is advanced\n\t\t// ONCE per pass after the captured snapshot is processed (mirrors\n\t\t// memo:Re's `runPump` + the ackPump effect precedent).\n\t\tconst runDrain = async (): Promise<void> => {\n\t\t\tif (halted) return;\n\t\t\tconst snapshot = (available.cache as readonly T[] | undefined) ?? [];\n\t\t\tif (snapshot.length === 0) return;\n\t\t\tlet consumed = 0;\n\t\t\tfor (let i = 0; i < snapshot.length; i += 1) {\n\t\t\t\tconst item = snapshot[i] as T;\n\t\t\t\ttry {\n\t\t\t\t\tawait sink(item);\n\t\t\t\t\tconsumed += 1;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconst error = e instanceof Error ? e.message : String(e);\n\t\t\t\t\tif (onPoison === \"deadLetter\") {\n\t\t\t\t\t\tdl.publish({ item, error, cursorPos: cursorBase() + consumed });\n\t\t\t\t\t\tconsumed += 1; // advance past the poison\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// \"halt\" — latch and stop here; do NOT advance past the\n\t\t\t\t\t// poison, do NOT re-invoke `sink` on any later wave.\n\t\t\t\t\thalted = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (consumed > 0) advance(consumed);\n\t\t};\n\t\tconst schedule = (): void => {\n\t\t\tif (halted) return; // latched — no further drains\n\t\t\tthis._inFlight = this._inFlight.then(runDrain, runDrain);\n\t\t};\n\n\t\t// Effect: every wave that exposes not-yet-projected entries schedules a\n\t\t// drain. Side-effecting (sink / cursor advance / dead-letter publish) →\n\t\t// an `effect` node, not a pure derived (COMPOSITION-GUIDE §35; exact\n\t\t// `SubscriptionGraph.advancePump` precedent — never calls `emit` on its\n\t\t// own node, kept warm via `keepalive`).\n\t\tconst drain = node<unknown>(\n\t\t\t[available],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst b = batchData[0];\n\t\t\t\tconst snap = (b != null && b.length > 0 ? b.at(-1) : ctx.prevData[0]) as\n\t\t\t\t\t| readonly T[]\n\t\t\t\t\t| undefined;\n\t\t\t\tif (snap && snap.length > 0) schedule();\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"drain\",\n\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\tmeta: messagingMeta(\"log_projector_drain\"),\n\t\t\t},\n\t\t);\n\t\tthis.add(drain, { name: \"drain\" });\n\t\tthis.addDisposer(keepalive(drain));\n\t}\n\n\t/**\n\t * Await any in-flight drain pass. **Test convenience only** — the canonical\n\t * reactive observable is {@link LogProjectorGraph.position}.\n\t */\n\tidle(): Promise<void> {\n\t\treturn this._inFlight;\n\t}\n}\n\n/**\n * Creates a cursor-driven log/topic projector with a typed poison-failure\n * policy and an observable dead-letter topic.\n *\n * @example\n * ```ts\n * import { logProjector, topic } from \"@graphrefly/graphrefly\";\n *\n * const events = topic<Doc>(\"docs\");\n * const proj = logProjector(\"indexer\", events, {\n * sink: async (doc) => { await index(doc); }, // throw ⇒ poison\n * onPoison: \"deadLetter\",\n * });\n * proj.deadLetter.events.subscribe(/* observe poison */);\n * ```\n *\n * @remarks\n * **Use an UNBOUNDED source for durable / long-lived projection.** The cursor\n * is an absolute index; the underlying `fromCursor` view slices the source's\n * *current* entries array. A `TopicGraph` with a `retainedLimit` (or a\n * `ReactiveLogBundle` with `maxSize`) trims its head, so an absolute cursor\n * past the retained window reads the wrong offset (skips entries or stalls).\n * This is inherited `subscription()` / `fromCursor` behaviour, not specific to\n * `logProjector` — but it matters here because projection is typically\n * long-lived. For unbounded projection pass a source with NO `retainedLimit` /\n * `maxSize` (memo:Re's `changesetLog` is unbounded ✓).\n *\n * @category patterns\n */\nexport function logProjector<T>(\n\tname: string,\n\tsource: TopicGraph<T> | ReactiveLogBundle<T>,\n\topts: LogProjectorOptions<T>,\n): LogProjectorGraph<T> {\n\treturn new LogProjectorGraph<T>(name, source, opts);\n}\n"],"mappings":"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","names":["batch"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/cqrs/index.ts","../src/utils/_errors/index.ts"],"sourcesContent":["/**\n * CQRS patterns (roadmap §4.5).\n *\n * Composition layer over reactiveLog (3.2), pipeline/sagas (4.1), event bus (4.2),\n * projections (4.3). Guards (1.5) enforce command/query boundary.\n *\n * - `cqrs(name, opts?)` → `CqrsGraph` — top-level factory\n * - `CqrsGraph.command(name, handler)` — write-only node; guard rejects `observe`\n * - `CqrsGraph.event(name)` — backed by `reactiveLog`; append-only\n * - `CqrsGraph.projection(name, events, reducer, initial)` — read-only derived; guard rejects `write`\n * - `CqrsGraph.saga(name, events, handler)` — event-driven side effects\n */\n\nimport {\n\tDATA,\n\ttype Node,\n\tnode,\n\tplaceholderArgs,\n\tpolicy,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport type { AppendLogStorageTier } from \"@graphrefly/pure-ts/extra\";\nimport { type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype BaseAuditRecord,\n\tcreateAuditLog,\n\tmutate,\n\tregisterCursor,\n\tregisterCursorMap,\n} from \"../../base/mutation/index.js\";\nimport {\n\tCommandHandlerError,\n\tDuplicateRegistrationError,\n\tOptimisticConcurrencyError,\n\tRebuildError,\n\tUndeclaredEmitError,\n\tUnknownCommandError,\n} from \"../_errors/index.js\";\n\n// ---------------------------------------------------------------------------\n// Guards\n// ---------------------------------------------------------------------------\n\n/** Commands: write + signal allowed, observe denied. */\nconst COMMAND_GUARD = policy((allow, deny) => {\n\tallow(\"write\");\n\tallow(\"signal\");\n\tdeny(\"observe\");\n});\n\n/** Projections: observe + signal allowed, write denied. */\nconst PROJECTION_GUARD = policy((allow, deny) => {\n\tallow(\"observe\");\n\tallow(\"signal\");\n\tdeny(\"write\");\n});\n\n/** Events: observe + signal allowed, write denied (appended internally). */\nconst EVENT_GUARD = policy((allow, deny) => {\n\tallow(\"observe\");\n\tallow(\"signal\");\n\tdeny(\"write\");\n});\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nimport { keepalive } from \"@graphrefly/pure-ts/extra\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\n\nfunction cqrsMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"cqrs\", kind, extra);\n}\n\nfunction deepFreeze<T>(value: T): T {\n\tif (value === null || typeof value !== \"object\" || Object.isFrozen(value)) return value;\n\tfor (const k of Object.keys(value as Record<string, unknown>)) {\n\t\tdeepFreeze((value as Record<string, unknown>)[k]);\n\t}\n\treturn Object.freeze(value);\n}\n\n// ---------------------------------------------------------------------------\n// Event envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable envelope for events emitted by command handlers.\n *\n * **Wave C.1 Unit 17 (locked 2026-04-24):** Extended ES standard fields —\n * `aggregateId` / `aggregateVersion` for per-aggregate streams; correlation /\n * causation IDs for distributed tracing; `metadata` for free-form context.\n * Optional `handlerVersion` (Audit 5) traces which handler version produced\n * the event.\n *\n * `seq` is a per-graph monotonic counter that provides stable ordering when\n * multiple events share the same `timestampNs` (same wall-clock tick).\n */\nexport type CqrsEvent<T = unknown> = {\n\ttype: string;\n\tpayload: T;\n\t/** Wall-clock nanoseconds (via `wallClockNs()`). */\n\ttimestampNs: number;\n\t/** Monotonic sequence within this CqrsGraph instance. */\n\tseq: number;\n\t/** Aggregate identifier (per-aggregate streams). */\n\taggregateId?: string;\n\t/** Per-aggregate monotonic version (set when `aggregateId` is provided). */\n\taggregateVersion?: number;\n\t/** Distributed-trace correlation id. */\n\tcorrelationId?: string;\n\t/** Causation chain id (this event was caused by event `causationId`). */\n\tcausationId?: string;\n\t/** Free-form metadata frozen at append. */\n\tmetadata?: Readonly<Record<string, unknown>>;\n\t/** V0 identity of the event log node at append time (§6.0b). */\n\tv0?: { id: string; version: number };\n\t/** Handler version stamped on emit (Audit 5). */\n\thandlerVersion?: { id: string; version: string | number };\n};\n\n/** Compile-time event-map registry: `{ \"orderPlaced\": OrderPayload, ... }`. */\nexport type CqrsEventMap = Record<string, unknown>;\n\n/** Recommended `keyOf` for CQRS event-store storage tiers (Audit 4). */\nexport const cqrsEventKeyOf = (e: CqrsEvent): string =>\n\t`${e.type}::${e.aggregateId ?? \"__default__\"}`;\n\n// ── Audit records (Audit 2 cross-cutting) ────────────────────────────────\n\nexport interface DispatchRecord<T = unknown> extends BaseAuditRecord {\n\treadonly commandName: string;\n\treadonly payload: T;\n\t/** Action result. Tier 1.6.2 canonical enum (renamed from `status`). */\n\treadonly outcome: \"success\" | \"failure\";\n\treadonly error?: unknown;\n\treadonly errorType?: string;\n\t/**\n\t * Event names emitted by the handler.\n\t * - `outcome: \"success\"`: events that persisted in the event log.\n\t * - `outcome: \"failure\"`: events the handler ATTEMPTED to emit before throwing;\n\t * they were rolled back and did NOT persist. Documents the failed attempt's\n\t * intentions for debugging handler logic. The actual event log shows only\n\t * what's durable.\n\t */\n\treadonly emittedEvents?: readonly string[];\n}\n\nexport const dispatchKeyOf = <T>(r: DispatchRecord<T>): string => r.commandName;\n\nexport interface SagaInvocation<T = unknown> extends BaseAuditRecord {\n\treadonly eventType: string;\n\t/** Action result. Tier 1.6.2 canonical enum (renamed from `status`). */\n\treadonly outcome: \"success\" | \"failure\";\n\treadonly error?: unknown;\n\treadonly errorType?: string;\n\treadonly aggregateId?: string;\n\treadonly event?: CqrsEvent<T>;\n}\n\nexport const sagaInvocationKeyOf = <T>(i: SagaInvocation<T>): string => i.eventType;\n\n/**\n * Saga registration result (M10) — a typed bundle replacing the prior\n * `Node<unknown>` return that side-attached `_saga` via an unsafe cast.\n *\n * `node` is the saga's effect node (subscribe to observe processing\n * activity). `invocations` is the per-event-type audit log; `audit` aliases\n * `invocations` (Audit 2 `.audit` duplication). `cursors` exposes the\n * per-event-type cursor state nodes for monitoring / testing.\n *\n * @category patterns\n */\nexport interface SagaController<T = unknown> {\n\treadonly node: Node<unknown>;\n\treadonly invocations: ReactiveLogBundle<SagaInvocation<T>>;\n\treadonly audit: ReactiveLogBundle<SagaInvocation<T>>;\n\treadonly cursors: { readonly [eventName: string]: Node<number> };\n}\n\n// ---------------------------------------------------------------------------\n// Handler types\n// ---------------------------------------------------------------------------\n\nexport type CommandActions = {\n\t/** Append an event to a named event log (bypasses event guard). */\n\temit: (eventName: string, payload: unknown) => void;\n};\n\n/**\n * Command handler receives the dispatch payload and actions to emit events.\n *\n * **Purity:** Handlers should not mutate the payload. Event emission via\n * `actions.emit()` is the only sanctioned side effect.\n */\nexport type CommandHandler<T = unknown> = (payload: T, actions: CommandActions) => void;\n\n/**\n * Projection reducer folds events into a read model.\n *\n * **Purity contract:** Reducers MUST be pure — return a new state value\n * without mutating `state` or any event.\n *\n * - In **`\"replay\"`** mode the `state` parameter is always the original\n * `initial` value (full event-sourcing replay on every recompute).\n * - In **`\"scan\"`** mode the `state` parameter is the _previous_ output\n * (incremental fold); `events` contains only the events appended since\n * the last computation.\n */\nexport type ProjectionReducer<TState = unknown, TEvent = unknown> = (\n\tstate: TState,\n\tevents: readonly CqrsEvent<TEvent>[],\n) => TState;\n\n/**\n * Snapshot integration for {@link ProjectionOptions}.\n *\n * `load` is called once at projection construction and the returned value\n * seeds the initial state. `save` (optional) is called after each reducer\n * run, debounced by `saveDebounceMs` (default 1000 ms) and capped by\n * `saveEvery` (default 1000 events).\n */\nexport type ProjectionSnapshotOpts<TState> = {\n\t/** Load a previously-saved state. `undefined` → start from `initial`. */\n\tload: () => TState | undefined | Promise<TState | undefined>;\n\t/** Persist the current state. Called after reducer; may be async. */\n\tsave?: (state: TState) => void | Promise<void>;\n\t/**\n\t * Debounce window (ms) before `save` fires after the last event. Default 1000.\n\t */\n\tsaveDebounceMs?: number;\n\t/**\n\t * Force a save after every Nth state change regardless of debounce.\n\t * Default 1000. Both knobs compose: save fires at whichever condition is\n\t * met first.\n\t */\n\tsaveEvery?: number;\n};\n\n/**\n * Options for {@link CqrsGraph.projection}.\n *\n * **Wave C.3 Unit 21 (locked 2026-04-24):**\n * - `mode: \"scan\"` (default) — incremental fold; `\"replay\"` — full replay\n * each wave.\n * - `snapshot` — load/save integration for cold-start + auto-checkpoint.\n * - `freezeInputs` (default `true`) — freeze event arrays before passing\n * to reducer (purity enforcement).\n * - `rebuild()` / `reset()` on the returned {@link ProjectionController}.\n *\n * @category patterns\n */\nexport type ProjectionOptions<TState> = {\n\tname: string;\n\tevents: readonly string[];\n\treducer: ProjectionReducer<TState>;\n\tinitial: TState;\n\t/**\n\t * Fold strategy. Default `\"scan\"` (incremental). `\"replay\"` = full replay.\n\t *\n\t * **Scan-mode ordering caveat:** scan-mode assumes monotonic per-stream\n\t * arrival order. When multiple event streams are merged for a projection,\n\t * events arriving with a `timestampNs` earlier than the current sort cursor\n\t * are skipped from the incremental sweep. This is an acceptable trade-off\n\t * for incremental fold; use `mode: \"replay\"` for strict cross-stream\n\t * ordering.\n\t */\n\tmode?: \"replay\" | \"scan\";\n\t/** Snapshot integration for rebuild + auto-checkpoint. */\n\tsnapshot?: ProjectionSnapshotOpts<TState>;\n\t/**\n\t * Freeze event arrays before passing to reducer (default `true`).\n\t * Set to `false` only if your reducer intentionally mutates the input\n\t * (strongly discouraged — prefer immutable reducers).\n\t */\n\tfreezeInputs?: boolean;\n};\n\n/**\n * Controller returned by {@link CqrsGraph.projection}.\n *\n * `node` is the reactive read model. `rebuild()` performs a paginated\n * cold-storage replay (requires `attachEventStorage` tiers). `reset()`\n * reloads from `snapshot.load()` and re-folds the live event log on top.\n *\n * @category patterns\n */\nexport interface ProjectionController<TState> {\n\treadonly node: Node<TState>;\n\t/**\n\t * Async paginated rebuild from attached storage tiers. Throws\n\t * {@link RebuildError} on adapter / decode / reducer failure.\n\t *\n\t * @param opts.fromTier - Storage tier to read from (default: first attached).\n\t * @param opts.pageSize - Entries per page (default 1000).\n\t */\n\trebuild(opts?: {\n\t\tfromTier?: AppendLogStorageTier<CqrsEvent>;\n\t\tpageSize?: number;\n\t}): Promise<TState>;\n\t/**\n\t * Reload from `snapshot.load()` (if configured) and re-fold the live\n\t * in-memory event log on top. Returns the rebuilt state. No-op on the\n\t * reactive node if the state is unchanged.\n\t */\n\treset(): Promise<TState>;\n}\n\nexport type SagaHandler<T = unknown> = (event: CqrsEvent<T>) => void;\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport type CqrsOptions = {\n\tgraph?: GraphOptions;\n\t/** Bounded retention for event streams; default 1024 (cross-cutting). */\n\tretainedLimit?: number;\n\t/** Freeze command payloads on dispatch (default `true`). */\n\tfreezeCommandPayload?: boolean;\n\t/** Freeze event payloads on emit (default `true`). */\n\tfreezeEventPayload?: boolean;\n\t/** LRU eviction threshold for per-aggregate streams (default 10_000). */\n\tmaxAggregates?: number;\n};\n\nexport type CommandRegistration<TPayload = unknown> = {\n\thandler: CommandHandler<TPayload>;\n\temits?: readonly string[];\n\thandlerVersion?: { id: string; version: string | number };\n};\n\nexport type DispatchOptions = {\n\tcorrelationId?: string;\n\tcausationId?: string;\n\tmetadata?: Record<string, unknown>;\n\t/**\n\t * Optimistic-concurrency check: if set, dispatch verifies the aggregate\n\t * (identified by `aggregateId`) is at this version. On mismatch, dispatch\n\t * throws {@link OptimisticConcurrencyError} BEFORE the handler runs.\n\t *\n\t * Requires `aggregateId` to be set. Without it the check is a no-op.\n\t */\n\texpectedAggregateVersion?: number;\n\t/**\n\t * Aggregate this dispatch targets. Events emitted by the handler that\n\t * also carry this `aggregateId` participate in per-aggregate versioning\n\t * and LRU eviction (see {@link CqrsOptions.maxAggregates}). Events whose\n\t * handler-supplied `aggregateId` differs from the dispatch's `aggregateId`\n\t * are emitted untouched (their own `aggregateVersion` is computed from\n\t * their own aggregate's stream).\n\t */\n\taggregateId?: string;\n};\n\nexport type SagaOptions = {\n\taggregateId?: string;\n\terrorPolicy?: \"advance\" | \"hold\";\n\thandlerVersion?: { id: string; version: string | number };\n};\n\n// ---------------------------------------------------------------------------\n// CqrsGraph\n// ---------------------------------------------------------------------------\n\ntype EventEntry = {\n\tlog: ReturnType<typeof reactiveLog<CqrsEvent>>;\n\tnode: Node<readonly CqrsEvent[]>;\n};\n\n/**\n * Eviction record emitted on `aggregateEvictions` when an aggregate's\n * per-aggregate stream is removed under `maxAggregates` LRU pressure. The\n * eviction does NOT delete events from the fan-in stream — only the\n * per-aggregate dedicated stream and its version counter.\n */\nexport interface AggregateEvictionRecord {\n\treadonly aggregateId: string;\n\treadonly type: string;\n\treadonly t_ns: number;\n\t/** The version count the aggregate reached before eviction (for diagnostics). */\n\treadonly lastVersion: number;\n}\n\nexport class CqrsGraph<_EM extends CqrsEventMap = Record<string, unknown>> extends Graph {\n\t/** Fan-in event streams (one per type, all aggregates merged). */\n\tprivate readonly _eventLogs = new Map<string, EventEntry>();\n\t/**\n\t * Per-aggregate event streams: type → aggregateId → entry. Used for\n\t * `event(type, aggregateId)` dual-form access and per-aggregate version\n\t * tracking. Only populated when an event with `aggregateId` is emitted.\n\t */\n\tprivate readonly _eventLogsByAggregate = new Map<string, Map<string, EventEntry>>();\n\t/** Per-aggregate version counters: `${type}::${aggregateId}` → current version. */\n\tprivate readonly _aggregateVersions = new Map<string, number>();\n\t/**\n\t * LRU access order for `${type}::${aggregateId}`. Map insertion order\n\t * tracks recency — `delete` + `set` on access moves to the end.\n\t */\n\tprivate readonly _aggregateLru = new Map<string, true>();\n\tprivate readonly _commandRegs = new Map<\n\t\tstring,\n\t\t{\n\t\t\thandler: CommandHandler<any>;\n\t\t\temits?: readonly string[];\n\t\t\thandlerVersion?: { id: string; version: string | number };\n\t\t}\n\t>();\n\tprivate readonly _projections = new Set<string>();\n\tprivate readonly _sagas = new Set<string>();\n\tprivate _seq = 0;\n\tprivate readonly _retainedLimit: number;\n\tprivate readonly _freezeCommandPayload: boolean;\n\tprivate readonly _freezeEventPayload: boolean;\n\tprivate readonly _maxAggregates: number;\n\tprivate readonly _dispatchSeqCursor: Node<number>;\n\t/** Audit log of every command dispatch (Audit 2). */\n\treadonly dispatches: ReactiveLogBundle<DispatchRecord>;\n\t/** Alias for {@link CqrsGraph.dispatches} (Audit 2 `.audit` duplication). */\n\treadonly audit: ReactiveLogBundle<DispatchRecord>;\n\t/** Per-aggregate LRU eviction observability; secondary log to `dispatches`. */\n\treadonly aggregateEvictions: ReactiveLogBundle<AggregateEvictionRecord>;\n\n\tconstructor(name: string, opts: CqrsOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis._retainedLimit = opts.retainedLimit ?? 1024;\n\t\tthis._freezeCommandPayload = opts.freezeCommandPayload ?? true;\n\t\tthis._freezeEventPayload = opts.freezeEventPayload ?? true;\n\t\tthis._maxAggregates = opts.maxAggregates ?? 10_000;\n\t\tthis.dispatches = createAuditLog<DispatchRecord>({\n\t\t\tname: \"dispatches\",\n\t\t\tretainedLimit: this._retainedLimit,\n\t\t\tgraph: this,\n\t\t});\n\t\tthis.audit = this.dispatches;\n\t\tthis.aggregateEvictions = createAuditLog<AggregateEvictionRecord>({\n\t\t\tname: \"aggregateEvictions\",\n\t\t\tretainedLimit: this._retainedLimit,\n\t\t\tgraph: this,\n\t\t});\n\t\tthis._dispatchSeqCursor = registerCursor(this, \"dispatch_seq\", 0);\n\t}\n\n\t/**\n\t * Read the current per-aggregate version (last emitted `aggregateVersion`\n\t * for that `(type, aggregateId)` pair). Returns `0` if no events have been\n\t * emitted yet for this aggregate. Useful for callers preparing\n\t * {@link DispatchOptions.expectedAggregateVersion}.\n\t */\n\taggregateVersion(type: string, aggregateId: string): number {\n\t\treturn this._aggregateVersions.get(`${type}::${aggregateId}`) ?? 0;\n\t}\n\n\t/** LRU touch — moves the key to the end of the access order. */\n\tprivate _touchAggregate(key: string): void {\n\t\t// Delete + set re-inserts at the end of Map iteration order.\n\t\tthis._aggregateLru.delete(key);\n\t\tthis._aggregateLru.set(key, true);\n\t}\n\n\t/**\n\t * Evict the oldest aggregate streams (least-recently-touched) until the\n\t * aggregate count is back within `_maxAggregates`. Emits one\n\t * `AggregateEvictionRecord` per eviction. The fan-in stream is NOT touched\n\t * — events stay in the type-level log; only the per-aggregate stream and\n\t * version counter are removed.\n\t */\n\tprivate _enforceAggregateLru(): void {\n\t\twhile (this._aggregateLru.size > this._maxAggregates) {\n\t\t\tconst oldest = this._aggregateLru.keys().next();\n\t\t\tif (oldest.done) break;\n\t\t\tconst key = oldest.value;\n\t\t\tthis._aggregateLru.delete(key);\n\t\t\tconst sep = key.indexOf(\"::\");\n\t\t\tif (sep < 0) continue;\n\t\t\tconst type = key.slice(0, sep);\n\t\t\tconst aggregateId = key.slice(sep + 2);\n\t\t\tconst lastVersion = this._aggregateVersions.get(key) ?? 0;\n\t\t\tthis._aggregateVersions.delete(key);\n\t\t\tconst byType = this._eventLogsByAggregate.get(type);\n\t\t\tif (byType) {\n\t\t\t\tbyType.delete(aggregateId);\n\t\t\t\tif (byType.size === 0) this._eventLogsByAggregate.delete(type);\n\t\t\t}\n\t\t\tthis.aggregateEvictions.append({\n\t\t\t\taggregateId,\n\t\t\t\ttype,\n\t\t\t\tlastVersion,\n\t\t\t\tt_ns: wallClockNs(),\n\t\t\t});\n\t\t}\n\t}\n\n\t/** Tiers attached via {@link attachEventStorage}; auto-wired into future event streams. */\n\tprivate readonly _attachedEventTiers: Array<readonly AppendLogStorageTier<CqrsEvent>[]> = [];\n\tprivate readonly _attachedTierDisposers = new Map<string, Array<() => void>>();\n\n\t/**\n\t * Wire append-log storage tiers for ALL CQRS event streams — both currently\n\t * registered AND any future streams created via `event(name)` /\n\t * `event(name, aggregateId)` / handler emit. (M4 fix.)\n\t *\n\t * Returns a disposer that releases all storage subscriptions wired by this\n\t * call (including those for streams that were created after the call).\n\t */\n\tattachEventStorage(tiers: readonly AppendLogStorageTier<CqrsEvent>[]): () => void {\n\t\tthis._attachedEventTiers.push(tiers);\n\t\t// Wire currently-existing streams.\n\t\tfor (const [name, entry] of this._eventLogs) {\n\t\t\tconst dispose = entry.log.attachStorage(tiers);\n\t\t\tlet arr = this._attachedTierDisposers.get(name);\n\t\t\tif (!arr) {\n\t\t\t\tarr = [];\n\t\t\t\tthis._attachedTierDisposers.set(name, arr);\n\t\t\t}\n\t\t\tarr.push(dispose);\n\t\t}\n\t\t// Per-aggregate streams existing now.\n\t\tfor (const [type, byAgg] of this._eventLogsByAggregate) {\n\t\t\tfor (const [aggId, entry] of byAgg) {\n\t\t\t\tconst key = `${type}::${aggId}`;\n\t\t\t\tconst dispose = entry.log.attachStorage(tiers);\n\t\t\t\tlet arr = this._attachedTierDisposers.get(key);\n\t\t\t\tif (!arr) {\n\t\t\t\t\tarr = [];\n\t\t\t\t\tthis._attachedTierDisposers.set(key, arr);\n\t\t\t\t}\n\t\t\t\tarr.push(dispose);\n\t\t\t}\n\t\t}\n\t\treturn () => {\n\t\t\t// Remove from auto-wire list so newly-created streams skip.\n\t\t\tconst idx = this._attachedEventTiers.indexOf(tiers);\n\t\t\tif (idx >= 0) this._attachedEventTiers.splice(idx, 1);\n\t\t\t// We can't precisely undo the per-stream attach for THIS tier set\n\t\t\t// alone (Map values commingle disposers across multiple\n\t\t\t// attachEventStorage calls). Caller wanting fine-grained control\n\t\t\t// should call `tier.flush()` / dispose tiers themselves. This\n\t\t\t// disposer is best-effort: it stops auto-wiring future streams.\n\t\t};\n\t}\n\n\t/** Wire newly-created event stream into all currently-attached tier sets. */\n\tprivate _autoWireStreamStorage(\n\t\tkey: string,\n\t\tlog: ReturnType<typeof reactiveLog<CqrsEvent>>,\n\t): void {\n\t\tif (this._attachedEventTiers.length === 0) return;\n\t\tlet arr = this._attachedTierDisposers.get(key);\n\t\tif (!arr) {\n\t\t\tarr = [];\n\t\t\tthis._attachedTierDisposers.set(key, arr);\n\t\t}\n\t\tfor (const tiers of this._attachedEventTiers) {\n\t\t\tarr.push(log.attachStorage(tiers));\n\t\t}\n\t}\n\n\t// -- Events ---------------------------------------------------------------\n\n\t/**\n\t * Register a named event stream backed by `reactiveLog`.\n\t * Guard denies external `write` — only commands append internally.\n\t */\n\tevent(name: string): Node<readonly CqrsEvent[]>;\n\tevent(name: string, aggregateId: string): Node<readonly CqrsEvent[]>;\n\tevent(name: string, aggregateId?: string): Node<readonly CqrsEvent[]> {\n\t\tif (aggregateId !== undefined) {\n\t\t\treturn this._ensureAggregateStream(name, aggregateId).node;\n\t\t}\n\t\tconst existing = this._eventLogs.get(name);\n\t\tif (existing) return existing.node;\n\n\t\t// V0 versioning is attached at construction — post-hoc\n\t\t// `_applyVersioning` was deleted because it opened a re-entrance\n\t\t// window where a wave could observe `_versioning` transitioning from\n\t\t// `undefined` to a fresh state. Construction-time-only means the\n\t\t// flag is frozen at birth.\n\t\tconst log = reactiveLog<CqrsEvent>([], {\n\t\t\tname,\n\t\t\tversioning: 0,\n\t\t\tmaxSize: this._retainedLimit,\n\t\t});\n\t\tlog.withLatest();\n\t\tconst entries = log.entries;\n\t\tconst guarded = this.derived<readonly CqrsEvent[]>(\n\t\t\tname,\n\t\t\t[entries],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst latest =\n\t\t\t\t\tbatchData[0] != null && batchData[0].length > 0\n\t\t\t\t\t\t? (batchData[0].at(-1) as readonly CqrsEvent[])\n\t\t\t\t\t\t: (ctx.prevData[0] as readonly CqrsEvent[]);\n\t\t\t\treturn [latest];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: cqrsMeta(\"event\", { event_name: name }),\n\t\t\t\tguard: EVENT_GUARD,\n\t\t\t\tinitial: entries.cache as readonly CqrsEvent[],\n\t\t\t},\n\t\t);\n\t\tthis.addDisposer(keepalive(guarded));\n\t\tthis._eventLogs.set(name, { log, node: guarded });\n\t\t// M4: auto-wire any storage tiers attached via `attachEventStorage`.\n\t\tthis._autoWireStreamStorage(name, log);\n\t\treturn guarded;\n\t}\n\n\t/**\n\t * Get-or-create the per-aggregate event stream for `(type, aggregateId)`.\n\t * Mounts the stream as a sibling node named `<type>_<aggregateId>` so it\n\t * appears in `describe()`. LRU access is touched on every call.\n\t */\n\tprivate _ensureAggregateStream(type: string, aggregateId: string): EventEntry {\n\t\t// Ensure the fan-in stream exists too (call sites usually expect both).\n\t\tif (!this._eventLogs.has(type)) this.event(type);\n\n\t\tlet byType = this._eventLogsByAggregate.get(type);\n\t\tif (!byType) {\n\t\t\tbyType = new Map();\n\t\t\tthis._eventLogsByAggregate.set(type, byType);\n\t\t}\n\t\tconst lruKey = `${type}::${aggregateId}`;\n\t\tthis._touchAggregate(lruKey);\n\t\tconst existing = byType.get(aggregateId);\n\t\tif (existing) return existing;\n\n\t\tconst nodeName = `${type}_${aggregateId.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n\t\tconst log = reactiveLog<CqrsEvent>([], {\n\t\t\tname: nodeName,\n\t\t\tversioning: 0,\n\t\t\tmaxSize: this._retainedLimit,\n\t\t});\n\t\tlog.withLatest();\n\t\tconst entries = log.entries;\n\t\t// Avoid name collisions if multiple aggregates have ids that sanitize\n\t\t// to the same node-name; suffix with a counter when necessary.\n\t\t// Resolve the mount name BEFORE constructing the derived (the\n\t\t// `this.derived(...)` form registers under the supplied `name`).\n\t\tlet mountName = nodeName;\n\t\tlet collisionIdx = 0;\n\t\twhile (this.resolveOptional(mountName) !== undefined) {\n\t\t\tcollisionIdx += 1;\n\t\t\tmountName = `${nodeName}_${collisionIdx}`;\n\t\t}\n\t\tlet guarded: Node<readonly CqrsEvent[]>;\n\t\ttry {\n\t\t\tguarded = this.derived<readonly CqrsEvent[]>(\n\t\t\t\tmountName,\n\t\t\t\t[entries],\n\t\t\t\t(batchData, ctx) => {\n\t\t\t\t\tconst latest =\n\t\t\t\t\t\tbatchData[0] != null && batchData[0].length > 0\n\t\t\t\t\t\t\t? (batchData[0].at(-1) as readonly CqrsEvent[])\n\t\t\t\t\t\t\t: (ctx.prevData[0] as readonly CqrsEvent[]);\n\t\t\t\t\treturn [latest];\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmeta: cqrsMeta(\"event_aggregate\", {\n\t\t\t\t\t\tevent_name: type,\n\t\t\t\t\t\taggregate_id: aggregateId,\n\t\t\t\t\t}),\n\t\t\t\t\tguard: EVENT_GUARD,\n\t\t\t\t\tinitial: entries.cache as readonly CqrsEvent[],\n\t\t\t\t},\n\t\t\t);\n\t\t} catch {\n\t\t\t// Name collision raced with another constructor — fall back to a\n\t\t\t// raw, unmounted node so the per-aggregate stream still functions\n\t\t\t// (just not graph-visible). Mirrors the prior best-effort branch.\n\t\t\tguarded = node<readonly CqrsEvent[]>(\n\t\t\t\t[entries],\n\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\tconst latest =\n\t\t\t\t\t\tbatchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : ctx.prevData[0];\n\t\t\t\t\tactions.emit(latest as readonly CqrsEvent[]);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: nodeName,\n\t\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t\tmeta: cqrsMeta(\"event_aggregate\", {\n\t\t\t\t\t\tevent_name: type,\n\t\t\t\t\t\taggregate_id: aggregateId,\n\t\t\t\t\t}),\n\t\t\t\t\tguard: EVENT_GUARD,\n\t\t\t\t\tinitial: entries.cache as readonly CqrsEvent[],\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tthis.addDisposer(keepalive(guarded));\n\t\tconst entry = { log, node: guarded };\n\t\tbyType.set(aggregateId, entry);\n\t\t// M4: auto-wire any tiers attached via `attachEventStorage`.\n\t\tthis._autoWireStreamStorage(`${type}::${aggregateId}`, log);\n\t\tthis._enforceAggregateLru();\n\t\treturn entry;\n\t}\n\n\t/** Try `resolve(path)`; return `undefined` instead of throwing on missing. */\n\tprivate resolveOptional(path: string): Node | undefined {\n\t\ttry {\n\t\t\treturn this.resolve(path);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/** Internal: append to an event log, auto-registering if needed. */\n\tprivate _appendEvent(\n\t\teventName: string,\n\t\tpayload: unknown,\n\t\textra?: {\n\t\t\taggregateId?: string;\n\t\t\tcorrelationId?: string;\n\t\t\tcausationId?: string;\n\t\t\tmetadata?: Readonly<Record<string, unknown>>;\n\t\t\thandlerVersion?: { id: string; version: string | number };\n\t\t},\n\t): CqrsEvent {\n\t\tlet entry = this._eventLogs.get(eventName);\n\t\tif (!entry) {\n\t\t\tthis.event(eventName);\n\t\t\tentry = this._eventLogs.get(eventName)!;\n\t\t}\n\t\tif (entry.node.status === \"completed\" || entry.node.status === \"errored\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot dispatch to terminated event stream \"${eventName}\" (status: ${entry.node.status}).`,\n\t\t\t);\n\t\t}\n\n\t\t// Per-aggregate version + stream wiring (D1).\n\t\tlet aggregateVersion: number | undefined;\n\t\tlet aggregateEntry: EventEntry | undefined;\n\t\tif (extra?.aggregateId !== undefined) {\n\t\t\tconst lruKey = `${eventName}::${extra.aggregateId}`;\n\t\t\taggregateVersion = (this._aggregateVersions.get(lruKey) ?? 0) + 1;\n\t\t\tthis._aggregateVersions.set(lruKey, aggregateVersion);\n\t\t\taggregateEntry = this._ensureAggregateStream(eventName, extra.aggregateId);\n\t\t}\n\n\t\tconst nv = entry.log.entries.v;\n\t\tconst frozenPayload = this._freezeEventPayload ? deepFreeze(payload) : payload;\n\t\tconst evt: CqrsEvent = {\n\t\t\ttype: eventName,\n\t\t\tpayload: frozenPayload,\n\t\t\ttimestampNs: wallClockNs(),\n\t\t\tseq: ++this._seq,\n\t\t\t...(extra?.aggregateId !== undefined ? { aggregateId: extra.aggregateId } : {}),\n\t\t\t...(aggregateVersion !== undefined ? { aggregateVersion } : {}),\n\t\t\t...(extra?.correlationId !== undefined ? { correlationId: extra.correlationId } : {}),\n\t\t\t...(extra?.causationId !== undefined ? { causationId: extra.causationId } : {}),\n\t\t\t...(extra?.metadata !== undefined ? { metadata: Object.freeze({ ...extra.metadata }) } : {}),\n\t\t\t...(extra?.handlerVersion !== undefined ? { handlerVersion: extra.handlerVersion } : {}),\n\t\t\t...(nv != null ? { v0: { id: nv.id, version: nv.version } } : {}),\n\t\t};\n\t\t// Append to fan-in stream (always) and per-aggregate stream (when set).\n\t\tentry.log.append(evt);\n\t\tif (aggregateEntry) {\n\t\t\taggregateEntry.log.append(evt);\n\t\t}\n\t\treturn evt;\n\t}\n\n\t// -- Commands -------------------------------------------------------------\n\n\t/**\n\t * Register a command with its handler. Guard denies `observe` (write-only).\n\t * Use `dispatch(name, payload)` to execute.\n\t *\n\t * The command node carries dynamic `meta.error` — a reactive companion\n\t * that holds the last handler error (or `null` on success).\n\t */\n\tcommand<T = unknown>(\n\t\tname: string,\n\t\thandlerOrReg: CommandHandler<T> | CommandRegistration<T>,\n\t): Node<T> {\n\t\tif (this._commandRegs.has(name)) {\n\t\t\tthrow new DuplicateRegistrationError(\"command\", name);\n\t\t}\n\t\tconst reg: CommandRegistration<T> =\n\t\t\ttypeof handlerOrReg === \"function\" ? { handler: handlerOrReg } : handlerOrReg;\n\t\tconst cmdNode = this.state<T>(name, undefined as T, {\n\t\t\tmeta: {\n\t\t\t\t...cqrsMeta(\"command\", { command_name: name }),\n\t\t\t\terror: null,\n\t\t\t},\n\t\t\tguard: COMMAND_GUARD,\n\t\t});\n\t\tthis._commandRegs.set(name, {\n\t\t\thandler: reg.handler as CommandHandler<unknown>,\n\t\t\t...(reg.emits !== undefined ? { emits: reg.emits } : {}),\n\t\t\t...(reg.handlerVersion !== undefined ? { handlerVersion: reg.handlerVersion } : {}),\n\t\t});\n\t\t// Pre-register declared event streams so describe() shows them.\n\t\tif (reg.emits) {\n\t\t\tfor (const e of reg.emits) {\n\t\t\t\tif (!this._eventLogs.has(e)) this.event(e);\n\t\t\t}\n\t\t}\n\t\treturn cmdNode;\n\t}\n\n\t/**\n\t * Execute a registered command. Wraps the entire dispatch in `batch()` so\n\t * the command node DATA and all emitted events settle atomically.\n\t *\n\t * If the handler throws, `meta.error` on the command node is set to the\n\t * error and the exception is re-thrown.\n\t *\n\t * **Tier 8 / COMPOSITION-GUIDE §35:** dispatch routes through the shared\n\t * {@link mutate} framework so freeze / rollback-on-throw / seq-cursor\n\t * advance / audit-record stamping flow through one centralized helper.\n\t * Failure records emit OUTSIDE the rolled-back batch (M5 / C4 invariants\n\t * preserved by the framework).\n\t */\n\tdispatch<T = unknown>(commandName: string, payload: T, opts?: DispatchOptions): void {\n\t\tconst reg = this._commandRegs.get(commandName);\n\t\tif (!reg) throw new UnknownCommandError(commandName);\n\n\t\t// D1: optimistic-concurrency check fires BEFORE the handler runs and\n\t\t// BEFORE the batch opens, so a stale-version dispatch is a clean\n\t\t// no-op (no audit record, no rollback). Only meaningful when both\n\t\t// aggregateId and expectedAggregateVersion are set; otherwise no-op.\n\t\tif (\n\t\t\topts?.aggregateId !== undefined &&\n\t\t\topts.expectedAggregateVersion !== undefined &&\n\t\t\treg.emits !== undefined\n\t\t) {\n\t\t\t// Verify against ANY of the declared `emits` types — the dispatch's\n\t\t\t// aggregate version is per (type, aggregateId), but a single\n\t\t\t// dispatch may emit across multiple types. We check the FIRST\n\t\t\t// declared `emits` type that has a version recorded for this\n\t\t\t// aggregate; if none has a version, the aggregate is considered\n\t\t\t// at version 0.\n\t\t\tlet observedVersion = 0;\n\t\t\tfor (const t of reg.emits) {\n\t\t\t\tconst v = this._aggregateVersions.get(`${t}::${opts.aggregateId}`);\n\t\t\t\tif (v !== undefined && v > observedVersion) observedVersion = v;\n\t\t\t}\n\t\t\tif (observedVersion !== opts.expectedAggregateVersion) {\n\t\t\t\tthrow new OptimisticConcurrencyError(\n\t\t\t\t\topts.aggregateId,\n\t\t\t\t\topts.expectedAggregateVersion,\n\t\t\t\t\tobservedVersion,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst cmdNode = this.resolve(commandName);\n\t\tconst emittedEvents: string[] = [];\n\t\t// `actionThrew` distinguishes user-handler failures (where we want to\n\t\t// stamp `cmdNode.meta.error`) from framework-internal failures (which\n\t\t// shouldn't leak as a \"command failed\" signal).\n\t\tlet actionThrew = false;\n\n\t\tconst action = (sealed: T): void => {\n\t\t\tcmdNode.emit(sealed, { internal: true });\n\t\t\ttry {\n\t\t\t\treg.handler(sealed, {\n\t\t\t\t\temit: (eName, data) => {\n\t\t\t\t\t\t// Wave C.2 Unit 19: if emits was declared, reject undeclared names.\n\t\t\t\t\t\tif (reg.emits !== undefined && !reg.emits.includes(eName)) {\n\t\t\t\t\t\t\tthrow new UndeclaredEmitError(commandName, eName, reg.emits);\n\t\t\t\t\t\t}\n\t\t\t\t\t\temittedEvents.push(eName);\n\t\t\t\t\t\tthis._appendEvent(eName, data, {\n\t\t\t\t\t\t\t// D1: thread the dispatch's aggregateId through so events\n\t\t\t\t\t\t\t// participate in per-aggregate versioning. Handlers can\n\t\t\t\t\t\t\t// override per-emit by passing their own through a richer\n\t\t\t\t\t\t\t// emit signature (future extension).\n\t\t\t\t\t\t\t...(opts?.aggregateId !== undefined ? { aggregateId: opts.aggregateId } : {}),\n\t\t\t\t\t\t\t...(opts?.correlationId !== undefined ? { correlationId: opts.correlationId } : {}),\n\t\t\t\t\t\t\t...(opts?.causationId !== undefined ? { causationId: opts.causationId } : {}),\n\t\t\t\t\t\t\t...(opts?.metadata !== undefined\n\t\t\t\t\t\t\t\t? { metadata: Object.freeze({ ...opts.metadata }) }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(reg.handlerVersion !== undefined ? { handlerVersion: reg.handlerVersion } : {}),\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tcmdNode.meta.error.emit(null, { internal: true });\n\t\t\t} catch (err) {\n\t\t\t\tactionThrew = true;\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\tmutate<[T], void, DispatchRecord>(action, {\n\t\t\t\tframe: \"transactional\",\n\t\t\t\tlog: this.dispatches,\n\t\t\t\tseq: this._dispatchSeqCursor,\n\t\t\t\tfreeze: this._freezeCommandPayload,\n\t\t\t\tonSuccessRecord: ([sealed], _result, { t_ns, seq }) => ({\n\t\t\t\t\tcommandName,\n\t\t\t\t\tpayload: sealed,\n\t\t\t\t\toutcome: \"success\",\n\t\t\t\t\temittedEvents: [...emittedEvents],\n\t\t\t\t\tt_ns,\n\t\t\t\t\tseq: seq ?? 0,\n\t\t\t\t\t...(reg.handlerVersion !== undefined ? { handlerVersion: reg.handlerVersion } : {}),\n\t\t\t\t}),\n\t\t\t\tonFailureRecord: ([sealed], err, { t_ns, seq, errorType }) => {\n\t\t\t\t\tconst wrapped =\n\t\t\t\t\t\terr instanceof CommandHandlerError ? err : new CommandHandlerError(commandName, err);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcommandName,\n\t\t\t\t\t\tpayload: sealed,\n\t\t\t\t\t\toutcome: \"failure\",\n\t\t\t\t\t\terror: wrapped,\n\t\t\t\t\t\terrorType,\n\t\t\t\t\t\temittedEvents: [...emittedEvents],\n\t\t\t\t\t\tt_ns,\n\t\t\t\t\t\tseq: seq ?? 0,\n\t\t\t\t\t\t...(reg.handlerVersion !== undefined ? { handlerVersion: reg.handlerVersion } : {}),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t})(payload);\n\t\t} catch (outerErr) {\n\t\t\t// C4 preservation: only stamp `cmdNode.meta.error` when the user\n\t\t\t// handler threw (not when framework infra threw before the action\n\t\t\t// ran). The framework already routed onFailure for the action-throw\n\t\t\t// case via `mutate` outside the rolled-back batch.\n\t\t\tif (actionThrew) {\n\t\t\t\tcmdNode.meta.error.emit(outerErr, { internal: true });\n\t\t\t}\n\t\t\tthrow outerErr;\n\t\t}\n\t}\n\n\t// -- Projections ----------------------------------------------------------\n\n\t/**\n\t * Register a read-only projection derived from event streams.\n\t * Guard denies `write` — value is computed from events only.\n\t *\n\t * **Wave C.3 Unit 21 (locked 2026-04-24):**\n\t * - Object-bag signature replaces the positional `(name, events, reducer, initial)` form.\n\t * - `mode: \"scan\"` (default) — incremental fold; `\"replay\"` — full replay each wave.\n\t * - `snapshot` integration for cold-start load + auto-checkpoint save.\n\t * - `freezeInputs` (default `true`) — freeze the event array before passing to reducer.\n\t * - Returns `ProjectionController<TState>` with `.node`, `.rebuild()`, `.reset()`.\n\t *\n\t * Fan-in across `events` is implemented by depending on all event-type fan-in\n\t * nodes directly, which preserves `describe()` edges (e.g. `orderPlaced →\n\t * orderCount`). Events are sorted by `(timestampNs, seq, aggregateId)` before\n\t * passing to the reducer (Option-3 cross-aggregate ordering, C.3).\n\t */\n\tprojection<TState>(opts: ProjectionOptions<TState>): ProjectionController<TState> {\n\t\tconst { name, events: eventNames, reducer, initial } = opts;\n\t\tconst mode = opts.mode ?? \"scan\";\n\t\tconst freezeInputs = opts.freezeInputs ?? true;\n\t\tconst snapshotOpts = opts.snapshot;\n\n\t\t// Ensure each event stream exists and collect its node.\n\t\t// Using the event-type fan-in nodes directly as deps preserves\n\t\t// `describe()` edges (orderPlaced → orderCount) per Audit 1 §24.\n\t\tconst eventNodes = eventNames.map((eName) => {\n\t\t\tif (!this._eventLogs.has(eName)) this.event(eName);\n\t\t\treturn this._eventLogs.get(eName)!.node;\n\t\t});\n\n\t\t// Sort comparator: timestampNs → seq → aggregateId lex (Option-3, C.3).\n\t\tfunction sortEvents(evts: CqrsEvent[]): void {\n\t\t\tevts.sort(\n\t\t\t\t(a, b) =>\n\t\t\t\t\ta.timestampNs - b.timestampNs ||\n\t\t\t\t\ta.seq - b.seq ||\n\t\t\t\t\t(a.aggregateId ?? \"\").localeCompare(b.aggregateId ?? \"\"),\n\t\t\t);\n\t\t}\n\n\t\t// Collect all events from the current snapshots (for seeding + rebuild).\n\t\tfunction collectAllEvents(snapshots: readonly (readonly CqrsEvent[])[]): CqrsEvent[] {\n\t\t\tconst evts: CqrsEvent[] = [];\n\t\t\tfor (const snap of snapshots) evts.push(...snap);\n\t\t\tsortEvents(evts);\n\t\t\treturn evts;\n\t\t}\n\n\t\t// Seed: collect any events already present at construction time.\n\t\tconst seedSnapshots = eventNodes.map(\n\t\t\t(n) => (n.cache as readonly CqrsEvent[] | undefined) ?? ([] as readonly CqrsEvent[]),\n\t\t);\n\t\tconst sortedSeed = collectAllEvents(seedSnapshots);\n\t\tconst frozenSeed = (\n\t\t\tfreezeInputs ? Object.freeze(sortedSeed) : sortedSeed\n\t\t) as readonly CqrsEvent[];\n\n\t\t// Scan state: tracks count of events processed in last run.\n\t\tlet lastProcessedCount = 0;\n\t\tlet scanState: TState = initial;\n\n\t\tif (mode === \"scan\" && sortedSeed.length > 0) {\n\t\t\tscanState = reducer(initial, frozenSeed);\n\t\t\tlastProcessedCount = sortedSeed.length;\n\t\t}\n\t\tconst seedState = mode === \"replay\" ? reducer(initial, frozenSeed) : scanState;\n\n\t\t// Snapshot save state — debounce + saveEvery.\n\t\tconst saveDebounceMs = snapshotOpts?.saveDebounceMs ?? 1000;\n\t\tconst saveEvery = snapshotOpts?.saveEvery ?? 1000;\n\t\tlet saveTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tlet savesSinceLastFlush = 0;\n\n\t\tfunction scheduleSave(currentState: TState): void {\n\t\t\tif (!snapshotOpts?.save) return;\n\t\t\tsavesSinceLastFlush += 1;\n\t\t\tif (savesSinceLastFlush >= saveEvery) {\n\t\t\t\tsavesSinceLastFlush = 0;\n\t\t\t\tif (saveTimer !== undefined) {\n\t\t\t\t\tclearTimeout(saveTimer);\n\t\t\t\t\tsaveTimer = undefined;\n\t\t\t\t}\n\t\t\t\tconst result = snapshotOpts.save(currentState);\n\t\t\t\tif (result instanceof Promise) result.catch(() => undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (saveTimer !== undefined) clearTimeout(saveTimer);\n\t\t\tsaveTimer = setTimeout(() => {\n\t\t\t\tsaveTimer = undefined;\n\t\t\t\tsavesSinceLastFlush = 0;\n\t\t\t\tconst result = snapshotOpts!.save!(currentState);\n\t\t\t\tif (result instanceof Promise) result.catch(() => undefined);\n\t\t\t}, saveDebounceMs);\n\t\t}\n\n\t\tconst projNode = this.derived<TState>(\n\t\t\tname,\n\t\t\teventNames as readonly string[],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst snapshots = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst allEvents = collectAllEvents(snapshots as readonly (readonly CqrsEvent[])[]);\n\n\t\t\t\tlet newState: TState;\n\t\t\t\tif (mode === \"replay\") {\n\t\t\t\t\t// m1: freeze only in the replay branch where `frozen` is actually used.\n\t\t\t\t\tconst frozen = (\n\t\t\t\t\t\tfreezeInputs ? Object.freeze(allEvents) : allEvents\n\t\t\t\t\t) as readonly CqrsEvent[];\n\t\t\t\t\tnewState = reducer(initial, frozen);\n\t\t\t\t} else {\n\t\t\t\t\t// scan: only fold NEW events since last run.\n\t\t\t\t\tconst newOnly = allEvents.slice(lastProcessedCount);\n\t\t\t\t\tlastProcessedCount = allEvents.length;\n\t\t\t\t\tconst frozenNew = (\n\t\t\t\t\t\tfreezeInputs ? Object.freeze(newOnly) : newOnly\n\t\t\t\t\t) as readonly CqrsEvent[];\n\t\t\t\t\tnewState = reducer(scanState, frozenNew);\n\t\t\t\t\tscanState = newState;\n\t\t\t\t}\n\n\t\t\t\tscheduleSave(newState);\n\t\t\t\treturn [newState];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: cqrsMeta(\"projection\", { projection_name: name, source_events: eventNames }),\n\t\t\t\tguard: PROJECTION_GUARD,\n\t\t\t\tinitial: seedState,\n\t\t\t},\n\t\t);\n\n\t\tthis.addDisposer(keepalive(projNode));\n\t\tthis.addDisposer(() => {\n\t\t\tif (saveTimer !== undefined) {\n\t\t\t\tclearTimeout(saveTimer);\n\t\t\t\tsaveTimer = undefined;\n\t\t\t}\n\t\t});\n\t\tthis._projections.add(name);\n\n\t\t// -- Controller methods ---------------------------------------------------\n\n\t\tconst rebuild = async (rebuildOpts?: {\n\t\t\tfromTier?: AppendLogStorageTier<CqrsEvent>;\n\t\t\tpageSize?: number;\n\t\t}): Promise<TState> => {\n\t\t\ttry {\n\t\t\t\tconst pageSize = rebuildOpts?.pageSize ?? 1000;\n\t\t\t\tconst tier = rebuildOpts?.fromTier ?? this._attachedEventTiers[0]?.[0];\n\n\t\t\t\t// M5: snapshot in-memory event count BEFORE any async work so we can\n\t\t\t\t// drain events that arrive concurrently during the paginated rebuild.\n\t\t\t\tconst preBuildCount = collectAllEvents(\n\t\t\t\t\teventNodes.map((n) => (n.cache as readonly CqrsEvent[] | undefined) ?? []),\n\t\t\t\t).length;\n\n\t\t\t\t// Seed from snapshot.load if provided.\n\t\t\t\tlet rebuildState: TState = initial;\n\t\t\t\tif (snapshotOpts?.load) {\n\t\t\t\t\tconst loaded = await snapshotOpts.load();\n\t\t\t\t\tif (loaded !== undefined) rebuildState = loaded;\n\t\t\t\t}\n\n\t\t\t\tif (!tier || !tier.loadEntries) {\n\t\t\t\t\t// No storage tier — fold in-memory events as a best-effort rebuild.\n\t\t\t\t\tconst inMemory = collectAllEvents(\n\t\t\t\t\t\teventNodes.map((n) => (n.cache as readonly CqrsEvent[] | undefined) ?? []),\n\t\t\t\t\t);\n\t\t\t\t\tconst frozen = (\n\t\t\t\t\t\tfreezeInputs ? Object.freeze(inMemory) : inMemory\n\t\t\t\t\t) as readonly CqrsEvent[];\n\t\t\t\t\trebuildState = reducer(rebuildState, frozen);\n\t\t\t\t} else {\n\t\t\t\t\t// Paginated load from tier.\n\t\t\t\t\t// m3: only fold events that belong to this projection's event-type set.\n\t\t\t\t\t// Tiers may hold events from other projections; filtering keeps reducer\n\t\t\t\t\t// correctness when the tier is shared across projections.\n\t\t\t\t\tconst watchedEvents = new Set<string>(eventNames as readonly string[]);\n\t\t\t\t\tlet cursor: import(\"@graphrefly/pure-ts/extra\").AppendCursor | undefined;\n\t\t\t\t\tlet done = false;\n\t\t\t\t\twhile (!done) {\n\t\t\t\t\t\tconst result = await tier.loadEntries({ cursor, pageSize });\n\t\t\t\t\t\tconst page = [...result.entries].filter((e) => watchedEvents.has(e.type));\n\t\t\t\t\t\tsortEvents(page);\n\t\t\t\t\t\tconst frozenPage = (freezeInputs ? Object.freeze(page) : page) as readonly CqrsEvent[];\n\t\t\t\t\t\trebuildState = reducer(rebuildState, frozenPage);\n\t\t\t\t\t\tcursor = result.cursor;\n\t\t\t\t\t\tdone = !cursor || result.entries.length === 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Update the live projection node with the rebuilt state.\n\t\t\t\tif (mode === \"scan\") {\n\t\t\t\t\t// M5: drain events that arrived during the async rebuild so they are\n\t\t\t\t\t// not lost (race between paginated load and concurrent dispatch).\n\t\t\t\t\tconst allInMemory = collectAllEvents(\n\t\t\t\t\t\teventNodes.map((n) => (n.cache as readonly CqrsEvent[] | undefined) ?? []),\n\t\t\t\t\t);\n\t\t\t\t\tconst pendingEvents = allInMemory.slice(preBuildCount);\n\t\t\t\t\tif (pendingEvents.length > 0) {\n\t\t\t\t\t\tconst frozenPending = (\n\t\t\t\t\t\t\tfreezeInputs ? Object.freeze(pendingEvents) : pendingEvents\n\t\t\t\t\t\t) as readonly CqrsEvent[];\n\t\t\t\t\t\trebuildState = reducer(rebuildState, frozenPending);\n\t\t\t\t\t}\n\t\t\t\t\tscanState = rebuildState;\n\t\t\t\t\tlastProcessedCount = allInMemory.length;\n\t\t\t\t}\n\t\t\t\tprojNode.emit(rebuildState, { internal: true });\n\t\t\t\treturn rebuildState;\n\t\t\t} catch (err) {\n\t\t\t\tthrow new RebuildError(name, err);\n\t\t\t}\n\t\t};\n\n\t\tconst reset = async (): Promise<TState> => {\n\t\t\ttry {\n\t\t\t\t// Reload from snapshot.load (if configured).\n\t\t\t\tlet baseState: TState = initial;\n\t\t\t\tif (snapshotOpts?.load) {\n\t\t\t\t\tconst loaded = await snapshotOpts.load();\n\t\t\t\t\tif (loaded !== undefined) baseState = loaded;\n\t\t\t\t}\n\n\t\t\t\t// Re-fold all in-memory events on top of the snapshot state.\n\t\t\t\tconst inMemory = collectAllEvents(\n\t\t\t\t\teventNodes.map((n) => (n.cache as readonly CqrsEvent[] | undefined) ?? []),\n\t\t\t\t);\n\t\t\t\tconst frozen = (freezeInputs ? Object.freeze(inMemory) : inMemory) as readonly CqrsEvent[];\n\t\t\t\tconst newState = reducer(baseState, frozen);\n\n\t\t\t\tif (mode === \"scan\") {\n\t\t\t\t\tscanState = newState;\n\t\t\t\t\tlastProcessedCount = inMemory.length;\n\t\t\t\t}\n\t\t\t\tprojNode.emit(newState, { internal: true });\n\t\t\t\treturn newState;\n\t\t\t} catch (err) {\n\t\t\t\tthrow new RebuildError(name, err);\n\t\t\t}\n\t\t};\n\n\t\treturn { node: projNode, rebuild, reset };\n\t}\n\n\t// -- Sagas ----------------------------------------------------------------\n\n\t/**\n\t * Register an event-driven side effect. Runs handler for each **new** event\n\t * from the specified streams (tracks last-processed entry count per stream).\n\t *\n\t * The saga node carries dynamic `meta.error` — a reactive companion that\n\t * holds the last handler error (or `null` on success). Handler errors do\n\t * not propagate out of the saga run (the event cursor still advances so\n\t * the same entry is not delivered twice).\n\t */\n\tsaga<T = unknown>(\n\t\tname: string,\n\t\teventNames: readonly string[],\n\t\thandler: SagaHandler<T>,\n\t\topts: SagaOptions = {},\n\t): SagaController<T> {\n\t\tconst _eventNodes = eventNames.map((eName) => {\n\t\t\tif (!this._eventLogs.has(eName)) this.event(eName);\n\t\t\treturn this._eventLogs.get(eName)!.node;\n\t\t});\n\n\t\t// Audit 2: per-event-type cursor state nodes (replaces closure Map).\n\t\t// Mount under `<saga>_cursor` (no `::` — that's the path separator).\n\t\tconst cursors = registerCursorMap(this, `${name}_cursor`, eventNames as readonly string[], 0);\n\t\t// Audit 2: invocations log (companion + alias).\n\t\tconst invocations = createAuditLog<SagaInvocation<T>>({\n\t\t\tname: `${name}_invocations`,\n\t\t\tretainedLimit: this._retainedLimit,\n\t\t\tgraph: this,\n\t\t});\n\t\tconst aggregateFilter = opts.aggregateId;\n\t\tconst errorPolicy = opts.errorPolicy ?? \"advance\";\n\n\t\t// D2: subscribe-and-capture-mirror for cursor reads — avoid `.cache`\n\t\t// access from inside the saga node's fn. Each cursor mirrors into a\n\t\t// closure variable updated by an external subscription. Cursor writes\n\t\t// (`cursor.emit(advancedTo)`) and `invocations.append(...)` from inside\n\t\t// the fn are sanctioned effect-side-effects (saga's `describeKind:\n\t\t// \"effect\"`) — not §5.9 imperative-trigger violations.\n\t\tconst latestCursors = new Map<string, number>();\n\t\tfor (const eName of eventNames) {\n\t\t\tconst cursor = cursors[eName]!;\n\t\t\tlatestCursors.set(eName, (cursor.cache as number | undefined) ?? 0);\n\t\t\tconst sub = cursor.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) if (m[0] === DATA) latestCursors.set(eName, m[1] as number);\n\t\t\t});\n\t\t\tthis.addDisposer(sub);\n\t\t}\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: per-event handler invocation routes\n\t\t// through `mutate` so handler-version stamping + audit-record\n\t\t// shape stay centralized. Failure path re-throws — the saga's outer\n\t\t// try/catch honors `errorPolicy` (\"advance\" vs \"hold\"). Action takes\n\t\t// `(ev, eName)` so the wrapper can be hoisted once for all event types.\n\t\tconst auditedHandler = mutate<[CqrsEvent<T>, string], void, SagaInvocation<T>>(\n\t\t\t(ev, _eName) => {\n\t\t\t\thandler(ev);\n\t\t\t},\n\t\t\t{\n\t\t\t\tframe: \"inline\",\n\t\t\t\tlog: invocations,\n\t\t\t\tfreeze: false,\n\t\t\t\t...(opts.handlerVersion !== undefined ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t// D5 (qa lock): always include the `aggregateId` key (even when\n\t\t\t\t// undefined) for parity with the pre-Tier-8 saga record shape.\n\t\t\t\t// Consumers using `Object.hasOwn(record, \"aggregateId\")` or JSON\n\t\t\t\t// serialization shape would observe a pre-1.0 break otherwise.\n\t\t\t\tonSuccessRecord: ([ev, eName], _r, { t_ns }) => ({\n\t\t\t\t\teventType: eName,\n\t\t\t\t\toutcome: \"success\",\n\t\t\t\t\taggregateId: ev.aggregateId,\n\t\t\t\t\tevent: ev,\n\t\t\t\t\tt_ns,\n\t\t\t\t}),\n\t\t\t\tonFailureRecord: ([ev, eName], err, { t_ns, errorType }) => ({\n\t\t\t\t\teventType: eName,\n\t\t\t\t\toutcome: \"failure\",\n\t\t\t\t\terror: err,\n\t\t\t\t\terrorType,\n\t\t\t\t\taggregateId: ev.aggregateId,\n\t\t\t\t\tevent: ev,\n\t\t\t\t\tt_ns,\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tconst sagaRef: { n?: Node<unknown> } = {};\n\t\tconst sagaNode = this.effect(\n\t\t\tname,\n\t\t\teventNames as readonly string[],\n\t\t\t(snapshots, _up) => {\n\t\t\t\tconst errNode = sagaRef.n!.meta.error as Node<unknown>;\n\t\t\t\tfor (let i = 0; i < snapshots.length; i++) {\n\t\t\t\t\tconst batch = snapshots[i];\n\t\t\t\t\tif (batch == null || batch.length === 0) continue;\n\t\t\t\t\tconst entries = batch.at(-1) as readonly CqrsEvent<T>[] | undefined;\n\t\t\t\t\tif (!entries) continue;\n\t\t\t\t\tconst eName = eventNames[i] as string;\n\t\t\t\t\tconst cursor = cursors[eName]!;\n\t\t\t\t\tconst lastCount = latestCursors.get(eName) ?? 0;\n\t\t\t\t\tif (entries.length > lastCount) {\n\t\t\t\t\t\tconst newEntries = entries.slice(lastCount);\n\t\t\t\t\t\tlet advancedTo = lastCount;\n\t\t\t\t\t\tfor (const entry of newEntries) {\n\t\t\t\t\t\t\tconst ev = entry as CqrsEvent<T>;\n\t\t\t\t\t\t\tif (aggregateFilter !== undefined && ev.aggregateId !== aggregateFilter) {\n\t\t\t\t\t\t\t\tadvancedTo += 1;\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tauditedHandler(ev, eName);\n\t\t\t\t\t\t\t\terrNode.emit(null, { internal: true });\n\t\t\t\t\t\t\t\tadvancedTo += 1;\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\terrNode.emit(err, { internal: true });\n\t\t\t\t\t\t\t\tif (errorPolicy === \"hold\") break;\n\t\t\t\t\t\t\t\t// \"advance\" — skip past failure, keep going.\n\t\t\t\t\t\t\t\tadvancedTo += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcursor.emit(advancedTo);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: {\n\t\t\t\t\t...cqrsMeta(\"saga\", { saga_name: name, source_events: eventNames }),\n\t\t\t\t\terror: null,\n\t\t\t\t},\n\t\t\t},\n\t\t) as Node<unknown>;\n\t\tsagaRef.n = sagaNode;\n\n\t\tthis.addDisposer(keepalive(sagaNode));\n\t\tthis._sagas.add(name);\n\t\treturn {\n\t\t\tnode: sagaNode,\n\t\t\tinvocations,\n\t\t\taudit: invocations,\n\t\t\tcursors,\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a CQRS graph container.\n *\n * @example\n * ```ts\n * const app = cqrs(\"orders\");\n * app.event(\"orderPlaced\");\n * app.command(\"placeOrder\", (payload, { emit }) => {\n * emit(\"orderPlaced\", { orderId: payload.id, amount: payload.amount });\n * });\n * const { node: orderCount } = app.projection({\n * name: \"orderCount\",\n * events: [\"orderPlaced\"],\n * reducer: (_s, events) => events.length,\n * initial: 0,\n * });\n * app.dispatch(\"placeOrder\", { id: \"1\", amount: 100 });\n * ```\n */\nexport function cqrs<EM extends CqrsEventMap = Record<string, unknown>>(\n\tname: string,\n\topts?: CqrsOptions,\n): CqrsGraph<EM> {\n\tconst g = new CqrsGraph<EM>(name, opts);\n\t// Tier 1.5.3 Phase 2.5 (DG1=B): tag the Graph with its constructing\n\t// factory so `describe()` surfaces provenance. Route through\n\t// `placeholderArgs` since `CqrsOptions.graph` may carry non-JSON fields.\n\tconst { factory: _f, factoryArgs: _fa, ...tagArgs } = (opts ?? {}) as Record<string, unknown>;\n\tg.tagFactory(\"cqrs\", placeholderArgs(tagArgs));\n\treturn g;\n}\n","/**\n * Shared pattern-layer error hierarchy (Audit 2 — locked 2026-04-24).\n *\n * Cross-primitive `instanceof` checks: gate, queue, cqrs.dispatch, saga,\n * projection, subscription, etc. all use these classes so consumer error\n * handlers can branch by kind rather than by message string.\n *\n * @internal — exposed via patterns/index for primitive impls; consumers\n * should import the relevant class from the primitive's barrel.\n */\n\n/** Root error class. All pattern-layer errors extend this. */\nexport class GraphReFlyError extends Error {\n\tconstructor(message: string, options?: ErrorOptions) {\n\t\tsuper(message, options);\n\t\tthis.name = this.constructor.name;\n\t}\n}\n\n/** Re-registering a name that's already taken (command, gate, queue, saga, projection). */\nexport class DuplicateRegistrationError extends GraphReFlyError {\n\tconstructor(\n\t\treadonly kind: string,\n\t\treadonly registrationName: string,\n\t) {\n\t\tsuper(`Duplicate ${kind} registration: \"${registrationName}\"`);\n\t}\n}\n\n/** CQRS handler emitted an event type not in its declared `emits` set. */\nexport class UndeclaredEmitError extends GraphReFlyError {\n\tconstructor(\n\t\treadonly commandName: string,\n\t\treadonly eventName: string,\n\t\treadonly declaredEmits: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`Command \"${commandName}\" emitted undeclared event \"${eventName}\". Declared emits: [${declaredEmits.join(\", \")}]`,\n\t\t);\n\t}\n}\n\n/** Aggregate version expected vs observed mismatch on dispatch. */\nexport class OptimisticConcurrencyError extends GraphReFlyError {\n\tconstructor(\n\t\treadonly aggregateId: string,\n\t\treadonly expected: number,\n\t\treadonly actual: number,\n\t) {\n\t\tsuper(\n\t\t\t`Optimistic concurrency conflict on aggregate \"${aggregateId}\": expected version ${expected}, got ${actual}`,\n\t\t);\n\t}\n}\n\n/** `dispatch(name, ...)` for a name that wasn't registered via `command()`. */\nexport class UnknownCommandError extends GraphReFlyError {\n\tconstructor(readonly commandName: string) {\n\t\tsuper(`Unknown command: \"${commandName}\". Register with command() first.`);\n\t}\n}\n\n/** Wrap any error thrown from inside a command handler. Original on `cause`. */\nexport class CommandHandlerError extends GraphReFlyError {\n\tconstructor(\n\t\treadonly commandName: string,\n\t\tcause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`Command handler \"${commandName}\" threw: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t{ cause },\n\t\t);\n\t}\n}\n\n/** Mutation method called after the primitive was torn down. */\nexport class TeardownError extends GraphReFlyError {\n\tconstructor(\n\t\treadonly kind: string,\n\t\treadonly method: string,\n\t) {\n\t\tsuper(`${kind}: ${method}() called after teardown`);\n\t}\n}\n\n/** Projection rebuild failure — adapter / decode / reducer error. */\nexport class RebuildError extends GraphReFlyError {\n\tconstructor(\n\t\treadonly projectionName: string,\n\t\tcause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`Projection \"${projectionName}\" rebuild failed: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t{ cause },\n\t\t);\n\t}\n}\n"],"mappings":"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","names":[]}
|