@graphrefly/graphrefly 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-RHI3GHZW.js → chunk-263BEJJO.js} +3 -3
- package/dist/{chunk-44HD4BTA.js → chunk-2GQLMQVJ.js} +3 -3
- package/dist/chunk-32N5A454.js +36 -0
- package/dist/chunk-32N5A454.js.map +1 -0
- package/dist/{chunk-IR3KMOLX.js → chunk-CWYPA63G.js} +3 -383
- package/dist/chunk-CWYPA63G.js.map +1 -0
- package/dist/{chunk-TH6COGOP.js → chunk-HVBX5KIW.js} +2 -2
- package/dist/chunk-JFONSPNF.js +391 -0
- package/dist/chunk-JFONSPNF.js.map +1 -0
- package/dist/{chunk-QA3RP5NH.js → chunk-NZMBRXQV.js} +101 -5
- package/dist/chunk-NZMBRXQV.js.map +1 -0
- package/dist/{chunk-MQBQOFDS.js → chunk-PNUZM7PC.js} +12 -31
- package/dist/chunk-PNUZM7PC.js.map +1 -0
- package/dist/{chunk-EQUZ5NLD.js → chunk-PX6PDUJ5.js} +11 -16
- package/dist/chunk-PX6PDUJ5.js.map +1 -0
- package/dist/{chunk-NXC35KC5.js → chunk-XRFJJ2IU.js} +3 -3
- package/dist/{chunk-BLD3IFYF.js → chunk-XTLYW4FR.js} +9 -7
- package/dist/{chunk-BLD3IFYF.js.map → chunk-XTLYW4FR.js.map} +1 -1
- package/dist/compat/nestjs/index.cjs +100 -4
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +6 -6
- package/dist/compat/nestjs/index.d.ts +6 -6
- package/dist/compat/nestjs/index.js +9 -7
- package/dist/core/index.cjs +100 -4
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +3 -3
- package/dist/extra/index.cjs +100 -4
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +4 -4
- package/dist/extra/index.d.ts +4 -4
- package/dist/extra/index.js +9 -7
- package/dist/graph/index.cjs +100 -4
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +5 -5
- package/dist/graph/index.d.ts +5 -5
- package/dist/graph/index.js +4 -4
- package/dist/{graph-ab1yPwIB.d.cts → graph-BtdSRHUc.d.cts} +3 -3
- package/dist/{graph-DFr0diXB.d.ts → graph-CEO2FkLY.d.ts} +3 -3
- package/dist/{index-BvWfZCTt.d.cts → index-B0tfuXwV.d.cts} +3 -3
- package/dist/{index-Dy04P4W3.d.cts → index-BFGjXbiP.d.cts} +2 -2
- package/dist/{index-DrJq9B1T.d.cts → index-BPlWVAKY.d.cts} +3 -3
- package/dist/{index-C9z6rU9P.d.cts → index-BUj3ASVe.d.cts} +25 -7
- package/dist/{index-DLE1Sp-L.d.cts → index-C59uSJAH.d.cts} +2 -2
- package/dist/{index-DsGxLfwL.d.ts → index-CkElcUY6.d.ts} +2 -2
- package/dist/{index-HdJx_BjO.d.ts → index-DSPc5rkv.d.ts} +25 -7
- package/dist/{index-D36MAQ3f.d.ts → index-DgscL7v0.d.ts} +3 -3
- package/dist/{index-BbYZma8G.d.ts → index-RXN94sHK.d.ts} +3 -3
- package/dist/{index-BHm3Ba5q.d.ts → index-jEtF4N7L.d.ts} +2 -2
- package/dist/index.cjs +109 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -15
- package/dist/index.d.ts +15 -15
- package/dist/index.js +26 -22
- package/dist/index.js.map +1 -1
- package/dist/{meta-n3FoVWML.d.ts → meta-3QjzotRv.d.ts} +1 -1
- package/dist/{meta--fr9sxRM.d.cts → meta-B-Lbs4-O.d.cts} +1 -1
- package/dist/{node-C5UD5MGq.d.cts → node-C7PD3sn9.d.cts} +42 -0
- package/dist/{node-C5UD5MGq.d.ts → node-C7PD3sn9.d.ts} +42 -0
- package/dist/{observable-CQRBtEbq.d.ts → observable-EyO-moQY.d.ts} +1 -1
- package/dist/{observable-DWydVy5b.d.cts → observable-axpzv1K2.d.cts} +1 -1
- package/dist/patterns/reactive-layout/index.cjs +214 -117
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +5 -5
- package/dist/patterns/reactive-layout/index.d.ts +5 -5
- package/dist/patterns/reactive-layout/index.js +6 -4
- package/dist/{storage-C9fZfMfM.d.ts → storage-CHT5WE9m.d.ts} +1 -1
- package/dist/{storage-Bew05Xy6.d.cts → storage-DIgAr7M_.d.cts} +1 -1
- package/package.json +2 -1
- package/dist/chunk-EQUZ5NLD.js.map +0 -1
- package/dist/chunk-IR3KMOLX.js.map +0 -1
- package/dist/chunk-MQBQOFDS.js.map +0 -1
- package/dist/chunk-QA3RP5NH.js.map +0 -1
- /package/dist/{chunk-RHI3GHZW.js.map → chunk-263BEJJO.js.map} +0 -0
- /package/dist/{chunk-44HD4BTA.js.map → chunk-2GQLMQVJ.js.map} +0 -0
- /package/dist/{chunk-TH6COGOP.js.map → chunk-HVBX5KIW.js.map} +0 -0
- /package/dist/{chunk-NXC35KC5.js.map → chunk-XRFJJ2IU.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/compat/nestjs/index.ts","../src/compat/nestjs/decorators.ts","../src/compat/nestjs/tokens.ts","../src/compat/nestjs/explorer.ts","../src/compat/nestjs/gateway.ts","../src/compat/nestjs/guard.ts","../src/compat/nestjs/module.ts","../src/patterns/cqrs.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// NestJS integration — Module, DI, Lifecycle, RxJS bridge (Phase 5.5)\n// ---------------------------------------------------------------------------\n// Bridges GraphReFly into NestJS's DI container and RxJS-based ecosystem.\n// NestJS and RxJS are peer dependencies — install them in your NestJS app.\n//\n// Usage:\n// import { GraphReflyModule, InjectGraph, InjectNode, toObservable }\n// from '@graphrefly/graphrefly-ts/compat/nestjs';\n// ---------------------------------------------------------------------------\n\n// RxJS bridge (re-exported from extra for convenience)\nexport { type ToObservableOptions, toObservable } from \"../../extra/observable.js\";\n\n// Decorators\nexport {\n\tCOMMAND_HANDLERS,\n\tCommandHandler,\n\ttype CommandHandlerMeta,\n\tCQRS_EVENT_HANDLERS,\n\tCRON_HANDLERS,\n\tEVENT_HANDLERS,\n\tEventHandler,\n\ttype EventHandlerMeta,\n\tGraphCron,\n\ttype GraphCronMeta,\n\tGraphInterval,\n\ttype GraphIntervalMeta,\n\tINTERVAL_HANDLERS,\n\tInjectCqrsGraph,\n\tInjectGraph,\n\tInjectNode,\n\tOnGraphEvent,\n\ttype OnGraphEventMeta,\n\tQUERY_HANDLERS,\n\tQueryHandler,\n\ttype QueryHandlerMeta,\n\tSAGA_HANDLERS,\n\tSagaHandler,\n\ttype SagaHandlerMeta,\n} from \"./decorators.js\";\n// Explorer (event/schedule discovery)\nexport { GraphReflyEventExplorer } from \"./explorer.js\";\n// Gateway helpers (Phase 5.1)\nexport {\n\tObserveGateway,\n\ttype ObserveGatewayOptions,\n\ttype ObserveSSEOptions,\n\ttype ObserveSubscriptionOptions,\n\ttype ObserveWsCommand,\n\ttype ObserveWsMessage,\n\tobserveSSE,\n\tobserveSubscription,\n} from \"./gateway.js\";\n// Actor bridge (Phase 5.1)\nexport {\n\tACTOR_KEY,\n\ttype ActorExtractor,\n\tfromHeader,\n\tfromJwtPayload,\n\tGraphReflyGuard,\n\tGraphReflyGuardImpl,\n\tgetActor,\n} from \"./guard.js\";\n// Module & DI\nexport {\n\ttype GraphReflyCqrsOptions,\n\ttype GraphReflyFeatureOptions,\n\tGraphReflyModule,\n\ttype GraphReflyRootOptions,\n} from \"./module.js\";\n// Injection tokens\nexport {\n\tGRAPHREFLY_REQUEST_GRAPH,\n\tGRAPHREFLY_ROOT_GRAPH,\n\tgetGraphToken,\n\tgetNodeToken,\n} from \"./tokens.js\";\n","// ---------------------------------------------------------------------------\n// NestJS decorators for GraphReFly DI, events, and scheduling.\n// ---------------------------------------------------------------------------\n// NOTE: esbuild (used by vitest/vite) uses TC39 Stage 3 decorators, not\n// legacy TypeScript experimental decorators. Method decorators receive\n// (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext). We use\n// context.addInitializer() to register metadata when the class instance is\n// created, which runs before NestJS lifecycle hooks.\n// ---------------------------------------------------------------------------\n\nimport { Inject } from \"@nestjs/common\";\nimport {\n\tGRAPHREFLY_REQUEST_GRAPH,\n\tGRAPHREFLY_ROOT_GRAPH,\n\tgetGraphToken,\n\tgetNodeToken,\n} from \"./tokens.js\";\n\n/** Class constructor key for decorator registries and Nest `ModuleRef.get()`. */\nexport type DecoratorHostConstructor = abstract new (...args: unknown[]) => unknown;\n\n/**\n * TC39 Stage 3 class method decorator first argument (the method itself).\n * Narrower than `Function` for Biome `noBannedTypes`.\n */\nexport type DecoratorBoundMethod = (...args: unknown[]) => unknown;\n\n// ---------------------------------------------------------------------------\n// Global registries (populated by decorator initializers, read by explorer)\n// ---------------------------------------------------------------------------\n\nexport interface OnGraphEventMeta {\n\tnodeName: string;\n\tmethodKey: string | symbol;\n}\n\nexport interface GraphIntervalMeta {\n\tms: number;\n\tmethodKey: string | symbol;\n}\n\nexport interface GraphCronMeta {\n\texpr: string;\n\tmethodKey: string | symbol;\n}\n\n/** Registry: constructor → event handler metadata. */\nexport const EVENT_HANDLERS = new Map<DecoratorHostConstructor, OnGraphEventMeta[]>();\n/** Registry: constructor → interval metadata. */\nexport const INTERVAL_HANDLERS = new Map<DecoratorHostConstructor, GraphIntervalMeta[]>();\n/** Registry: constructor → cron metadata. */\nexport const CRON_HANDLERS = new Map<DecoratorHostConstructor, GraphCronMeta[]>();\n\n// ---------------------------------------------------------------------------\n// CQRS decorator metadata & registries (Phase 5.5 — CQRS replacement)\n// ---------------------------------------------------------------------------\n\nexport interface CommandHandlerMeta {\n\tcqrsName: string;\n\tcommandName: string;\n\tmethodKey: string | symbol;\n}\n\nexport interface EventHandlerMeta {\n\tcqrsName: string;\n\teventName: string;\n\tmethodKey: string | symbol;\n}\n\nexport interface QueryHandlerMeta {\n\tcqrsName: string;\n\tprojectionName: string;\n\tmethodKey: string | symbol;\n}\n\nexport interface SagaHandlerMeta {\n\tcqrsName: string;\n\teventNames: readonly string[];\n\tsagaName: string;\n\tmethodKey: string | symbol;\n}\n\n/** Registry: constructor → command handler metadata. */\nexport const COMMAND_HANDLERS = new Map<DecoratorHostConstructor, CommandHandlerMeta[]>();\n/** Registry: constructor → event handler metadata. */\nexport const CQRS_EVENT_HANDLERS = new Map<DecoratorHostConstructor, EventHandlerMeta[]>();\n/** Registry: constructor → query handler metadata. */\nexport const QUERY_HANDLERS = new Map<DecoratorHostConstructor, QueryHandlerMeta[]>();\n/** Registry: constructor → saga handler metadata. */\nexport const SAGA_HANDLERS = new Map<DecoratorHostConstructor, SagaHandlerMeta[]>();\n\n// ---------------------------------------------------------------------------\n// DI decorators\n// ---------------------------------------------------------------------------\n\n/**\n * Inject a `Graph` instance into a NestJS service or controller.\n *\n * - No argument → injects the root graph (from `forRoot()`).\n * - With `name` → injects the named feature graph (from `forFeature({ name })`).\n * - With `\"request\"` → injects the request-scoped graph (requires `requestScope: true`).\n *\n * @example\n * ```ts\n * @Injectable()\n * export class PaymentService {\n * constructor(\n * @InjectGraph() private root: Graph,\n * @InjectGraph(\"payments\") private payments: Graph,\n * ) {}\n * }\n * ```\n */\nexport function InjectGraph(name?: string): ParameterDecorator & PropertyDecorator {\n\tif (name === \"request\") return Inject(GRAPHREFLY_REQUEST_GRAPH);\n\treturn Inject(name ? getGraphToken(name) : GRAPHREFLY_ROOT_GRAPH);\n}\n\n/**\n * Inject a `CqrsGraph` instance into a NestJS service or controller.\n *\n * Typed alternative to `@InjectGraph(name)` — returns `CqrsGraph` instead of `Graph`,\n * giving access to `.command()`, `.dispatch()`, `.event()`, `.projection()`, `.saga()`.\n *\n * @param name - The CQRS graph name (from `forCqrs({ name })`).\n *\n * @example\n * ```ts\n * @Injectable()\n * export class OrderService {\n * constructor(@InjectCqrsGraph(\"orders\") private orders: CqrsGraph) {\n * orders.dispatch(\"placeOrder\", { id: \"1\" }); // fully typed\n * }\n * }\n * ```\n */\nexport function InjectCqrsGraph(name: string): ParameterDecorator & PropertyDecorator {\n\treturn Inject(getGraphToken(name));\n}\n\n/**\n * Inject a `Node` from the graph by its qualified path.\n *\n * The path must be declared in the `nodes` array of `forRoot()` or `forFeature()`.\n * The module registers a factory provider that resolves the node from the root graph\n * at injection time.\n *\n * @example\n * ```ts\n * GraphReflyModule.forRoot({ nodes: [\"payment::validate\"] })\n *\n * @Injectable()\n * export class PaymentService {\n * constructor(@InjectNode(\"payment::validate\") private validate: Node<boolean>) {}\n * }\n * ```\n */\nexport function InjectNode(path: string): ParameterDecorator & PropertyDecorator {\n\treturn Inject(getNodeToken(path));\n}\n\n// ---------------------------------------------------------------------------\n// Event & schedule method decorators (TC39 Stage 3 decorator API)\n// ---------------------------------------------------------------------------\n\n/**\n * Subscribe a method to a graph node's DATA emissions — replaces `@OnEvent()`.\n *\n * The method is called with the value payload on each `DATA` message from the\n * named node. Routes through `graph.observe()` so actor guards are respected.\n * Subscription is created on module init and disposed on destroy.\n *\n * For full protocol access (DIRTY, COMPLETE, ERROR, custom types), use\n * `graph.observe()` directly instead of this decorator.\n *\n * @param nodeName - Qualified node path (e.g. `\"orders::placed\"`).\n *\n * @example\n * ```ts\n * @Injectable()\n * export class OrderService {\n * @OnGraphEvent(\"orders::placed\")\n * handleOrder(value: Order) { ... }\n * }\n * ```\n */\nexport function OnGraphEvent(\n\tnodeName: string,\n): (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => void {\n\treturn (_value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => {\n\t\tconst methodKey = context.name;\n\t\tcontext.addInitializer(function (this: unknown) {\n\t\t\tconst ctor = (this as { constructor: DecoratorHostConstructor }).constructor;\n\t\t\tconst existing = EVENT_HANDLERS.get(ctor) ?? [];\n\t\t\texisting.push({ nodeName, methodKey });\n\t\t\tEVENT_HANDLERS.set(ctor, existing);\n\t\t});\n\t};\n}\n\n/**\n * Run a method on a fixed interval — replaces `@Interval()` from `@nestjs/schedule`.\n *\n * Backed by a `fromTimer` node added to the root graph as `__schedule__.<className>.<methodName>`.\n * Visible in `graph.describe()`, pausable via `graph.signal(name, [[PAUSE, lockId]])`.\n *\n * @param ms - Interval in milliseconds.\n *\n * @example\n * ```ts\n * @Injectable()\n * export class CleanupService {\n * @GraphInterval(5000)\n * pruneStale() { ... }\n * }\n * ```\n */\nexport function GraphInterval(\n\tms: number,\n): (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => void {\n\treturn (_value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => {\n\t\tconst methodKey = context.name;\n\t\tcontext.addInitializer(function (this: unknown) {\n\t\t\tconst ctor = (this as { constructor: DecoratorHostConstructor }).constructor;\n\t\t\tconst existing = INTERVAL_HANDLERS.get(ctor) ?? [];\n\t\t\texisting.push({ ms, methodKey });\n\t\t\tINTERVAL_HANDLERS.set(ctor, existing);\n\t\t});\n\t};\n}\n\n/**\n * Run a method on a cron schedule — replaces `@Cron()` from `@nestjs/schedule`.\n *\n * Backed by a `fromCron` node added to the root graph as `__schedule__.<className>.<methodName>`.\n * Visible in `graph.describe()`, pausable via PAUSE/RESUME signals.\n *\n * @param expr - 5-field cron expression (`min hour dom month dow`).\n *\n * @example\n * ```ts\n * @Injectable()\n * export class ReportService {\n * @GraphCron(\"0 9 * * 1\")\n * weeklyReport() { ... }\n * }\n * ```\n */\nexport function GraphCron(\n\texpr: string,\n): (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => void {\n\treturn (_value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => {\n\t\tconst methodKey = context.name;\n\t\tcontext.addInitializer(function (this: unknown) {\n\t\t\tconst ctor = (this as { constructor: DecoratorHostConstructor }).constructor;\n\t\t\tconst existing = CRON_HANDLERS.get(ctor) ?? [];\n\t\t\texisting.push({ expr, methodKey });\n\t\t\tCRON_HANDLERS.set(ctor, existing);\n\t\t});\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// CQRS method decorators (Phase 5.5 — CQRS replacement)\n// ---------------------------------------------------------------------------\n\n/**\n * Register a method as a CQRS command handler — replaces `@CommandHandler()` from `@nestjs/cqrs`.\n *\n * The method receives `(payload, { emit })` — same signature as `CqrsGraph.command()` handlers.\n * Wired reactively via the explorer on module init.\n *\n * @param cqrsName - Name of the CQRS graph (from `forCqrs({ name })`).\n * @param commandName - Command to handle.\n *\n * @example\n * ```ts\n * @Injectable()\n * export class OrderService {\n * @CommandHandler(\"orders\", \"placeOrder\")\n * handlePlace(payload: PlaceOrderDto, { emit }: CommandActions) {\n * emit(\"orderPlaced\", { orderId: payload.id, amount: payload.amount });\n * }\n * }\n * ```\n */\nexport function CommandHandler(\n\tcqrsName: string,\n\tcommandName: string,\n): (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => void {\n\treturn (_value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => {\n\t\tconst methodKey = context.name;\n\t\tcontext.addInitializer(function (this: unknown) {\n\t\t\tconst ctor = (this as { constructor: DecoratorHostConstructor }).constructor;\n\t\t\tconst existing = COMMAND_HANDLERS.get(ctor) ?? [];\n\t\t\texisting.push({ cqrsName, commandName, methodKey });\n\t\t\tCOMMAND_HANDLERS.set(ctor, existing);\n\t\t});\n\t};\n}\n\n/**\n * Subscribe a method to CQRS event stream DATA — replaces `@EventsHandler()` from `@nestjs/cqrs`.\n *\n * The method receives each `CqrsEvent` envelope as events arrive. Subscription is reactive\n * via `graph.observe()` — actor guards are respected.\n *\n * @param cqrsName - Name of the CQRS graph.\n * @param eventName - Event stream to subscribe to.\n *\n * @example\n * ```ts\n * @Injectable()\n * export class NotificationService {\n * @EventHandler(\"orders\", \"orderPlaced\")\n * onOrderPlaced(event: CqrsEvent<{ orderId: string }>) {\n * console.log(\"Order placed:\", event.payload.orderId);\n * }\n * }\n * ```\n */\nexport function EventHandler(\n\tcqrsName: string,\n\teventName: string,\n): (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => void {\n\treturn (_value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => {\n\t\tconst methodKey = context.name;\n\t\tcontext.addInitializer(function (this: unknown) {\n\t\t\tconst ctor = (this as { constructor: DecoratorHostConstructor }).constructor;\n\t\t\tconst existing = CQRS_EVENT_HANDLERS.get(ctor) ?? [];\n\t\t\texisting.push({ cqrsName, eventName, methodKey });\n\t\t\tCQRS_EVENT_HANDLERS.set(ctor, existing);\n\t\t});\n\t};\n}\n\n/**\n * Subscribe a method to CQRS projection changes — replaces `@QueryHandler()` from `@nestjs/cqrs`.\n *\n * The method is called reactively whenever the projection's value changes (DATA emission).\n * This is push-based, not request-response — the projection recomputes on upstream events.\n *\n * @param cqrsName - Name of the CQRS graph.\n * @param projectionName - Projection to observe.\n *\n * @example\n * ```ts\n * @Injectable()\n * export class DashboardService {\n * @QueryHandler(\"orders\", \"orderCount\")\n * onCountChanged(count: number) {\n * this.broadcast({ type: \"orderCount\", value: count });\n * }\n * }\n * ```\n */\nexport function QueryHandler(\n\tcqrsName: string,\n\tprojectionName: string,\n): (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => void {\n\treturn (_value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => {\n\t\tconst methodKey = context.name;\n\t\tcontext.addInitializer(function (this: unknown) {\n\t\t\tconst ctor = (this as { constructor: DecoratorHostConstructor }).constructor;\n\t\t\tconst existing = QUERY_HANDLERS.get(ctor) ?? [];\n\t\t\texisting.push({ cqrsName, projectionName, methodKey });\n\t\t\tQUERY_HANDLERS.set(ctor, existing);\n\t\t});\n\t};\n}\n\n/**\n * Register a method as a CQRS saga — replaces RxJS saga streams from `@nestjs/cqrs`.\n *\n * The method receives each new `CqrsEvent` from the specified event streams. Backed by\n * `CqrsGraph.saga()` — tracks last-processed entry, only delivers new events.\n *\n * @param cqrsName - Name of the CQRS graph.\n * @param sagaName - Name for this saga node in the graph.\n * @param eventNames - Event streams to react to.\n *\n * @example\n * ```ts\n * @Injectable()\n * export class FulfillmentService {\n * @SagaHandler(\"orders\", \"fulfillment\", [\"orderPlaced\", \"paymentConfirmed\"])\n * onOrderFlow(event: CqrsEvent) {\n * if (event.type === \"paymentConfirmed\") this.shipOrder(event.payload);\n * }\n * }\n * ```\n */\nexport function SagaHandler(\n\tcqrsName: string,\n\tsagaName: string,\n\teventNames: readonly string[],\n): (value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => void {\n\treturn (_value: DecoratorBoundMethod, context: ClassMethodDecoratorContext) => {\n\t\tconst methodKey = context.name;\n\t\tcontext.addInitializer(function (this: unknown) {\n\t\t\tconst ctor = (this as { constructor: DecoratorHostConstructor }).constructor;\n\t\t\tconst existing = SAGA_HANDLERS.get(ctor) ?? [];\n\t\t\texisting.push({ cqrsName, eventNames, sagaName, methodKey });\n\t\t\tSAGA_HANDLERS.set(ctor, existing);\n\t\t});\n\t};\n}\n","// ---------------------------------------------------------------------------\n// NestJS DI tokens for GraphReFly integration.\n// ---------------------------------------------------------------------------\n\n/** Injection token for the root `Graph` singleton created by `forRoot()`. */\nexport const GRAPHREFLY_ROOT_GRAPH = Symbol.for(\"graphrefly:root-graph\");\n\n/** Injection token for `forRoot()` / `forFeature()` options. */\nexport const GRAPHREFLY_MODULE_OPTIONS = Symbol.for(\"graphrefly:module-options\");\n\n/** Injection token for the request-scoped `Graph` created by request scope config. */\nexport const GRAPHREFLY_REQUEST_GRAPH = Symbol.for(\"graphrefly:request-graph\");\n\n/**\n * Get the injection token for a named feature graph.\n *\n * Feature graphs registered via `GraphReflyModule.forFeature({ name })` are\n * injectable using this token (or via the `@InjectGraph(name)` decorator).\n */\nexport function getGraphToken(name: string): symbol {\n\treturn Symbol.for(`graphrefly:graph:${name}`);\n}\n\n/**\n * Get the injection token for a node at a qualified path.\n *\n * Nodes declared in `forRoot({ nodes })` or `forFeature({ nodes })` are\n * injectable using this token (or via the `@InjectNode(path)` decorator).\n */\nexport function getNodeToken(path: string): symbol {\n\treturn Symbol.for(`graphrefly:node:${path}`);\n}\n","// ---------------------------------------------------------------------------\n// GraphReflyEventExplorer — discovers @OnGraphEvent, @GraphInterval, @GraphCron\n// decorated methods and wires them to the root graph.\n// ---------------------------------------------------------------------------\n// Registered by `forRoot()`. On module init, reads global decorator registries,\n// resolves provider instances via ModuleRef, and creates reactive subscriptions\n// / timer nodes. On module destroy, disposes all subscriptions and removes\n// schedule nodes from the graph.\n//\n// Runtime is fully reactive — push-based via graph.observe().\n// No polling, no microtasks, no promises. Timer nodes use central fromTimer /\n// fromCron primitives.\n// ---------------------------------------------------------------------------\n\nimport type { OnModuleDestroy, OnModuleInit } from \"@nestjs/common\";\nimport type { ModuleRef } from \"@nestjs/core\";\nimport { DATA, type Messages } from \"../../core/messages.js\";\nimport { fromCron, fromTimer } from \"../../extra/sources.js\";\nimport type { Graph, GraphObserveOne } from \"../../graph/graph.js\";\nimport type { CqrsGraph } from \"../../patterns/cqrs.js\";\nimport {\n\tCOMMAND_HANDLERS,\n\ttype CommandHandlerMeta,\n\tCQRS_EVENT_HANDLERS,\n\tCRON_HANDLERS,\n\ttype DecoratorBoundMethod,\n\ttype DecoratorHostConstructor,\n\tEVENT_HANDLERS,\n\ttype EventHandlerMeta,\n\ttype GraphCronMeta,\n\ttype GraphIntervalMeta,\n\tINTERVAL_HANDLERS,\n\ttype OnGraphEventMeta,\n\tQUERY_HANDLERS,\n\ttype QueryHandlerMeta,\n\tSAGA_HANDLERS,\n\ttype SagaHandlerMeta,\n} from \"./decorators.js\";\nimport { getGraphToken } from \"./tokens.js\";\n\n/** Monotonic counter for schedule node name disambiguation. */\nlet scheduleSeq = 0;\n\nexport class GraphReflyEventExplorer implements OnModuleInit, OnModuleDestroy {\n\tprivate readonly disposers: Array<() => void> = [];\n\tprivate readonly scheduleNodeNames: string[] = [];\n\n\tconstructor(\n\t\tprivate readonly graph: Graph,\n\t\tprivate readonly moduleRef: ModuleRef,\n\t) {}\n\n\tonModuleInit(): void {\n\t\tthis.wireEvents();\n\t\tthis.wireIntervals();\n\t\tthis.wireCrons();\n\t\tthis.wireCqrsCommands();\n\t\tthis.wireCqrsEvents();\n\t\tthis.wireCqrsQueries();\n\t\tthis.wireCqrsSagas();\n\t}\n\n\tonModuleDestroy(): void {\n\t\tfor (const dispose of this.disposers) dispose();\n\t\tthis.disposers.length = 0;\n\n\t\tfor (const name of this.scheduleNodeNames) {\n\t\t\ttry {\n\t\t\t\tthis.graph.remove(name);\n\t\t\t} catch {\n\t\t\t\t// Node may already be gone if graph.destroy() ran first.\n\t\t\t}\n\t\t}\n\t\tthis.scheduleNodeNames.length = 0;\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// @OnGraphEvent — reactive subscription via graph.observe()\n\t// -----------------------------------------------------------------------\n\n\tprivate wireEvents(): void {\n\t\tfor (const [ctor, metas] of EVENT_HANDLERS) {\n\t\t\tconst instance = this.resolveInstance(ctor);\n\t\t\tif (!instance) continue;\n\n\t\t\tfor (const meta of metas) {\n\t\t\t\tthis.wireEventHandler(instance, meta);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate wireEventHandler(instance: object, meta: OnGraphEventMeta): void {\n\t\tconst method = (instance as Record<string | symbol, DecoratorBoundMethod>)[meta.methodKey];\n\t\tif (typeof method !== \"function\") return;\n\n\t\tconst bound = method.bind(instance);\n\n\t\t// Route through graph.observe() so actor guards are respected.\n\t\tconst handle = this.observeNode(meta.nodeName);\n\t\tconst unsub = handle.subscribe((msgs: Messages) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tbound(m[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.disposers.push(unsub);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// @GraphInterval — reactive via fromTimer central timer primitive\n\t// -----------------------------------------------------------------------\n\n\tprivate wireIntervals(): void {\n\t\tfor (const [ctor, metas] of INTERVAL_HANDLERS) {\n\t\t\tconst instance = this.resolveInstance(ctor);\n\t\t\tif (!instance) continue;\n\n\t\t\tfor (const meta of metas) {\n\t\t\t\tthis.wireIntervalHandler(instance, ctor, meta);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate wireIntervalHandler(\n\t\tinstance: object,\n\t\tctor: DecoratorHostConstructor,\n\t\tmeta: GraphIntervalMeta,\n\t): void {\n\t\tconst method = (instance as Record<string | symbol, DecoratorBoundMethod>)[meta.methodKey];\n\t\tif (typeof method !== \"function\") return;\n\n\t\tconst bound = method.bind(instance);\n\t\tconst className = ctor.name ?? \"anonymous\";\n\t\tconst nodeName = `__schedule__.${className}.${String(meta.methodKey)}.${scheduleSeq++}`;\n\n\t\tconst timerNode = fromTimer(meta.ms, { period: meta.ms, name: nodeName });\n\t\tthis.graph.add(nodeName, timerNode);\n\t\tthis.scheduleNodeNames.push(nodeName);\n\n\t\t// Subscribe through graph.observe() for consistency.\n\t\tconst handle = this.observeNode(nodeName);\n\t\tconst unsub = handle.subscribe((msgs: Messages) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) bound(m[1]);\n\t\t\t}\n\t\t});\n\t\tthis.disposers.push(unsub);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// @GraphCron — reactive via fromCron central timer primitive\n\t// -----------------------------------------------------------------------\n\n\tprivate wireCrons(): void {\n\t\tfor (const [ctor, metas] of CRON_HANDLERS) {\n\t\t\tconst instance = this.resolveInstance(ctor);\n\t\t\tif (!instance) continue;\n\n\t\t\tfor (const meta of metas) {\n\t\t\t\tthis.wireCronHandler(instance, ctor, meta);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate wireCronHandler(\n\t\tinstance: object,\n\t\tctor: DecoratorHostConstructor,\n\t\tmeta: GraphCronMeta,\n\t): void {\n\t\tconst method = (instance as Record<string | symbol, DecoratorBoundMethod>)[meta.methodKey];\n\t\tif (typeof method !== \"function\") return;\n\n\t\tconst bound = method.bind(instance);\n\t\tconst className = ctor.name ?? \"anonymous\";\n\t\tconst nodeName = `__schedule__.${className}.${String(meta.methodKey)}.${scheduleSeq++}`;\n\n\t\tconst cronNode = fromCron(meta.expr, { name: nodeName });\n\t\tthis.graph.add(nodeName, cronNode);\n\t\tthis.scheduleNodeNames.push(nodeName);\n\n\t\t// Subscribe through graph.observe() for consistency.\n\t\tconst handle = this.observeNode(nodeName);\n\t\tconst unsub = handle.subscribe((msgs: Messages) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) bound(m[1]);\n\t\t\t}\n\t\t});\n\t\tthis.disposers.push(unsub);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// @CommandHandler — register method as CqrsGraph command handler\n\t// -----------------------------------------------------------------------\n\n\tprivate wireCqrsCommands(): void {\n\t\tfor (const [ctor, metas] of COMMAND_HANDLERS) {\n\t\t\tconst instance = this.resolveInstance(ctor);\n\t\t\tif (!instance) continue;\n\n\t\t\tfor (const meta of metas) {\n\t\t\t\tthis.wireCqrsCommand(instance, meta);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate wireCqrsCommand(instance: object, meta: CommandHandlerMeta): void {\n\t\tconst method = (instance as Record<string | symbol, DecoratorBoundMethod>)[meta.methodKey];\n\t\tif (typeof method !== \"function\") return;\n\n\t\tconst bound = method.bind(instance);\n\t\tconst cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);\n\t\tif (!cqrsGraph) return;\n\n\t\tcqrsGraph.command(meta.commandName, bound);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// @EventHandler — subscribe method to CQRS event stream\n\t// -----------------------------------------------------------------------\n\n\tprivate wireCqrsEvents(): void {\n\t\tfor (const [ctor, metas] of CQRS_EVENT_HANDLERS) {\n\t\t\tconst instance = this.resolveInstance(ctor);\n\t\t\tif (!instance) continue;\n\n\t\t\tfor (const meta of metas) {\n\t\t\t\tthis.wireCqrsEventHandler(instance, meta);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate wireCqrsEventHandler(instance: object, meta: EventHandlerMeta): void {\n\t\tconst method = (instance as Record<string | symbol, DecoratorBoundMethod>)[meta.methodKey];\n\t\tif (typeof method !== \"function\") return;\n\n\t\tconst bound = method.bind(instance);\n\t\tconst cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);\n\t\tif (!cqrsGraph) return;\n\n\t\t// Ensure the event stream exists.\n\t\tcqrsGraph.event(meta.eventName);\n\n\t\t// Snapshot the highest seq already in the log so we only deliver new events.\n\t\t// Tracking by seq (monotonic per-graph) is robust against reactive log trim.\n\t\tconst eventNode = cqrsGraph.resolve(meta.eventName);\n\t\tconst existingEntries = eventNode.cache as readonly { seq: number }[] | undefined;\n\t\tlet lastSeq =\n\t\t\texistingEntries && existingEntries.length > 0\n\t\t\t\t? existingEntries[existingEntries.length - 1].seq\n\t\t\t\t: 0;\n\n\t\t// Subscribe reactively via graph.observe() — respects actor guards.\n\t\tconst handle = this.observeNodeOn(cqrsGraph, meta.eventName);\n\t\tconst unsub = handle.subscribe((msgs: Messages) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tconst entries = m[1] as readonly { seq: number }[];\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tif (entry.seq > lastSeq) {\n\t\t\t\t\t\t\tbound(entry);\n\t\t\t\t\t\t\tlastSeq = entry.seq;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.disposers.push(unsub);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// @QueryHandler — subscribe method to CQRS projection changes\n\t// -----------------------------------------------------------------------\n\n\tprivate wireCqrsQueries(): void {\n\t\tfor (const [ctor, metas] of QUERY_HANDLERS) {\n\t\t\tconst instance = this.resolveInstance(ctor);\n\t\t\tif (!instance) continue;\n\n\t\t\tfor (const meta of metas) {\n\t\t\t\tthis.wireCqrsQuery(instance, meta);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate wireCqrsQuery(instance: object, meta: QueryHandlerMeta): void {\n\t\tconst method = (instance as Record<string | symbol, DecoratorBoundMethod>)[meta.methodKey];\n\t\tif (typeof method !== \"function\") return;\n\n\t\tconst bound = method.bind(instance);\n\t\tconst cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);\n\t\tif (!cqrsGraph) return;\n\n\t\t// Subscribe reactively to the projection node — push on every DATA.\n\t\tconst handle = this.observeNodeOn(cqrsGraph, meta.projectionName);\n\t\tconst unsub = handle.subscribe((msgs: Messages) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tbound(m[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.disposers.push(unsub);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// @SagaHandler — register method as CqrsGraph saga (subgraph side effect)\n\t// -----------------------------------------------------------------------\n\n\tprivate wireCqrsSagas(): void {\n\t\tfor (const [ctor, metas] of SAGA_HANDLERS) {\n\t\t\tconst instance = this.resolveInstance(ctor);\n\t\t\tif (!instance) continue;\n\n\t\t\tfor (const meta of metas) {\n\t\t\t\tthis.wireCqrsSaga(instance, meta);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate wireCqrsSaga(instance: object, meta: SagaHandlerMeta): void {\n\t\tconst method = (instance as Record<string | symbol, DecoratorBoundMethod>)[meta.methodKey];\n\t\tif (typeof method !== \"function\") return;\n\n\t\tconst bound = method.bind(instance);\n\t\tconst cqrsGraph = this.resolveCqrsGraph(meta.cqrsName);\n\t\tif (!cqrsGraph) return;\n\n\t\tcqrsGraph.saga(meta.sagaName, meta.eventNames, bound);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Helpers\n\t// -----------------------------------------------------------------------\n\n\tprivate observeNode(name: string): GraphObserveOne {\n\t\t// Overload resolution picks ObserveResult; cast to the correct single-node type.\n\t\treturn this.graph.observe(name) as unknown as GraphObserveOne;\n\t}\n\n\tprivate observeNodeOn(graph: Graph, name: string): GraphObserveOne {\n\t\treturn graph.observe(name) as unknown as GraphObserveOne;\n\t}\n\n\tprivate resolveCqrsGraph(name: string): CqrsGraph | null {\n\t\ttry {\n\t\t\treturn this.moduleRef.get(getGraphToken(name), { strict: false }) as CqrsGraph;\n\t\t} catch {\n\t\t\tconsole.warn(\n\t\t\t\t`[GraphReFly] CqrsGraph \"${name}\" not found in DI — ` +\n\t\t\t\t\t`did you import GraphReflyModule.forCqrs({ name: \"${name}\" })?`,\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate resolveInstance(ctor: DecoratorHostConstructor): object | null {\n\t\ttry {\n\t\t\treturn this.moduleRef.get(ctor, { strict: false });\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n}\n","// ---------------------------------------------------------------------------\n// NestJS Gateway helpers — reactive bridges from graph.observe() to transports.\n// ---------------------------------------------------------------------------\n// All helpers are push-based: they subscribe to `graph.observe()` with actor\n// context and forward DATA messages to the transport. No polling.\n//\n// Actor-scoped observation respects node guards (Phase 1.5). Clients only\n// see DATA values from nodes their Actor is allowed to observe.\n// ---------------------------------------------------------------------------\n\nimport type { Actor } from \"../../core/actor.js\";\nimport { COMPLETE, DATA, ERROR, type Messages, TEARDOWN } from \"../../core/messages.js\";\nimport { createWatermarkController, type WatermarkController } from \"../../extra/backpressure.js\";\nimport type { Graph, GraphObserveOne } from \"../../graph/graph.js\";\n\n// ---------------------------------------------------------------------------\n// Shared types\n// ---------------------------------------------------------------------------\n\n/**\n * Client-to-server commands for the WebSocket observe protocol.\n */\nexport type ObserveWsCommand =\n\t| { type: \"subscribe\"; path: string }\n\t| { type: \"unsubscribe\"; path: string }\n\t| { type: \"ack\"; path: string; count?: number };\n\n/**\n * Server-to-client messages for the WebSocket observe protocol.\n */\nexport type ObserveWsMessage<T = unknown> =\n\t| { type: \"data\"; path: string; value: T }\n\t| { type: \"error\"; path: string; error: string }\n\t| { type: \"complete\"; path: string }\n\t| { type: \"subscribed\"; path: string }\n\t| { type: \"unsubscribed\"; path: string }\n\t| { type: \"err\"; message: string };\n\n// ---------------------------------------------------------------------------\n// observeSSE — graph.observe() → SSE ReadableStream\n// ---------------------------------------------------------------------------\n\nexport type ObserveSSEOptions = {\n\tactor?: Actor;\n\tserialize?: (value: unknown) => string;\n\tkeepAliveMs?: number;\n\tsignal?: AbortSignal;\n\t/** Pending DATA count at which PAUSE is sent upstream. Enables backpressure when set. */\n\thighWaterMark?: number;\n\t/** Pending DATA count at which RESUME is sent upstream. Defaults to `Math.floor(highWaterMark / 2)`. */\n\tlowWaterMark?: number;\n};\n\n/**\n * Creates an SSE `ReadableStream` that streams DATA values from a graph node.\n *\n * Routes through `graph.observe(path, { actor })` so node guards are respected.\n * The stream emits `event: data` for DATA, `event: error` for ERROR, and\n * `event: complete` for COMPLETE (then closes). TEARDOWN also closes the stream.\n *\n * @param graph - The graph to observe.\n * @param path - Qualified node path to observe.\n * @param opts - Actor context, serialization, keep-alive.\n * @returns A `ReadableStream<Uint8Array>` suitable for NestJS SSE endpoints.\n *\n * @example\n * ```ts\n * @Sse(\"events/:path\")\n * streamEvents(@Param(\"path\") path: string, @Req() req: Request) {\n * return observeSSE(this.graph, path, { actor: getActor(req) });\n * }\n * ```\n */\nexport function observeSSE(\n\tgraph: Graph,\n\tpath: string,\n\topts?: ObserveSSEOptions,\n): ReadableStream<Uint8Array> {\n\tconst { actor, serialize = defaultSerialize, keepAliveMs, signal } = opts ?? {};\n\tconst encoder = new TextEncoder();\n\tlet stop: (() => void) | undefined;\n\tconst useBackpressure = opts?.highWaterMark != null;\n\n\tlet wm: WatermarkController | undefined;\n\tlet pullResolve: (() => void) | undefined;\n\n\t// When backpressure is enabled we tag buffered entries so pull() only calls\n\t// onDequeue for DATA frames (not keepalive, ERROR, or COMPLETE frames).\n\ttype BufEntry = { frame: Uint8Array; counted: boolean };\n\tconst taggedBuf: BufEntry[] = [];\n\tlet closed = false;\n\n\treturn new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tlet keepAlive: ReturnType<typeof setInterval> | undefined;\n\t\t\tlet unsub: () => void = () => {};\n\t\t\tconst close = () => {\n\t\t\t\tif (closed) return;\n\t\t\t\tclosed = true;\n\t\t\t\tif (keepAlive !== undefined) clearInterval(keepAlive);\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t// Unsub first to prevent further sink callbacks during dispose.\n\t\t\t\tunsub();\n\t\t\t\twm?.dispose();\n\t\t\t\t// Resolve any parked pull() promise so the stream can finish.\n\t\t\t\tpullResolve?.();\n\t\t\t\tpullResolve = undefined;\n\t\t\t\t// Flush remaining buffered frames before closing.\n\t\t\t\tfor (const entry of taggedBuf) controller.enqueue(entry.frame);\n\t\t\t\ttaggedBuf.length = 0;\n\t\t\t\tcontroller.close();\n\t\t\t};\n\t\t\tstop = close;\n\t\t\tconst onAbort = () => close();\n\n\t\t\tconst handle = graph.observe(path, { actor }) as unknown as GraphObserveOne;\n\n\t\t\tif (useBackpressure) {\n\t\t\t\twm = createWatermarkController((msgs) => handle.up(msgs), {\n\t\t\t\t\thighWaterMark: opts!.highWaterMark!,\n\t\t\t\t\tlowWaterMark: opts!.lowWaterMark ?? Math.floor(opts!.highWaterMark! / 2),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tunsub = handle.subscribe((msgs: Messages) => {\n\t\t\t\tfor (const msg of msgs) {\n\t\t\t\t\tif (closed) return;\n\t\t\t\t\tconst t = msg[0];\n\t\t\t\t\tif (t === DATA) {\n\t\t\t\t\t\tconst frame = encoder.encode(sseFrame(\"data\", serialize(msg[1])));\n\t\t\t\t\t\tif (useBackpressure) {\n\t\t\t\t\t\t\ttaggedBuf.push({ frame, counted: true });\n\t\t\t\t\t\t\twm!.onEnqueue();\n\t\t\t\t\t\t\tpullResolve?.();\n\t\t\t\t\t\t\tpullResolve = undefined;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontroller.enqueue(frame);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\tconst frame = encoder.encode(sseFrame(\"error\", serialize(msg[1])));\n\t\t\t\t\t\tif (useBackpressure) {\n\t\t\t\t\t\t\ttaggedBuf.push({ frame, counted: false });\n\t\t\t\t\t\t\tpullResolve?.();\n\t\t\t\t\t\t\tpullResolve = undefined;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontroller.enqueue(frame);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tclose();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else if (t === COMPLETE || t === TEARDOWN) {\n\t\t\t\t\t\tif (t === COMPLETE) {\n\t\t\t\t\t\t\tconst frame = encoder.encode(sseFrame(\"complete\"));\n\t\t\t\t\t\t\tif (useBackpressure) {\n\t\t\t\t\t\t\t\ttaggedBuf.push({ frame, counted: false });\n\t\t\t\t\t\t\t\tpullResolve?.();\n\t\t\t\t\t\t\t\tpullResolve = undefined;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcontroller.enqueue(frame);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tclose();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// DIRTY, RESOLVED, and other protocol internals are not exposed to SSE clients\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (keepAliveMs !== undefined && keepAliveMs > 0) {\n\t\t\t\tkeepAlive = setInterval(() => {\n\t\t\t\t\tif (closed) return;\n\t\t\t\t\tif (useBackpressure) {\n\t\t\t\t\t\t// Keepalive frames bypass watermark accounting entirely.\n\t\t\t\t\t\ttaggedBuf.push({ frame: encoder.encode(\": keepalive\\n\\n\"), counted: false });\n\t\t\t\t\t\tpullResolve?.();\n\t\t\t\t\t\tpullResolve = undefined;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontroller.enqueue(encoder.encode(\": keepalive\\n\\n\"));\n\t\t\t\t\t}\n\t\t\t\t}, keepAliveMs);\n\t\t\t}\n\t\t\tif (signal?.aborted) onAbort();\n\t\t\telse signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t},\n\t\tpull(controller) {\n\t\t\tif (!useBackpressure) return;\n\t\t\tif (closed) return;\n\t\t\tif (taggedBuf.length > 0) {\n\t\t\t\tconst entry = taggedBuf.shift()!;\n\t\t\t\tcontroller.enqueue(entry.frame);\n\t\t\t\tif (entry.counted) wm!.onDequeue();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// No data available — park until the sink callback pushes more.\n\t\t\treturn new Promise<void>((resolve) => {\n\t\t\t\tpullResolve = resolve;\n\t\t\t});\n\t\t},\n\t\tcancel() {\n\t\t\t// Guard against double-close (cancel may fire after COMPLETE/ERROR already closed).\n\t\t\ttry {\n\t\t\t\tstop?.();\n\t\t\t} catch {\n\t\t\t\t/* already closed */\n\t\t\t}\n\t\t},\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// observeSubscription — graph.observe() → AsyncIterableIterator (GraphQL)\n// ---------------------------------------------------------------------------\n\nexport type ObserveSubscriptionOptions<T = unknown> = {\n\tactor?: Actor;\n\t/**\n\t * Optional value filter. Only matching DATA values are enqueued.\n\t *\n\t * **Note:** `filter` and `highWaterMark` are semantically decoupled — the\n\t * watermark counts items that pass the filter, not total upstream work.\n\t * If the filter rejects most items, backpressure may never engage despite\n\t * high upstream throughput. For upstream-level resource protection, place a\n\t * filtering derived node in the graph before the observe point instead.\n\t */\n\tfilter?: (value: T) => boolean;\n\t/** Pending DATA count at which PAUSE is sent upstream. Enables backpressure when set. */\n\thighWaterMark?: number;\n\t/** Pending DATA count at which RESUME is sent upstream. Defaults to `Math.floor(highWaterMark / 2)`. */\n\tlowWaterMark?: number;\n};\n\n/**\n * Creates an `AsyncIterableIterator` that yields DATA values from a graph node.\n *\n * Designed for GraphQL subscription resolvers (Apollo, Mercurius, etc.).\n * Routes through `graph.observe(path, { actor })` for guard-scoped access.\n *\n * The iterator completes on COMPLETE/TEARDOWN and throws on ERROR.\n *\n * @param graph - The graph to observe.\n * @param path - Qualified node path to observe.\n * @param opts - Actor context, optional value filter.\n * @returns An async iterable that yields DATA payloads.\n *\n * @example\n * ```ts\n * // Apollo-style resolver\n * Subscription: {\n * orderStatus: {\n * subscribe: (_parent, args, ctx) =>\n * observeSubscription(ctx.graph, `orders::${args.id}::status`, {\n * actor: ctx.actor,\n * }),\n * },\n * }\n * ```\n */\nexport function observeSubscription<T = unknown>(\n\tgraph: Graph,\n\tpath: string,\n\topts?: ObserveSubscriptionOptions<T>,\n): AsyncIterableIterator<T> {\n\tconst { actor, filter } = opts ?? {};\n\n\ttype QueueItem = { done: false; value: T } | { done: true; value?: undefined; error?: Error };\n\n\tconst queue: QueueItem[] = [];\n\tconst waiters: Array<{\n\t\tresolve: (result: IteratorResult<T>) => void;\n\t\treject: (err: unknown) => void;\n\t}> = [];\n\tlet disposed = false;\n\n\tconst handle = graph.observe(path, { actor }) as unknown as GraphObserveOne;\n\n\tconst wm =\n\t\topts?.highWaterMark != null\n\t\t\t? createWatermarkController((msgs) => handle.up(msgs), {\n\t\t\t\t\thighWaterMark: opts.highWaterMark,\n\t\t\t\t\tlowWaterMark: opts.lowWaterMark ?? Math.floor(opts.highWaterMark / 2),\n\t\t\t\t})\n\t\t\t: undefined;\n\n\tconst dispose = () => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\twm?.dispose();\n\t\tunsub();\n\t};\n\n\tconst push = (item: QueueItem) => {\n\t\tif (disposed) return;\n\t\tif (waiters.length > 0) {\n\t\t\tconst w = waiters.shift()!;\n\t\t\tif (item.done && item.error) w.reject(item.error);\n\t\t\telse if (item.done) w.resolve({ done: true, value: undefined });\n\t\t\telse w.resolve({ done: false, value: item.value as T });\n\t\t\t// Direct handoff to waiter — no queue growth, no watermark increment.\n\t\t} else {\n\t\t\tqueue.push(item);\n\t\t\tif (!item.done) wm?.onEnqueue();\n\t\t}\n\t};\n\n\tconst unsub = handle.subscribe((msgs: Messages) => {\n\t\tfor (const msg of msgs) {\n\t\t\tconst t = msg[0];\n\t\t\tif (t === DATA) {\n\t\t\t\tconst value = msg[1] as T;\n\t\t\t\tif (filter && !filter(value)) continue;\n\t\t\t\tpush({ done: false, value });\n\t\t\t} else if (t === ERROR) {\n\t\t\t\tconst err = msg[1] instanceof Error ? msg[1] : new Error(String(msg[1]));\n\t\t\t\tpush({ done: true, error: err });\n\t\t\t\tdispose();\n\t\t\t\treturn;\n\t\t\t} else if (t === COMPLETE || t === TEARDOWN) {\n\t\t\t\tpush({ done: true });\n\t\t\t\tdispose();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t});\n\n\tconst iterator: AsyncIterableIterator<T> = {\n\t\tnext(): Promise<IteratorResult<T>> {\n\t\t\tif (queue.length > 0) {\n\t\t\t\tconst item = queue.shift()!;\n\t\t\t\tif (!item.done) wm?.onDequeue();\n\t\t\t\tif (item.done && item.error) return Promise.reject(item.error);\n\t\t\t\treturn Promise.resolve(\n\t\t\t\t\titem.done ? { done: true, value: undefined } : { done: false, value: item.value as T },\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (disposed) return Promise.resolve({ done: true, value: undefined });\n\t\t\treturn new Promise<IteratorResult<T>>((resolve, reject) => {\n\t\t\t\twaiters.push({ resolve, reject });\n\t\t\t});\n\t\t},\n\t\treturn(): Promise<IteratorReturnResult<undefined>> {\n\t\t\tdispose();\n\t\t\t// Resolve any pending waiters\n\t\t\tfor (const w of waiters) w.resolve({ done: true, value: undefined });\n\t\t\twaiters.length = 0;\n\t\t\treturn Promise.resolve({ done: true, value: undefined });\n\t\t},\n\t\tthrow(err: unknown): Promise<IteratorResult<T>> {\n\t\t\tdispose();\n\t\t\treturn Promise.reject(err);\n\t\t},\n\t\t[Symbol.asyncIterator]() {\n\t\t\treturn this;\n\t\t},\n\t};\n\n\treturn iterator;\n}\n\n// ---------------------------------------------------------------------------\n// ObserveGateway — graph.observe() → WebSocket (multi-path subscription)\n// ---------------------------------------------------------------------------\n\nexport type ObserveGatewayOptions = {\n\textractActor?: (client: unknown) => Actor | undefined;\n\tparse?: (data: string) => ObserveWsCommand;\n\t/** Pending DATA count per subscription at which PAUSE is sent upstream. Enables backpressure when set. */\n\thighWaterMark?: number;\n\t/** Pending DATA count per subscription at which RESUME is sent upstream. Defaults to `Math.floor(highWaterMark / 2)`. */\n\tlowWaterMark?: number;\n};\n\n/**\n * Manages per-client WebSocket subscriptions to graph nodes via `observe()`.\n *\n * Not a NestJS decorator or base class — a standalone helper that can be\n * wired into any WebSocket gateway. Each client can subscribe/unsubscribe\n * to individual node paths. Actor-scoped observation respects node guards.\n *\n * @example\n * ```ts\n * @WebSocketGateway()\n * export class GraphGateway {\n * private gw = new ObserveGateway(this.graph);\n *\n * constructor(@InjectGraph() private graph: Graph) {}\n *\n * handleConnection(client: WebSocket) {\n * this.gw.handleConnection(client);\n * }\n *\n * handleDisconnect(client: WebSocket) {\n * this.gw.handleDisconnect(client);\n * }\n *\n * @SubscribeMessage(\"observe\")\n * onObserve(client: WebSocket, data: unknown) {\n * this.gw.handleMessage(client, data);\n * }\n * }\n * ```\n */\nexport class ObserveGateway {\n\tprivate readonly clients = new Map<\n\t\tunknown,\n\t\tMap<string, { unsub: () => void; wm?: WatermarkController }>\n\t>();\n\tprivate readonly extractActor: (client: unknown) => Actor | undefined;\n\tprivate readonly parse: (data: string) => ObserveWsCommand;\n\tprivate readonly highWaterMark: number | undefined;\n\tprivate readonly lowWaterMark: number | undefined;\n\n\tconstructor(\n\t\tprivate readonly graph: Graph,\n\t\topts?: ObserveGatewayOptions,\n\t) {\n\t\tthis.extractActor = opts?.extractActor ?? (() => undefined);\n\t\tthis.parse = opts?.parse ?? defaultParseCommand;\n\t\tthis.highWaterMark = opts?.highWaterMark;\n\t\tthis.lowWaterMark = opts?.lowWaterMark;\n\t}\n\n\t/**\n\t * Register a new client. Call from `handleConnection`.\n\t */\n\thandleConnection(client: unknown): void {\n\t\tif (!this.clients.has(client)) {\n\t\t\tthis.clients.set(client, new Map());\n\t\t}\n\t}\n\n\t/**\n\t * Unregister a client and dispose all its subscriptions. Call from `handleDisconnect`.\n\t */\n\thandleDisconnect(client: unknown): void {\n\t\tconst subs = this.clients.get(client);\n\t\tif (!subs) return;\n\t\tfor (const entry of subs.values()) {\n\t\t\tentry.wm?.dispose();\n\t\t\tentry.unsub();\n\t\t}\n\t\tthis.clients.delete(client);\n\t}\n\n\t/**\n\t * Handle an incoming client message (subscribe/unsubscribe/ack command).\n\t *\n\t * @param client - The WebSocket client reference.\n\t * @param raw - Raw message data (string or parsed object).\n\t * @param send - Function to send a message back to the client.\n\t * Defaults to `client.send(JSON.stringify(msg))`.\n\t */\n\thandleMessage(client: unknown, raw: unknown, send?: (msg: ObserveWsMessage) => void): void {\n\t\tconst sender = send ?? defaultSend.bind(null, client);\n\t\tlet cmd: ObserveWsCommand;\n\t\ttry {\n\t\t\tcmd = typeof raw === \"string\" ? this.parse(raw) : (raw as ObserveWsCommand);\n\t\t} catch {\n\t\t\tsender({ type: \"err\", message: \"invalid command\" });\n\t\t\treturn;\n\t\t}\n\n\t\tif (cmd.type === \"subscribe\") {\n\t\t\tthis.subscribe(client, cmd.path, sender);\n\t\t} else if (cmd.type === \"unsubscribe\") {\n\t\t\tthis.unsubscribe(client, cmd.path, sender);\n\t\t} else if (cmd.type === \"ack\") {\n\t\t\tthis.ack(client, cmd.path, cmd.count ?? 1);\n\t\t} else {\n\t\t\tsender({ type: \"err\", message: `unknown command type: ${(cmd as { type: string }).type}` });\n\t\t}\n\t}\n\n\t/**\n\t * Number of active subscriptions for a client. Useful for tests.\n\t */\n\tsubscriptionCount(client: unknown): number {\n\t\treturn this.clients.get(client)?.size ?? 0;\n\t}\n\n\t/**\n\t * Dispose all clients and subscriptions.\n\t */\n\tdestroy(): void {\n\t\tfor (const [client] of this.clients) {\n\t\t\tthis.handleDisconnect(client);\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Internal\n\t// -----------------------------------------------------------------------\n\n\tprivate subscribe(client: unknown, path: string, send: (msg: ObserveWsMessage) => void): void {\n\t\tlet subs = this.clients.get(client);\n\t\tif (!subs) {\n\t\t\tsubs = new Map();\n\t\t\tthis.clients.set(client, subs);\n\t\t}\n\t\tif (subs.has(path)) {\n\t\t\tsend({ type: \"subscribed\", path });\n\t\t\treturn;\n\t\t}\n\n\t\tconst actor = this.extractActor(client);\n\t\tlet handle: GraphObserveOne;\n\t\ttry {\n\t\t\thandle = this.graph.observe(path, { actor }) as unknown as GraphObserveOne;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tsend({ type: \"err\", message });\n\t\t\treturn;\n\t\t}\n\n\t\tconst wm =\n\t\t\tthis.highWaterMark != null\n\t\t\t\t? createWatermarkController((msgs) => handle.up(msgs), {\n\t\t\t\t\t\thighWaterMark: this.highWaterMark,\n\t\t\t\t\t\tlowWaterMark: this.lowWaterMark ?? Math.floor(this.highWaterMark / 2),\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\n\t\tconst cleanup = () => {\n\t\t\twm?.dispose();\n\t\t\tunsub();\n\t\t\tsubs!.delete(path);\n\t\t};\n\n\t\tconst unsub = handle.subscribe((msgs: Messages) => {\n\t\t\tfor (const msg of msgs) {\n\t\t\t\tconst t = msg[0];\n\t\t\t\tif (t === DATA) {\n\t\t\t\t\twm?.onEnqueue();\n\t\t\t\t\ttrySend(send, { type: \"data\", path, value: msg[1] });\n\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\tconst errMsg = msg[1] instanceof Error ? msg[1].message : String(msg[1]);\n\t\t\t\t\ttrySend(send, { type: \"error\", path, error: errMsg });\n\t\t\t\t\tcleanup();\n\t\t\t\t\treturn;\n\t\t\t\t} else if (t === COMPLETE || t === TEARDOWN) {\n\t\t\t\t\ttrySend(send, { type: \"complete\", path });\n\t\t\t\t\tcleanup();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// DIRTY, RESOLVED not exposed to WS clients\n\t\t\t}\n\t\t});\n\n\t\tsubs.set(path, { unsub, wm });\n\t\tsend({ type: \"subscribed\", path });\n\t}\n\n\tprivate unsubscribe(client: unknown, path: string, send: (msg: ObserveWsMessage) => void): void {\n\t\tconst subs = this.clients.get(client);\n\t\tconst entry = subs?.get(path);\n\t\tif (entry) {\n\t\t\tentry.wm?.dispose();\n\t\t\tentry.unsub();\n\t\t\tsubs!.delete(path);\n\t\t}\n\t\tsend({ type: \"unsubscribed\", path });\n\t}\n\n\tprivate ack(client: unknown, path: string, count: number): void {\n\t\tconst entry = this.clients.get(client)?.get(path);\n\t\tif (!entry?.wm) return;\n\t\tconst n = Math.min(Math.max(0, Math.floor(count)), 1024);\n\t\tfor (let i = 0; i < n; i++) entry.wm.onDequeue();\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction defaultSerialize(value: unknown): string {\n\tif (value instanceof Error) return value.message;\n\ttry {\n\t\treturn JSON.stringify(value);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n\nfunction sseFrame(event: string, data?: string): string {\n\tlet frame = `event: ${event}\\n`;\n\tif (data !== undefined) {\n\t\tfor (const line of data.split(\"\\n\")) {\n\t\t\tframe += `data: ${line}\\n`;\n\t\t}\n\t}\n\tframe += \"\\n\";\n\treturn frame;\n}\n\nfunction defaultParseCommand(data: string): ObserveWsCommand {\n\treturn JSON.parse(data) as ObserveWsCommand;\n}\n\nfunction defaultSend(client: unknown, msg: ObserveWsMessage): void {\n\ttry {\n\t\t(client as { send: (data: string) => void }).send(JSON.stringify(msg));\n\t} catch {\n\t\t/* client may have disconnected — swallow transport errors */\n\t}\n}\n\nfunction trySend(send: (msg: ObserveWsMessage) => void, msg: ObserveWsMessage): void {\n\ttry {\n\t\tsend(msg);\n\t} catch {\n\t\t/* transport error — client may have disconnected */\n\t}\n}\n","// ---------------------------------------------------------------------------\n// NestJS Actor bridge — maps NestJS ExecutionContext to GraphReFly Actor.\n// ---------------------------------------------------------------------------\n// Implements the NestJS `CanActivate` interface to extract an `Actor` from the\n// request (JWT payload, session, custom header, etc.) and attach it to the\n// request object for downstream graph operations.\n//\n// The decorator does NOT enforce access control — it merely bridges the NestJS\n// authentication context to GraphReFly's ABAC model. Actual access control\n// flows through node `policy()` guards reactively.\n// ---------------------------------------------------------------------------\n\nimport type { CanActivate, ExecutionContext } from \"@nestjs/common\";\nimport { type Actor, DEFAULT_ACTOR, normalizeActor } from \"../../core/actor.js\";\n\n/**\n * Property name under which the extracted {@link Actor} is stored on the\n * request object. Downstream code (controllers, gateways) reads\n * `req[ACTOR_KEY]` to pass actor context to graph operations.\n */\nexport const ACTOR_KEY = \"graphReflyActor\" as const;\n\n/**\n * Extracts a GraphReFly {@link Actor} from a NestJS {@link ExecutionContext}.\n *\n * Return `undefined` to fall back to {@link DEFAULT_ACTOR}.\n */\nexport type ActorExtractor = (context: ExecutionContext) => Actor | undefined;\n\n/**\n * Creates an {@link ActorExtractor} that reads a JWT payload from `req.user`\n * (the standard Passport.js location) and maps it to a GraphReFly {@link Actor}.\n *\n * @param mapping - Optional transform from the JWT payload to an Actor.\n * When omitted, the payload is used directly (must have `type` and `id`).\n *\n * @example\n * ```ts\n * // Default: req.user is already { type, id, ... }\n * GraphReflyGuard(fromJwtPayload())\n *\n * // Custom mapping from your JWT claims\n * GraphReflyGuard(fromJwtPayload((payload) => ({\n * type: payload.role === \"admin\" ? \"human\" : \"llm\",\n * id: payload.sub,\n * org: payload.org_id,\n * })))\n * ```\n */\nexport function fromJwtPayload(mapping?: (payload: unknown) => Actor): ActorExtractor {\n\treturn (context: ExecutionContext): Actor | undefined => {\n\t\tconst req = context.switchToHttp().getRequest();\n\t\tconst user = req?.user;\n\t\tif (user == null) return undefined;\n\t\tif (mapping) return mapping(user);\n\t\treturn user as Actor;\n\t};\n}\n\n/**\n * Creates an {@link ActorExtractor} that reads an Actor from a request header.\n *\n * The header value is parsed as JSON. Useful for service-to-service calls\n * where the caller embeds actor context in a custom header.\n *\n * @param headerName - HTTP header name (case-insensitive). Default: `\"x-graphrefly-actor\"`.\n *\n * @example\n * ```ts\n * GraphReflyGuard(fromHeader(\"x-actor\"))\n * ```\n */\nexport function fromHeader(headerName = \"x-graphrefly-actor\"): ActorExtractor {\n\treturn (context: ExecutionContext): Actor | undefined => {\n\t\tconst req = context.switchToHttp().getRequest();\n\t\tconst raw = req?.headers?.[headerName.toLowerCase()];\n\t\tif (typeof raw !== \"string\" || raw.length === 0) return undefined;\n\t\ttry {\n\t\t\treturn JSON.parse(raw) as Actor;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t};\n}\n\n/**\n * Reads the extracted {@link Actor} from a request object (set by {@link GraphReflyGuardImpl}).\n *\n * Returns {@link DEFAULT_ACTOR} if no actor was attached.\n *\n * @example\n * ```ts\n * @Get(\"status\")\n * getStatus(@Req() req: Request) {\n * const actor = getActor(req);\n * return this.graph.describe({ actor });\n * }\n * ```\n */\nexport function getActor(req: unknown): Actor {\n\tconst actor = (req as Record<string, unknown>)?.[ACTOR_KEY];\n\treturn actor != null ? normalizeActor(actor as Actor) : DEFAULT_ACTOR;\n}\n\n/**\n * NestJS guard that extracts a GraphReFly {@link Actor} from the execution\n * context and attaches it to the request as `req.graphReflyActor`.\n *\n * This guard always returns `true` (allows the request through). Access\n * control is handled by GraphReFly node guards (`policy()`), not by this\n * NestJS guard. The purpose is purely to **bridge** authentication context.\n *\n * @example\n * ```ts\n * // Global guard — every request gets an Actor\n * app.useGlobalGuards(new GraphReflyGuardImpl(fromJwtPayload()));\n *\n * // Controller-scoped\n * @UseGuards(GraphReflyGuard(fromJwtPayload()))\n * @Controller(\"api\")\n * export class ApiController { ... }\n * ```\n */\nexport class GraphReflyGuardImpl implements CanActivate {\n\tconstructor(private readonly extractor: ActorExtractor) {}\n\n\tcanActivate(context: ExecutionContext): boolean {\n\t\tconst actor = normalizeActor(this.extractor(context));\n\t\tconst req = context.switchToHttp().getRequest();\n\t\tif (req != null) {\n\t\t\t(req as Record<string, unknown>)[ACTOR_KEY] = actor;\n\t\t}\n\t\treturn true;\n\t}\n}\n\n/**\n * Factory that creates a {@link GraphReflyGuardImpl} instance. Use with\n * NestJS `@UseGuards()` or `app.useGlobalGuards()`.\n *\n * @param extractor - How to extract an Actor from the request context.\n * Defaults to {@link fromJwtPayload} (reads `req.user`).\n *\n * @example\n * ```ts\n * import { GraphReflyGuard, fromJwtPayload } from \"@graphrefly/graphrefly-ts/compat/nestjs\";\n *\n * @UseGuards(GraphReflyGuard())\n * @Controller(\"graph\")\n * export class GraphController { ... }\n * ```\n */\nexport function GraphReflyGuard(extractor?: ActorExtractor): GraphReflyGuardImpl {\n\treturn new GraphReflyGuardImpl(extractor ?? fromJwtPayload());\n}\n","// ---------------------------------------------------------------------------\n// GraphReflyModule — NestJS dynamic module for GraphReFly integration.\n// ---------------------------------------------------------------------------\n// Provides `forRoot()` and `forFeature()` following the standard NestJS\n// dynamic-module pattern. Lifecycle hooks wire graph creation on init and\n// `graph.destroy()` on teardown — TEARDOWN propagates through the graph\n// per GRAPHREFLY-SPEC §3.7.\n//\n// No decorator usage in this file — all DI is done via factory providers\n// so the library doesn't require `experimentalDecorators` in consumer's\n// tsconfig (only the consumer's NestJS app needs it).\n// ---------------------------------------------------------------------------\n\nimport {\n\ttype DynamicModule,\n\tModule,\n\ttype OnModuleDestroy,\n\ttype Provider,\n\tScope,\n} from \"@nestjs/common\";\nimport { ModuleRef } from \"@nestjs/core\";\nimport { Graph, type GraphPersistSnapshot } from \"../../graph/graph.js\";\nimport {\n\ttype CqrsGraph,\n\ttype CqrsOptions,\n\tcqrs,\n\ttype EventStoreAdapter,\n} from \"../../patterns/cqrs.js\";\nimport { GraphReflyEventExplorer } from \"./explorer.js\";\nimport {\n\tGRAPHREFLY_REQUEST_GRAPH,\n\tGRAPHREFLY_ROOT_GRAPH,\n\tgetGraphToken,\n\tgetNodeToken,\n} from \"./tokens.js\";\n\n// ---------------------------------------------------------------------------\n// Option types\n// ---------------------------------------------------------------------------\n\nexport interface GraphReflyRootOptions {\n\t/** Root graph name (default: `\"root\"`). */\n\tname?: string;\n\t/** Snapshot to hydrate via `graph.restore()` after build. */\n\tsnapshot?: GraphPersistSnapshot;\n\t/** Build callback — registers nodes/mounts on the graph. */\n\tbuild?: (graph: Graph) => void;\n\t/** Qualified node paths to expose as injectable providers. */\n\tnodes?: readonly string[];\n\t/** Enable a request-scoped graph (injectable via `@InjectGraph(\"request\")`). */\n\trequestScope?: boolean;\n}\n\nexport interface GraphReflyCqrsOptions {\n\t/** Feature name — becomes the mount name in the root graph. */\n\tname: string;\n\t/** CQRS graph options (forwarded to `cqrs()` factory). */\n\tcqrs?: CqrsOptions;\n\t/** Build callback — registers commands, events, projections, sagas on the CqrsGraph. */\n\tbuild?: (graph: CqrsGraph) => void;\n\t/** Event store adapter for persistence (wired via `useEventStore()`). */\n\teventStore?: EventStoreAdapter;\n\t/**\n\t * Node paths (local to this feature) to expose as injectable providers.\n\t * Tokens are auto-qualified as `featureName::path`.\n\t */\n\tnodes?: readonly string[];\n}\n\nexport interface GraphReflyFeatureOptions {\n\t/** Feature name — becomes the mount name in the root graph. */\n\tname: string;\n\t/** Build callback — registers nodes/mounts on the feature graph. */\n\tbuild?: (graph: Graph) => void;\n\t/** Snapshot to hydrate after build. */\n\tsnapshot?: GraphPersistSnapshot;\n\t/**\n\t * Node paths (local to this feature) to expose as injectable providers.\n\t * Tokens are auto-qualified as `featureName::path` to avoid collisions.\n\t */\n\tnodes?: readonly string[];\n}\n\n// ---------------------------------------------------------------------------\n// Lifecycle classes (no decorators — DI is handled via factory providers)\n// ---------------------------------------------------------------------------\n\nclass GraphReflyRootLifecycle implements OnModuleDestroy {\n\tconstructor(readonly graph: Graph) {}\n\n\tonModuleDestroy(): void {\n\t\tthis.graph.destroy();\n\t}\n}\n\nclass GraphReflyRequestLifecycle implements OnModuleDestroy {\n\treadonly graph = new Graph(\"request\");\n\n\tonModuleDestroy(): void {\n\t\tthis.graph.destroy();\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Module\n// ---------------------------------------------------------------------------\n\n// NestJS dynamic modules convention: static `forRoot` / `forFeature` factories on a `@Module` class.\n@Module({})\n// biome-ignore lint/complexity/noStaticOnlyClass: NestJS `DynamicModule` pattern (`@Module` + static factories)\nexport class GraphReflyModule {\n\t/**\n\t * Register the root `Graph` singleton in the NestJS DI container.\n\t *\n\t * The root graph is `@Global()` — injectable everywhere without importing\n\t * the module again. Use `@InjectGraph()` to inject it.\n\t *\n\t * Lifecycle:\n\t * - **init:** Graph created in factory. If `build` is provided, it runs\n\t * first (registers nodes/mounts). If `snapshot` is provided, values\n\t * are restored via `graph.restore()`.\n\t * - **destroy:** Calls `graph.destroy()` — sends `[[TEARDOWN]]` to all\n\t * nodes, including mounted feature subgraphs (cascading teardown).\n\t */\n\tstatic forRoot(opts?: GraphReflyRootOptions): DynamicModule {\n\t\tconst options = opts ?? {};\n\t\tconst graphName = options.name ?? \"root\";\n\n\t\tconst providers: Provider[] = [\n\t\t\t{\n\t\t\t\tprovide: GRAPHREFLY_ROOT_GRAPH,\n\t\t\t\tuseFactory: () => {\n\t\t\t\t\tconst g = new Graph(graphName);\n\t\t\t\t\tif (options.build) options.build(g);\n\t\t\t\t\tif (options.snapshot) g.restore(options.snapshot);\n\t\t\t\t\treturn g;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tprovide: Symbol.for(\"graphrefly:root-lifecycle\"),\n\t\t\t\tuseFactory: (graph: Graph) => new GraphReflyRootLifecycle(graph),\n\t\t\t\tinject: [GRAPHREFLY_ROOT_GRAPH],\n\t\t\t},\n\t\t\t{\n\t\t\t\tprovide: GraphReflyEventExplorer,\n\t\t\t\tuseFactory: (graph: Graph, moduleRef: InstanceType<typeof ModuleRef>) =>\n\t\t\t\t\tnew GraphReflyEventExplorer(graph, moduleRef),\n\t\t\t\tinject: [GRAPHREFLY_ROOT_GRAPH, ModuleRef],\n\t\t\t},\n\t\t];\n\n\t\t// Node factory providers — each declared path gets a factory that\n\t\t// resolves the node from the root graph at injection time.\n\t\tif (options.nodes) {\n\t\t\tfor (const path of options.nodes) {\n\t\t\t\tproviders.push({\n\t\t\t\t\tprovide: getNodeToken(path),\n\t\t\t\t\tuseFactory: (graph: Graph) => graph.resolve(path),\n\t\t\t\t\tinject: [GRAPHREFLY_ROOT_GRAPH],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Request-scoped graph provider (opt-in).\n\t\tif (options.requestScope) {\n\t\t\tproviders.push(\n\t\t\t\t{\n\t\t\t\t\tprovide: Symbol.for(\"graphrefly:request-lifecycle\"),\n\t\t\t\t\tuseFactory: () => new GraphReflyRequestLifecycle(),\n\t\t\t\t\tscope: Scope.REQUEST,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tprovide: GRAPHREFLY_REQUEST_GRAPH,\n\t\t\t\t\tuseFactory: (lifecycle: GraphReflyRequestLifecycle) => lifecycle.graph,\n\t\t\t\t\tinject: [Symbol.for(\"graphrefly:request-lifecycle\")],\n\t\t\t\t\tscope: Scope.REQUEST,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tmodule: GraphReflyModule,\n\t\t\tglobal: true,\n\t\t\tproviders,\n\t\t\texports: [\n\t\t\t\tGRAPHREFLY_ROOT_GRAPH,\n\t\t\t\t...(options.nodes ?? []).map(getNodeToken),\n\t\t\t\t...(options.requestScope ? [GRAPHREFLY_REQUEST_GRAPH] : []),\n\t\t\t],\n\t\t};\n\t}\n\n\t/**\n\t * Register a feature subgraph that auto-mounts into the root graph.\n\t *\n\t * The feature graph is created in the factory, built/restored, then\n\t * mounted into root via `root.mount(name, featureGraph)`. On app\n\t * shutdown, root's `graph.destroy()` cascades TEARDOWN through all\n\t * mounted subgraphs (no explicit remove needed).\n\t *\n\t * Node tokens are auto-qualified as `featureName::path` to prevent\n\t * collisions between features declaring nodes with the same local name.\n\t *\n\t * Injectable via `@InjectGraph(name)`.\n\t */\n\tstatic forFeature(opts: GraphReflyFeatureOptions): DynamicModule {\n\t\tconst providers: Provider[] = [\n\t\t\t{\n\t\t\t\tprovide: getGraphToken(opts.name),\n\t\t\t\tuseFactory: (rootGraph: Graph) => {\n\t\t\t\t\tconst g = new Graph(opts.name);\n\t\t\t\t\tif (opts.build) opts.build(g);\n\t\t\t\t\tif (opts.snapshot) g.restore(opts.snapshot);\n\t\t\t\t\trootGraph.mount(opts.name, g);\n\t\t\t\t\treturn g;\n\t\t\t\t},\n\t\t\t\tinject: [GRAPHREFLY_ROOT_GRAPH],\n\t\t\t},\n\t\t];\n\n\t\t// Node factory providers for feature-scoped nodes.\n\t\t// Tokens are qualified as `featureName::path` to avoid cross-feature collisions.\n\t\tif (opts.nodes) {\n\t\t\tfor (const path of opts.nodes) {\n\t\t\t\tproviders.push({\n\t\t\t\t\tprovide: getNodeToken(`${opts.name}::${path}`),\n\t\t\t\t\tuseFactory: (graph: Graph) => graph.resolve(path),\n\t\t\t\t\tinject: [getGraphToken(opts.name)],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmodule: GraphReflyModule,\n\t\t\tproviders,\n\t\t\texports: [\n\t\t\t\tgetGraphToken(opts.name),\n\t\t\t\t...(opts.nodes ?? []).map((p) => getNodeToken(`${opts.name}::${p}`)),\n\t\t\t],\n\t\t};\n\t}\n\n\t/**\n\t * Register a CQRS subgraph that auto-mounts into the root graph.\n\t *\n\t * Creates a `CqrsGraph` via the `cqrs()` factory (roadmap §4.5), mounts it\n\t * into the root graph, and exposes it for DI via `@InjectGraph(name)`.\n\t *\n\t * CQRS decorators (`@CommandHandler`, `@EventHandler`, `@QueryHandler`,\n\t * `@SagaHandler`) are discovered by the explorer and wired to this graph\n\t * on module init.\n\t *\n\t * @example\n\t * ```ts\n\t * GraphReflyModule.forCqrs({\n\t * name: \"orders\",\n\t * build: (g) => {\n\t * g.event(\"orderPlaced\");\n\t * g.projection(\"orderCount\", [\"orderPlaced\"], (_s, evts) => evts.length, 0);\n\t * },\n\t * })\n\t * ```\n\t */\n\tstatic forCqrs(opts: GraphReflyCqrsOptions): DynamicModule {\n\t\tconst providers: Provider[] = [\n\t\t\t{\n\t\t\t\tprovide: getGraphToken(opts.name),\n\t\t\t\tuseFactory: (rootGraph: Graph) => {\n\t\t\t\t\tconst g = cqrs(opts.name, opts.cqrs);\n\t\t\t\t\t// `useEventStore` is CqrsGraph API, not a React hook (Biome false positive).\n\t\t\t\t\t// biome-ignore lint/correctness/useHookAtTopLevel: not React; Nest provider factory\n\t\t\t\t\tif (opts.eventStore) g.useEventStore(opts.eventStore);\n\t\t\t\t\tif (opts.build) opts.build(g);\n\t\t\t\t\trootGraph.mount(opts.name, g);\n\t\t\t\t\treturn g;\n\t\t\t\t},\n\t\t\t\tinject: [GRAPHREFLY_ROOT_GRAPH],\n\t\t\t},\n\t\t];\n\n\t\tif (opts.nodes) {\n\t\t\tfor (const path of opts.nodes) {\n\t\t\t\tproviders.push({\n\t\t\t\t\tprovide: getNodeToken(`${opts.name}::${path}`),\n\t\t\t\t\tuseFactory: (graph: Graph) => graph.resolve(path),\n\t\t\t\t\tinject: [getGraphToken(opts.name)],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmodule: GraphReflyModule,\n\t\t\tproviders,\n\t\t\texports: [\n\t\t\t\tgetGraphToken(opts.name),\n\t\t\t\t...(opts.nodes ?? []).map((p) => getNodeToken(`${opts.name}::${p}`)),\n\t\t\t],\n\t\t};\n\t}\n}\n","/**\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 { batch } from \"../core/batch.js\";\nimport { wallClockNs } from \"../core/clock.js\";\nimport { policy } from \"../core/guard.js\";\nimport { DATA, derived, type Node, node, state } from \"../core/index.js\";\nimport { reactiveLog } from \"../extra/reactive-log.js\";\nimport { Graph, type GraphOptions } from \"../graph/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 { domainMeta, keepalive } from \"./_internal.js\";\n\nfunction cqrsMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"cqrs\", kind, extra);\n}\n\n// ---------------------------------------------------------------------------\n// Event envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable envelope for events emitted by command handlers.\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/** V0 identity of the event log node at append time (§6.0b). */\n\tv0?: { id: string; version: number };\n};\n\n// ---------------------------------------------------------------------------\n// Event store adapter\n// ---------------------------------------------------------------------------\n\n/**\n * Opaque replay cursor returned by `loadEvents`. Pass it back to\n * `loadEvents` to resume from the last position.\n */\nexport type EventStoreCursor = {\n\treadonly __brand?: \"EventStoreCursor\";\n\t[key: string]: unknown;\n};\n\n/**\n * Result of `loadEvents` — events plus an opaque cursor for resumption.\n */\nexport type LoadEventsResult = {\n\tevents: CqrsEvent[];\n\tcursor: EventStoreCursor | undefined;\n};\n\n/**\n * Pluggable persistence for CQRS events.\n *\n * **`persist`:** Must be synchronous. Called from the dispatch path inside\n * `batch()`. Adapters that need async I/O should buffer internally and\n * expose a `flush()` method for explicit drain.\n */\nexport interface EventStoreAdapter {\n\tpersist(event: CqrsEvent): void;\n\t/**\n\t * Load persisted events. When `cursor` is provided, returns only events\n\t * after that position. The returned `cursor` should be passed to the next\n\t * `loadEvents` call for incremental replay.\n\t */\n\tloadEvents(\n\t\teventType: string,\n\t\tcursor?: EventStoreCursor,\n\t): LoadEventsResult | Promise<LoadEventsResult>;\n\t/** Optional explicit flush for adapters with async I/O. */\n\tflush?(): Promise<void>;\n}\n\nexport class MemoryEventStore implements EventStoreAdapter {\n\tprivate readonly _store = new Map<string, CqrsEvent[]>();\n\n\tpersist(event: CqrsEvent): void {\n\t\tlet list = this._store.get(event.type);\n\t\tif (!list) {\n\t\t\tlist = [];\n\t\t\tthis._store.set(event.type, list);\n\t\t}\n\t\tlist.push(event);\n\t}\n\n\tloadEvents(eventType: string, cursor?: EventStoreCursor): LoadEventsResult {\n\t\tconst list = this._store.get(eventType) ?? [];\n\t\tconst sinceTs = (cursor as { timestampNs?: number } | undefined)?.timestampNs;\n\t\tconst sinceSeq = (cursor as { seq?: number } | undefined)?.seq;\n\t\tconst events =\n\t\t\tsinceTs == null\n\t\t\t\t? [...list]\n\t\t\t\t: list.filter(\n\t\t\t\t\t\t(e) =>\n\t\t\t\t\t\t\te.timestampNs > sinceTs || (e.timestampNs === sinceTs && e.seq > (sinceSeq ?? -1)),\n\t\t\t\t\t);\n\t\tconst lastEvent = events.length > 0 ? events[events.length - 1] : undefined;\n\t\treturn {\n\t\t\tevents,\n\t\t\tcursor: lastEvent ? { timestampNs: lastEvent.timestampNs, seq: lastEvent.seq } : cursor,\n\t\t};\n\t}\n\n\tclear(): void {\n\t\tthis._store.clear();\n\t}\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. The `state` parameter is the\n * original `initial` value on every invocation (full event-sourcing replay),\n * so mutation would corrupt future recomputations.\n */\nexport type ProjectionReducer<TState = unknown, TEvent = unknown> = (\n\tstate: TState,\n\tevents: readonly CqrsEvent<TEvent>[],\n) => TState;\n\nexport type SagaHandler<T = unknown> = (event: CqrsEvent<T>) => void;\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport type CqrsOptions = {\n\tgraph?: GraphOptions;\n};\n\n// ---------------------------------------------------------------------------\n// CqrsGraph\n// ---------------------------------------------------------------------------\n\ntype EventEntry = {\n\tlog: ReturnType<typeof reactiveLog<CqrsEvent>>;\n\tnode: Node<readonly CqrsEvent[]>;\n};\n\nexport class CqrsGraph extends Graph {\n\tprivate readonly _eventLogs = new Map<string, EventEntry>();\n\tprivate readonly _commandHandlers = new Map<string, CommandHandler<any>>();\n\tprivate readonly _projections = new Set<string>();\n\tprivate readonly _sagas = new Set<string>();\n\tprivate readonly _keepaliveDisposers: Array<() => void> = [];\n\tprivate _eventStore: EventStoreAdapter | undefined;\n\tprivate _seq = 0;\n\n\tconstructor(name: string, opts: CqrsOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t}\n\n\toverride destroy(): void {\n\t\tfor (const dispose of this._keepaliveDisposers) dispose();\n\t\tthis._keepaliveDisposers.length = 0;\n\t\tsuper.destroy();\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\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>([], { name, versioning: 0 });\n\t\tconst entries = log.entries;\n\t\tconst guarded = derived<readonly CqrsEvent[]>(\n\t\t\t[entries],\n\t\t\t([snapshot]) => snapshot as readonly CqrsEvent[],\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"state\",\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.add(name, guarded);\n\t\tthis._keepaliveDisposers.push(keepalive(guarded));\n\t\tthis._eventLogs.set(name, { log, node: guarded });\n\t\treturn guarded;\n\t}\n\n\t/** Internal: append to an event log, auto-registering if needed. */\n\tprivate _appendEvent(eventName: string, payload: unknown): void {\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\t// Guard: reject dispatch to terminated event streams\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\t\tconst nv = entry.log.entries.v;\n\t\tconst evt: CqrsEvent = {\n\t\t\ttype: eventName,\n\t\t\tpayload,\n\t\t\ttimestampNs: wallClockNs(),\n\t\t\tseq: ++this._seq,\n\t\t\t...(nv != null ? { v0: { id: nv.id, version: nv.version } } : {}),\n\t\t};\n\t\tentry.log.append(evt);\n\t\tif (this._eventStore) {\n\t\t\tthis._eventStore.persist(evt);\n\t\t}\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>(name: string, handler: CommandHandler<T>): Node<T> {\n\t\tconst cmdNode = state<T>(undefined as T, {\n\t\t\tname,\n\t\t\tdescribeKind: \"state\",\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.add(name, cmdNode);\n\t\tthis._commandHandlers.set(name, handler as CommandHandler<any>);\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\tdispatch<T = unknown>(commandName: string, payload: T): void {\n\t\tconst handler = this._commandHandlers.get(commandName);\n\t\tif (!handler) {\n\t\t\tthrow new Error(`Unknown command: \"${commandName}\". Register with .command() first.`);\n\t\t}\n\t\tconst cmdNode = this.resolve(commandName);\n\t\tbatch(() => {\n\t\t\tcmdNode.down([[DATA, payload]], { internal: true });\n\t\t\ttry {\n\t\t\t\thandler(payload, { emit: (eName, data) => this._appendEvent(eName, data) });\n\t\t\t\tcmdNode.meta.error.down([[DATA, null]], { internal: true });\n\t\t\t} catch (err) {\n\t\t\t\tcmdNode.meta.error.down([[DATA, err]], { internal: true });\n\t\t\t\tthrow err;\n\t\t\t}\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 * **Purity contract:** The `reducer` must be a pure function — it receives\n\t * the original `initial` on every invocation (full event-sourcing replay).\n\t * Never mutate `initial`; always return a new value.\n\t */\n\tprojection<TState>(\n\t\tname: string,\n\t\teventNames: readonly string[],\n\t\treducer: ProjectionReducer<TState>,\n\t\tinitial: TState,\n\t): Node<TState> {\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\tconst projNode = derived<TState>(\n\t\t\teventNodes,\n\t\t\t(snapshots) => {\n\t\t\t\tconst allEvents: CqrsEvent[] = [];\n\t\t\t\tfor (const snapshot of snapshots) {\n\t\t\t\t\tconst entries = snapshot as readonly CqrsEvent[];\n\t\t\t\t\tallEvents.push(...entries);\n\t\t\t\t}\n\t\t\t\tallEvents.sort((a, b) => a.timestampNs - b.timestampNs || a.seq - b.seq);\n\t\t\t\treturn reducer(initial, allEvents);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\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,\n\t\t\t},\n\t\t);\n\n\t\tthis.add(name, projNode);\n\t\tthis._keepaliveDisposers.push(keepalive(projNode));\n\t\tthis._projections.add(name);\n\t\treturn projNode;\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): Node<unknown> {\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// Track last-processed entry count per event to only process new entries\n\t\tconst lastCounts = new Map<string, number>();\n\n\t\tconst sagaRef: { n?: Node<unknown> } = {};\n\t\tconst sagaNode = node(\n\t\t\teventNodes,\n\t\t\t(snapshots, _actions) => {\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];\n\t\t\t\t\tconst lastCount = lastCounts.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\tfor (const entry of newEntries) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\thandler(entry as CqrsEvent<T>);\n\t\t\t\t\t\t\t\terrNode.down([[DATA, null]], { internal: true });\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\terrNode.down([[DATA, err]], { internal: true });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastCounts.set(eName, entries.length);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"effect\",\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.add(name, sagaNode);\n\t\tthis._keepaliveDisposers.push(keepalive(sagaNode));\n\t\tthis._sagas.add(name);\n\t\treturn sagaNode;\n\t}\n\n\t// -- Event store ----------------------------------------------------------\n\n\tuseEventStore(adapter: EventStoreAdapter): void {\n\t\tthis._eventStore = adapter;\n\t}\n\n\t/**\n\t * Replay persisted events through a reducer to rebuild a read model.\n\t * Requires an event store adapter wired via `useEventStore()`.\n\t */\n\tasync rebuildProjection<TState>(\n\t\teventNames: readonly string[],\n\t\treducer: ProjectionReducer<TState>,\n\t\tinitial: TState,\n\t): Promise<TState> {\n\t\tif (!this._eventStore) {\n\t\t\tthrow new Error(\"No event store wired. Call useEventStore() first.\");\n\t\t}\n\t\tconst allEvents: CqrsEvent[] = [];\n\t\tfor (const eName of eventNames) {\n\t\t\tconst result = await this._eventStore.loadEvents(eName);\n\t\t\tallEvents.push(...result.events);\n\t\t}\n\t\tallEvents.sort((a, b) => a.timestampNs - b.timestampNs || a.seq - b.seq);\n\t\treturn reducer(initial, allEvents);\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 * app.projection(\"orderCount\", [\"orderPlaced\"], (_s, events) => events.length, 0);\n * app.dispatch(\"placeOrder\", { id: \"1\", amount: 100 });\n * ```\n */\nexport function cqrs(name: string, opts?: CqrsOptions): CqrsGraph {\n\treturn new CqrsGraph(name, opts);\n}\n"],"mappings":"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","names":["batch"]}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
emitToMeta
|
|
3
|
+
} from "./chunk-32N5A454.js";
|
|
1
4
|
import {
|
|
2
5
|
Graph
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XRFJJ2IU.js";
|
|
4
7
|
import {
|
|
5
|
-
DATA,
|
|
6
8
|
__export,
|
|
7
|
-
defaultConfig,
|
|
8
9
|
derived,
|
|
9
|
-
downWithBatch,
|
|
10
10
|
monotonicNs,
|
|
11
11
|
node,
|
|
12
12
|
state
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-NZMBRXQV.js";
|
|
14
14
|
|
|
15
15
|
// src/patterns/reactive-layout/index.ts
|
|
16
16
|
var reactive_layout_exports = {};
|
|
@@ -766,13 +766,9 @@ function reactiveLayout(opts) {
|
|
|
766
766
|
const hitRate = lookups === 0 ? 1 : measureStats.hits / lookups;
|
|
767
767
|
const meta = segmentsNode.meta;
|
|
768
768
|
if (meta) {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
const tierOf = defaultConfig.tierOf;
|
|
773
|
-
downWithBatch((msgs) => meta["cache-hit-rate"]?.down(msgs), [[DATA, hr]], tierOf);
|
|
774
|
-
downWithBatch((msgs) => meta["segment-count"]?.down(msgs), [[DATA, len]], tierOf);
|
|
775
|
-
downWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, el]], tierOf);
|
|
769
|
+
emitToMeta(meta["cache-hit-rate"], hitRate);
|
|
770
|
+
emitToMeta(meta["segment-count"], result.length);
|
|
771
|
+
emitToMeta(meta["layout-time-ns"], elapsed);
|
|
776
772
|
}
|
|
777
773
|
actions.emit(result);
|
|
778
774
|
return () => {
|
|
@@ -992,9 +988,8 @@ function reactiveBlockLayout(opts) {
|
|
|
992
988
|
const elapsed = monotonicNs() - t0;
|
|
993
989
|
const meta = measuredBlocksNode.meta;
|
|
994
990
|
if (meta) {
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
downWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, elapsed]], tierOf);
|
|
991
|
+
emitToMeta(meta["block-count"], result.length);
|
|
992
|
+
emitToMeta(meta["layout-time-ns"], elapsed);
|
|
998
993
|
}
|
|
999
994
|
actions.emit(result);
|
|
1000
995
|
return () => {
|
|
@@ -1083,4 +1078,4 @@ export {
|
|
|
1083
1078
|
reactiveBlockLayout,
|
|
1084
1079
|
reactive_layout_exports
|
|
1085
1080
|
};
|
|
1086
|
-
//# sourceMappingURL=chunk-
|
|
1081
|
+
//# sourceMappingURL=chunk-PX6PDUJ5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/patterns/reactive-layout/index.ts","../src/patterns/reactive-layout/measurement-adapters.ts","../src/patterns/reactive-layout/reactive-layout.ts","../src/patterns/reactive-layout/reactive-block-layout.ts"],"sourcesContent":["/**\n * Reactive layout pattern — standalone subpath export.\n *\n * ```ts\n * import { reactiveLayout, CliMeasureAdapter } from \"@graphrefly/graphrefly-ts/reactive-layout\";\n * ```\n */\n\nexport * from \"./measurement-adapters.js\";\nexport * from \"./reactive-block-layout.js\";\nexport * from \"./reactive-layout.js\";\n","/**\n * MeasurementAdapter implementations (roadmap §7.1 — pluggable backends).\n *\n * All adapters implement {@link MeasurementAdapter} from `reactive-layout.ts`.\n * Sync constructors, sync `measureSegment()` — no async, no polling.\n */\n\nimport type { MeasurementAdapter } from \"./reactive-layout.js\";\n\n// ---------------------------------------------------------------------------\n// Shared: East Asian Width detection for CLI adapter\n// ---------------------------------------------------------------------------\n\n/**\n * Return the display-cell width of a single codepoint in a monospace terminal.\n * Fullwidth / wide CJK → 2 cells; combining marks → 0 cells; everything else → 1 cell.\n *\n * Approximates UAX #11 East_Asian_Width (W/F → 2). Not a full EAW table —\n * covers CJK, Hangul, fullwidth forms, common emoji, and Extensions B-G.\n * Python's `unicodedata.east_asian_width()` is authoritative; this tracks it\n * closely but may diverge on rare/ambiguous codepoints.\n */\nfunction cellWidth(code: number): 0 | 1 | 2 {\n\t// Combining marks (Mn, Mc, Me) → 0 cells\n\tif (\n\t\t(code >= 0x0300 && code <= 0x036f) || // Combining Diacritical Marks\n\t\t(code >= 0x0483 && code <= 0x0489) || // Cyrillic combining marks\n\t\t(code >= 0x0591 && code <= 0x05bd) || // Hebrew combining marks\n\t\t(code >= 0x0610 && code <= 0x061a) || // Arabic combining marks\n\t\t(code >= 0x064b && code <= 0x065f) || // Arabic combining marks\n\t\t(code >= 0x0670 && code === 0x0670) || // Arabic superscript alef\n\t\t(code >= 0x06d6 && code <= 0x06dc) || // Arabic combining marks\n\t\t(code >= 0x06df && code <= 0x06e4) || // Arabic combining marks\n\t\t(code >= 0x06e7 && code <= 0x06e8) || // Arabic combining marks\n\t\t(code >= 0x06ea && code <= 0x06ed) || // Arabic combining marks\n\t\t(code >= 0x0730 && code <= 0x074a) || // Syriac combining marks\n\t\t(code >= 0x07a6 && code <= 0x07b0) || // Thaana combining marks\n\t\t(code >= 0x0900 && code <= 0x0903) || // Devanagari combining marks\n\t\t(code >= 0x093a && code <= 0x094f) || // Devanagari combining marks\n\t\t(code >= 0x0951 && code <= 0x0957) || // Devanagari combining marks\n\t\t(code >= 0x0962 && code <= 0x0963) || // Devanagari combining marks\n\t\t(code >= 0x0981 && code <= 0x0983) || // Bengali combining marks\n\t\t(code >= 0x09bc && code <= 0x09cd) || // Bengali combining marks\n\t\t(code >= 0x0a01 && code <= 0x0a03) || // Gurmukhi combining marks\n\t\t(code >= 0x0a3c && code <= 0x0a51) || // Gurmukhi combining marks\n\t\t(code >= 0x0a70 && code <= 0x0a71) || // Gurmukhi combining marks\n\t\t(code >= 0x0a75 && code === 0x0a75) || // Gurmukhi combining mark\n\t\t(code >= 0x0e31 && code === 0x0e31) || // Thai combining mark\n\t\t(code >= 0x0e34 && code <= 0x0e3a) || // Thai combining marks\n\t\t(code >= 0x0e47 && code <= 0x0e4e) || // Thai combining marks\n\t\t(code >= 0x0eb1 && code === 0x0eb1) || // Lao combining mark\n\t\t(code >= 0x0eb4 && code <= 0x0ebc) || // Lao combining marks\n\t\t(code >= 0x0ec8 && code <= 0x0ece) || // Lao combining marks\n\t\t(code >= 0x1dc0 && code <= 0x1dff) || // Combining Diacritical Marks Supplement\n\t\t(code >= 0x20d0 && code <= 0x20ff) || // Combining Diacritical Marks for Symbols\n\t\t(code >= 0xfe00 && code <= 0xfe0f) || // Variation Selectors\n\t\t(code >= 0xfe20 && code <= 0xfe2f) || // Combining Half Marks\n\t\tcode === 0x200d // Zero Width Joiner\n\t) {\n\t\treturn 0;\n\t}\n\t// Wide / fullwidth → 2 cells\n\tif (\n\t\t(code >= 0x1100 && code <= 0x115f) || // Hangul Jamo\n\t\t(code >= 0x231a && code <= 0x231b) || // Watch, Hourglass\n\t\t(code >= 0x2329 && code <= 0x232a) || // Angle brackets\n\t\t(code >= 0x23e9 && code <= 0x23f3) || // Media control symbols\n\t\t(code >= 0x23f8 && code <= 0x23fa) || // Media control symbols\n\t\t(code >= 0x25fd && code <= 0x25fe) || // Medium squares\n\t\t(code >= 0x2614 && code <= 0x2615) || // Umbrella, Hot Beverage\n\t\t(code >= 0x2648 && code <= 0x2653) || // Zodiac symbols\n\t\tcode === 0x267f || // Wheelchair\n\t\tcode === 0x2693 || // Anchor\n\t\tcode === 0x26a1 || // High Voltage\n\t\t(code >= 0x26aa && code <= 0x26ab) || // Medium circles\n\t\t(code >= 0x26bd && code <= 0x26be) || // Soccer, Baseball\n\t\t(code >= 0x26c4 && code <= 0x26c5) || // Snowman, Sun behind cloud\n\t\tcode === 0x26ce || // Ophiuchus\n\t\tcode === 0x26d4 || // No Entry\n\t\tcode === 0x26ea || // Church\n\t\t(code >= 0x26f2 && code <= 0x26f3) || // Fountain, Golf\n\t\tcode === 0x26f5 || // Sailboat\n\t\tcode === 0x26fa || // Tent\n\t\tcode === 0x26fd || // Fuel Pump\n\t\tcode === 0x2702 || // Scissors\n\t\tcode === 0x2705 || // Check Mark\n\t\t(code >= 0x2708 && code <= 0x270d) || // Airplane...Writing Hand\n\t\tcode === 0x270f || // Pencil\n\t\t(code >= 0x2753 && code <= 0x2755) || // Question marks\n\t\tcode === 0x2757 || // Exclamation\n\t\t(code >= 0x2795 && code <= 0x2797) || // Plus, Minus, Divide\n\t\tcode === 0x27b0 || // Curly Loop\n\t\tcode === 0x27bf || // Double Curly Loop\n\t\t(code >= 0x2934 && code <= 0x2935) || // Arrows\n\t\t(code >= 0x2b05 && code <= 0x2b07) || // Arrows\n\t\t(code >= 0x2b1b && code <= 0x2b1c) || // Squares\n\t\tcode === 0x2b50 || // Star\n\t\tcode === 0x2b55 || // Circle\n\t\t(code >= 0x2e80 && code <= 0x303e) || // CJK Radicals, Symbols, Punctuation\n\t\t(code >= 0x3040 && code <= 0x309f) || // Hiragana\n\t\t(code >= 0x30a0 && code <= 0x30ff) || // Katakana\n\t\t(code >= 0x3105 && code <= 0x312f) || // Bopomofo\n\t\t(code >= 0x3131 && code <= 0x318e) || // Hangul Compatibility Jamo\n\t\t(code >= 0x3190 && code <= 0x31e3) || // Kanbun, CJK Strokes\n\t\t(code >= 0x31f0 && code <= 0x321e) || // Katakana Phonetic Extensions\n\t\t(code >= 0x3220 && code <= 0x3247) || // Enclosed CJK\n\t\t(code >= 0x3250 && code <= 0x4dbf) || // CJK Extensions + Unified block\n\t\t(code >= 0x4e00 && code <= 0x9fff) || // CJK Unified Ideographs\n\t\t(code >= 0xa960 && code <= 0xa97c) || // Hangul Jamo Extended-A\n\t\t(code >= 0xac00 && code <= 0xd7a3) || // Hangul Syllables\n\t\t(code >= 0xf900 && code <= 0xfaff) || // CJK Compatibility Ideographs\n\t\t(code >= 0xfe10 && code <= 0xfe19) || // Vertical forms\n\t\t(code >= 0xfe30 && code <= 0xfe6b) || // CJK Compatibility Forms\n\t\t(code >= 0xff01 && code <= 0xff60) || // Fullwidth Forms (excl. halfwidth)\n\t\t(code >= 0xffe0 && code <= 0xffe6) || // Fullwidth Signs\n\t\t(code >= 0x1f004 && code === 0x1f004) || // Mahjong Red Dragon\n\t\tcode === 0x1f0cf || // Joker\n\t\t(code >= 0x1f170 && code <= 0x1f171) || // A/B buttons\n\t\tcode === 0x1f17e || // O button\n\t\tcode === 0x1f17f || // P button\n\t\tcode === 0x1f18e || // AB button\n\t\t(code >= 0x1f191 && code <= 0x1f19a) || // Squared symbols\n\t\t(code >= 0x1f1e0 && code <= 0x1f1ff) || // Regional Indicator Symbols\n\t\t(code >= 0x1f200 && code <= 0x1f202) || // Enclosed ideographic\n\t\tcode === 0x1f21a || // Squared CJK\n\t\tcode === 0x1f22f || // Squared CJK\n\t\t(code >= 0x1f232 && code <= 0x1f23a) || // Squared CJK\n\t\t(code >= 0x1f250 && code <= 0x1f251) || // Circled ideographic\n\t\t(code >= 0x1f300 && code <= 0x1f9ff) || // Misc Symbols / Emoticons / Emoji\n\t\t(code >= 0x1fa00 && code <= 0x1faff) || // Chess, Symbols Extended-A\n\t\t(code >= 0x1fb00 && code <= 0x1fbff) || // Symbols for Legacy Computing\n\t\t(code >= 0x20000 && code <= 0x2fffd) || // CJK Extension B-F (excl. nonchars)\n\t\t(code >= 0x30000 && code <= 0x3fffd) // CJK Extension G+ (excl. nonchars)\n\t) {\n\t\treturn 2;\n\t}\n\treturn 1;\n}\n\n/**\n * Count total display cells for a string in a monospace terminal.\n *\n * Combining marks contribute 0 cells; CJK/fullwidth contribute 2.\n * Does not handle ZWJ emoji sequences (multi-codepoint clusters that\n * render as a single glyph) — terminal support for these varies widely.\n */\nfunction countCells(text: string): number {\n\tlet cells = 0;\n\tfor (const ch of text) {\n\t\tcells += cellWidth(ch.codePointAt(0)!);\n\t}\n\treturn cells;\n}\n\n// ---------------------------------------------------------------------------\n// CliMeasureAdapter\n// ---------------------------------------------------------------------------\n\nexport type CliMeasureAdapterOptions = {\n\t/** Pixel width per terminal cell (default: 8). */\n\tcellPx?: number;\n};\n\n/**\n * Monospace terminal measurement adapter.\n *\n * Width = cell count × `cellPx`. CJK / fullwidth characters count as 2 cells.\n * No external dependencies. Works in any JS environment.\n */\nexport class CliMeasureAdapter implements MeasurementAdapter {\n\tprivate readonly cellPx: number;\n\n\tconstructor(opts?: CliMeasureAdapterOptions) {\n\t\tthis.cellPx = opts?.cellPx ?? 8;\n\t}\n\n\tmeasureSegment(text: string, _font: string): { width: number } {\n\t\treturn { width: countCells(text) * this.cellPx };\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// PrecomputedAdapter\n// ---------------------------------------------------------------------------\n\nexport type PrecomputedAdapterOptions = {\n\t/**\n\t * Pre-computed metrics: `{ font: { segment: widthPx } }`.\n\t * Outer key is the CSS font string; inner key is the text segment.\n\t */\n\tmetrics: Record<string, Record<string, number>>;\n\t/**\n\t * Fallback when a segment is not found in the metrics map.\n\t * - `\"per-char\"`: sum individual character widths from the same font map (default)\n\t * - `\"error\"`: throw an error for unknown segments\n\t */\n\tfallback?: \"per-char\" | \"error\";\n};\n\nclass PrecomputedAdapterKeyError extends Error {\n\tname = \"KeyError\";\n}\n\n/**\n * Pre-computed measurement adapter for SSR / snapshot replay.\n *\n * Reads from a static metrics object — zero measurement at runtime.\n * Ideal for server-side rendering or replaying snapshotted layouts.\n */\nexport class PrecomputedAdapter implements MeasurementAdapter {\n\tprivate readonly metrics: Record<string, Record<string, number>>;\n\tprivate readonly fallback: \"per-char\" | \"error\";\n\n\tconstructor(opts: PrecomputedAdapterOptions) {\n\t\tthis.metrics = opts.metrics;\n\t\tconst fb = opts.fallback ?? \"per-char\";\n\t\tif (fb !== \"per-char\" && fb !== \"error\") {\n\t\t\t// Keep parity with Python: validate at runtime.\n\t\t\tthrow new Error(\n\t\t\t\t`fallback must be 'per-char' or 'error', got ${JSON.stringify(opts.fallback)}`,\n\t\t\t);\n\t\t}\n\t\tthis.fallback = fb;\n\t}\n\n\tmeasureSegment(text: string, font: string): { width: number } {\n\t\tconst fontMap = this.metrics[font];\n\t\tif (fontMap) {\n\t\t\tconst w = fontMap[text];\n\t\t\tif (w !== undefined) return { width: w };\n\t\t}\n\n\t\tif (this.fallback === \"error\") {\n\t\t\tthrow new PrecomputedAdapterKeyError(\n\t\t\t\t`PrecomputedAdapter: no metrics for segment ${JSON.stringify(text)} in font ${JSON.stringify(font)}`,\n\t\t\t);\n\t\t}\n\n\t\t// per-char fallback: sum individual character widths\n\t\tlet total = 0;\n\t\tif (fontMap) {\n\t\t\tfor (const ch of text) {\n\t\t\t\tconst cw = fontMap[ch];\n\t\t\t\tif (cw !== undefined) {\n\t\t\t\t\ttotal += cw;\n\t\t\t\t}\n\t\t\t\t// unknown char contributes 0 (best-effort)\n\t\t\t}\n\t\t}\n\t\treturn { width: total };\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// CanvasMeasureAdapter (browser)\n// ---------------------------------------------------------------------------\n\nexport type CanvasMeasureAdapterOptions = {\n\t/** Emoji width correction factor (default: 1, no correction). */\n\temojiCorrection?: number;\n};\n\n/**\n * Browser measurement adapter using `OffscreenCanvas.measureText()`.\n *\n * Lazily creates an OffscreenCanvas and 2D context on first call.\n * Requires a browser environment with OffscreenCanvas support.\n */\nexport class CanvasMeasureAdapter implements MeasurementAdapter {\n\tprivate ctx: OffscreenCanvasRenderingContext2D | null = null;\n\tprivate currentFont = \"\";\n\tprivate readonly emojiCorrection: number;\n\n\tconstructor(opts?: CanvasMeasureAdapterOptions) {\n\t\tthis.emojiCorrection = opts?.emojiCorrection ?? 1;\n\t}\n\n\tprivate getContext(): OffscreenCanvasRenderingContext2D {\n\t\tif (!this.ctx) {\n\t\t\tif (typeof OffscreenCanvas === \"undefined\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"CanvasMeasureAdapter requires a browser environment with OffscreenCanvas support. \" +\n\t\t\t\t\t\t\"Use CliMeasureAdapter or NodeCanvasMeasureAdapter for Node.js.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst canvas = new OffscreenCanvas(0, 0);\n\t\t\tconst ctx = canvas.getContext(\"2d\");\n\t\t\tif (!ctx) throw new Error(\"CanvasMeasureAdapter: failed to get 2d context\");\n\t\t\tthis.ctx = ctx;\n\t\t}\n\t\treturn this.ctx;\n\t}\n\n\tmeasureSegment(text: string, font: string): { width: number } {\n\t\tconst ctx = this.getContext();\n\t\tif (font !== this.currentFont) {\n\t\t\tctx.font = font;\n\t\t\tthis.currentFont = font;\n\t\t}\n\t\tlet width = ctx.measureText(text).width;\n\t\t// Apply emoji correction if configured\n\t\tif (this.emojiCorrection !== 1 && /\\p{Emoji_Presentation}/u.test(text)) {\n\t\t\twidth *= this.emojiCorrection;\n\t\t}\n\t\treturn { width };\n\t}\n\n\tclearCache(): void {\n\t\t// No segment cache; context font is the only state.\n\t\tthis.currentFont = \"\";\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// NodeCanvasMeasureAdapter (Node.js / CLI with canvas package)\n// ---------------------------------------------------------------------------\n\n/**\n * Canvas API subset expected from `@napi-rs/canvas` or `skia-canvas`.\n * Passed via dependency injection — no dynamic import, no polling.\n */\nexport type CanvasModule = {\n\tcreateCanvas(\n\t\twidth: number,\n\t\theight: number,\n\t): {\n\t\tgetContext(type: \"2d\"): {\n\t\t\tfont: string;\n\t\t\tmeasureText(text: string): { width: number };\n\t\t};\n\t};\n};\n\n/**\n * Node.js measurement adapter using an injected canvas module.\n *\n * ```ts\n * import * as canvas from \"@napi-rs/canvas\";\n * const adapter = new NodeCanvasMeasureAdapter(canvas);\n * ```\n *\n * Works with `@napi-rs/canvas`, `skia-canvas`, or any module exposing\n * `createCanvas(w, h).getContext(\"2d\").measureText(text)`.\n */\nexport class NodeCanvasMeasureAdapter implements MeasurementAdapter {\n\tprivate ctx: { font: string; measureText(text: string): { width: number } } | null = null;\n\tprivate currentFont = \"\";\n\tprivate readonly canvasModule: CanvasModule;\n\n\tconstructor(canvasModule: CanvasModule) {\n\t\tthis.canvasModule = canvasModule;\n\t}\n\n\tprivate getContext(): { font: string; measureText(text: string): { width: number } } {\n\t\tif (!this.ctx) {\n\t\t\tconst canvas = this.canvasModule.createCanvas(0, 0);\n\t\t\tconst ctx = canvas.getContext(\"2d\");\n\t\t\tif (!ctx) throw new Error(\"NodeCanvasMeasureAdapter: failed to get 2d context\");\n\t\t\tthis.ctx = ctx;\n\t\t}\n\t\treturn this.ctx;\n\t}\n\n\tmeasureSegment(text: string, font: string): { width: number } {\n\t\tconst ctx = this.getContext();\n\t\tif (font !== this.currentFont) {\n\t\t\tctx.font = font;\n\t\t\tthis.currentFont = font;\n\t\t}\n\t\treturn { width: ctx.measureText(text).width };\n\t}\n\n\tclearCache(): void {\n\t\tthis.currentFont = \"\";\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// SvgBoundsAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * SVG measurement adapter — extracts dimensions from `viewBox` attribute\n * or explicit `width`/`height` attributes in the SVG string.\n *\n * Pure arithmetic: parses the SVG string for dimension attributes.\n * No DOM required. Works in any JS environment.\n *\n * Browser users who need `getBBox()` should pre-measure and pass explicit\n * `viewBox` on the content block instead.\n */\nexport class SvgBoundsAdapter {\n\tmeasureSvg(content: string): { width: number; height: number } {\n\t\t// Try viewBox first: viewBox=\"minX minY width height\"\n\t\tconst viewBoxMatch = content.match(/viewBox\\s*=\\s*[\"']([^\"']+)[\"']/);\n\t\tif (viewBoxMatch) {\n\t\t\tconst parts = viewBoxMatch[1]!.trim().split(/[\\s,]+/);\n\t\t\tif (parts.length >= 4) {\n\t\t\t\tconst w = Number.parseFloat(parts[2]!);\n\t\t\t\tconst h = Number.parseFloat(parts[3]!);\n\t\t\t\tif (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {\n\t\t\t\t\treturn { width: w, height: h };\n\t\t\t\t}\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"SvgBoundsAdapter: viewBox width/height are missing, non-finite, or not positive\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to explicit width/height attributes\n\t\tconst widthMatch = content.match(/<svg[^>]*\\bwidth\\s*=\\s*[\"']?([\\d.]+)/);\n\t\tconst heightMatch = content.match(/<svg[^>]*\\bheight\\s*=\\s*[\"']?([\\d.]+)/);\n\t\tif (widthMatch && heightMatch) {\n\t\t\tconst w = Number.parseFloat(widthMatch[1]!);\n\t\t\tconst h = Number.parseFloat(heightMatch[1]!);\n\t\t\tif (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {\n\t\t\t\treturn { width: w, height: h };\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t\"SvgBoundsAdapter: svg width/height attributes are non-finite or not positive\",\n\t\t\t);\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t\"SvgBoundsAdapter: cannot determine dimensions — SVG has no viewBox or width/height attributes\",\n\t\t);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// ImageSizeAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * Image measurement adapter — returns pre-registered dimensions by src key.\n *\n * Sync-only: dimensions must be provided upfront via the `sizes` map.\n * No I/O, no polling, no async. For browser use, pre-measure via\n * `Image.onload` and pass natural dimensions on the content block directly,\n * or register them here.\n *\n * ```ts\n * const adapter = new ImageSizeAdapter({\n * \"hero.png\": { width: 1200, height: 630 },\n * \"logo.svg\": { width: 120, height: 40 },\n * });\n * ```\n */\nexport class ImageSizeAdapter {\n\tprivate readonly sizes: Map<string, { width: number; height: number }>;\n\n\tconstructor(sizes: Record<string, { width: number; height: number }>) {\n\t\tthis.sizes = new Map(Object.entries(sizes));\n\t}\n\n\tmeasureImage(src: string): { width: number; height: number } {\n\t\tconst dims = this.sizes.get(src);\n\t\tif (!dims) {\n\t\t\tthrow new Error(`ImageSizeAdapter: no dimensions registered for ${JSON.stringify(src)}`);\n\t\t}\n\t\treturn { width: dims.width, height: dims.height };\n\t}\n}\n","/**\n * Reactive text layout engine (roadmap §7.1 — Pretext parity).\n *\n * Pure-arithmetic text measurement and line breaking without DOM thrashing.\n * Inspired by [Pretext](https://github.com/chenglou/pretext), rebuilt as a\n * GraphReFly graph — inspectable via `describe()`, snapshotable, debuggable.\n *\n * Two-tier DX:\n * - `reactiveLayout({ adapter, text?, font?, lineHeight?, maxWidth?, name? })` — convenience factory\n * - `MeasurementAdapter` — pluggable backends (`measureSegment`; optional `clearCache`)\n */\nimport { monotonicNs } from \"../../core/clock.js\";\nimport type { Node } from \"../../core/node.js\";\nimport { node } from \"../../core/node.js\";\nimport { derived, state } from \"../../core/sugar.js\";\nimport { Graph } from \"../../graph/graph.js\";\nimport { emitToMeta } from \"../_internal.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Pluggable measurement backend. */\nexport interface MeasurementAdapter {\n\tmeasureSegment(text: string, font: string): { width: number };\n\t/** Optional; adapters may omit for read-only / stateless measurement. */\n\tclearCache?(): void;\n}\n\n/** Mutable counters for `analyzeAndMeasure` cache hit ratio (hits / (hits + misses)). */\nexport type SegmentMeasureStats = { hits: number; misses: number };\n\n/** Break kind for each segment (ported from Pretext analysis.ts). */\nexport type SegmentBreakKind = \"text\" | \"space\" | \"zero-width-break\" | \"soft-hyphen\" | \"hard-break\";\n\n/** A measured text segment ready for line breaking. */\nexport type PreparedSegment = {\n\ttext: string;\n\twidth: number;\n\tkind: SegmentBreakKind;\n\t/** Grapheme widths for overflow-wrap: break-word (null if single grapheme). */\n\tgraphemeWidths: number[] | null;\n};\n\n/** A laid-out line with start/end cursors. */\nexport type LayoutLine = {\n\ttext: string;\n\twidth: number;\n\tstartSegment: number;\n\tstartGrapheme: number;\n\tendSegment: number;\n\tendGrapheme: number;\n};\n\n/** Per-character position for hit testing. */\nexport type CharPosition = {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n\tline: number;\n};\n\n/** Full layout result from the line-breaks derived node. */\nexport type LineBreaksResult = {\n\tlines: LayoutLine[];\n\tlineCount: number;\n};\n\n/** Result of the reactive layout graph's describe-accessible state. */\nexport type ReactiveLayoutBundle = {\n\tgraph: Graph;\n\t/** Set input text. */\n\tsetText: (text: string) => void;\n\t/** Set CSS font string. */\n\tsetFont: (font: string) => void;\n\t/** Set line height (px). */\n\tsetLineHeight: (lineHeight: number) => void;\n\t/** Set max width constraint (px). */\n\tsetMaxWidth: (maxWidth: number) => void;\n\t/** Segments node. */\n\tsegments: Node<PreparedSegment[]>;\n\t/** Line breaks node. */\n\tlineBreaks: Node<LineBreaksResult>;\n\t/** Total height node. */\n\theight: Node<number>;\n\t/** Per-character positions node. */\n\tcharPositions: Node<CharPosition[]>;\n};\n\n// ---------------------------------------------------------------------------\n// Text analysis (ported from Pretext analysis.ts — core subset)\n// ---------------------------------------------------------------------------\n\n// CJK detection (Unicode CJK Unified Ideographs + common ranges)\nfunction isCJK(s: string): boolean {\n\tfor (const ch of s) {\n\t\tconst c = ch.codePointAt(0)!;\n\t\tif (\n\t\t\t(c >= 0x4e00 && c <= 0x9fff) || // CJK Unified Ideographs\n\t\t\t(c >= 0x3400 && c <= 0x4dbf) || // CJK Extension A\n\t\t\t(c >= 0x3000 && c <= 0x303f) || // CJK Symbols and Punctuation\n\t\t\t(c >= 0x3040 && c <= 0x309f) || // Hiragana\n\t\t\t(c >= 0x30a0 && c <= 0x30ff) || // Katakana\n\t\t\t(c >= 0xac00 && c <= 0xd7af) || // Hangul\n\t\t\t(c >= 0xff00 && c <= 0xffef) // Fullwidth Forms\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n// Kinsoku: characters that cannot start a line (CJK punctuation)\nconst kinsokuStart = new Set([\n\t\"\\uff0c\",\n\t\"\\uff0e\",\n\t\"\\uff01\",\n\t\"\\uff1a\",\n\t\"\\uff1b\",\n\t\"\\uff1f\",\n\t\"\\u3001\",\n\t\"\\u3002\",\n\t\"\\u30fb\",\n\t\"\\uff09\",\n\t\"\\u3015\",\n\t\"\\u3009\",\n\t\"\\u300b\",\n\t\"\\u300d\",\n\t\"\\u300f\",\n\t\"\\u3011\",\n]);\n\n// Left-sticky punctuation (merges into preceding segment)\nconst leftStickyPunctuation = new Set([\n\t\".\",\n\t\",\",\n\t\"!\",\n\t\"?\",\n\t\":\",\n\t\";\",\n\t\")\",\n\t\"]\",\n\t\"}\",\n\t\"%\",\n\t'\"',\n\t\"\\u201d\",\n\t\"\\u2019\",\n\t\"\\u00bb\",\n\t\"\\u203a\",\n\t\"\\u2026\",\n]);\n\n/** Normalize collapsible whitespace (CSS white-space: normal). */\nfunction normalizeWhitespace(text: string): string {\n\treturn text.replace(/[\\t\\n\\r\\f ]+/g, \" \").replace(/^ | $/g, \"\");\n}\n\n/**\n * Segment text using Intl.Segmenter (word granularity) and classify break kinds.\n * Returns raw segmentation pieces before merging.\n */\nfunction segmentText(normalized: string): {\n\ttexts: string[];\n\tisWordLike: boolean[];\n\tkinds: SegmentBreakKind[];\n}[] {\n\tconst wordSegmenter = new Intl.Segmenter(undefined, { granularity: \"word\" });\n\tconst pieces: {\n\t\ttexts: string[];\n\t\tisWordLike: boolean[];\n\t\tkinds: SegmentBreakKind[];\n\t}[] = [];\n\n\tfor (const s of wordSegmenter.segment(normalized)) {\n\t\tconst text = s.segment;\n\t\tconst isWordLike = s.isWordLike ?? false;\n\n\t\t// Split segment by break-relevant characters\n\t\tconst texts: string[] = [];\n\t\tconst wordLikes: boolean[] = [];\n\t\tconst kinds: SegmentBreakKind[] = [];\n\n\t\tlet currentText = \"\";\n\t\tlet currentKind: SegmentBreakKind | null = null;\n\n\t\tfor (const ch of text) {\n\t\t\tlet kind: SegmentBreakKind;\n\t\t\tif (ch === \" \") kind = \"space\";\n\t\t\telse if (ch === \"\\u200b\") kind = \"zero-width-break\";\n\t\t\telse if (ch === \"\\u00ad\") kind = \"soft-hyphen\";\n\t\t\telse if (ch === \"\\n\") kind = \"hard-break\";\n\t\t\telse kind = \"text\";\n\n\t\t\tif (currentKind !== null && kind === currentKind) {\n\t\t\t\tcurrentText += ch;\n\t\t\t} else {\n\t\t\t\tif (currentKind !== null) {\n\t\t\t\t\ttexts.push(currentText);\n\t\t\t\t\twordLikes.push(currentKind === \"text\" && isWordLike);\n\t\t\t\t\tkinds.push(currentKind);\n\t\t\t\t}\n\t\t\t\tcurrentText = ch;\n\t\t\t\tcurrentKind = kind;\n\t\t\t}\n\t\t}\n\n\t\tif (currentKind !== null) {\n\t\t\ttexts.push(currentText);\n\t\t\twordLikes.push(currentKind === \"text\" && isWordLike);\n\t\t\tkinds.push(currentKind);\n\t\t}\n\n\t\tpieces.push({ texts, isWordLike: wordLikes, kinds });\n\t}\n\treturn pieces;\n}\n\n/**\n * Merge segmentation pieces: sticky punctuation, CJK per-grapheme splitting,\n * and produce the final measured segment list.\n */\nexport function analyzeAndMeasure(\n\ttext: string,\n\tfont: string,\n\tadapter: MeasurementAdapter,\n\tcache: Map<string, Map<string, number>>,\n\tstats?: SegmentMeasureStats,\n): PreparedSegment[] {\n\tconst normalized = normalizeWhitespace(text);\n\tif (normalized.length === 0) return [];\n\n\tconst pieces = segmentText(normalized);\n\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\tgranularity: \"grapheme\",\n\t});\n\n\t// Flatten pieces into a single segment list with merging\n\tconst rawTexts: string[] = [];\n\tconst rawKinds: SegmentBreakKind[] = [];\n\tconst rawWordLike: boolean[] = [];\n\n\tfor (const piece of pieces) {\n\t\tfor (let i = 0; i < piece.texts.length; i++) {\n\t\t\trawTexts.push(piece.texts[i]!);\n\t\t\trawKinds.push(piece.kinds[i]!);\n\t\t\trawWordLike.push(piece.isWordLike[i]!);\n\t\t}\n\t}\n\n\t// Merge: left-sticky punctuation and kinsoku-start into preceding text segment\n\tconst mergedTexts: string[] = [];\n\tconst mergedKinds: SegmentBreakKind[] = [];\n\tconst mergedWordLike: boolean[] = [];\n\n\tfor (let i = 0; i < rawTexts.length; i++) {\n\t\tconst t = rawTexts[i]!;\n\t\tconst k = rawKinds[i]!;\n\t\tconst wl = rawWordLike[i]!;\n\n\t\t// Merge left-sticky punctuation into preceding text\n\t\tif (\n\t\t\tk === \"text\" &&\n\t\t\t!wl &&\n\t\t\tmergedTexts.length > 0 &&\n\t\t\tmergedKinds[mergedKinds.length - 1] === \"text\"\n\t\t) {\n\t\t\tconst isSticky = t.length === 1 && (leftStickyPunctuation.has(t) || kinsokuStart.has(t));\n\t\t\tif (isSticky) {\n\t\t\t\tmergedTexts[mergedTexts.length - 1] += t;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Merge hyphen after word into preceding text (\"well-known\" stays together)\n\t\tif (\n\t\t\tt === \"-\" &&\n\t\t\tmergedTexts.length > 0 &&\n\t\t\tmergedKinds[mergedKinds.length - 1] === \"text\" &&\n\t\t\tmergedWordLike[mergedWordLike.length - 1]\n\t\t) {\n\t\t\tmergedTexts[mergedTexts.length - 1] += t;\n\t\t\tcontinue;\n\t\t}\n\n\t\tmergedTexts.push(t);\n\t\tmergedKinds.push(k);\n\t\tmergedWordLike.push(wl);\n\t}\n\n\t// Get or create font-specific cache\n\tlet fontCache = cache.get(font);\n\tif (!fontCache) {\n\t\tfontCache = new Map<string, number>();\n\t\tcache.set(font, fontCache);\n\t}\n\n\tfunction measureCached(seg: string): number {\n\t\tlet w = fontCache!.get(seg);\n\t\tif (w === undefined) {\n\t\t\tif (stats) stats.misses += 1;\n\t\t\tw = adapter.measureSegment(seg, font).width;\n\t\t\tfontCache!.set(seg, w);\n\t\t} else if (stats) {\n\t\t\tstats.hits += 1;\n\t\t}\n\t\treturn w;\n\t}\n\n\t// Build final prepared segments, splitting CJK into per-grapheme\n\tconst segments: PreparedSegment[] = [];\n\n\tfor (let i = 0; i < mergedTexts.length; i++) {\n\t\tconst t = mergedTexts[i]!;\n\t\tconst k = mergedKinds[i]!;\n\n\t\tif (k !== \"text\") {\n\t\t\t// Non-text segments: space, hard-break, soft-hyphen, zero-width-break\n\t\t\tsegments.push({\n\t\t\t\ttext: t,\n\t\t\t\twidth: k === \"space\" ? measureCached(\" \") * t.length : 0,\n\t\t\t\tkind: k,\n\t\t\t\tgraphemeWidths: null,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// CJK text: split into per-grapheme segments for line breaking\n\t\tif (isCJK(t)) {\n\t\t\tlet unitText = \"\";\n\t\t\tfor (const gs of graphemeSegmenter.segment(t)) {\n\t\t\t\tconst grapheme = gs.segment;\n\n\t\t\t\t// Kinsoku: line-start-prohibited chars stick to preceding unit\n\t\t\t\tif (unitText.length > 0 && kinsokuStart.has(grapheme)) {\n\t\t\t\t\tunitText += grapheme;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (unitText.length > 0) {\n\t\t\t\t\tconst w = measureCached(unitText);\n\t\t\t\t\tsegments.push({\n\t\t\t\t\t\ttext: unitText,\n\t\t\t\t\t\twidth: w,\n\t\t\t\t\t\tkind: \"text\",\n\t\t\t\t\t\tgraphemeWidths: null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tunitText = grapheme;\n\t\t\t}\n\t\t\tif (unitText.length > 0) {\n\t\t\t\tconst w = measureCached(unitText);\n\t\t\t\tsegments.push({\n\t\t\t\t\ttext: unitText,\n\t\t\t\t\twidth: w,\n\t\t\t\t\tkind: \"text\",\n\t\t\t\t\tgraphemeWidths: null,\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Non-CJK text: measure whole segment, pre-compute grapheme widths for break-word\n\t\tconst w = measureCached(t);\n\t\tlet graphemeWidths: number[] | null = null;\n\n\t\tif (mergedWordLike[i] && t.length > 1) {\n\t\t\tconst gWidths: number[] = [];\n\t\t\tfor (const gs of graphemeSegmenter.segment(t)) {\n\t\t\t\tgWidths.push(measureCached(gs.segment));\n\t\t\t}\n\t\t\tif (gWidths.length > 1) {\n\t\t\t\tgraphemeWidths = gWidths;\n\t\t\t}\n\t\t}\n\n\t\tsegments.push({ text: t, width: w, kind: \"text\", graphemeWidths });\n\t}\n\n\treturn segments;\n}\n\n// ---------------------------------------------------------------------------\n// Line breaking (greedy, ported from Pretext line-break.ts — core subset)\n// ---------------------------------------------------------------------------\n\n/**\n * Greedy line-breaking algorithm.\n *\n * Walks segments left to right, accumulating width. Breaks when a segment would\n * overflow maxWidth. Supports:\n * - Trailing space hang (spaces don't trigger breaks)\n * - overflow-wrap: break-word via grapheme widths\n * - Soft hyphens (break opportunity, adds visible hyphen width)\n * - Hard breaks (forced newline)\n */\nexport function computeLineBreaks(\n\tsegments: PreparedSegment[],\n\tmaxWidth: number,\n\tadapter: MeasurementAdapter,\n\tfont: string,\n\tcache: Map<string, Map<string, number>>,\n): LineBreaksResult {\n\tif (segments.length === 0) {\n\t\treturn { lines: [], lineCount: 0 };\n\t}\n\n\tconst lines: LayoutLine[] = [];\n\tlet lineW = 0;\n\tlet hasContent = false;\n\tlet lineStartSeg = 0;\n\tlet lineStartGrapheme = 0;\n\tlet lineEndSeg = 0;\n\tlet lineEndGrapheme = 0;\n\tlet pendingBreakSeg = -1;\n\tlet pendingBreakWidth = 0;\n\n\t// Measure hyphen for soft-hyphen support\n\tlet fontCache = cache.get(font);\n\tif (!fontCache) {\n\t\tfontCache = new Map<string, number>();\n\t\tcache.set(font, fontCache);\n\t}\n\tlet hyphenWidth = fontCache.get(\"-\");\n\tif (hyphenWidth === undefined) {\n\t\thyphenWidth = adapter.measureSegment(\"-\", font).width;\n\t\tfontCache.set(\"-\", hyphenWidth);\n\t}\n\n\tfunction flushLine(endSeg = lineEndSeg, endGrapheme = lineEndGrapheme, width = lineW) {\n\t\t// Build line text\n\t\tlet text = \"\";\n\t\tfor (let i = lineStartSeg; i < endSeg; i++) {\n\t\t\tconst seg = segments[i]!;\n\t\t\tif (seg.kind === \"soft-hyphen\" || seg.kind === \"hard-break\") continue;\n\t\t\tif (i === lineStartSeg && lineStartGrapheme > 0 && seg.graphemeWidths) {\n\t\t\t\t// Partial segment from grapheme break\n\t\t\t\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\t\t\t\tgranularity: \"grapheme\",\n\t\t\t\t});\n\t\t\t\tconst graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);\n\t\t\t\ttext += graphemes.slice(lineStartGrapheme).join(\"\");\n\t\t\t} else {\n\t\t\t\ttext += seg.text;\n\t\t\t}\n\t\t}\n\t\t// Handle partial end segment\n\t\tif (endGrapheme > 0 && endSeg < segments.length) {\n\t\t\tconst seg = segments[endSeg]!;\n\t\t\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\t\t\tgranularity: \"grapheme\",\n\t\t\t});\n\t\t\tconst graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);\n\t\t\tconst startG = lineStartSeg === endSeg ? lineStartGrapheme : 0;\n\t\t\ttext += graphemes.slice(startG, endGrapheme).join(\"\");\n\t\t}\n\t\t// Add visible hyphen if line ends at soft-hyphen\n\t\tif (\n\t\t\tendSeg > 0 &&\n\t\t\tsegments[endSeg - 1]?.kind === \"soft-hyphen\" &&\n\t\t\t!(lineStartSeg === endSeg && lineStartGrapheme > 0)\n\t\t) {\n\t\t\ttext += \"-\";\n\t\t}\n\n\t\tlines.push({\n\t\t\ttext,\n\t\t\twidth,\n\t\t\tstartSegment: lineStartSeg,\n\t\t\tstartGrapheme: lineStartGrapheme,\n\t\t\tendSegment: endSeg,\n\t\t\tendGrapheme,\n\t\t});\n\t\tlineW = 0;\n\t\thasContent = false;\n\t\tpendingBreakSeg = -1;\n\t\tpendingBreakWidth = 0;\n\t}\n\n\tfunction canBreakAfter(kind: SegmentBreakKind): boolean {\n\t\treturn kind === \"space\" || kind === \"zero-width-break\" || kind === \"soft-hyphen\";\n\t}\n\n\tfunction startLine(segIdx: number, graphemeIdx: number, width: number) {\n\t\thasContent = true;\n\t\tlineStartSeg = segIdx;\n\t\tlineStartGrapheme = graphemeIdx;\n\t\tlineEndSeg = segIdx + 1;\n\t\tlineEndGrapheme = 0;\n\t\tlineW = width;\n\t}\n\n\tfunction startLineAtGrapheme(segIdx: number, graphemeIdx: number, width: number) {\n\t\thasContent = true;\n\t\tlineStartSeg = segIdx;\n\t\tlineStartGrapheme = graphemeIdx;\n\t\tlineEndSeg = segIdx;\n\t\tlineEndGrapheme = graphemeIdx + 1;\n\t\tlineW = width;\n\t}\n\n\tfor (let i = 0; i < segments.length; i++) {\n\t\tconst seg = segments[i]!;\n\n\t\t// Hard break: emit current line, start fresh\n\t\tif (seg.kind === \"hard-break\") {\n\t\t\tif (hasContent) {\n\t\t\t\tflushLine();\n\t\t\t} else {\n\t\t\t\t// Empty line\n\t\t\t\tlines.push({\n\t\t\t\t\ttext: \"\",\n\t\t\t\t\twidth: 0,\n\t\t\t\t\tstartSegment: i,\n\t\t\t\t\tstartGrapheme: 0,\n\t\t\t\t\tendSegment: i,\n\t\t\t\t\tendGrapheme: 0,\n\t\t\t\t});\n\t\t\t}\n\t\t\tlineStartSeg = i + 1;\n\t\t\tlineStartGrapheme = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst w = seg.width;\n\n\t\tif (!hasContent) {\n\t\t\t// First content on a new line\n\t\t\tif (w > maxWidth && seg.graphemeWidths) {\n\t\t\t\t// Word wider than maxWidth: break at grapheme level\n\t\t\t\tappendBreakableSegment(i, 0, seg.graphemeWidths);\n\t\t\t} else {\n\t\t\t\tstartLine(i, 0, w);\n\t\t\t}\n\t\t\tif (canBreakAfter(seg.kind)) {\n\t\t\t\tpendingBreakSeg = i + 1;\n\t\t\t\tpendingBreakWidth = seg.kind === \"space\" ? lineW - w : lineW;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst newW = lineW + w;\n\n\t\tif (newW > maxWidth + 0.005) {\n\t\t\t// Overflow\n\t\t\tif (canBreakAfter(seg.kind)) {\n\t\t\t\t// Trailing space: hang past edge, then break\n\t\t\t\tlineW += w;\n\t\t\t\tlineEndSeg = i + 1;\n\t\t\t\tlineEndGrapheme = 0;\n\t\t\t\tflushLine(i + 1, 0, seg.kind === \"space\" ? lineW - w : lineW);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (pendingBreakSeg >= 0) {\n\t\t\t\t// Break at last break opportunity\n\t\t\t\tflushLine(pendingBreakSeg, 0, pendingBreakWidth);\n\t\t\t\t// Don't advance i — re-process current segment on new line\n\t\t\t\ti--;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (w > maxWidth && seg.graphemeWidths) {\n\t\t\t\t// Break-word: split at grapheme level\n\t\t\t\tflushLine();\n\t\t\t\tappendBreakableSegment(i, 0, seg.graphemeWidths);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// No break opportunity: force break before this segment\n\t\t\tflushLine();\n\t\t\ti--;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Fits on current line\n\t\tlineW = newW;\n\t\tlineEndSeg = i + 1;\n\t\tlineEndGrapheme = 0;\n\n\t\tif (canBreakAfter(seg.kind)) {\n\t\t\tpendingBreakSeg = i + 1;\n\t\t\tpendingBreakWidth = seg.kind === \"space\" ? lineW - w : lineW;\n\t\t}\n\t}\n\n\tif (hasContent) {\n\t\tflushLine();\n\t}\n\n\treturn { lines, lineCount: lines.length };\n\n\tfunction appendBreakableSegment(segIdx: number, startG: number, gWidths: number[]) {\n\t\tfor (let g = startG; g < gWidths.length; g++) {\n\t\t\tconst gw = gWidths[g]!;\n\t\t\tif (!hasContent) {\n\t\t\t\tstartLineAtGrapheme(segIdx, g, gw);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (lineW + gw > maxWidth + 0.005) {\n\t\t\t\tflushLine();\n\t\t\t\tstartLineAtGrapheme(segIdx, g, gw);\n\t\t\t} else {\n\t\t\t\tlineW += gw;\n\t\t\t\tlineEndSeg = segIdx;\n\t\t\t\tlineEndGrapheme = g + 1;\n\t\t\t}\n\t\t}\n\t\t// If we consumed the whole segment, advance end past it\n\t\tif (hasContent && lineEndSeg === segIdx && lineEndGrapheme === gWidths.length) {\n\t\t\tlineEndSeg = segIdx + 1;\n\t\t\tlineEndGrapheme = 0;\n\t\t}\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Character positions\n// ---------------------------------------------------------------------------\n\n/** Compute per-character x,y positions from line breaks and segments. */\nexport function computeCharPositions(\n\tlineBreaks: LineBreaksResult,\n\tsegments: PreparedSegment[],\n\tlineHeight: number,\n): CharPosition[] {\n\tconst positions: CharPosition[] = [];\n\tconst graphemeSegmenter = new Intl.Segmenter(undefined, {\n\t\tgranularity: \"grapheme\",\n\t});\n\n\tfor (let lineIdx = 0; lineIdx < lineBreaks.lines.length; lineIdx++) {\n\t\tconst line = lineBreaks.lines[lineIdx]!;\n\t\tconst y = lineIdx * lineHeight;\n\t\tlet x = 0;\n\n\t\tfor (let si = line.startSegment; si < segments.length; si++) {\n\t\t\tconst seg = segments[si]!;\n\t\t\tif (seg.kind === \"soft-hyphen\" || seg.kind === \"hard-break\") {\n\t\t\t\t// Skip non-visual segments but stop if past the line\n\t\t\t\tif (si >= line.endSegment && line.endGrapheme === 0) break;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst graphemes = [...graphemeSegmenter.segment(seg.text)].map((g) => g.segment);\n\t\t\tif (graphemes.length === 0) continue;\n\t\t\tconst startG = si === line.startSegment ? line.startGrapheme : 0;\n\n\t\t\t// Determine how many graphemes of this segment belong to this line\n\t\t\tlet endG: number;\n\t\t\tif (si < line.endSegment) {\n\t\t\t\t// Full segment is on this line\n\t\t\t\tendG = graphemes.length;\n\t\t\t} else if (si === line.endSegment && line.endGrapheme > 0) {\n\t\t\t\t// Partial segment (grapheme-level break)\n\t\t\t\tendG = line.endGrapheme;\n\t\t\t} else {\n\t\t\t\t// Past the line's content\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tfor (let g = startG; g < endG; g++) {\n\t\t\t\tconst gWidth = seg.graphemeWidths ? seg.graphemeWidths[g]! : seg.width / graphemes.length;\n\t\t\t\tpositions.push({ x, y, width: gWidth, height: lineHeight, line: lineIdx });\n\t\t\t\tx += gWidth;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn positions;\n}\n\n// ---------------------------------------------------------------------------\n// Reactive graph factory\n// ---------------------------------------------------------------------------\n\nexport type ReactiveLayoutOptions = {\n\t/** Measurement backend (required). */\n\tadapter: MeasurementAdapter;\n\t/** Graph name (default: \"reactive-layout\"). */\n\tname?: string;\n\t/** Initial text. */\n\ttext?: string;\n\t/** Initial CSS font string. */\n\tfont?: string;\n\t/** Initial line height in px. */\n\tlineHeight?: number;\n\t/** Initial max width in px (clamped to ≥ 0). */\n\tmaxWidth?: number;\n};\n\n/**\n * Create a reactive text layout graph.\n *\n * ```\n * Graph(\"reactive-layout\")\n * ├── state(\"text\")\n * ├── state(\"font\")\n * ├── state(\"line-height\")\n * ├── state(\"max-width\")\n * ├── derived(\"segments\") — text + font → PreparedSegment[]\n * ├── derived(\"line-breaks\") — segments + max-width → LineBreaksResult\n * ├── derived(\"height\") — line-breaks → number\n * └── derived(\"char-positions\") — line-breaks + segments → CharPosition[]\n * ```\n */\nexport function reactiveLayout(opts: ReactiveLayoutOptions): ReactiveLayoutBundle {\n\tconst { adapter, name = \"reactive-layout\" } = opts;\n\tconst g = new Graph(name);\n\n\t// Shared measurement cache: Map<font, Map<segment, width>>\n\tconst measureCache = new Map<string, Map<string, number>>();\n\n\t// --- State nodes ---\n\tconst textNode = state<string>(opts.text ?? \"\", { name: \"text\" });\n\tconst fontNode = state<string>(opts.font ?? \"16px sans-serif\", {\n\t\tname: \"font\",\n\t});\n\tconst lineHeightNode = state<number>(opts.lineHeight ?? 20, {\n\t\tname: \"line-height\",\n\t});\n\tconst maxWidthNode = state<number>(Math.max(0, opts.maxWidth ?? 800), {\n\t\tname: \"max-width\",\n\t});\n\n\t// --- Derived: segments (text + font → PreparedSegment[]) ---\n\tfunction graphemeWidthsEqual(a: number[] | null, b: number[] | null): boolean {\n\t\tif (a === null || b === null) return a === b;\n\t\tif (a.length !== b.length) return false;\n\t\tfor (let i = 0; i < a.length; i++) {\n\t\t\tif (a[i] !== b[i]!) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Raw `node(...)` instead of `derived(...)` so the fn can return a\n\t// cleanup function. Core fires function-form cleanup on INVALIDATE (see\n\t// `node.ts:_updateState` INVALIDATE branch), which replaces the old v4\n\t// per-node `onMessage` hook that watched for INVALIDATE/TEARDOWN to flush\n\t// measurement caches.\n\tconst segmentsNode: Node<PreparedSegment[]> = node<PreparedSegment[]>(\n\t\t[textNode, fontNode],\n\t\t(data, actions, ctx) => {\n\t\t\tconst b0 = data[0];\n\t\t\tconst textVal = (b0 != null && b0.length > 0 ? b0.at(-1) : ctx.prevData[0]) as string;\n\t\t\tconst b1 = data[1];\n\t\t\tconst fontVal = (b1 != null && b1.length > 0 ? b1.at(-1) : ctx.prevData[1]) as string;\n\t\t\tconst t0 = monotonicNs();\n\t\t\tconst measureStats: SegmentMeasureStats = { hits: 0, misses: 0 };\n\t\t\tconst result = analyzeAndMeasure(\n\t\t\t\ttextVal as string,\n\t\t\t\tfontVal as string,\n\t\t\t\tadapter,\n\t\t\t\tmeasureCache,\n\t\t\t\tmeasureStats,\n\t\t\t);\n\t\t\tconst elapsed = monotonicNs() - t0;\n\n\t\t\tconst lookups = measureStats.hits + measureStats.misses;\n\t\t\tconst hitRate = lookups === 0 ? 1 : measureStats.hits / lookups;\n\n\t\t\t// After parent `segments` auto-emits DATA/RESOLVED, deliver metrics\n\t\t\t// via phase-3 deferral so observers see the parent value first.\n\t\t\t// `emitToMeta` wraps the tier-3 downWithBatch forwarding + absent-meta\n\t\t\t// null guard (parity with Python `defer_down` → `down_with_batch` phase 3).\n\t\t\tconst meta = segmentsNode.meta;\n\t\t\tif (meta) {\n\t\t\t\temitToMeta(meta[\"cache-hit-rate\"], hitRate);\n\t\t\t\temitToMeta(meta[\"segment-count\"], result.length);\n\t\t\t\temitToMeta(meta[\"layout-time-ns\"], elapsed);\n\t\t\t}\n\n\t\t\tactions.emit(result);\n\n\t\t\t// Function-form cleanup: fires before the next run AND on\n\t\t\t// deactivation AND on INVALIDATE. Flushes the shared measurement\n\t\t\t// cache + the adapter's own cache so stale measurements don't\n\t\t\t// persist across INVALIDATE broadcasts.\n\t\t\treturn () => {\n\t\t\t\tmeasureCache.clear();\n\t\t\t\tadapter.clearCache?.();\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\tname: \"segments\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: {\n\t\t\t\t\"cache-hit-rate\": 0,\n\t\t\t\t\"segment-count\": 0,\n\t\t\t\t\"layout-time-ns\": 0,\n\t\t\t},\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst sa = a as PreparedSegment[] | null;\n\t\t\t\tconst sb = b as PreparedSegment[] | null;\n\t\t\t\tif (sa == null || sb == null) return sa === sb;\n\t\t\t\tif (sa.length !== sb.length) return false;\n\t\t\t\tfor (let i = 0; i < sa.length; i++) {\n\t\t\t\t\tconst pa = sa[i]!;\n\t\t\t\t\tconst pb = sb[i]!;\n\t\t\t\t\tif (\n\t\t\t\t\t\tpa.text !== pb.text ||\n\t\t\t\t\t\tpa.width !== pb.width ||\n\t\t\t\t\t\tpa.kind !== pb.kind ||\n\t\t\t\t\t\t!graphemeWidthsEqual(pa.graphemeWidths ?? null, pb.graphemeWidths ?? null)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: line-breaks (segments + max-width + font → LineBreaksResult) ---\n\tconst lineBreaksNode = derived<LineBreaksResult>(\n\t\t[segmentsNode, maxWidthNode, fontNode],\n\t\t([segs, mw, font]) => {\n\t\t\treturn computeLineBreaks(\n\t\t\t\tsegs as PreparedSegment[],\n\t\t\t\tmw as number,\n\t\t\t\tadapter,\n\t\t\t\tfont as string,\n\t\t\t\tmeasureCache,\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tname: \"line-breaks\",\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst la = a as LineBreaksResult | null;\n\t\t\t\tconst lb = b as LineBreaksResult | null;\n\t\t\t\tif (la == null || lb == null) return la === lb;\n\t\t\t\tif (la.lineCount !== lb.lineCount) return false;\n\t\t\t\tfor (let i = 0; i < la.lines.length; i++) {\n\t\t\t\t\tconst lineA = la.lines[i]!;\n\t\t\t\t\tconst lineB = lb.lines[i]!;\n\t\t\t\t\tif (\n\t\t\t\t\t\tlineA.text !== lineB.text ||\n\t\t\t\t\t\tlineA.width !== lineB.width ||\n\t\t\t\t\t\tlineA.startSegment !== lineB.startSegment ||\n\t\t\t\t\t\tlineA.startGrapheme !== lineB.startGrapheme ||\n\t\t\t\t\t\tlineA.endSegment !== lineB.endSegment ||\n\t\t\t\t\t\tlineA.endGrapheme !== lineB.endGrapheme\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: height ---\n\tconst heightNode = derived<number>(\n\t\t[lineBreaksNode, lineHeightNode],\n\t\t([lb, lh]) => (lb as LineBreaksResult).lineCount * (lh as number),\n\t\t{ name: \"height\" },\n\t);\n\n\t// --- Derived: char-positions ---\n\tconst charPositionsNode = derived<CharPosition[]>(\n\t\t[lineBreaksNode, segmentsNode, lineHeightNode],\n\t\t([lb, segs, lh]) => {\n\t\t\treturn computeCharPositions(lb as LineBreaksResult, segs as PreparedSegment[], lh as number);\n\t\t},\n\t\t{\n\t\t\tname: \"char-positions\",\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst ca = a as CharPosition[] | null;\n\t\t\t\tconst cb = b as CharPosition[] | null;\n\t\t\t\tif (ca == null || cb == null) return ca === cb;\n\t\t\t\tif (ca.length !== cb.length) return false;\n\t\t\t\tfor (let i = 0; i < ca.length; i++) {\n\t\t\t\t\tif (ca[i]!.x !== cb[i]!.x || ca[i]!.y !== cb[i]!.y || ca[i]!.width !== cb[i]!.width)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Register in graph ---\n\tg.add(\"text\", textNode);\n\tg.add(\"font\", fontNode);\n\tg.add(\"line-height\", lineHeightNode);\n\tg.add(\"max-width\", maxWidthNode);\n\tg.add(\"segments\", segmentsNode);\n\tg.add(\"line-breaks\", lineBreaksNode);\n\tg.add(\"height\", heightNode);\n\tg.add(\"char-positions\", charPositionsNode);\n\n\t// --- Edges (for describe() visibility) ---\n\n\treturn {\n\t\tgraph: g,\n\t\tsetText: (text: string) => g.set(\"text\", text),\n\t\tsetFont: (font: string) => g.set(\"font\", font),\n\t\tsetLineHeight: (lh: number) => g.set(\"line-height\", lh),\n\t\tsetMaxWidth: (mw: number) => g.set(\"max-width\", Math.max(0, mw)),\n\t\tsegments: segmentsNode,\n\t\tlineBreaks: lineBreaksNode,\n\t\theight: heightNode,\n\t\tcharPositions: charPositionsNode,\n\t};\n}\n","/**\n * Reactive multi-content block layout engine (roadmap §7.1 — mixed content).\n *\n * Extends the text-only `reactiveLayout` with support for image and SVG blocks.\n * Pure-arithmetic layout over measured child sizes — no DOM, no async.\n *\n * Graph shape:\n * ```\n * Graph(\"reactive-block-layout\")\n * ├── state(\"blocks\") — ContentBlock[] input\n * ├── state(\"max-width\") — container constraint\n * ├── state(\"gap\") — vertical gap between blocks (px)\n * ├── derived(\"measured-blocks\") — blocks → MeasuredBlock[] (per-type measurement)\n * ├── derived(\"block-flow\") — measured-blocks + max-width + gap → PositionedBlock[]\n * ├── derived(\"total-height\") — block-flow → total height\n * └── meta: { block-count, layout-time-ns }\n * ```\n */\nimport { monotonicNs } from \"../../core/clock.js\";\nimport type { Node } from \"../../core/node.js\";\nimport { node } from \"../../core/node.js\";\nimport { derived, state } from \"../../core/sugar.js\";\nimport { Graph } from \"../../graph/graph.js\";\nimport { emitToMeta } from \"../_internal.js\";\nimport {\n\tanalyzeAndMeasure,\n\ttype CharPosition,\n\tcomputeCharPositions,\n\tcomputeLineBreaks,\n\ttype LineBreaksResult,\n\ttype MeasurementAdapter,\n\ttype PreparedSegment,\n} from \"./reactive-layout.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Pluggable measurement backend for SVG content. */\nexport interface SvgMeasurer {\n\tmeasureSvg(content: string): { width: number; height: number };\n}\n\n/** Pluggable measurement backend for image content. */\nexport interface ImageMeasurer {\n\tmeasureImage(src: string): { width: number; height: number };\n}\n\n/** Adapters map for `reactiveBlockLayout`. */\nexport type BlockAdapters = {\n\t/** Text measurement adapter (required — delegates to `reactiveLayout` internals). */\n\ttext: MeasurementAdapter;\n\t/** SVG measurement (optional — required only if SVG blocks are present). */\n\tsvg?: SvgMeasurer;\n\t/** Image measurement (optional — required only if image blocks without explicit dimensions are present). */\n\timage?: ImageMeasurer;\n};\n\n/** A content block — text, image, or SVG. */\nexport type ContentBlock =\n\t| {\n\t\t\ttype: \"text\";\n\t\t\ttext: string;\n\t\t\tfont?: string;\n\t\t\tlineHeight?: number;\n\t }\n\t| {\n\t\t\ttype: \"image\";\n\t\t\tsrc: string;\n\t\t\t/** Natural width in px. Required if no ImageMeasurer adapter is provided. */\n\t\t\tnaturalWidth?: number;\n\t\t\t/** Natural height in px. Required if no ImageMeasurer adapter is provided. */\n\t\t\tnaturalHeight?: number;\n\t }\n\t| {\n\t\t\ttype: \"svg\";\n\t\t\tcontent: string;\n\t\t\t/** Explicit viewBox dimensions. Required if no SvgMeasurer adapter is provided. */\n\t\t\tviewBox?: { width: number; height: number };\n\t };\n\n/**\n * A block after measurement — knows its natural dimensions.\n *\n * **Equality note:** The reactive `measured-blocks` node uses dimension-only equality\n * (`type`, `width`, `height`, `index`). Inner text layout data (`textSegments`,\n * `textLineBreaks`, `textCharPositions`) is NOT compared for change detection.\n * If you need text-level reactivity, use `reactiveLayout()` directly per text block.\n */\nexport type MeasuredBlock = {\n\tindex: number;\n\ttype: \"text\" | \"image\" | \"svg\";\n\twidth: number;\n\theight: number;\n\t/** For text blocks: the inner layout results. */\n\ttextSegments?: PreparedSegment[];\n\ttextLineBreaks?: LineBreaksResult;\n\ttextCharPositions?: CharPosition[];\n};\n\n/** A block after flow — positioned in the container. */\nexport type PositionedBlock = MeasuredBlock & {\n\tx: number;\n\ty: number;\n};\n\n/** Options for `reactiveBlockLayout`. */\nexport type ReactiveBlockLayoutOptions = {\n\tadapters: BlockAdapters;\n\tname?: string;\n\tblocks?: ContentBlock[];\n\t/** Container max width in px (clamped to ≥ 0 on init and `setMaxWidth`). */\n\tmaxWidth?: number;\n\t/** Vertical gap between blocks in px (default 0). */\n\tgap?: number;\n\t/** Default font for text blocks that don't specify one. */\n\tdefaultFont?: string;\n\t/** Default line height for text blocks that don't specify one. */\n\tdefaultLineHeight?: number;\n};\n\n/** Result bundle from `reactiveBlockLayout`. */\nexport type ReactiveBlockLayoutBundle = {\n\tgraph: Graph;\n\tsetBlocks: (blocks: ContentBlock[]) => void;\n\tsetMaxWidth: (maxWidth: number) => void;\n\tsetGap: (gap: number) => void;\n\tmeasuredBlocks: Node<MeasuredBlock[]>;\n\tblockFlow: Node<PositionedBlock[]>;\n\ttotalHeight: Node<number>;\n};\n\n// ---------------------------------------------------------------------------\n// Block measurement (pure functions)\n// ---------------------------------------------------------------------------\n\n/**\n * Measure a single content block, returning natural (unconstrained) dimensions.\n * Text blocks use the text layout pipeline; image/SVG use adapters or explicit dims.\n */\nexport function measureBlock(\n\tblock: ContentBlock,\n\tmaxWidth: number,\n\tadapters: BlockAdapters,\n\tmeasureCache: Map<string, Map<string, number>>,\n\tdefaultFont: string,\n\tdefaultLineHeight: number,\n\tindex: number,\n): MeasuredBlock {\n\tswitch (block.type) {\n\t\tcase \"text\": {\n\t\t\tconst font = block.font ?? defaultFont;\n\t\t\tconst lineHeight = block.lineHeight ?? defaultLineHeight;\n\t\t\tconst segments = analyzeAndMeasure(block.text, font, adapters.text, measureCache);\n\t\t\tconst lineBreaks = computeLineBreaks(segments, maxWidth, adapters.text, font, measureCache);\n\t\t\tconst charPositions = computeCharPositions(lineBreaks, segments, lineHeight);\n\t\t\tconst height = lineBreaks.lineCount * lineHeight;\n\t\t\t// Width is the max line width (clamped to maxWidth)\n\t\t\tlet width = 0;\n\t\t\tfor (const line of lineBreaks.lines) {\n\t\t\t\tif (line.width > width) width = line.width;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tindex,\n\t\t\t\ttype: \"text\",\n\t\t\t\twidth: Math.min(width, maxWidth),\n\t\t\t\theight,\n\t\t\t\ttextSegments: segments,\n\t\t\t\ttextLineBreaks: lineBreaks,\n\t\t\t\ttextCharPositions: charPositions,\n\t\t\t};\n\t\t}\n\t\tcase \"image\": {\n\t\t\tlet w: number;\n\t\t\tlet h: number;\n\t\t\tif (block.naturalWidth != null && block.naturalHeight != null) {\n\t\t\t\tw = block.naturalWidth;\n\t\t\t\th = block.naturalHeight;\n\t\t\t} else if (adapters.image) {\n\t\t\t\tconst dims = adapters.image.measureImage(block.src);\n\t\t\t\tw = dims.width;\n\t\t\t\th = dims.height;\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Image block at index ${index} has no naturalWidth/naturalHeight and no ImageMeasurer adapter`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Scale proportionally to fit maxWidth\n\t\t\tif (w > maxWidth) {\n\t\t\t\th = (h * maxWidth) / w;\n\t\t\t\tw = maxWidth;\n\t\t\t}\n\t\t\treturn { index, type: \"image\", width: w, height: h };\n\t\t}\n\t\tcase \"svg\": {\n\t\t\tlet w: number;\n\t\t\tlet h: number;\n\t\t\tif (block.viewBox) {\n\t\t\t\tw = block.viewBox.width;\n\t\t\t\th = block.viewBox.height;\n\t\t\t} else if (adapters.svg) {\n\t\t\t\tconst dims = adapters.svg.measureSvg(block.content);\n\t\t\t\tw = dims.width;\n\t\t\t\th = dims.height;\n\t\t\t} else {\n\t\t\t\tthrow new Error(`SVG block at index ${index} has no viewBox and no SvgMeasurer adapter`);\n\t\t\t}\n\t\t\t// Scale proportionally to fit maxWidth\n\t\t\tif (w > maxWidth) {\n\t\t\t\th = (h * maxWidth) / w;\n\t\t\t\tw = maxWidth;\n\t\t\t}\n\t\t\treturn { index, type: \"svg\", width: w, height: h };\n\t\t}\n\t}\n}\n\n/**\n * Measure all blocks in a content array.\n */\nexport function measureBlocks(\n\tblocks: ContentBlock[],\n\tmaxWidth: number,\n\tadapters: BlockAdapters,\n\tmeasureCache: Map<string, Map<string, number>>,\n\tdefaultFont: string,\n\tdefaultLineHeight: number,\n): MeasuredBlock[] {\n\treturn blocks.map((block, i) =>\n\t\tmeasureBlock(block, maxWidth, adapters, measureCache, defaultFont, defaultLineHeight, i),\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Block flow (pure function)\n// ---------------------------------------------------------------------------\n\n/**\n * Vertical stacking flow: blocks are placed top-to-bottom, left-aligned,\n * separated by `gap` pixels. Pure arithmetic over measured sizes.\n */\nexport function computeBlockFlow(measured: MeasuredBlock[], gap: number): PositionedBlock[] {\n\tconst result: PositionedBlock[] = [];\n\tlet y = 0;\n\tfor (let i = 0; i < measured.length; i++) {\n\t\tconst m = measured[i]!;\n\t\tresult.push({ ...m, x: 0, y });\n\t\ty += m.height + (i < measured.length - 1 ? gap : 0);\n\t}\n\treturn result;\n}\n\n/**\n * Compute total height from positioned blocks.\n */\nexport function computeTotalHeight(flow: PositionedBlock[]): number {\n\tif (flow.length === 0) return 0;\n\tconst last = flow[flow.length - 1]!;\n\treturn last.y + last.height;\n}\n\n// ---------------------------------------------------------------------------\n// Reactive graph factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a reactive block layout graph for mixed content (text + image + SVG).\n *\n * ```\n * Graph(\"reactive-block-layout\")\n * ├── state(\"blocks\") — ContentBlock[] input\n * ├── state(\"max-width\") — container constraint\n * ├── state(\"gap\") — vertical gap (px)\n * ├── derived(\"measured-blocks\") — blocks + max-width → MeasuredBlock[]\n * ├── derived(\"block-flow\") — measured-blocks + gap → PositionedBlock[]\n * ├── derived(\"total-height\") — block-flow → number\n * └── meta: { block-count, layout-time-ns }\n * ```\n */\nexport function reactiveBlockLayout(opts: ReactiveBlockLayoutOptions): ReactiveBlockLayoutBundle {\n\tconst {\n\t\tadapters,\n\t\tname = \"reactive-block-layout\",\n\t\tdefaultFont = \"16px sans-serif\",\n\t\tdefaultLineHeight = 20,\n\t} = opts;\n\tconst g = new Graph(name);\n\n\t// Shared text measurement cache (same structure as reactiveLayout)\n\tconst measureCache = new Map<string, Map<string, number>>();\n\n\t// --- State nodes ---\n\tconst blocksNode = state<ContentBlock[]>(opts.blocks ?? [], { name: \"blocks\" });\n\tconst maxWidthNode = state<number>(Math.max(0, opts.maxWidth ?? 800), { name: \"max-width\" });\n\tconst gapNode = state<number>(opts.gap ?? 0, { name: \"gap\" });\n\n\t// --- Derived: measured-blocks ---\n\t// Raw `node(...)` instead of `derived(...)` so the fn can return a\n\t// cleanup function. Core fires function-form cleanup on INVALIDATE (see\n\t// `node.ts:_updateState` INVALIDATE branch), which lets us flush the\n\t// measure cache and the downstream adapter cache reactively — replaces\n\t// the old v4 per-node `onMessage` hook that watched for INVALIDATE.\n\tconst measuredBlocksNode: Node<MeasuredBlock[]> = node<MeasuredBlock[]>(\n\t\t[blocksNode, maxWidthNode],\n\t\t(data, actions, ctx) => {\n\t\t\tconst blocksVal = data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0];\n\t\t\tconst mwVal = data[1] != null && data[1].length > 0 ? data[1].at(-1) : ctx.prevData[1];\n\t\t\tconst t0 = monotonicNs();\n\t\t\tconst result = measureBlocks(\n\t\t\t\tblocksVal as ContentBlock[],\n\t\t\t\tmwVal as number,\n\t\t\t\tadapters,\n\t\t\t\tmeasureCache,\n\t\t\t\tdefaultFont,\n\t\t\t\tdefaultLineHeight,\n\t\t\t);\n\t\t\tconst elapsed = monotonicNs() - t0;\n\n\t\t\t// Phase-3 meta deferral (parity with reactiveLayout)\n\t\t\tconst meta = measuredBlocksNode.meta;\n\t\t\tif (meta) {\n\t\t\t\temitToMeta(meta[\"block-count\"], result.length);\n\t\t\t\temitToMeta(meta[\"layout-time-ns\"], elapsed);\n\t\t\t}\n\n\t\t\tactions.emit(result);\n\n\t\t\t// Function-form cleanup: fires before the next run AND on\n\t\t\t// deactivation AND on INVALIDATE (per `node.ts:_updateState`).\n\t\t\t// Flushes the shared measurement cache + the text adapter's\n\t\t\t// cache so stale measurements don't persist across INVALIDATE\n\t\t\t// broadcasts. Image/SVG measurers don't expose a cache hook.\n\t\t\treturn () => {\n\t\t\t\tmeasureCache.clear();\n\t\t\t\tadapters.text.clearCache?.();\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\tname: \"measured-blocks\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: { \"block-count\": 0, \"layout-time-ns\": 0 },\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst ma = a as MeasuredBlock[] | null;\n\t\t\t\tconst mb = b as MeasuredBlock[] | null;\n\t\t\t\tif (ma == null || mb == null) return ma === mb;\n\t\t\t\tif (ma.length !== mb.length) return false;\n\t\t\t\tfor (let i = 0; i < ma.length; i++) {\n\t\t\t\t\tconst ba = ma[i]!;\n\t\t\t\t\tconst bb = mb[i]!;\n\t\t\t\t\tif (\n\t\t\t\t\t\tba.type !== bb.type ||\n\t\t\t\t\t\tba.width !== bb.width ||\n\t\t\t\t\t\tba.height !== bb.height ||\n\t\t\t\t\t\tba.index !== bb.index\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: block-flow ---\n\tconst blockFlowNode = derived<PositionedBlock[]>(\n\t\t[measuredBlocksNode, gapNode],\n\t\t([measured, gapVal]) => {\n\t\t\treturn computeBlockFlow(measured as MeasuredBlock[], gapVal as number);\n\t\t},\n\t\t{\n\t\t\tname: \"block-flow\",\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst fa = a as PositionedBlock[] | null;\n\t\t\t\tconst fb = b as PositionedBlock[] | null;\n\t\t\t\tif (fa == null || fb == null) return fa === fb;\n\t\t\t\tif (fa.length !== fb.length) return false;\n\t\t\t\tfor (let i = 0; i < fa.length; i++) {\n\t\t\t\t\tconst pa = fa[i]!;\n\t\t\t\t\tconst pb = fb[i]!;\n\t\t\t\t\tif (pa.x !== pb.x || pa.y !== pb.y || pa.width !== pb.width || pa.height !== pb.height)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\n\t// --- Derived: total-height ---\n\tconst totalHeightNode = derived<number>(\n\t\t[blockFlowNode],\n\t\t([flow]) => computeTotalHeight(flow as PositionedBlock[]),\n\t\t{ name: \"total-height\" },\n\t);\n\n\t// --- Register in graph ---\n\tg.add(\"blocks\", blocksNode);\n\tg.add(\"max-width\", maxWidthNode);\n\tg.add(\"gap\", gapNode);\n\tg.add(\"measured-blocks\", measuredBlocksNode);\n\tg.add(\"block-flow\", blockFlowNode);\n\tg.add(\"total-height\", totalHeightNode);\n\n\t// --- Edges (for describe() visibility) ---\n\n\treturn {\n\t\tgraph: g,\n\t\tsetBlocks: (blocks: ContentBlock[]) => g.set(\"blocks\", blocks),\n\t\tsetMaxWidth: (mw: number) => g.set(\"max-width\", Math.max(0, mw)),\n\t\tsetGap: (gap: number) => g.set(\"gap\", gap),\n\t\tmeasuredBlocks: measuredBlocksNode,\n\t\tblockFlow: blockFlowNode,\n\t\ttotalHeight: totalHeightNode,\n\t};\n}\n"],"mappings":"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","names":["w"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
describeNode,
|
|
3
3
|
resolveDescribeFields
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HVBX5KIW.js";
|
|
5
5
|
import {
|
|
6
6
|
ResettableTimer,
|
|
7
7
|
RingBuffer
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
isBatching,
|
|
26
26
|
monotonicNs,
|
|
27
27
|
state
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-NZMBRXQV.js";
|
|
29
29
|
|
|
30
30
|
// src/extra/utils/sizeof.ts
|
|
31
31
|
var OVERHEAD = {
|
|
@@ -2414,4 +2414,4 @@ export {
|
|
|
2414
2414
|
diffForWAL,
|
|
2415
2415
|
reachable
|
|
2416
2416
|
};
|
|
2417
|
-
//# sourceMappingURL=chunk-
|
|
2417
|
+
//# sourceMappingURL=chunk-XRFJJ2IU.js.map
|