effect-durable-agent-cloudflare 0.1.0-alpha.22 → 0.1.0-alpha.24

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-object-store-Dct3N6rk.js","names":[],"sources":["../src/durable-object-json.ts","../src/durable-object-transcript-tables.ts","../src/durable-object-transcript-maintenance.ts","../src/durable-object-store.ts"],"sourcesContent":["/** Conservative JSON limit below the Durable Object SQLite per-value ceiling (2 MB). */\nexport const durableObjectSerializedJsonHardCapBytes = 1_500_000;\n\nconst jsonEncoder = new TextEncoder();\n\n/** Serialize and size-check one JSON column before it reaches DO SQLite. */\nexport const stringifyJsonForColumn = (value: unknown, column: string): string => {\n const json = JSON.stringify(value);\n if (json === undefined) {\n throw new Error(`${column} value is not JSON serializable`);\n }\n const bytes = jsonEncoder.encode(json).byteLength;\n if (bytes > durableObjectSerializedJsonHardCapBytes) {\n throw new Error(\n `${column} serialized JSON is ${bytes} bytes; hard cap is ${durableObjectSerializedJsonHardCapBytes} bytes`,\n );\n }\n return json;\n};\n","import * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\n\nimport { IdGenerator } from \"effect-durable-agent/services/id-generator\";\nimport { SequenceNumber } from \"effect-durable-agent/types/core\";\nimport {\n TranscriptAliasNamespace,\n TranscriptLogIncarnation,\n TranscriptRecordFromEnvelope,\n TranscriptVersion,\n isPendingTranscriptUserRecord,\n isTopLevelTranscriptRecord,\n type TranscriptChangePlan,\n type TranscriptLookup,\n type TranscriptOrderKey,\n type TranscriptRecord,\n TranscriptRecordId,\n type TranscriptTopLevelRecord,\n type TranscriptToolRecord,\n type TranscriptUserRecord,\n type TranscriptVersionMeta,\n type TranscriptVersionStatus,\n type TranscriptWindowSource,\n} from \"effect-durable-agent/transcript\";\nimport { stringifyJsonForColumn } from \"./durable-object-json\";\nimport type { DurableObjectSqlStorage } from \"./durable-object-storage\";\n\n/**\n * SQL layout of the transcript projection (design §5.1), created by the store's forward migration.\n *\n * Rows are keyed by a **slot**: one stored instance of one transcript version. A version is built\n * in a fresh slot, so a retired slot that is still being deleted in bounded slices never collides\n * with a later slot of the same version. At most one slot is `active` and at most one is\n * `building`; `retired` slots are garbage awaiting cleanup and are never read.\n *\n * `_eda_log_incarnation` holds the identity of this physical event log (§8); `_eda_alarm_wakeups`\n * holds each alarm owner's durable wakeup (see `durable-object-alarms.ts`).\n */\nexport const transcriptTableStatements: ReadonlyArray<string> = [\n `CREATE TABLE IF NOT EXISTS _eda_transcript_meta (\n slot INTEGER PRIMARY KEY AUTOINCREMENT,\n version TEXT NOT NULL,\n role TEXT NOT NULL CHECK (role IN ('active', 'building', 'retired')),\n cursor INTEGER NOT NULL,\n status TEXT NOT NULL CHECK (status IN ('ok', 'failed')),\n failed_at_seq INTEGER,\n error TEXT\n )`,\n `CREATE UNIQUE INDEX IF NOT EXISTS _eda_transcript_meta_role_idx\n ON _eda_transcript_meta(role) WHERE role IN ('active', 'building')`,\n `CREATE TABLE IF NOT EXISTS _eda_transcript_records (\n slot INTEGER NOT NULL,\n id TEXT NOT NULL,\n kind TEXT NOT NULL,\n anchor_seq INTEGER,\n ordinal INTEGER,\n top_level INTEGER NOT NULL,\n pending INTEGER NOT NULL,\n assistant_id TEXT,\n updated_seq INTEGER NOT NULL,\n envelope_json TEXT NOT NULL,\n PRIMARY KEY (slot, id)\n )`,\n // Transcript order over top-level records, for keyset paging in either direction.\n `CREATE INDEX IF NOT EXISTS _eda_transcript_records_order_idx\n ON _eda_transcript_records(slot, top_level, anchor_seq, ordinal, id)`,\n // Ordinal allocation among every positioned record of one anchor event.\n `CREATE INDEX IF NOT EXISTS _eda_transcript_records_anchor_idx\n ON _eda_transcript_records(slot, anchor_seq, ordinal) WHERE anchor_seq IS NOT NULL`,\n // Changes since a cut, for delivery that replaces what changed after `throughSeq`.\n `CREATE INDEX IF NOT EXISTS _eda_transcript_records_updated_idx\n ON _eda_transcript_records(slot, updated_seq)`,\n `CREATE INDEX IF NOT EXISTS _eda_transcript_records_pending_idx\n ON _eda_transcript_records(slot, id) WHERE pending = 1`,\n // The typed dependency lookup: tools of one assistant.\n `CREATE INDEX IF NOT EXISTS _eda_transcript_records_tool_idx\n ON _eda_transcript_records(slot, assistant_id) WHERE assistant_id IS NOT NULL`,\n `CREATE TABLE IF NOT EXISTS _eda_transcript_aliases (\n slot INTEGER NOT NULL,\n namespace TEXT NOT NULL,\n key TEXT NOT NULL,\n record_id TEXT NOT NULL,\n PRIMARY KEY (slot, namespace, key)\n )`,\n `CREATE TABLE IF NOT EXISTS _eda_log_incarnation (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n incarnation TEXT NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS _eda_alarm_wakeups (\n owner TEXT PRIMARY KEY,\n at_ms INTEGER NOT NULL\n )`,\n];\n\n/** Role of a stored slot. Only `active` and `building` are visible through the port. */\nexport type TranscriptSlotRole = \"active\" | \"building\" | \"retired\";\n\n/** One `_eda_transcript_meta` row, decoded. */\nexport interface TranscriptSlot {\n readonly slot: number;\n readonly version: TranscriptVersion;\n readonly role: TranscriptSlotRole;\n readonly cursor: SequenceNumber;\n readonly status: TranscriptVersionStatus;\n}\n\ninterface TranscriptMetaRow {\n readonly slot: number;\n readonly version: string;\n readonly role: string;\n readonly cursor: number;\n readonly status: string;\n readonly failed_at_seq: number | null;\n readonly error: string | null;\n}\n\nconst decodeVersion = Schema.decodeUnknownSync(TranscriptVersion);\n\nconst decodeSlot = (row: TranscriptMetaRow): TranscriptSlot => {\n if (row.role !== \"active\" && row.role !== \"building\" && row.role !== \"retired\") {\n throw new Error(`transcript slot ${row.slot} has unknown role ${row.role}`);\n }\n if (row.status === \"failed\" && (row.failed_at_seq === null || row.error === null)) {\n throw new Error(`failed transcript slot ${row.slot} has no failure seq or error`);\n }\n return {\n slot: row.slot,\n version: decodeVersion(row.version),\n role: row.role,\n cursor: SequenceNumber.make(row.cursor),\n status:\n row.status === \"failed\"\n ? {\n _tag: \"Failed\",\n failedAtSeq: SequenceNumber.make(row.failed_at_seq ?? 0),\n error: row.error ?? \"\",\n }\n : { _tag: \"Ok\" },\n };\n};\n\n/** Every stored slot, in creation order. */\nexport const readTranscriptSlots = (sql: DurableObjectSqlStorage): ReadonlyArray<TranscriptSlot> =>\n sql\n .exec<TranscriptMetaRow>(\n \"SELECT slot, version, role, cursor, status, failed_at_seq, error FROM _eda_transcript_meta ORDER BY slot\",\n )\n .toArray()\n .map(decodeSlot);\n\n/** The port's view of a slot; retired slots have none. */\nexport const transcriptVersionMetaOf = (slot: TranscriptSlot): TranscriptVersionMeta | undefined =>\n slot.role === \"retired\"\n ? undefined\n : { version: slot.version, role: slot.role, cursor: slot.cursor, status: slot.status };\n\nexport const insertTranscriptSlot = (\n sql: DurableObjectSqlStorage,\n version: TranscriptVersion,\n role: \"active\" | \"building\",\n): void => {\n sql.exec(\n \"INSERT INTO _eda_transcript_meta (version, role, cursor, status) VALUES (?, ?, 0, 'ok')\",\n version,\n role,\n );\n};\n\nexport const setTranscriptSlotRole = (\n sql: DurableObjectSqlStorage,\n slot: number,\n role: TranscriptSlotRole,\n): void => {\n sql.exec(\"UPDATE _eda_transcript_meta SET role = ? WHERE slot = ?\", role, slot);\n};\n\n/** Freeze a slot at its unchanged cursor. A failed slot is never written again. */\nexport const markTranscriptSlotFailed = (\n sql: DurableObjectSqlStorage,\n slot: number,\n failedAtSeq: SequenceNumber,\n error: string,\n): void => {\n sql.exec(\n \"UPDATE _eda_transcript_meta SET status = 'failed', failed_at_seq = ?, error = ? WHERE slot = ?\",\n failedAtSeq,\n error,\n slot,\n );\n};\n\n/**\n * Delete up to `limit` rows of a retired slot, records first, and the slot itself once empty.\n * Returns the number of rows deleted.\n */\nexport const deleteRetiredTranscriptRows = (\n sql: DurableObjectSqlStorage,\n slot: number,\n limit: number,\n): number => {\n const records = sql\n .exec<{ readonly deleted: number }>(\n `DELETE FROM _eda_transcript_records WHERE rowid IN (\n SELECT rowid FROM _eda_transcript_records WHERE slot = ? LIMIT ?\n ) RETURNING 1 AS deleted`,\n slot,\n limit,\n )\n .toArray().length;\n const aliases =\n records >= limit\n ? 0\n : sql\n .exec<{ readonly deleted: number }>(\n `DELETE FROM _eda_transcript_aliases WHERE rowid IN (\n SELECT rowid FROM _eda_transcript_aliases WHERE slot = ? LIMIT ?\n ) RETURNING 1 AS deleted`,\n slot,\n limit - records,\n )\n .toArray().length;\n if (records + aliases < limit) {\n sql.exec(\"DELETE FROM _eda_transcript_meta WHERE slot = ? AND role = 'retired'\", slot);\n }\n return records + aliases;\n};\n\n// ---------------------------------------------------------------------------------------------\n// Records\n// ---------------------------------------------------------------------------------------------\n\ninterface TranscriptRecordRow {\n readonly envelope_json: string;\n}\n\nconst encodeEnvelope = Schema.encodeSync(TranscriptRecordFromEnvelope);\nconst decodeEnvelope = Schema.decodeUnknownSync(TranscriptRecordFromEnvelope);\n\n/** A stored record row this release cannot decode. */\nexport class TranscriptRowDecodeError extends Error {\n override readonly name = \"TranscriptRowDecodeError\";\n}\n\n/**\n * Decode one stored row. A row this release cannot decode throws; maintenance treats that as a\n * projection failure and reads as an unreadable window, never as a wrong view.\n */\nconst decodeRecordRow = (row: TranscriptRecordRow): TranscriptRecord => {\n try {\n return decodeEnvelope(JSON.parse(row.envelope_json));\n } catch (cause) {\n throw new TranscriptRowDecodeError(\n `undecodable transcript row: ${cause instanceof Error ? cause.message : String(cause)}`,\n { cause },\n );\n }\n};\n\nconst positionOf = (record: TranscriptRecord) =>\n \"position\" in record ? record.position : undefined;\n\n/**\n * A change plan already encoded into rows: every envelope serialized and size-checked. Encoding\n * is where a plan can still fail recoverably, so it happens before any write.\n */\nexport interface EncodedTranscriptPlan {\n readonly records: ReadonlyArray<ReadonlyArray<string | number | null>>;\n readonly aliases: ReadonlyArray<TranscriptChangePlan[\"aliases\"][number]>;\n readonly throughSeq: SequenceNumber;\n}\n\nexport const encodeTranscriptPlan = (plan: TranscriptChangePlan): EncodedTranscriptPlan => ({\n records: plan.records.map((record) => {\n const position = positionOf(record);\n return [\n record.id,\n record.kind,\n position?.anchorSeq ?? null,\n position?.ordinal ?? null,\n isTopLevelTranscriptRecord(record) ? 1 : 0,\n isPendingTranscriptUserRecord(record) ? 1 : 0,\n record.kind === \"tool\" ? record.assistantId : null,\n record.updatedSeq,\n stringifyJsonForColumn(encodeEnvelope(record), \"_eda_transcript_records.envelope_json\"),\n ];\n }),\n aliases: plan.aliases,\n throughSeq: plan.throughSeq,\n});\n\n/** Write an encoded plan to a slot and advance its cursor; the caller owns the transaction. */\nexport const writeTranscriptPlan = (\n sql: DurableObjectSqlStorage,\n slot: number,\n plan: EncodedTranscriptPlan,\n): void => {\n for (const row of plan.records) {\n sql.exec(\n `INSERT INTO _eda_transcript_records (\n slot, id, kind, anchor_seq, ordinal, top_level, pending, assistant_id, updated_seq, envelope_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(slot, id) DO UPDATE SET\n kind = excluded.kind,\n anchor_seq = excluded.anchor_seq,\n ordinal = excluded.ordinal,\n top_level = excluded.top_level,\n pending = excluded.pending,\n assistant_id = excluded.assistant_id,\n updated_seq = excluded.updated_seq,\n envelope_json = excluded.envelope_json`,\n slot,\n ...row,\n );\n }\n for (const alias of plan.aliases) {\n // Aliases are inserts only: an alias never moves to another record.\n sql.exec(\n `INSERT INTO _eda_transcript_aliases (slot, namespace, key, record_id) VALUES (?, ?, ?, ?)\n ON CONFLICT(slot, namespace, key) DO NOTHING`,\n slot,\n alias.namespace,\n alias.key,\n alias.recordId,\n );\n }\n sql.exec(\"UPDATE _eda_transcript_meta SET cursor = ? WHERE slot = ?\", plan.throughSeq, slot);\n};\n\nconst readRecord = (\n sql: DurableObjectSqlStorage,\n slot: number,\n id: string,\n): TranscriptRecord | undefined => {\n const row = sql\n .exec<TranscriptRecordRow>(\n \"SELECT envelope_json FROM _eda_transcript_records WHERE slot = ? AND id = ?\",\n slot,\n id,\n )\n .toArray()[0];\n return row === undefined ? undefined : decodeRecordRow(row);\n};\n\nconst decodeRecordId = Schema.decodeUnknownSync(TranscriptRecordId);\n\nconst readAlias = (\n sql: DurableObjectSqlStorage,\n slot: number,\n namespace: TranscriptAliasNamespace,\n key: string,\n): TranscriptRecordId | undefined => {\n const row = sql\n .exec<{ readonly record_id: string }>(\n \"SELECT record_id FROM _eda_transcript_aliases WHERE slot = ? AND namespace = ? AND key = ?\",\n slot,\n namespace,\n key,\n )\n .toArray()[0];\n return row === undefined ? undefined : decodeRecordId(row.record_id);\n};\n\n/** Indexed synchronous reads of one slot as committed so far in this transaction. */\nexport const makeTranscriptLookup = (\n sql: DurableObjectSqlStorage,\n slot: TranscriptSlot,\n): TranscriptLookup => ({\n cursor: slot.cursor,\n record: (id) => readRecord(sql, slot.slot, id),\n alias: (namespace, key) => readAlias(sql, slot.slot, namespace, key),\n nextOrdinal: (anchorSeq) =>\n sql\n .exec<{ readonly next: number | null }>(\n `SELECT MAX(ordinal) + 1 AS next FROM _eda_transcript_records\n WHERE slot = ? AND anchor_seq = ?`,\n slot.slot,\n anchorSeq,\n )\n .one().next ?? 0,\n});\n\nconst topLevel = (record: TranscriptRecord): TranscriptTopLevelRecord => {\n if (!isTopLevelTranscriptRecord(record)) {\n throw new TranscriptRowDecodeError(\n `transcript record ${record.id} is indexed as top-level but is not`,\n );\n }\n return record;\n};\n\n/**\n * Window reads over one served slot. Every method is a synchronous indexed query, so a window\n * assembled from them inside one synchronous call is one cut. Record ids are ASCII, so SQLite's\n * binary text order equals `TranscriptOrder`'s code-unit order.\n */\nexport const makeTranscriptWindowSource = (\n sql: DurableObjectSqlStorage,\n incarnation: TranscriptLogIncarnation,\n slot: TranscriptSlot,\n carried: boolean,\n): TranscriptWindowSource => {\n const meta = transcriptVersionMetaOf(slot);\n if (meta === undefined) throw new Error(`retired transcript slot ${slot.slot} is not servable`);\n const topLevelPage = (\n key: TranscriptOrderKey | undefined,\n limit: number,\n inclusive: boolean,\n direction: \"before\" | \"after\",\n ): ReadonlyArray<TranscriptTopLevelRecord> => {\n const comparison = direction === \"before\" ? (inclusive ? \"<=\" : \"<\") : inclusive ? \">=\" : \">\";\n const order = direction === \"before\" ? \"DESC\" : \"ASC\";\n const keyClause =\n key === undefined ? \"\" : `AND (anchor_seq, ordinal, id) ${comparison} (?, ?, ?)`;\n const keyBindings = key === undefined ? [] : [key.anchorSeq, key.ordinal, key.recordId];\n return sql\n .exec<TranscriptRecordRow>(\n `SELECT envelope_json FROM _eda_transcript_records\n WHERE slot = ? AND top_level = 1 ${keyClause}\n ORDER BY anchor_seq ${order}, ordinal ${order}, id ${order}\n LIMIT ?`,\n slot.slot,\n ...keyBindings,\n limit,\n )\n .toArray()\n .map((row) => topLevel(decodeRecordRow(row)));\n };\n return {\n incarnation,\n meta,\n carried,\n topLevelBefore: (key, limit, inclusive) => topLevelPage(key, limit, inclusive, \"before\"),\n topLevelAfter: (key, limit, inclusive) => topLevelPage(key, limit, inclusive, \"after\"),\n record: (id) => readRecord(sql, slot.slot, id),\n alias: (namespace, key) => readAlias(sql, slot.slot, namespace, key),\n toolsOf: (assistantId) =>\n sql\n .exec<TranscriptRecordRow>(\n \"SELECT envelope_json FROM _eda_transcript_records WHERE slot = ? AND assistant_id = ?\",\n slot.slot,\n assistantId,\n )\n .toArray()\n .flatMap((row): ReadonlyArray<TranscriptToolRecord> => {\n const record = decodeRecordRow(row);\n return record.kind === \"tool\" ? [record] : [];\n }),\n pendingUsers: () =>\n sql\n .exec<TranscriptRecordRow>(\n \"SELECT envelope_json FROM _eda_transcript_records WHERE slot = ? AND pending = 1\",\n slot.slot,\n )\n .toArray()\n .flatMap((row): ReadonlyArray<TranscriptUserRecord> => {\n const record = decodeRecordRow(row);\n return record.kind === \"user\" ? [record] : [];\n }),\n };\n};\n\n// ---------------------------------------------------------------------------------------------\n// Log incarnation\n// ---------------------------------------------------------------------------------------------\n\n/**\n * A host's existing synchronous key/value incarnation to adopt (Gia: `gia.log_incarnation` in the\n * Durable Object's `ctx.storage.kv`). The adapter adopts the host's value when one exists and\n * otherwise writes the value it mints there too, so host and adapter always name the same log.\n */\nexport interface AdoptedLogIncarnation {\n readonly key: string;\n readonly kv: {\n readonly get: (key: string) => unknown;\n readonly put: (key: string, value: string) => void;\n };\n}\n\nconst mintUuidV7 = (): string =>\n Effect.runSync(\n Effect.gen(function* () {\n const ids = yield* IdGenerator;\n return yield* ids.makeCorrelationId();\n }).pipe(Effect.provide(IdGenerator.Live)),\n );\n\n/**\n * Read this log's incarnation, minting one on first need. The caller runs it inside a\n * `transactionSync`, so read-or-mint is atomic; storage wipes delete the row and so mint anew.\n */\nexport const readOrMintLogIncarnation = (\n sql: DurableObjectSqlStorage,\n adopt: AdoptedLogIncarnation | undefined,\n): TranscriptLogIncarnation => {\n const row = sql\n .exec<{ readonly incarnation: string }>(\n \"SELECT incarnation FROM _eda_log_incarnation WHERE id = 1\",\n )\n .toArray()[0];\n if (row !== undefined) return TranscriptLogIncarnation.make(row.incarnation);\n const adopted = adopt?.kv.get(adopt.key);\n const incarnation = typeof adopted === \"string\" && adopted.length > 0 ? adopted : mintUuidV7();\n if (adopt !== undefined && adopted !== incarnation) adopt.kv.put(adopt.key, incarnation);\n sql.exec(\"INSERT INTO _eda_log_incarnation (id, incarnation) VALUES (1, ?)\", incarnation);\n return TranscriptLogIncarnation.make(incarnation);\n};\n","import type { CommittedDurableEvent } from \"effect-durable-agent/services/session-store\";\nimport { SequenceNumber } from \"effect-durable-agent/types/core\";\nimport {\n planTranscriptBatch,\n type TranscriptDefinition,\n type TranscriptMaintenanceConfig,\n type TranscriptVersion,\n} from \"effect-durable-agent/transcript\";\nimport type { DurableObjectSessionStorage } from \"./durable-object-storage\";\nimport {\n deleteRetiredTranscriptRows,\n encodeTranscriptPlan,\n insertTranscriptSlot,\n makeTranscriptLookup,\n markTranscriptSlotFailed,\n readTranscriptSlots,\n setTranscriptSlotRole,\n writeTranscriptPlan,\n type AdoptedLogIncarnation,\n type EncodedTranscriptPlan,\n type TranscriptSlot,\n} from \"./durable-object-transcript-tables\";\n\n/**\n * Something an operator must look at, raised after the transaction that caused it commits.\n *\n * - `ProjectionFailed`: a version froze at its last good cursor (§5.2). On the active version\n * readers see a degraded tail until a new definition rebuilds it; on a building version the\n * active version keeps serving and the backfill reports it.\n * - `MissedSession`: the active version is one this release no longer carries, so its history is\n * frozen behind the log and `current` is being built at once (§7 safety net).\n */\nexport type TranscriptAlert =\n | {\n readonly _tag: \"ProjectionFailed\";\n readonly version: TranscriptVersion;\n readonly role: \"active\" | \"building\";\n readonly failedAtSeq: SequenceNumber;\n readonly error: string;\n }\n | {\n readonly _tag: \"MissedSession\";\n readonly activeVersion: TranscriptVersion;\n readonly currentVersion: TranscriptVersion;\n };\n\n/**\n * Host hooks for transcript maintenance. Every hook runs only after the transaction that caused\n * it has committed, so nothing observed here can be rolled back afterwards.\n */\nexport interface DurableObjectTranscriptObserver {\n readonly onAlert?: (alert: TranscriptAlert) => void;\n /** A built version became active; connected clients need a window replacement (§9.4). */\n readonly onActivated?: (activation: {\n readonly version: TranscriptVersion;\n readonly previousVersion: TranscriptVersion | undefined;\n }) => void;\n /** Bounded builder or cleanup work is pending; the host schedules a slice. */\n readonly onPendingWork?: () => void;\n}\n\n/** Bounds on one builder slice. */\nexport interface DurableObjectTranscriptSliceLimits {\n /** Log events projected into the building version per slice. */\n readonly maxEvents: number;\n /** Events decoded and planned together; matches the store's bounded event read page. */\n readonly pageEvents: number;\n /** Rows of retired versions deleted per slice. */\n readonly maxDeletedRows: number;\n}\n\nexport const defaultTranscriptSliceLimits: DurableObjectTranscriptSliceLimits = {\n maxEvents: 512,\n pageEvents: 16,\n maxDeletedRows: 2_000,\n};\n\n/** Transcript maintenance configuration of one session store. */\nexport interface DurableObjectTranscriptOptions {\n /** The definitions this release carries; supplied by the host. */\n readonly definitions: TranscriptMaintenanceConfig;\n /** Adopt a host's existing log incarnation instead of minting a new one. */\n readonly adoptIncarnation?: AdoptedLogIncarnation;\n readonly observer?: DurableObjectTranscriptObserver;\n readonly sliceLimits?: Partial<DurableObjectTranscriptSliceLimits>;\n}\n\n/** Synchronous reads of the committed event log a builder needs. */\nexport interface TranscriptEventLog {\n readonly head: () => SequenceNumber;\n /** Up to `limit` committed events after `afterSeq`, in seq order. */\n readonly after: (afterSeq: SequenceNumber, limit: number) => ReadonlyArray<CommittedDurableEvent>;\n}\n\n/** Outcomes collected inside a transaction and published only after it commits. */\nexport interface TranscriptEffects {\n readonly alerts: Array<TranscriptAlert>;\n activated?: {\n readonly version: TranscriptVersion;\n readonly previousVersion: TranscriptVersion | undefined;\n };\n pendingWork: boolean;\n}\n\nexport const emptyTranscriptEffects = (): TranscriptEffects => ({\n alerts: [],\n pendingWork: false,\n});\n\n/**\n * Publish committed outcomes to the host. Call only after the outer transaction returns. A hook\n * that throws is reported and otherwise ignored: the work it describes is already committed.\n */\nexport const publishTranscriptEffects = (\n observer: DurableObjectTranscriptObserver | undefined,\n effects: TranscriptEffects,\n): void => {\n const notify = (hook: () => void) => {\n try {\n hook();\n } catch (error) {\n console.error(\"EDA transcript observer failed\", error);\n }\n };\n for (const alert of effects.alerts) notify(() => observer?.onAlert?.(alert));\n const activated = effects.activated;\n if (activated !== undefined) notify(() => observer?.onActivated?.(activated));\n if (effects.pendingWork) notify(() => observer?.onPendingWork?.());\n};\n\n/** The carried definition for a stored version, if this release still carries it. */\nexport const carriedDefinition = (\n config: TranscriptMaintenanceConfig,\n version: TranscriptVersion,\n): TranscriptDefinition | undefined =>\n config.current.version === version\n ? config.current\n : config.previous?.version === version\n ? config.previous\n : undefined;\n\nconst liveSlots = (storage: DurableObjectSessionStorage): ReadonlyArray<TranscriptSlot> =>\n readTranscriptSlots(storage.sql).filter((slot) => slot.role !== \"retired\");\n\n/**\n * Bring the stored versions in line with this release's definitions (§7 steps 2, 3 and 5),\n * writing only metadata. Rows are never touched here: building and cleanup happen in slices.\n *\n * - No version yet: an empty log starts `current` as active at seq 0; a log written before\n * transcripts existed builds `current` from the log while nothing is served.\n * - A building version that is not `current` is retired (discarded).\n * - If the active version is not `current` and no build of `current` exists, one starts. A build\n * of `current` that failed counts as existing, so it is never retried.\n */\nexport const reconcileTranscriptSlots = (\n storage: DurableObjectSessionStorage,\n config: TranscriptMaintenanceConfig,\n head: SequenceNumber,\n effects: TranscriptEffects,\n): void => {\n const { sql } = storage;\n const current = config.current.version;\n const slots = liveSlots(storage);\n if (slots.length === 0) {\n insertTranscriptSlot(sql, current, head === 0 ? \"active\" : \"building\");\n if (head > 0) effects.pendingWork = true;\n return;\n }\n for (const slot of slots) {\n if (slot.role === \"building\" && slot.version !== current) {\n setTranscriptSlotRole(sql, slot.slot, \"retired\");\n effects.pendingWork = true;\n }\n }\n const active = slots.find((slot) => slot.role === \"active\");\n const buildingCurrent = slots.some(\n (slot) => slot.role === \"building\" && slot.version === current,\n );\n if (active?.version !== current && !buildingCurrent) {\n insertTranscriptSlot(sql, current, \"building\");\n effects.pendingWork = true;\n }\n};\n\nconst nestedTransactionSupport = new WeakMap<DurableObjectSessionStorage, boolean>();\nconst nestedTransactionRejection = /cannot start a transaction within a transaction/i;\n\n/**\n * Whether this storage runs a `transactionSync` nested in another as an independent inner\n * transaction. workerd does; celld rejects nesting (\"cannot start a transaction within a\n * transaction\") without disturbing the enclosing transaction. Probed once per storage object.\n */\nconst supportsNestedTransactions = (storage: DurableObjectSessionStorage): boolean => {\n const known = nestedTransactionSupport.get(storage);\n if (known !== undefined) return known;\n let supported: boolean;\n try {\n storage.transactionSync(() => storage.transactionSync(() => undefined));\n supported = true;\n } catch (error) {\n // Only the platform's refusal to nest means \"unsupported\"; anything else is a real failure.\n if (!(error instanceof Error && nestedTransactionRejection.test(error.message))) throw error;\n supported = false;\n }\n nestedTransactionSupport.set(storage, supported);\n return supported;\n};\n\n/** Freeze a slot at its unchanged cursor and raise the alert. */\nconst freezeSlot = (\n storage: DurableObjectSessionStorage,\n slot: TranscriptSlot,\n failedAtSeq: SequenceNumber,\n cause: unknown,\n effects: TranscriptEffects,\n): TranscriptSlot => {\n const error = cause instanceof Error ? cause.message : String(cause);\n markTranscriptSlotFailed(storage.sql, slot.slot, failedAtSeq, error);\n if (slot.role !== \"retired\") {\n effects.alerts.push({\n _tag: \"ProjectionFailed\",\n version: slot.version,\n role: slot.role,\n failedAtSeq,\n error,\n });\n }\n return { ...slot, status: { _tag: \"Failed\", failedAtSeq, error } };\n};\n\n/**\n * Project committed events into one slot, or freeze the slot (§5.2).\n *\n * Planning, row decoding and row encoding (serialization and the size cap) all run before any\n * write, so every recoverable projection error is raised before the slot is touched. Where the\n * platform nests transactions (workerd), the writes also run inside an inner `transactionSync`,\n * so even a failing write rolls back only that slot. Either way the failure is recorded in the\n * caller's transaction and the events the caller appended still commit. Where it does not\n * (celld), a write that fails after planning succeeded is a storage failure, which fails the\n * caller's whole transaction atomically, exactly as a failed event insert does.\n */\nconst advanceSlot = (\n storage: DurableObjectSessionStorage,\n slot: TranscriptSlot,\n definition: TranscriptDefinition,\n events: ReadonlyArray<CommittedDurableEvent>,\n effects: TranscriptEffects,\n): TranscriptSlot => {\n const first = events.find((entry) => entry.position.seq > slot.cursor);\n if (first === undefined || slot.status._tag === \"Failed\" || slot.role === \"retired\") return slot;\n const nested = supportsNestedTransactions(storage);\n const project = () => {\n const plan = encodeTranscriptPlan(\n planTranscriptBatch(makeTranscriptLookup(storage.sql, slot), events, definition),\n );\n if (nested) writeTranscriptPlan(storage.sql, slot.slot, plan);\n return plan;\n };\n let plan: EncodedTranscriptPlan;\n try {\n plan = nested ? storage.transactionSync(project) : project();\n } catch (cause) {\n return freezeSlot(storage, slot, first.position.seq, cause, effects);\n }\n if (!nested) writeTranscriptPlan(storage.sql, slot.slot, plan);\n return { ...slot, cursor: plan.throughSeq };\n};\n\n/**\n * The append hook: one batch-level call inside the append transaction, after every entry has\n * been inserted.\n *\n * A version is maintained here exactly when it is carried, healthy and caught up — its cursor is\n * the head the batch started from — so the new events are precisely what it is missing. Anything\n * behind (a building version) is caught up by builder slices instead, and frozen versions are\n * never touched. Each version fails independently.\n */\nexport const maintainTranscriptsOnAppend = (\n storage: DurableObjectSessionStorage,\n config: TranscriptMaintenanceConfig,\n headBeforeBatch: SequenceNumber,\n appended: ReadonlyArray<CommittedDurableEvent>,\n effects: TranscriptEffects,\n): void => {\n reconcileTranscriptSlots(storage, config, headBeforeBatch, effects);\n if (appended.length === 0) return;\n for (const slot of liveSlots(storage)) {\n const definition = carriedDefinition(config, slot.version);\n if (definition === undefined || slot.status._tag === \"Failed\") continue;\n if (slot.cursor !== headBeforeBatch) continue;\n advanceSlot(storage, slot, definition, appended, effects);\n }\n};\n\n/**\n * The missed-session alert for a session whose active version this release no longer carries,\n * raised whenever an object starts, so it does not depend on observing the build's creation.\n */\nexport const missedSessionAlert = (\n storage: DurableObjectSessionStorage,\n config: TranscriptMaintenanceConfig,\n): TranscriptAlert | undefined => {\n const active = liveSlots(storage).find((slot) => slot.role === \"active\");\n return active === undefined || carriedDefinition(config, active.version) !== undefined\n ? undefined\n : {\n _tag: \"MissedSession\",\n activeVersion: active.version,\n currentVersion: config.current.version,\n };\n};\n\n/** The one slot a builder slice advances: the building version, else an active one behind. */\nconst buildTarget = (\n config: TranscriptMaintenanceConfig,\n slots: ReadonlyArray<TranscriptSlot>,\n head: SequenceNumber,\n): TranscriptSlot | undefined => {\n const healthy = (slot: TranscriptSlot) =>\n slot.status._tag === \"Ok\" && carriedDefinition(config, slot.version) !== undefined;\n return (\n slots.find((slot) => slot.role === \"building\" && healthy(slot)) ??\n slots.find((slot) => slot.role === \"active\" && healthy(slot) && slot.cursor < head)\n );\n};\n\n/** Whether any builder or cleanup slice has work to do. Read-only. */\nexport const hasPendingTranscriptWork = (\n storage: DurableObjectSessionStorage,\n config: TranscriptMaintenanceConfig,\n head: SequenceNumber,\n): boolean => {\n const slots = readTranscriptSlots(storage.sql);\n if (slots.some((slot) => slot.role === \"retired\")) return true;\n const live = slots.filter((slot) => slot.role !== \"retired\");\n // An empty log initializes on its first read or append; only an existing log needs a build.\n if (live.length === 0) return head > 0;\n const current = config.current.version;\n if (live.some((slot) => slot.role === \"building\" && slot.version !== current)) return true;\n const active = live.find((slot) => slot.role === \"active\");\n if (\n active?.version !== current &&\n !live.some((slot) => slot.role === \"building\" && slot.version === current)\n ) {\n return true;\n }\n return buildTarget(config, live, head) !== undefined;\n};\n\n/**\n * One bounded builder slice. The caller runs it inside one outer `transactionSync`.\n *\n * It reconciles versions, projects at most `maxEvents` log events into the building version\n * (page by page, each page's rows and cursor committed together, so an eviction resumes from the\n * cursor), activates the build when its cursor equals the head re-read in this transaction, and\n * deletes a bounded number of retired rows. Returns whether more work remains.\n */\nexport const runTranscriptSlice = (\n storage: DurableObjectSessionStorage,\n config: TranscriptMaintenanceConfig,\n log: TranscriptEventLog,\n limits: DurableObjectTranscriptSliceLimits,\n effects: TranscriptEffects,\n): boolean => {\n const { sql } = storage;\n const head = log.head();\n reconcileTranscriptSlots(storage, config, head, effects);\n const slots = liveSlots(storage);\n const target = buildTarget(config, slots, head);\n if (target !== undefined) {\n const definition = carriedDefinition(config, target.version);\n let slot = target;\n let remaining = limits.maxEvents;\n while (\n definition !== undefined &&\n slot.status._tag === \"Ok\" &&\n slot.cursor < head &&\n remaining > 0\n ) {\n let page: ReadonlyArray<CommittedDurableEvent>;\n try {\n page = log.after(slot.cursor, Math.min(limits.pageEvents, remaining));\n } catch (cause) {\n // A log event this release cannot decode: the build cannot pass it, so freeze it\n // rather than retry forever. A new definition (with a reader for it) repairs it.\n slot = freezeSlot(storage, slot, SequenceNumber.make(slot.cursor + 1), cause, effects);\n break;\n }\n if (page.length === 0) break;\n remaining -= page.length;\n slot = advanceSlot(storage, slot, definition, page, effects);\n }\n if (slot.role === \"building\" && slot.status._tag === \"Ok\" && slot.cursor === log.head()) {\n const previous = slots.find((candidate) => candidate.role === \"active\");\n if (previous !== undefined) setTranscriptSlotRole(sql, previous.slot, \"retired\");\n setTranscriptSlotRole(sql, slot.slot, \"active\");\n effects.activated = { version: slot.version, previousVersion: previous?.version };\n }\n }\n let deleteBudget = limits.maxDeletedRows;\n for (const slot of readTranscriptSlots(sql)) {\n if (deleteBudget <= 0) break;\n if (slot.role === \"retired\") {\n deleteBudget -= deleteRetiredTranscriptRows(sql, slot.slot, deleteBudget);\n }\n }\n return hasPendingTranscriptWork(storage, config, log.head());\n};\n","import * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport * as Stream from \"effect/Stream\";\n\nimport {\n SequenceNumber,\n SessionId,\n SummaryId,\n durablePosition,\n} from \"effect-durable-agent/types/core\";\nimport { CompactionSummaryArtifact } from \"effect-durable-agent/domain/context-projection\";\nimport {\n SummaryCreatedPayload,\n ContextRebasedPayload,\n DurableEventEnvelope,\n assistantMessageCommittedEventType,\n assistantMessageImportedEventType,\n assistantPartialCommittedEventType,\n commandAdmittedEventType,\n commandCancelledEventType,\n commandCompletedEventType,\n commandFailedEventType,\n commandStartedEventType,\n contextRebasedEventType,\n decodeDurableEventSync,\n effectDurableAgentNamespace,\n steeringMessageQueuedEventType,\n summaryCreatedEventType,\n systemMessageCommittedEventType,\n userMessageCommittedEventType,\n} from \"effect-durable-agent/types/events\";\nimport {\n CommittedDurableEvent,\n DurableAppendBatch,\n DurableAppendEntry,\n EDASessionStore,\n EDASessionStoreError,\n type EDAReducerCheckpoint,\n type EDASessionStoreShape,\n type SaveReducerCheckpointInput,\n} from \"effect-durable-agent/services/session-store\";\nimport { annotateEdaSpan, committedBatchAttributes } from \"effect-durable-agent/services/tracing\";\nimport { stringifyJsonForColumn } from \"./durable-object-json\";\nimport {\n emptyTranscriptEffects,\n maintainTranscriptsOnAppend,\n publishTranscriptEffects,\n type DurableObjectTranscriptOptions,\n type TranscriptEventLog,\n} from \"./durable-object-transcript-maintenance\";\nimport { transcriptTableStatements } from \"./durable-object-transcript-tables\";\nimport type {\n DurableObjectSessionStorage,\n DurableObjectSessionStoreOptions,\n DurableObjectSqlStorage,\n} from \"./durable-object-storage\";\n\nexport { durableObjectSerializedJsonHardCapBytes } from \"./durable-object-json\";\n\nconst ProjectionPayload = Schema.Record(Schema.String, Schema.Unknown);\nconst AdmittedCommandProjection = Schema.Struct({\n commandId: Schema.Unknown,\n idempotencyKey: Schema.optionalKey(Schema.Unknown),\n});\n\ninterface DurableObjectEventRow {\n readonly seq: number;\n readonly event_id: string;\n readonly namespace: string;\n readonly type: string;\n readonly schema_version: number;\n readonly created_at_ms: number;\n readonly trace_json: string;\n readonly fact_json: string;\n}\n\ninterface DurableObjectEventHeadRow {\n readonly head: number | null;\n}\n\ninterface DurableObjectEventPageCursor {\n readonly afterSeq: SequenceNumber;\n readonly throughSeq: SequenceNumber | undefined;\n}\n\ninterface DurableObjectMigrationRow {\n readonly version: number | null;\n}\n\ninterface DurableObjectMessagePayloadRow {\n readonly context_seq: number;\n readonly payload_json: string;\n}\n\ninterface DurableObjectSummaryPayloadRow {\n readonly payload_json: string;\n}\n\ninterface DurableObjectCommandLookupRow {\n readonly admitted_seq: number;\n}\n\ninterface DurableObjectCommandInputPayloadRow {\n readonly payload_json: string;\n}\n\ninterface DurableObjectReducerCheckpointRow {\n readonly reducer_name: string;\n readonly schema_version: number;\n readonly through_seq: number;\n readonly payload_json: string;\n readonly updated_at_ms: number;\n}\n\n/** Squashed pre-release framework schema. */\nconst durableObjectSessionStoreSchemaVersion = 1;\n/** Forward migration adding the transcript projection, log incarnation and alarm wakeups. */\nconst durableObjectTranscriptSchemaVersion = 2;\n\n/**\n * Bound one synchronous DO SQLite event-log read/decode to a small CPU and memory slice.\n *\n * A single logical event can already approach the per-row JSON hard cap, and logical decode may\n * touch sidecar rows. Sixteen rows keeps worst-case page memory materially below isolate limits\n * while still amortizing SQL cursor setup for normal small framework events. Revisit with page\n * duration/byte telemetry before increasing.\n */\nconst durableObjectEventReadPageRows = 16;\n\n/**\n * Durable Object SQLite-backed implementation of the semantic `EDASessionStore`.\n *\n * This adapter is the only place EDA framework storage code touches DO SQL. It\n * translates domain append intent into synchronous SQLite writes while keeping\n * `SessionState` and runners SQL-agnostic.\n */\nexport class DurableObjectSessionStore {\n /** Run the single squashed framework migration for the current pre-release schema. */\n static readonly migrate = (storage: DurableObjectSessionStorage) =>\n migrateDurableObjectSessionStore(storage);\n\n /** Build a session-scoped store after migrations have completed. */\n static readonly make = ({\n sessionId,\n storage,\n transcript,\n }: DurableObjectSessionStoreOptions): Effect.Effect<EDASessionStoreShape, EDASessionStoreError> =>\n Effect.gen(function* () {\n yield* DurableObjectSessionStore.migrate(storage);\n return makeDurableObjectSessionStore(sessionId, storage, transcript);\n });\n\n /** Layer constructor used by the Durable Object host runtime graph. */\n static readonly layer = (options: DurableObjectSessionStoreOptions) =>\n Layer.effect(EDASessionStore, DurableObjectSessionStore.make(options));\n}\n\n/**\n * Create all framework-owned tables in one idempotent startup step.\n *\n * The project is still pre-release, so this remains a squashed version-1 schema\n * rather than a chain of compatibility migrations.\n */\nconst migrateDurableObjectSessionStore = (storage: DurableObjectSessionStorage) =>\n Effect.try({\n try: () =>\n storage.transactionSync(() => {\n const { sql } = storage;\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_schema_migrations (\n id INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `);\n\n const currentVersion =\n sql\n .exec<DurableObjectMigrationRow>(\n \"SELECT COALESCE(MAX(id), 0) AS version FROM _eda_schema_migrations\",\n )\n .one().version ?? 0;\n\n if (currentVersion < durableObjectSessionStoreSchemaVersion) {\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_event_log (\n seq INTEGER PRIMARY KEY AUTOINCREMENT,\n event_id TEXT NOT NULL UNIQUE,\n namespace TEXT NOT NULL,\n type TEXT NOT NULL,\n schema_version INTEGER NOT NULL,\n created_at_ms INTEGER NOT NULL,\n trace_json TEXT NOT NULL,\n fact_json TEXT NOT NULL\n )\n `);\n sql.exec(`\n CREATE INDEX IF NOT EXISTS _eda_event_log_namespace_type_seq_idx\n ON _eda_event_log(namespace, type, seq)\n `);\n\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_command_state (\n command_id TEXT PRIMARY KEY,\n admitted_seq INTEGER NOT NULL,\n status TEXT NOT NULL,\n idempotency_key TEXT,\n payload_json TEXT NOT NULL\n )\n `);\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_command_inputs (\n command_id TEXT PRIMARY KEY,\n admitted_seq INTEGER NOT NULL UNIQUE,\n payload_json TEXT NOT NULL\n )\n `);\n sql.exec(`\n CREATE INDEX IF NOT EXISTS _eda_command_state_status_seq_idx\n ON _eda_command_state(status, admitted_seq)\n `);\n sql.exec(`\n CREATE UNIQUE INDEX IF NOT EXISTS _eda_command_state_idempotency_idx\n ON _eda_command_state(idempotency_key) WHERE idempotency_key IS NOT NULL\n `);\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_context_messages (\n message_id TEXT PRIMARY KEY,\n context_seq INTEGER NOT NULL UNIQUE,\n payload_json TEXT NOT NULL\n )\n `);\n sql.exec(`\n CREATE INDEX IF NOT EXISTS _eda_context_messages_context_seq_idx\n ON _eda_context_messages(context_seq)\n `);\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_context_summaries (\n summary_id TEXT PRIMARY KEY,\n created_seq INTEGER NOT NULL UNIQUE,\n payload_json TEXT NOT NULL\n )\n `);\n sql.exec(`\n CREATE INDEX IF NOT EXISTS _eda_context_summaries_created_seq_idx\n ON _eda_context_summaries(created_seq)\n `);\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_reducer_checkpoints (\n reducer_name TEXT PRIMARY KEY,\n schema_version INTEGER NOT NULL,\n through_seq INTEGER NOT NULL,\n payload_json TEXT NOT NULL,\n updated_at_ms INTEGER NOT NULL\n )\n `);\n sql.exec(`\n CREATE TABLE IF NOT EXISTS _eda_sink_cursors (\n sink_name TEXT PRIMARY KEY,\n after_seq INTEGER NOT NULL,\n payload_json TEXT NOT NULL\n )\n `);\n sql.exec(\n \"INSERT INTO _eda_schema_migrations (id) VALUES (?)\",\n durableObjectSessionStoreSchemaVersion,\n );\n }\n\n if (currentVersion < durableObjectTranscriptSchemaVersion) {\n for (const statement of transcriptTableStatements) sql.exec(statement);\n sql.exec(\n \"INSERT INTO _eda_schema_migrations (id) VALUES (?)\",\n durableObjectTranscriptSchemaVersion,\n );\n }\n }),\n catch: (error) => durableStoreError(\"migrating DurableObjectSessionStore\", error),\n });\n\n/**\n * Interpret the semantic store API with native DO SQLite.\n *\n * All writes that affect durable ordering happen inside `transactionSync`; replay\n * and lookup reads stay synchronous SQL wrapped in Effect boundaries.\n */\nconst makeDurableObjectSessionStore = (\n sessionId: SessionId,\n storage: DurableObjectSessionStorage,\n transcript: DurableObjectTranscriptOptions | undefined,\n): EDASessionStoreShape => {\n const { sql } = storage;\n const ensureSession = (event: DurableEventEnvelope) => {\n if (event.sessionId !== sessionId) {\n throw new Error(\n `DurableObjectSessionStore is scoped to session ${sessionId}; received ${event.sessionId}`,\n );\n }\n };\n\n /**\n * Insert one append entry or return its existing idempotent event position.\n *\n * The event row is the sequence allocator. Artifact/projection writes happen\n * only for newly inserted events, preventing duplicate appends from advancing\n * body rows or metadata; only those are collected into `inserted`.\n */\n const insertOrRead = (\n entry: DurableAppendEntry,\n inserted: Array<CommittedDurableEvent>,\n ): CommittedDurableEvent => {\n const { event } = entry;\n ensureSession(event);\n const existing = readCommittedByEventIdOptional(sql, sessionId, event.eventId);\n if (existing !== undefined) {\n return existing;\n }\n\n const encoded = encodeEventLogRow(event);\n sql.exec(\n `\n INSERT INTO _eda_event_log (\n event_id,\n namespace,\n type,\n schema_version,\n created_at_ms,\n trace_json,\n fact_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n `,\n encoded.eventId,\n encoded.namespace,\n encoded.type,\n encoded.schemaVersion,\n encoded.createdAtMs,\n encoded.traceJson,\n encoded.factJson,\n );\n const row = readEventLogRowByEventId(sql, event.eventId);\n applySynchronousProjections(sql, entry, SequenceNumber.make(row.seq), encoded.factJson);\n const committed = rowToCommittedDurableEvent(sql, row, sessionId);\n inserted.push(committed);\n return committed;\n };\n\n /**\n * Execute an entire append batch as one synchronous SQLite transaction.\n *\n * Transcript maintenance is one batch-level hook inside the same transaction, after every\n * entry. A projection failure freezes only the failing version and never fails the append;\n * its alert is published only after the transaction commits.\n */\n const append = (batch: DurableAppendBatch) =>\n Effect.try({\n try: () => {\n const effects = emptyTranscriptEffects();\n const committed = storage.transactionSync(() => {\n const headBeforeBatch = transcript === undefined ? undefined : readEventLogHead(sql);\n const inserted: Array<CommittedDurableEvent> = [];\n const entries = batch.entries.map((entry) => insertOrRead(entry, inserted));\n if (transcript !== undefined && headBeforeBatch !== undefined) {\n maintainTranscriptsOnAppend(\n storage,\n transcript.definitions,\n headBeforeBatch,\n inserted,\n effects,\n );\n }\n return entries;\n });\n publishTranscriptEffects(transcript?.observer, effects);\n return committed;\n },\n catch: (error) => durableStoreError(\"appending DurableObjectSessionStore batch\", error),\n }).pipe(Effect.tap((committed) => annotateEdaSpan(committedBatchAttributes(committed))));\n\n return {\n append,\n eventsAfter: (afterSeq) => makeCommittedEventStream(sql, sessionId, afterSeq),\n loadCommittedEventsBySeq: (seqs) =>\n Effect.try({\n try: () =>\n uniqueSequenceNumbers(seqs)\n .sort((left, right) => left - right)\n .map((seq) => readCommittedBySeq(sql, sessionId, seq)),\n catch: (error) =>\n durableStoreError(\"loading DurableObjectSessionStore events by seq\", error),\n }),\n findCommandAdmission: (input) =>\n Effect.try({\n try: () => {\n const row = findCommandAdmissionRow(sql, input.commandId, input.idempotencyKey);\n return row === undefined\n ? undefined\n : readCommittedBySeq(sql, sessionId, row.admitted_seq);\n },\n catch: (error) => durableStoreError(\"finding command admission\", error),\n }),\n loadSummaryArtifact: (summaryId) =>\n Effect.try({\n try: () => readSummaryPayloadOptional(sql, summaryId),\n catch: (error) => durableStoreError(\"loading DurableObjectSessionStore summary\", error),\n }),\n loadReducerCheckpoint: (name) =>\n Effect.try({\n try: () => readReducerCheckpoint(sql, name),\n catch: (error) =>\n durableStoreError(`loading DurableObjectSessionStore reducer checkpoint ${name}`, error),\n }),\n saveReducerCheckpoint: (checkpoint) =>\n Effect.try({\n try: () => writeReducerCheckpoint(sql, checkpoint),\n catch: (error) =>\n durableStoreError(\n `saving DurableObjectSessionStore reducer checkpoint ${checkpoint.name}`,\n error,\n ),\n }),\n saveReducerCheckpoints: (checkpoints) =>\n Effect.try({\n try: () =>\n storage.transactionSync(() =>\n checkpoints.forEach((checkpoint) => writeReducerCheckpoint(sql, checkpoint)),\n ),\n catch: (error) =>\n durableStoreError(\"saving DurableObjectSessionStore reducer checkpoints\", error),\n }),\n };\n};\n\n/** Synchronous committed-log reads for the transcript builder, decoded like every replay. */\nexport const makeDurableObjectEventLog = (\n sql: DurableObjectSqlStorage,\n sessionId: SessionId,\n): TranscriptEventLog => ({\n head: () => readEventLogHead(sql),\n after: (afterSeq, limit) =>\n sql\n .exec<DurableObjectEventRow>(\n `\n SELECT seq, event_id, namespace, type, schema_version, created_at_ms, trace_json, fact_json\n FROM _eda_event_log\n WHERE seq > ?\n ORDER BY seq ASC\n LIMIT ?\n `,\n afterSeq,\n limit,\n )\n .toArray()\n .map((row) => rowToCommittedDurableEvent(sql, row, sessionId)),\n});\n\nconst makeCommittedEventStream = (\n sql: DurableObjectSqlStorage,\n sessionId: SessionId,\n afterSeq: SequenceNumber,\n): Stream.Stream<CommittedDurableEvent, EDASessionStoreError> =>\n Stream.fromPull(\n Effect.sync(() => {\n let cursor: DurableObjectEventPageCursor = { afterSeq, throughSeq: undefined };\n let done = false;\n return Effect.gen(function* () {\n if (done) {\n return yield* Cause.done();\n }\n // DO SQLite is synchronous; yield between bounded pages so eager consumers do not\n // monopolize the isolate with one long replay/decode loop.\n yield* Effect.yieldNow;\n const page = yield* readCommittedEventPage(sql, sessionId, cursor);\n if (page.events.length === 0) {\n done = true;\n return yield* Cause.done();\n }\n if (Option.isSome(page.next)) {\n cursor = page.next.value;\n } else {\n done = true;\n }\n return page.events as readonly [CommittedDurableEvent, ...Array<CommittedDurableEvent>];\n });\n }),\n );\n\nconst readCommittedEventPage = (\n sql: DurableObjectSqlStorage,\n sessionId: SessionId,\n cursor: DurableObjectEventPageCursor,\n): Effect.Effect<\n {\n readonly events: ReadonlyArray<CommittedDurableEvent>;\n readonly next: Option.Option<DurableObjectEventPageCursor>;\n },\n EDASessionStoreError\n> =>\n Effect.try({\n try: () => {\n const throughSeq = cursor.throughSeq ?? readEventLogHead(sql);\n if (cursor.afterSeq >= throughSeq) {\n return { events: [], next: Option.none() };\n }\n\n const events = sql\n .exec<DurableObjectEventRow>(\n `\n SELECT seq, event_id, namespace, type, schema_version, created_at_ms, trace_json, fact_json\n FROM _eda_event_log\n WHERE seq > ? AND seq <= ?\n ORDER BY seq ASC\n LIMIT ?\n `,\n cursor.afterSeq,\n throughSeq,\n durableObjectEventReadPageRows,\n )\n .toArray()\n .map((row) => rowToCommittedDurableEvent(sql, row, sessionId));\n const lastSeq = events.at(-1)?.position.seq ?? cursor.afterSeq;\n return {\n events,\n next:\n lastSeq < throughSeq\n ? Option.some({ afterSeq: lastSeq, throughSeq } satisfies DurableObjectEventPageCursor)\n : Option.none(),\n };\n },\n catch: (error) => durableStoreError(\"replaying DurableObjectSessionStore events\", error),\n });\n\nconst readEventLogHead = (sql: DurableObjectSqlStorage): SequenceNumber =>\n SequenceNumber.make(\n sql\n .exec<DurableObjectEventHeadRow>(\n `\n SELECT COALESCE(MAX(seq), 0) AS head\n FROM _eda_event_log\n `,\n )\n .one().head ?? 0,\n );\n\nconst uniqueSequenceNumbers = (seqs: ReadonlyArray<SequenceNumber>): Array<SequenceNumber> =>\n Array.from(new Set(seqs.map((seq) => Number(seq)))).map((seq) => SequenceNumber.make(seq));\n\nconst readEventLogRowByEventId = (\n sql: DurableObjectSqlStorage,\n eventId: DurableEventEnvelope[\"eventId\"],\n): DurableObjectEventRow =>\n sql\n .exec<DurableObjectEventRow>(\n `\n SELECT seq, event_id, namespace, type, schema_version, created_at_ms, trace_json, fact_json\n FROM _eda_event_log\n WHERE event_id = ?\n `,\n eventId,\n )\n .one();\n\nconst readCommittedByEventIdOptional = (\n sql: DurableObjectSqlStorage,\n sessionId: SessionId,\n eventId: DurableEventEnvelope[\"eventId\"],\n): CommittedDurableEvent | undefined => {\n const row = sql\n .exec<DurableObjectEventRow>(\n `\n SELECT seq, event_id, namespace, type, schema_version, created_at_ms, trace_json, fact_json\n FROM _eda_event_log\n WHERE event_id = ?\n `,\n eventId,\n )\n .toArray()[0];\n return row === undefined ? undefined : rowToCommittedDurableEvent(sql, row, sessionId);\n};\n\nconst readReducerCheckpoint = (\n sql: DurableObjectSqlStorage,\n name: string,\n): EDAReducerCheckpoint | undefined => {\n const row = sql\n .exec<DurableObjectReducerCheckpointRow>(\n `\n SELECT reducer_name, schema_version, through_seq, payload_json, updated_at_ms\n FROM _eda_reducer_checkpoints\n WHERE reducer_name = ?\n `,\n name,\n )\n .toArray()[0];\n return row === undefined\n ? undefined\n : {\n name: row.reducer_name,\n schemaVersion: row.schema_version,\n throughSeq: SequenceNumber.make(row.through_seq),\n payload: JSON.parse(row.payload_json),\n updatedAtMs: row.updated_at_ms,\n };\n};\n\nconst writeReducerCheckpoint = (\n sql: DurableObjectSqlStorage,\n checkpoint: SaveReducerCheckpointInput,\n): void => {\n sql.exec(\n `\n INSERT INTO _eda_reducer_checkpoints (\n reducer_name,\n schema_version,\n through_seq,\n payload_json,\n updated_at_ms\n ) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(reducer_name) DO UPDATE SET\n schema_version = excluded.schema_version,\n through_seq = excluded.through_seq,\n payload_json = excluded.payload_json,\n updated_at_ms = excluded.updated_at_ms\n `,\n checkpoint.name,\n checkpoint.schemaVersion,\n checkpoint.throughSeq,\n stringifyJsonForColumn(checkpoint.payload, \"_eda_reducer_checkpoints.payload_json\"),\n checkpoint.updatedAtMs,\n );\n};\n\nconst readMessagePayloadByContextSeq = (\n sql: DurableObjectSqlStorage,\n contextSeq: number,\n): DurableObjectMessagePayloadRow => {\n const message = sql\n .exec<DurableObjectMessagePayloadRow>(\n `\n SELECT context_seq, payload_json\n FROM _eda_context_messages\n WHERE context_seq = ?\n `,\n contextSeq,\n )\n .toArray()[0];\n if (message === undefined) {\n throw new Error(`Context message at seq ${contextSeq} missing from _eda_context_messages`);\n }\n return message;\n};\n\nconst readCommittedBySeq = (\n sql: DurableObjectSqlStorage,\n sessionId: SessionId,\n seq: number,\n): CommittedDurableEvent => {\n const row = sql\n .exec<DurableObjectEventRow>(\n `\n SELECT seq, event_id, namespace, type, schema_version, created_at_ms, trace_json, fact_json\n FROM _eda_event_log\n WHERE seq = ?\n `,\n seq,\n )\n .one();\n return rowToCommittedDurableEvent(sql, row, sessionId);\n};\n\nconst rowToCommittedDurableEvent = (\n sql: DurableObjectSqlStorage,\n row: DurableObjectEventRow,\n sessionId: SessionId,\n): CommittedDurableEvent => ({\n position: durablePosition(SequenceNumber.make(row.seq)),\n event: decodeDurableEventSync({\n namespace: row.namespace,\n type: row.type,\n schemaVersion: row.schema_version,\n durability: \"durable\",\n eventId: row.event_id,\n sessionId,\n createdAtMs: row.created_at_ms,\n trace: JSON.parse(row.trace_json),\n payload: readLogicalPayload(sql, row),\n }),\n});\n\ninterface EncodedEventLogRow {\n readonly eventId: string;\n readonly namespace: string;\n readonly type: string;\n readonly schemaVersion: number;\n readonly createdAtMs: number;\n readonly traceJson: string;\n readonly factJson: string;\n}\n\nconst encodeEventLogRow = (event: DurableEventEnvelope): EncodedEventLogRow => {\n const encoded = Schema.encodeSync(DurableEventEnvelope)(event);\n return {\n eventId: encoded.eventId,\n namespace: encoded.namespace,\n type: encoded.type,\n schemaVersion: encoded.schemaVersion,\n createdAtMs: encoded.createdAtMs,\n traceJson: stringifyJsonForColumn(encoded.trace, \"_eda_event_log.trace_json\"),\n factJson: stringifyJsonForColumn(\n eventLogFactPayload(encoded.namespace, encoded.type, encoded.payload),\n \"_eda_event_log.fact_json\",\n ),\n };\n};\n\nconst readLogicalPayload = (sql: DurableObjectSqlStorage, row: DurableObjectEventRow): unknown => {\n if (row.namespace !== effectDurableAgentNamespace) {\n return JSON.parse(row.fact_json);\n }\n if (row.type === commandAdmittedEventType) {\n const commandId = readCommandIdFromFact(row);\n const command = readCommandInputPayload(sql, commandId);\n return { command };\n }\n if (contextMessageEventTypes.has(row.type)) {\n return JSON.parse(readMessagePayloadByContextSeq(sql, row.seq).payload_json);\n }\n if (row.type === summaryCreatedEventType) {\n return {\n ...(JSON.parse(row.fact_json) as Record<string, unknown>),\n summary: readSummaryPayloadFromCreatedSeq(sql, row.seq),\n };\n }\n return JSON.parse(row.fact_json);\n};\n\nconst eventLogFactPayload = (namespace: string, type: string, payload: unknown): unknown => {\n if (\n namespace !== effectDurableAgentNamespace ||\n typeof payload !== \"object\" ||\n payload === null\n ) {\n return payload;\n }\n\n const record = Schema.decodeUnknownSync(Schema.Record(Schema.String, Schema.Unknown))(payload);\n switch (type) {\n case commandAdmittedEventType:\n return { command: commandFact(record.command) };\n case systemMessageCommittedEventType:\n return pick(record, [\"messageId\"]);\n case userMessageCommittedEventType:\n return pick(record, [\"commandId\", \"messageId\"]);\n case steeringMessageQueuedEventType:\n return pick(record, [\"commandId\", \"messageId\", \"runId\"]);\n case assistantMessageCommittedEventType:\n case assistantMessageImportedEventType:\n return pick(record, [\"messageId\", \"runId\", \"turnId\", \"inferenceId\"]);\n case assistantPartialCommittedEventType:\n return pick(record, [\"messageId\", \"runId\", \"turnId\", \"inferenceId\", \"reason\"]);\n case summaryCreatedEventType:\n return pick(record, [\"compactionId\", \"summaryId\", \"sourceFromSeq\", \"sourceToSeq\"]);\n default:\n return payload;\n }\n};\n\nconst commandFact = (command: unknown): unknown => {\n if (typeof command !== \"object\" || command === null) {\n return command;\n }\n const record = command as Record<string, unknown>;\n return record._tag === \"SubmitMessage\"\n ? pick(record, [\"_tag\", \"commandId\", \"disposition\", \"idempotencyKey\"])\n : command;\n};\n\nconst pick = (\n record: Record<string, unknown>,\n keys: ReadonlyArray<string>,\n): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n for (const key of keys) {\n if (record[key] !== undefined) {\n out[key] = record[key];\n }\n }\n return out;\n};\n\nconst readCommandIdFromFact = (row: DurableObjectEventRow): string => {\n const {\n command: { commandId },\n } = Schema.decodeUnknownSync(\n Schema.Struct({\n command: Schema.Struct({ commandId: Schema.String }),\n }),\n )(JSON.parse(row.fact_json));\n if (typeof commandId !== \"string\") {\n throw new Error(`CommandAdmitted fact at seq ${row.seq} missing command.commandId`);\n }\n return commandId;\n};\n\nconst readCommandInputPayload = (sql: DurableObjectSqlStorage, commandId: string): unknown => {\n const row = sql\n .exec<DurableObjectCommandInputPayloadRow>(\n `\n SELECT payload_json\n FROM _eda_command_inputs\n WHERE command_id = ?\n `,\n commandId,\n )\n .toArray()[0];\n if (row === undefined) {\n throw new Error(`Command input ${commandId} missing from _eda_command_inputs`);\n }\n return JSON.parse(row.payload_json);\n};\n\nconst readSummaryPayloadOptional = (\n sql: DurableObjectSqlStorage,\n summaryId: SummaryId,\n): CompactionSummaryArtifact | undefined => {\n const row = sql\n .exec<DurableObjectSummaryPayloadRow>(\n `\n SELECT payload_json\n FROM _eda_context_summaries\n WHERE summary_id = ?\n `,\n summaryId,\n )\n .toArray()[0];\n return row === undefined\n ? undefined\n : Schema.decodeUnknownSync(CompactionSummaryArtifact)(JSON.parse(row.payload_json));\n};\n\nconst readSummaryPayloadFromCreatedSeq = (\n sql: DurableObjectSqlStorage,\n createdSeq: number,\n): unknown => {\n const row = sql\n .exec<DurableObjectSummaryPayloadRow>(\n `\n SELECT payload_json\n FROM _eda_context_summaries\n WHERE created_seq = ?\n `,\n createdSeq,\n )\n .toArray()[0];\n if (row === undefined) {\n throw new Error(`SummaryCreated at seq ${createdSeq} missing from _eda_context_summaries`);\n }\n return JSON.parse(row.payload_json);\n};\n\n/**\n * Maintain bounded storage projections in the same transaction as the event.\n *\n * These rows are durability aids, not a second source of lifecycle truth: event\n * order still comes from `_eda_event_log.seq`, while projections make command\n * lookup and body-sidecar hydration bounded.\n */\nconst applySynchronousProjections = (\n sql: DurableObjectSqlStorage,\n entry: DurableAppendEntry,\n seq: SequenceNumber,\n factJson: string,\n): void => {\n const { event } = entry;\n if (event.namespace !== effectDurableAgentNamespace) {\n return;\n }\n\n writeCommandProjection(sql, event, seq, factJson);\n writeCommandInputProjection(sql, event, seq);\n writeMessageProjection(sql, event, seq);\n writeSummaryProjection(sql, event, seq);\n writeContextRebaseProjection(sql, event, seq);\n};\n\nconst writeCommandProjection = (\n sql: DurableObjectSqlStorage,\n event: DurableEventEnvelope,\n seq: SequenceNumber,\n factJson: string,\n): void => {\n const payload = Schema.decodeUnknownSync(ProjectionPayload)(event.payload);\n switch (event.type) {\n case commandAdmittedEventType: {\n const command = Schema.decodeUnknownSync(AdmittedCommandProjection)(payload.command);\n const commandId = command.commandId;\n if (commandId === undefined) {\n throw new Error(\"CommandAdmitted missing command.commandId\");\n }\n sql.exec(\n `\n INSERT INTO _eda_command_state (\n command_id,\n admitted_seq,\n status,\n idempotency_key,\n payload_json\n ) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(command_id) DO UPDATE SET\n admitted_seq = excluded.admitted_seq,\n status = excluded.status,\n idempotency_key = excluded.idempotency_key,\n payload_json = excluded.payload_json\n `,\n commandId,\n seq,\n \"admitted\",\n command.idempotencyKey ?? null,\n factJson,\n );\n return;\n }\n case commandStartedEventType:\n writeCommandStatus(sql, payload.commandId, seq, \"started\", factJson);\n return;\n case commandCompletedEventType:\n writeCommandStatus(sql, payload.commandId, seq, \"completed\", factJson);\n return;\n case commandFailedEventType:\n writeCommandStatus(sql, payload.commandId, seq, \"failed\", factJson);\n return;\n case commandCancelledEventType:\n writeCommandStatus(sql, payload.commandId, seq, \"cancelled\", factJson);\n return;\n default:\n return;\n }\n};\n\nconst writeCommandStatus = (\n sql: DurableObjectSqlStorage,\n commandId: unknown,\n seq: SequenceNumber,\n status: string,\n payloadJson: string,\n): void => {\n if (commandId === undefined) {\n throw new Error(`${status} command event missing commandId`);\n }\n sql.exec(\n `\n INSERT INTO _eda_command_state (\n command_id,\n admitted_seq,\n status,\n idempotency_key,\n payload_json\n ) VALUES (?, ?, ?, NULL, ?)\n ON CONFLICT(command_id) DO UPDATE SET\n status = excluded.status,\n payload_json = excluded.payload_json\n `,\n commandId,\n seq,\n status,\n payloadJson,\n );\n};\n\nconst writeCommandInputProjection = (\n sql: DurableObjectSqlStorage,\n event: DurableEventEnvelope,\n seq: SequenceNumber,\n): void => {\n if (event.type !== commandAdmittedEventType) {\n return;\n }\n const encoded = Schema.encodeSync(DurableEventEnvelope)(event);\n const { command } = Schema.decodeUnknownSync(\n Schema.Struct({ command: Schema.Record(Schema.String, Schema.Unknown) }),\n )(encoded.payload);\n const commandId = command?.commandId;\n if (commandId === undefined) {\n throw new Error(\"CommandAdmitted missing command.commandId\");\n }\n sql.exec(\n `\n INSERT INTO _eda_command_inputs (\n command_id,\n admitted_seq,\n payload_json\n ) VALUES (?, ?, ?)\n ON CONFLICT(command_id) DO UPDATE SET\n admitted_seq = excluded.admitted_seq,\n payload_json = excluded.payload_json\n `,\n commandId,\n seq,\n stringifyJsonForColumn(command, \"_eda_command_inputs.payload_json\"),\n );\n};\n\nconst contextMessageEventTypes = new Set<string>([\n systemMessageCommittedEventType,\n userMessageCommittedEventType,\n steeringMessageQueuedEventType,\n assistantMessageCommittedEventType,\n assistantMessageImportedEventType,\n assistantPartialCommittedEventType,\n]);\n\n/** Persist model-visible message bodies with the seq that exposed them to context. */\nconst writeMessageProjection = (\n sql: DurableObjectSqlStorage,\n event: DurableEventEnvelope,\n seq: SequenceNumber,\n): void => {\n if (!contextMessageEventTypes.has(event.type)) {\n return;\n }\n\n const encoded = Schema.encodeSync(DurableEventEnvelope)(event);\n const { messageId } = Schema.decodeUnknownSync(Schema.Struct({ messageId: Schema.Unknown }))(\n encoded.payload,\n );\n if (messageId === undefined) {\n throw new Error(`${event.type} missing messageId`);\n }\n\n sql.exec(\n `\n INSERT INTO _eda_context_messages (\n message_id,\n context_seq,\n payload_json\n ) VALUES (?, ?, ?)\n ON CONFLICT(message_id) DO UPDATE SET\n context_seq = excluded.context_seq,\n payload_json = excluded.payload_json\n `,\n messageId,\n seq,\n stringifyJsonForColumn(encoded.payload, \"_eda_context_messages.payload_json\"),\n );\n};\n\n/**\n * Persist a cumulative summary artifact without making it the active context.\n *\n * `ContextRebased` selects summaries in the framework reduced-state checkpoint;\n * failed compactions can leave orphaned summaries without changing future context.\n */\nconst writeSummaryProjection = (\n sql: DurableObjectSqlStorage,\n event: DurableEventEnvelope,\n seq: SequenceNumber,\n): void => {\n if (event.type !== summaryCreatedEventType) {\n return;\n }\n\n const payload = Schema.decodeUnknownSync(SummaryCreatedPayload)(event.payload);\n const summaryId = payload.summaryId;\n if (summaryId === undefined) {\n throw new Error(\"SummaryCreated missing summaryId\");\n }\n if (payload.summary === undefined) {\n throw new Error(\"SummaryCreated requires summary payload\");\n }\n\n const summary = Schema.decodeUnknownSync(CompactionSummaryArtifact)(payload.summary);\n if (summary.summaryId !== summaryId) {\n throw new Error(\"SummaryCreated summaryId does not match summary payload\");\n }\n if (summary.compactionId !== payload.compactionId) {\n throw new Error(\"SummaryCreated compactionId does not match summary payload\");\n }\n\n sql.exec(\n `\n INSERT INTO _eda_context_summaries (\n summary_id,\n created_seq,\n payload_json\n ) VALUES (?, ?, ?)\n ON CONFLICT(summary_id) DO UPDATE SET\n created_seq = excluded.created_seq,\n payload_json = excluded.payload_json\n `,\n summaryId,\n seq,\n stringifyJsonForColumn(summary, \"_eda_context_summaries.payload_json\"),\n );\n};\n\n/** Validate that `ContextRebased` points at a committed summary sidecar. */\nconst writeContextRebaseProjection = (\n sql: DurableObjectSqlStorage,\n event: DurableEventEnvelope,\n _seq: SequenceNumber,\n): void => {\n if (event.type !== contextRebasedEventType) {\n return;\n }\n\n const payload = Schema.decodeUnknownSync(ContextRebasedPayload)(event.payload);\n if (payload.summaryId === undefined) {\n throw new Error(\"ContextRebased missing summaryId\");\n }\n const summary = readSummaryPayloadOptional(sql, SummaryId.make(String(payload.summaryId)));\n if (summary === undefined) {\n throw new Error(`ContextRebased references unknown summaryId ${String(payload.summaryId)}`);\n }\n if (summary.compactionId !== payload.compactionId) {\n throw new Error(\"ContextRebased summary compactionId does not match event payload\");\n }\n if (summary.retainedFromContextSeq !== payload.retainedFromContextSeq) {\n throw new Error(\"ContextRebased retained cursor does not match summary payload\");\n }\n};\n\n/**\n * Lookup prior command admission through `_eda_command_state` instead of genesis replay.\n *\n * Idempotency key wins over explicit command id so caller-owned retry keys remain\n * the stable dedupe surface for external ingress.\n */\nconst findCommandAdmissionRow = (\n sql: DurableObjectSqlStorage,\n commandId: unknown,\n idempotencyKey: unknown,\n): DurableObjectCommandLookupRow | undefined => {\n if (idempotencyKey !== undefined) {\n const row = sql\n .exec<DurableObjectCommandLookupRow>(\n `\n SELECT admitted_seq\n FROM _eda_command_state\n WHERE idempotency_key = ?\n `,\n idempotencyKey,\n )\n .toArray()[0];\n if (row !== undefined) {\n return row;\n }\n }\n\n if (commandId === undefined) {\n return undefined;\n }\n return sql\n .exec<DurableObjectCommandLookupRow>(\n `\n SELECT admitted_seq\n FROM _eda_command_state\n WHERE command_id = ?\n `,\n commandId,\n )\n .toArray()[0];\n};\n\nconst durableStoreError = (operation: string, cause: unknown) =>\n new EDASessionStoreError({\n message:\n cause instanceof Error ? `${operation}: ${cause.message}` : `${operation}: ${String(cause)}`,\n });\n"],"mappings":";;;;;;;;;;;;;;;AACA,MAAa,0CAA0C;AAEvD,MAAM,cAAc,IAAI,YAAY;;AAGpC,MAAa,0BAA0B,OAAgB,WAA2B;CAChF,MAAM,OAAO,KAAK,UAAU,KAAK;CACjC,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,MAAM,GAAG,OAAO,gCAAgC;CAE5D,MAAM,QAAQ,YAAY,OAAO,IAAI,CAAC,CAAC;CACvC,IAAI,QAAA,MACF,MAAM,IAAI,MACR,GAAG,OAAO,sBAAsB,MAAM,sBAAsB,wCAAwC,OACtG;CAEF,OAAO;AACT;;;;;;;;;;;;;;ACoBA,MAAa,4BAAmD;CAC9D;;;;;;;;;CASA;;CAEA;;;;;;;;;;;;;CAcA;;CAGA;;CAGA;;CAEA;;CAGA;;CAEA;;;;;;;CAOA;;;;CAIA;;;;AAIF;AAwBA,MAAM,gBAAgB,OAAO,kBAAkB,iBAAiB;AAEhE,MAAM,cAAc,QAA2C;CAC7D,IAAI,IAAI,SAAS,YAAY,IAAI,SAAS,cAAc,IAAI,SAAS,WACnE,MAAM,IAAI,MAAM,mBAAmB,IAAI,KAAK,oBAAoB,IAAI,MAAM;CAE5E,IAAI,IAAI,WAAW,aAAa,IAAI,kBAAkB,QAAQ,IAAI,UAAU,OAC1E,MAAM,IAAI,MAAM,0BAA0B,IAAI,KAAK,6BAA6B;CAElF,OAAO;EACL,MAAM,IAAI;EACV,SAAS,cAAc,IAAI,OAAO;EAClC,MAAM,IAAI;EACV,QAAQ,eAAe,KAAK,IAAI,MAAM;EACtC,QACE,IAAI,WAAW,WACX;GACE,MAAM;GACN,aAAa,eAAe,KAAK,IAAI,iBAAiB,CAAC;GACvD,OAAO,IAAI,SAAS;EACtB,IACA,EAAE,MAAM,KAAK;CACrB;AACF;;AAGA,MAAa,uBAAuB,QAClC,IACG,KACC,0GACF,CAAC,CACA,QAAQ,CAAC,CACT,IAAI,UAAU;;AAGnB,MAAa,2BAA2B,SACtC,KAAK,SAAS,YACV,KAAA,IACA;CAAE,SAAS,KAAK;CAAS,MAAM,KAAK;CAAM,QAAQ,KAAK;CAAQ,QAAQ,KAAK;AAAO;AAEzF,MAAa,wBACX,KACA,SACA,SACS;CACT,IAAI,KACF,2FACA,SACA,IACF;AACF;AAEA,MAAa,yBACX,KACA,MACA,SACS;CACT,IAAI,KAAK,2DAA2D,MAAM,IAAI;AAChF;;AAGA,MAAa,4BACX,KACA,MACA,aACA,UACS;CACT,IAAI,KACF,kGACA,aACA,OACA,IACF;AACF;;;;;AAMA,MAAa,+BACX,KACA,MACA,UACW;CACX,MAAM,UAAU,IACb,KACC;;iCAGA,MACA,KACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,MAAM,UACJ,WAAW,QACP,IACA,IACG,KACC;;uCAGA,MACA,QAAQ,OACV,CAAC,CACA,QAAQ,CAAC,CAAC;CACnB,IAAI,UAAU,UAAU,OACtB,IAAI,KAAK,wEAAwE,IAAI;CAEvF,OAAO,UAAU;AACnB;AAUA,MAAM,iBAAiB,OAAO,WAAW,4BAA4B;AACrE,MAAM,iBAAiB,OAAO,kBAAkB,4BAA4B;;AAG5E,IAAa,2BAAb,cAA8C,MAAM;CAClD,OAAyB;AAC3B;;;;;AAMA,MAAM,mBAAmB,QAA+C;CACtE,IAAI;EACF,OAAO,eAAe,KAAK,MAAM,IAAI,aAAa,CAAC;CACrD,SAAS,OAAO;EACd,MAAM,IAAI,yBACR,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KACpF,EAAE,MAAM,CACV;CACF;AACF;AAEA,MAAM,cAAc,WAClB,cAAc,SAAS,OAAO,WAAW,KAAA;AAY3C,MAAa,wBAAwB,UAAuD;CAC1F,SAAS,KAAK,QAAQ,KAAK,WAAW;EACpC,MAAM,WAAW,WAAW,MAAM;EAClC,OAAO;GACL,OAAO;GACP,OAAO;GACP,UAAU,aAAa;GACvB,UAAU,WAAW;GACrB,2BAA2B,MAAM,IAAI,IAAI;GACzC,8BAA8B,MAAM,IAAI,IAAI;GAC5C,OAAO,SAAS,SAAS,OAAO,cAAc;GAC9C,OAAO;GACP,uBAAuB,eAAe,MAAM,GAAG,uCAAuC;EACxF;CACF,CAAC;CACD,SAAS,KAAK;CACd,YAAY,KAAK;AACnB;;AAGA,MAAa,uBACX,KACA,MACA,SACS;CACT,KAAK,MAAM,OAAO,KAAK,SACrB,IAAI,KACF;;;;;;;;;;;iDAYA,MACA,GAAG,GACL;CAEF,KAAK,MAAM,SAAS,KAAK,SAEvB,IAAI,KACF;qDAEA,MACA,MAAM,WACN,MAAM,KACN,MAAM,QACR;CAEF,IAAI,KAAK,6DAA6D,KAAK,YAAY,IAAI;AAC7F;AAEA,MAAM,cACJ,KACA,MACA,OACiC;CACjC,MAAM,MAAM,IACT,KACC,+EACA,MACA,EACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,OAAO,QAAQ,KAAA,IAAY,KAAA,IAAY,gBAAgB,GAAG;AAC5D;AAEA,MAAM,iBAAiB,OAAO,kBAAkB,kBAAkB;AAElE,MAAM,aACJ,KACA,MACA,WACA,QACmC;CACnC,MAAM,MAAM,IACT,KACC,8FACA,MACA,WACA,GACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,OAAO,QAAQ,KAAA,IAAY,KAAA,IAAY,eAAe,IAAI,SAAS;AACrE;;AAGA,MAAa,wBACX,KACA,UACsB;CACtB,QAAQ,KAAK;CACb,SAAS,OAAO,WAAW,KAAK,KAAK,MAAM,EAAE;CAC7C,QAAQ,WAAW,QAAQ,UAAU,KAAK,KAAK,MAAM,WAAW,GAAG;CACnE,cAAc,cACZ,IACG,KACC;4CAEA,KAAK,MACL,SACF,CAAC,CACA,IAAI,CAAC,CAAC,QAAQ;AACrB;AAEA,MAAM,YAAY,WAAuD;CACvE,IAAI,CAAC,2BAA2B,MAAM,GACpC,MAAM,IAAI,yBACR,qBAAqB,OAAO,GAAG,oCACjC;CAEF,OAAO;AACT;;;;;;AAOA,MAAa,8BACX,KACA,aACA,MACA,YAC2B;CAC3B,MAAM,OAAO,wBAAwB,IAAI;CACzC,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,2BAA2B,KAAK,KAAK,iBAAiB;CAC9F,MAAM,gBACJ,KACA,OACA,WACA,cAC4C;EAC5C,MAAM,aAAa,cAAc,WAAY,YAAY,OAAO,MAAO,YAAY,OAAO;EAC1F,MAAM,QAAQ,cAAc,WAAW,SAAS;EAChD,MAAM,YACJ,QAAQ,KAAA,IAAY,KAAK,iCAAiC,WAAW;EACvE,MAAM,cAAc,QAAQ,KAAA,IAAY,CAAC,IAAI;GAAC,IAAI;GAAW,IAAI;GAAS,IAAI;EAAQ;EACtF,OAAO,IACJ,KACC;2CACmC,UAAU;8BACvB,MAAM,YAAY,MAAM,OAAO,MAAM;kBAE3D,KAAK,MACL,GAAG,aACH,KACF,CAAC,CACA,QAAQ,CAAC,CACT,KAAK,QAAQ,SAAS,gBAAgB,GAAG,CAAC,CAAC;CAChD;CACA,OAAO;EACL;EACA;EACA;EACA,iBAAiB,KAAK,OAAO,cAAc,aAAa,KAAK,OAAO,WAAW,QAAQ;EACvF,gBAAgB,KAAK,OAAO,cAAc,aAAa,KAAK,OAAO,WAAW,OAAO;EACrF,SAAS,OAAO,WAAW,KAAK,KAAK,MAAM,EAAE;EAC7C,QAAQ,WAAW,QAAQ,UAAU,KAAK,KAAK,MAAM,WAAW,GAAG;EACnE,UAAU,gBACR,IACG,KACC,yFACA,KAAK,MACL,WACF,CAAC,CACA,QAAQ,CAAC,CACT,SAAS,QAA6C;GACrD,MAAM,SAAS,gBAAgB,GAAG;GAClC,OAAO,OAAO,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC;EAC9C,CAAC;EACL,oBACE,IACG,KACC,oFACA,KAAK,IACP,CAAC,CACA,QAAQ,CAAC,CACT,SAAS,QAA6C;GACrD,MAAM,SAAS,gBAAgB,GAAG;GAClC,OAAO,OAAO,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC;EAC9C,CAAC;CACP;AACF;AAmBA,MAAM,mBACJ,OAAO,QACL,OAAO,IAAI,aAAa;CAEtB,OAAO,QAAO,OADK,YAAA,CACD,kBAAkB;AACtC,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,YAAY,IAAI,CAAC,CAC1C;;;;;AAMF,MAAa,4BACX,KACA,UAC6B;CAC7B,MAAM,MAAM,IACT,KACC,2DACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,IAAI,QAAQ,KAAA,GAAW,OAAO,yBAAyB,KAAK,IAAI,WAAW;CAC3E,MAAM,UAAU,OAAO,GAAG,IAAI,MAAM,GAAG;CACvC,MAAM,cAAc,OAAO,YAAY,YAAY,QAAQ,SAAS,IAAI,UAAU,WAAW;CAC7F,IAAI,UAAU,KAAA,KAAa,YAAY,aAAa,MAAM,GAAG,IAAI,MAAM,KAAK,WAAW;CACvF,IAAI,KAAK,oEAAoE,WAAW;CACxF,OAAO,yBAAyB,KAAK,WAAW;AAClD;;;AClbA,MAAa,+BAAmE;CAC9E,WAAW;CACX,YAAY;CACZ,gBAAgB;AAClB;AA6BA,MAAa,gCAAmD;CAC9D,QAAQ,CAAC;CACT,aAAa;AACf;;;;;AAMA,MAAa,4BACX,UACA,YACS;CACT,MAAM,UAAU,SAAqB;EACnC,IAAI;GACF,KAAK;EACP,SAAS,OAAO;GACd,QAAQ,MAAM,kCAAkC,KAAK;EACvD;CACF;CACA,KAAK,MAAM,SAAS,QAAQ,QAAQ,aAAa,UAAU,UAAU,KAAK,CAAC;CAC3E,MAAM,YAAY,QAAQ;CAC1B,IAAI,cAAc,KAAA,GAAW,aAAa,UAAU,cAAc,SAAS,CAAC;CAC5E,IAAI,QAAQ,aAAa,aAAa,UAAU,gBAAgB,CAAC;AACnE;;AAGA,MAAa,qBACX,QACA,YAEA,OAAO,QAAQ,YAAY,UACvB,OAAO,UACP,OAAO,UAAU,YAAY,UAC3B,OAAO,WACP,KAAA;AAER,MAAM,aAAa,YACjB,oBAAoB,QAAQ,GAAG,CAAC,CAAC,QAAQ,SAAS,KAAK,SAAS,SAAS;;;;;;;;;;;AAY3E,MAAa,4BACX,SACA,QACA,MACA,YACS;CACT,MAAM,EAAE,QAAQ;CAChB,MAAM,UAAU,OAAO,QAAQ;CAC/B,MAAM,QAAQ,UAAU,OAAO;CAC/B,IAAI,MAAM,WAAW,GAAG;EACtB,qBAAqB,KAAK,SAAS,SAAS,IAAI,WAAW,UAAU;EACrE,IAAI,OAAO,GAAG,QAAQ,cAAc;EACpC;CACF;CACA,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,cAAc,KAAK,YAAY,SAAS;EACxD,sBAAsB,KAAK,KAAK,MAAM,SAAS;EAC/C,QAAQ,cAAc;CACxB;CAEF,MAAM,SAAS,MAAM,MAAM,SAAS,KAAK,SAAS,QAAQ;CAC1D,MAAM,kBAAkB,MAAM,MAC3B,SAAS,KAAK,SAAS,cAAc,KAAK,YAAY,OACzD;CACA,IAAI,QAAQ,YAAY,WAAW,CAAC,iBAAiB;EACnD,qBAAqB,KAAK,SAAS,UAAU;EAC7C,QAAQ,cAAc;CACxB;AACF;AAEA,MAAM,2CAA2B,IAAI,QAA8C;AACnF,MAAM,6BAA6B;;;;;;AAOnC,MAAM,8BAA8B,YAAkD;CACpF,MAAM,QAAQ,yBAAyB,IAAI,OAAO;CAClD,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,IAAI;CACJ,IAAI;EACF,QAAQ,sBAAsB,QAAQ,sBAAsB,KAAA,CAAS,CAAC;EACtE,YAAY;CACd,SAAS,OAAO;EAEd,IAAI,EAAE,iBAAiB,SAAS,2BAA2B,KAAK,MAAM,OAAO,IAAI,MAAM;EACvF,YAAY;CACd;CACA,yBAAyB,IAAI,SAAS,SAAS;CAC/C,OAAO;AACT;;AAGA,MAAM,cACJ,SACA,MACA,aACA,OACA,YACmB;CACnB,MAAM,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CACnE,yBAAyB,QAAQ,KAAK,KAAK,MAAM,aAAa,KAAK;CACnE,IAAI,KAAK,SAAS,WAChB,QAAQ,OAAO,KAAK;EAClB,MAAM;EACN,SAAS,KAAK;EACd,MAAM,KAAK;EACX;EACA;CACF,CAAC;CAEH,OAAO;EAAE,GAAG;EAAM,QAAQ;GAAE,MAAM;GAAU;GAAa;EAAM;CAAE;AACnE;;;;;;;;;;;;AAaA,MAAM,eACJ,SACA,MACA,YACA,QACA,YACmB;CACnB,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,SAAS,MAAM,KAAK,MAAM;CACrE,IAAI,UAAU,KAAA,KAAa,KAAK,OAAO,SAAS,YAAY,KAAK,SAAS,WAAW,OAAO;CAC5F,MAAM,SAAS,2BAA2B,OAAO;CACjD,MAAM,gBAAgB;EACpB,MAAM,OAAO,qBACX,oBAAoB,qBAAqB,QAAQ,KAAK,IAAI,GAAG,QAAQ,UAAU,CACjF;EACA,IAAI,QAAQ,oBAAoB,QAAQ,KAAK,KAAK,MAAM,IAAI;EAC5D,OAAO;CACT;CACA,IAAI;CACJ,IAAI;EACF,OAAO,SAAS,QAAQ,gBAAgB,OAAO,IAAI,QAAQ;CAC7D,SAAS,OAAO;EACd,OAAO,WAAW,SAAS,MAAM,MAAM,SAAS,KAAK,OAAO,OAAO;CACrE;CACA,IAAI,CAAC,QAAQ,oBAAoB,QAAQ,KAAK,KAAK,MAAM,IAAI;CAC7D,OAAO;EAAE,GAAG;EAAM,QAAQ,KAAK;CAAW;AAC5C;;;;;;;;;;AAWA,MAAa,+BACX,SACA,QACA,iBACA,UACA,YACS;CACT,yBAAyB,SAAS,QAAQ,iBAAiB,OAAO;CAClE,IAAI,SAAS,WAAW,GAAG;CAC3B,KAAK,MAAM,QAAQ,UAAU,OAAO,GAAG;EACrC,MAAM,aAAa,kBAAkB,QAAQ,KAAK,OAAO;EACzD,IAAI,eAAe,KAAA,KAAa,KAAK,OAAO,SAAS,UAAU;EAC/D,IAAI,KAAK,WAAW,iBAAiB;EACrC,YAAY,SAAS,MAAM,YAAY,UAAU,OAAO;CAC1D;AACF;;;;;AAMA,MAAa,sBACX,SACA,WACgC;CAChC,MAAM,SAAS,UAAU,OAAO,CAAC,CAAC,MAAM,SAAS,KAAK,SAAS,QAAQ;CACvE,OAAO,WAAW,KAAA,KAAa,kBAAkB,QAAQ,OAAO,OAAO,MAAM,KAAA,IACzE,KAAA,IACA;EACE,MAAM;EACN,eAAe,OAAO;EACtB,gBAAgB,OAAO,QAAQ;CACjC;AACN;;AAGA,MAAM,eACJ,QACA,OACA,SAC+B;CAC/B,MAAM,WAAW,SACf,KAAK,OAAO,SAAS,QAAQ,kBAAkB,QAAQ,KAAK,OAAO,MAAM,KAAA;CAC3E,OACE,MAAM,MAAM,SAAS,KAAK,SAAS,cAAc,QAAQ,IAAI,CAAC,KAC9D,MAAM,MAAM,SAAS,KAAK,SAAS,YAAY,QAAQ,IAAI,KAAK,KAAK,SAAS,IAAI;AAEtF;;AAGA,MAAa,4BACX,SACA,QACA,SACY;CACZ,MAAM,QAAQ,oBAAoB,QAAQ,GAAG;CAC7C,IAAI,MAAM,MAAM,SAAS,KAAK,SAAS,SAAS,GAAG,OAAO;CAC1D,MAAM,OAAO,MAAM,QAAQ,SAAS,KAAK,SAAS,SAAS;CAE3D,IAAI,KAAK,WAAW,GAAG,OAAO,OAAO;CACrC,MAAM,UAAU,OAAO,QAAQ;CAC/B,IAAI,KAAK,MAAM,SAAS,KAAK,SAAS,cAAc,KAAK,YAAY,OAAO,GAAG,OAAO;CAEtF,IADe,KAAK,MAAM,SAAS,KAAK,SAAS,QAE1C,CAAC,EAAE,YAAY,WACpB,CAAC,KAAK,MAAM,SAAS,KAAK,SAAS,cAAc,KAAK,YAAY,OAAO,GAEzE,OAAO;CAET,OAAO,YAAY,QAAQ,MAAM,IAAI,MAAM,KAAA;AAC7C;;;;;;;;;AAUA,MAAa,sBACX,SACA,QACA,KACA,QACA,YACY;CACZ,MAAM,EAAE,QAAQ;CAChB,MAAM,OAAO,IAAI,KAAK;CACtB,yBAAyB,SAAS,QAAQ,MAAM,OAAO;CACvD,MAAM,QAAQ,UAAU,OAAO;CAC/B,MAAM,SAAS,YAAY,QAAQ,OAAO,IAAI;CAC9C,IAAI,WAAW,KAAA,GAAW;EACxB,MAAM,aAAa,kBAAkB,QAAQ,OAAO,OAAO;EAC3D,IAAI,OAAO;EACX,IAAI,YAAY,OAAO;EACvB,OACE,eAAe,KAAA,KACf,KAAK,OAAO,SAAS,QACrB,KAAK,SAAS,QACd,YAAY,GACZ;GACA,IAAI;GACJ,IAAI;IACF,OAAO,IAAI,MAAM,KAAK,QAAQ,KAAK,IAAI,OAAO,YAAY,SAAS,CAAC;GACtE,SAAS,OAAO;IAGd,OAAO,WAAW,SAAS,MAAM,eAAe,KAAK,KAAK,SAAS,CAAC,GAAG,OAAO,OAAO;IACrF;GACF;GACA,IAAI,KAAK,WAAW,GAAG;GACvB,aAAa,KAAK;GAClB,OAAO,YAAY,SAAS,MAAM,YAAY,MAAM,OAAO;EAC7D;EACA,IAAI,KAAK,SAAS,cAAc,KAAK,OAAO,SAAS,QAAQ,KAAK,WAAW,IAAI,KAAK,GAAG;GACvF,MAAM,WAAW,MAAM,MAAM,cAAc,UAAU,SAAS,QAAQ;GACtE,IAAI,aAAa,KAAA,GAAW,sBAAsB,KAAK,SAAS,MAAM,SAAS;GAC/E,sBAAsB,KAAK,KAAK,MAAM,QAAQ;GAC9C,QAAQ,YAAY;IAAE,SAAS,KAAK;IAAS,iBAAiB,UAAU;GAAQ;EAClF;CACF;CACA,IAAI,eAAe,OAAO;CAC1B,KAAK,MAAM,QAAQ,oBAAoB,GAAG,GAAG;EAC3C,IAAI,gBAAgB,GAAG;EACvB,IAAI,KAAK,SAAS,WAChB,gBAAgB,4BAA4B,KAAK,KAAK,MAAM,YAAY;CAE5E;CACA,OAAO,yBAAyB,SAAS,QAAQ,IAAI,KAAK,CAAC;AAC7D;;;ACzVA,MAAM,oBAAoB,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;AACrE,MAAM,4BAA4B,OAAO,OAAO;CAC9C,WAAW,OAAO;CAClB,gBAAgB,OAAO,YAAY,OAAO,OAAO;AACnD,CAAC;;AAoDD,MAAM,yCAAyC;;AAE/C,MAAM,uCAAuC;;;;;;;;;AAU7C,MAAM,iCAAiC;;;;;;;;AASvC,IAAa,4BAAb,MAAa,0BAA0B;;CAErC,OAAgB,WAAW,YACzB,iCAAiC,OAAO;;CAG1C,OAAgB,QAAQ,EACtB,WACA,SACA,iBAEA,OAAO,IAAI,aAAa;EACtB,OAAO,0BAA0B,QAAQ,OAAO;EAChD,OAAO,8BAA8B,WAAW,SAAS,UAAU;CACrE,CAAC;;CAGH,OAAgB,SAAS,YACvB,MAAM,OAAO,iBAAiB,0BAA0B,KAAK,OAAO,CAAC;AACzE;;;;;;;AAQA,MAAM,oCAAoC,YACxC,OAAO,IAAI;CACT,WACE,QAAQ,sBAAsB;EAC5B,MAAM,EAAE,QAAQ;EAChB,IAAI,KAAK;;;;;SAKR;EAED,MAAM,iBACJ,IACG,KACC,oEACF,CAAC,CACA,IAAI,CAAC,CAAC,WAAW;EAEtB,IAAI,iBAAiB,wCAAwC;GAC3D,IAAI,KAAK;;;;;;;;;;;WAWR;GACD,IAAI,KAAK;;;WAGR;GAED,IAAI,KAAK;;;;;;;;WAQR;GACD,IAAI,KAAK;;;;;;WAMR;GACD,IAAI,KAAK;;;WAGR;GACD,IAAI,KAAK;;;WAGR;GACD,IAAI,KAAK;;;;;;WAMR;GACD,IAAI,KAAK;;;WAGR;GACD,IAAI,KAAK;;;;;;WAMR;GACD,IAAI,KAAK;;;WAGR;GACD,IAAI,KAAK;;;;;;;;WAQR;GACD,IAAI,KAAK;;;;;;WAMR;GACD,IAAI,KACF,sDACA,sCACF;EACF;EAEA,IAAI,iBAAiB,sCAAsC;GACzD,KAAK,MAAM,aAAa,2BAA2B,IAAI,KAAK,SAAS;GACrE,IAAI,KACF,sDACA,oCACF;EACF;CACF,CAAC;CACH,QAAQ,UAAU,kBAAkB,uCAAuC,KAAK;AAClF,CAAC;;;;;;;AAQH,MAAM,iCACJ,WACA,SACA,eACyB;CACzB,MAAM,EAAE,QAAQ;CAChB,MAAM,iBAAiB,UAAgC;EACrD,IAAI,MAAM,cAAc,WACtB,MAAM,IAAI,MACR,kDAAkD,UAAU,aAAa,MAAM,WACjF;CAEJ;;;;;;;;CASA,MAAM,gBACJ,OACA,aAC0B;EAC1B,MAAM,EAAE,UAAU;EAClB,cAAc,KAAK;EACnB,MAAM,WAAW,+BAA+B,KAAK,WAAW,MAAM,OAAO;EAC7E,IAAI,aAAa,KAAA,GACf,OAAO;EAGT,MAAM,UAAU,kBAAkB,KAAK;EACvC,IAAI,KACF;;;;;;;;;;SAWA,QAAQ,SACR,QAAQ,WACR,QAAQ,MACR,QAAQ,eACR,QAAQ,aACR,QAAQ,WACR,QAAQ,QACV;EACA,MAAM,MAAM,yBAAyB,KAAK,MAAM,OAAO;EACvD,4BAA4B,KAAK,OAAO,eAAe,KAAK,IAAI,GAAG,GAAG,QAAQ,QAAQ;EACtF,MAAM,YAAY,2BAA2B,KAAK,KAAK,SAAS;EAChE,SAAS,KAAK,SAAS;EACvB,OAAO;CACT;;;;;;;;CASA,MAAM,UAAU,UACd,OAAO,IAAI;EACT,WAAW;GACT,MAAM,UAAU,uBAAuB;GACvC,MAAM,YAAY,QAAQ,sBAAsB;IAC9C,MAAM,kBAAkB,eAAe,KAAA,IAAY,KAAA,IAAY,iBAAiB,GAAG;IACnF,MAAM,WAAyC,CAAC;IAChD,MAAM,UAAU,MAAM,QAAQ,KAAK,UAAU,aAAa,OAAO,QAAQ,CAAC;IAC1E,IAAI,eAAe,KAAA,KAAa,oBAAoB,KAAA,GAClD,4BACE,SACA,WAAW,aACX,iBACA,UACA,OACF;IAEF,OAAO;GACT,CAAC;GACD,yBAAyB,YAAY,UAAU,OAAO;GACtD,OAAO;EACT;EACA,QAAQ,UAAU,kBAAkB,6CAA6C,KAAK;CACxF,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK,cAAc,gBAAgB,yBAAyB,SAAS,CAAC,CAAC,CAAC;CAEzF,OAAO;EACL;EACA,cAAc,aAAa,yBAAyB,KAAK,WAAW,QAAQ;EAC5E,2BAA2B,SACzB,OAAO,IAAI;GACT,WACE,sBAAsB,IAAI,CAAC,CACxB,MAAM,MAAM,UAAU,OAAO,KAAK,CAAC,CACnC,KAAK,QAAQ,mBAAmB,KAAK,WAAW,GAAG,CAAC;GACzD,QAAQ,UACN,kBAAkB,mDAAmD,KAAK;EAC9E,CAAC;EACH,uBAAuB,UACrB,OAAO,IAAI;GACT,WAAW;IACT,MAAM,MAAM,wBAAwB,KAAK,MAAM,WAAW,MAAM,cAAc;IAC9E,OAAO,QAAQ,KAAA,IACX,KAAA,IACA,mBAAmB,KAAK,WAAW,IAAI,YAAY;GACzD;GACA,QAAQ,UAAU,kBAAkB,6BAA6B,KAAK;EACxE,CAAC;EACH,sBAAsB,cACpB,OAAO,IAAI;GACT,WAAW,2BAA2B,KAAK,SAAS;GACpD,QAAQ,UAAU,kBAAkB,6CAA6C,KAAK;EACxF,CAAC;EACH,wBAAwB,SACtB,OAAO,IAAI;GACT,WAAW,sBAAsB,KAAK,IAAI;GAC1C,QAAQ,UACN,kBAAkB,wDAAwD,QAAQ,KAAK;EAC3F,CAAC;EACH,wBAAwB,eACtB,OAAO,IAAI;GACT,WAAW,uBAAuB,KAAK,UAAU;GACjD,QAAQ,UACN,kBACE,uDAAuD,WAAW,QAClE,KACF;EACJ,CAAC;EACH,yBAAyB,gBACvB,OAAO,IAAI;GACT,WACE,QAAQ,sBACN,YAAY,SAAS,eAAe,uBAAuB,KAAK,UAAU,CAAC,CAC7E;GACF,QAAQ,UACN,kBAAkB,wDAAwD,KAAK;EACnF,CAAC;CACL;AACF;;AAGA,MAAa,6BACX,KACA,eACwB;CACxB,YAAY,iBAAiB,GAAG;CAChC,QAAQ,UAAU,UAChB,IACG,KACC;;;;;;WAOA,UACA,KACF,CAAC,CACA,QAAQ,CAAC,CACT,KAAK,QAAQ,2BAA2B,KAAK,KAAK,SAAS,CAAC;AACnE;AAEA,MAAM,4BACJ,KACA,WACA,aAEA,OAAO,SACL,OAAO,WAAW;CAChB,IAAI,SAAuC;EAAE;EAAU,YAAY,KAAA;CAAU;CAC7E,IAAI,OAAO;CACX,OAAO,OAAO,IAAI,aAAa;EAC7B,IAAI,MACF,OAAO,OAAO,MAAM,KAAK;EAI3B,OAAO,OAAO;EACd,MAAM,OAAO,OAAO,uBAAuB,KAAK,WAAW,MAAM;EACjE,IAAI,KAAK,OAAO,WAAW,GAAG;GAC5B,OAAO;GACP,OAAO,OAAO,MAAM,KAAK;EAC3B;EACA,IAAI,OAAO,OAAO,KAAK,IAAI,GACzB,SAAS,KAAK,KAAK;OAEnB,OAAO;EAET,OAAO,KAAK;CACd,CAAC;AACH,CAAC,CACH;AAEF,MAAM,0BACJ,KACA,WACA,WAQA,OAAO,IAAI;CACT,WAAW;EACT,MAAM,aAAa,OAAO,cAAc,iBAAiB,GAAG;EAC5D,IAAI,OAAO,YAAY,YACrB,OAAO;GAAE,QAAQ,CAAC;GAAG,MAAM,OAAO,KAAK;EAAE;EAG3C,MAAM,SAAS,IACZ,KACC;;;;;;aAOA,OAAO,UACP,YACA,8BACF,CAAC,CACA,QAAQ,CAAC,CACT,KAAK,QAAQ,2BAA2B,KAAK,KAAK,SAAS,CAAC;EAC/D,MAAM,UAAU,OAAO,GAAG,EAAE,CAAC,EAAE,SAAS,OAAO,OAAO;EACtD,OAAO;GACL;GACA,MACE,UAAU,aACN,OAAO,KAAK;IAAE,UAAU;IAAS;GAAW,CAAwC,IACpF,OAAO,KAAK;EACpB;CACF;CACA,QAAQ,UAAU,kBAAkB,8CAA8C,KAAK;AACzF,CAAC;AAEH,MAAM,oBAAoB,QACxB,eAAe,KACb,IACG,KACC;;;SAIF,CAAC,CACA,IAAI,CAAC,CAAC,QAAQ,CACnB;AAEF,MAAM,yBAAyB,SAC7B,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,QAAQ,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,eAAe,KAAK,GAAG,CAAC;AAE3F,MAAM,4BACJ,KACA,YAEA,IACG,KACC;;;;SAKA,OACF,CAAC,CACA,IAAI;AAET,MAAM,kCACJ,KACA,WACA,YACsC;CACtC,MAAM,MAAM,IACT,KACC;;;;SAKA,OACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,OAAO,QAAQ,KAAA,IAAY,KAAA,IAAY,2BAA2B,KAAK,KAAK,SAAS;AACvF;AAEA,MAAM,yBACJ,KACA,SACqC;CACrC,MAAM,MAAM,IACT,KACC;;;;SAKA,IACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,OAAO,QAAQ,KAAA,IACX,KAAA,IACA;EACE,MAAM,IAAI;EACV,eAAe,IAAI;EACnB,YAAY,eAAe,KAAK,IAAI,WAAW;EAC/C,SAAS,KAAK,MAAM,IAAI,YAAY;EACpC,aAAa,IAAI;CACnB;AACN;AAEA,MAAM,0BACJ,KACA,eACS;CACT,IAAI,KACF;;;;;;;;;;;;;OAcA,WAAW,MACX,WAAW,eACX,WAAW,YACX,uBAAuB,WAAW,SAAS,uCAAuC,GAClF,WAAW,WACb;AACF;AAEA,MAAM,kCACJ,KACA,eACmC;CACnC,MAAM,UAAU,IACb,KACC;;;;SAKA,UACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,IAAI,YAAY,KAAA,GACd,MAAM,IAAI,MAAM,0BAA0B,WAAW,oCAAoC;CAE3F,OAAO;AACT;AAEA,MAAM,sBACJ,KACA,WACA,QAC0B;CAC1B,MAAM,MAAM,IACT,KACC;;;;SAKA,GACF,CAAC,CACA,IAAI;CACP,OAAO,2BAA2B,KAAK,KAAK,SAAS;AACvD;AAEA,MAAM,8BACJ,KACA,KACA,eAC2B;CAC3B,UAAU,gBAAgB,eAAe,KAAK,IAAI,GAAG,CAAC;CACtD,OAAO,uBAAuB;EAC5B,WAAW,IAAI;EACf,MAAM,IAAI;EACV,eAAe,IAAI;EACnB,YAAY;EACZ,SAAS,IAAI;EACb;EACA,aAAa,IAAI;EACjB,OAAO,KAAK,MAAM,IAAI,UAAU;EAChC,SAAS,mBAAmB,KAAK,GAAG;CACtC,CAAC;AACH;AAYA,MAAM,qBAAqB,UAAoD;CAC7E,MAAM,UAAU,OAAO,WAAW,oBAAoB,CAAC,CAAC,KAAK;CAC7D,OAAO;EACL,SAAS,QAAQ;EACjB,WAAW,QAAQ;EACnB,MAAM,QAAQ;EACd,eAAe,QAAQ;EACvB,aAAa,QAAQ;EACrB,WAAW,uBAAuB,QAAQ,OAAO,2BAA2B;EAC5E,UAAU,uBACR,oBAAoB,QAAQ,WAAW,QAAQ,MAAM,QAAQ,OAAO,GACpE,0BACF;CACF;AACF;AAEA,MAAM,sBAAsB,KAA8B,QAAwC;CAChG,IAAI,IAAI,cAAc,6BACpB,OAAO,KAAK,MAAM,IAAI,SAAS;CAEjC,IAAI,IAAI,SAAS,0BAA0B;EACzC,MAAM,YAAY,sBAAsB,GAAG;EAE3C,OAAO,EAAE,SADO,wBAAwB,KAAK,SAC9B,EAAE;CACnB;CACA,IAAI,yBAAyB,IAAI,IAAI,IAAI,GACvC,OAAO,KAAK,MAAM,+BAA+B,KAAK,IAAI,GAAG,CAAC,CAAC,YAAY;CAE7E,IAAI,IAAI,SAAS,yBACf,OAAO;EACL,GAAI,KAAK,MAAM,IAAI,SAAS;EAC5B,SAAS,iCAAiC,KAAK,IAAI,GAAG;CACxD;CAEF,OAAO,KAAK,MAAM,IAAI,SAAS;AACjC;AAEA,MAAM,uBAAuB,WAAmB,MAAc,YAA8B;CAC1F,IACE,cAAc,+BACd,OAAO,YAAY,YACnB,YAAY,MAEZ,OAAO;CAGT,MAAM,SAAS,OAAO,kBAAkB,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO;CAC7F,QAAQ,MAAR;EACE,KAAK,0BACH,OAAO,EAAE,SAAS,YAAY,OAAO,OAAO,EAAE;EAChD,KAAK,iCACH,OAAO,KAAK,QAAQ,CAAC,WAAW,CAAC;EACnC,KAAK,+BACH,OAAO,KAAK,QAAQ,CAAC,aAAa,WAAW,CAAC;EAChD,KAAK,gCACH,OAAO,KAAK,QAAQ;GAAC;GAAa;GAAa;EAAO,CAAC;EACzD,KAAK;EACL,KAAK,mCACH,OAAO,KAAK,QAAQ;GAAC;GAAa;GAAS;GAAU;EAAa,CAAC;EACrE,KAAK,oCACH,OAAO,KAAK,QAAQ;GAAC;GAAa;GAAS;GAAU;GAAe;EAAQ,CAAC;EAC/E,KAAK,yBACH,OAAO,KAAK,QAAQ;GAAC;GAAgB;GAAa;GAAiB;EAAa,CAAC;EACnF,SACE,OAAO;CACX;AACF;AAEA,MAAM,eAAe,YAA8B;CACjD,IAAI,OAAO,YAAY,YAAY,YAAY,MAC7C,OAAO;CAET,MAAM,SAAS;CACf,OAAO,OAAO,SAAS,kBACnB,KAAK,QAAQ;EAAC;EAAQ;EAAa;EAAe;CAAgB,CAAC,IACnE;AACN;AAEA,MAAM,QACJ,QACA,SAC4B;CAC5B,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,OAAO,MAChB,IAAI,OAAO,SAAS,KAAA,GAClB,IAAI,OAAO,OAAO;CAGtB,OAAO;AACT;AAEA,MAAM,yBAAyB,QAAuC;CACpE,MAAM,EACJ,SAAS,EAAE,gBACT,OAAO,kBACT,OAAO,OAAO,EACZ,SAAS,OAAO,OAAO,EAAE,WAAW,OAAO,OAAO,CAAC,EACrD,CAAC,CACH,CAAC,CAAC,KAAK,MAAM,IAAI,SAAS,CAAC;CAC3B,IAAI,OAAO,cAAc,UACvB,MAAM,IAAI,MAAM,+BAA+B,IAAI,IAAI,2BAA2B;CAEpF,OAAO;AACT;AAEA,MAAM,2BAA2B,KAA8B,cAA+B;CAC5F,MAAM,MAAM,IACT,KACC;;;;SAKA,SACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,IAAI,QAAQ,KAAA,GACV,MAAM,IAAI,MAAM,iBAAiB,UAAU,kCAAkC;CAE/E,OAAO,KAAK,MAAM,IAAI,YAAY;AACpC;AAEA,MAAM,8BACJ,KACA,cAC0C;CAC1C,MAAM,MAAM,IACT,KACC;;;;SAKA,SACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,OAAO,QAAQ,KAAA,IACX,KAAA,IACA,OAAO,kBAAkB,yBAAyB,CAAC,CAAC,KAAK,MAAM,IAAI,YAAY,CAAC;AACtF;AAEA,MAAM,oCACJ,KACA,eACY;CACZ,MAAM,MAAM,IACT,KACC;;;;SAKA,UACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,IAAI,QAAQ,KAAA,GACV,MAAM,IAAI,MAAM,yBAAyB,WAAW,qCAAqC;CAE3F,OAAO,KAAK,MAAM,IAAI,YAAY;AACpC;;;;;;;;AASA,MAAM,+BACJ,KACA,OACA,KACA,aACS;CACT,MAAM,EAAE,UAAU;CAClB,IAAI,MAAM,cAAc,6BACtB;CAGF,uBAAuB,KAAK,OAAO,KAAK,QAAQ;CAChD,4BAA4B,KAAK,OAAO,GAAG;CAC3C,uBAAuB,KAAK,OAAO,GAAG;CACtC,uBAAuB,KAAK,OAAO,GAAG;CACtC,6BAA6B,KAAK,OAAO,GAAG;AAC9C;AAEA,MAAM,0BACJ,KACA,OACA,KACA,aACS;CACT,MAAM,UAAU,OAAO,kBAAkB,iBAAiB,CAAC,CAAC,MAAM,OAAO;CACzE,QAAQ,MAAM,MAAd;EACE,KAAK,0BAA0B;GAC7B,MAAM,UAAU,OAAO,kBAAkB,yBAAyB,CAAC,CAAC,QAAQ,OAAO;GACnF,MAAM,YAAY,QAAQ;GAC1B,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MAAM,2CAA2C;GAE7D,IAAI,KACF;;;;;;;;;;;;;WAcA,WACA,KACA,YACA,QAAQ,kBAAkB,MAC1B,QACF;GACA;EACF;EACA,KAAK;GACH,mBAAmB,KAAK,QAAQ,WAAW,KAAK,WAAW,QAAQ;GACnE;EACF,KAAK;GACH,mBAAmB,KAAK,QAAQ,WAAW,KAAK,aAAa,QAAQ;GACrE;EACF,KAAK;GACH,mBAAmB,KAAK,QAAQ,WAAW,KAAK,UAAU,QAAQ;GAClE;EACF,KAAK;GACH,mBAAmB,KAAK,QAAQ,WAAW,KAAK,aAAa,QAAQ;GACrE;EACF,SACE;CACJ;AACF;AAEA,MAAM,sBACJ,KACA,WACA,KACA,QACA,gBACS;CACT,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MAAM,GAAG,OAAO,iCAAiC;CAE7D,IAAI,KACF;;;;;;;;;;;OAYA,WACA,KACA,QACA,WACF;AACF;AAEA,MAAM,+BACJ,KACA,OACA,QACS;CACT,IAAI,MAAM,SAAS,0BACjB;CAEF,MAAM,UAAU,OAAO,WAAW,oBAAoB,CAAC,CAAC,KAAK;CAC7D,MAAM,EAAE,YAAY,OAAO,kBACzB,OAAO,OAAO,EAAE,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,EAAE,CAAC,CACzE,CAAC,CAAC,QAAQ,OAAO;CACjB,MAAM,YAAY,SAAS;CAC3B,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MAAM,2CAA2C;CAE7D,IAAI,KACF;;;;;;;;;OAUA,WACA,KACA,uBAAuB,SAAS,kCAAkC,CACpE;AACF;AAEA,MAAM,2CAA2B,IAAI,IAAY;CAC/C;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,0BACJ,KACA,OACA,QACS;CACT,IAAI,CAAC,yBAAyB,IAAI,MAAM,IAAI,GAC1C;CAGF,MAAM,UAAU,OAAO,WAAW,oBAAoB,CAAC,CAAC,KAAK;CAC7D,MAAM,EAAE,cAAc,OAAO,kBAAkB,OAAO,OAAO,EAAE,WAAW,OAAO,QAAQ,CAAC,CAAC,CAAC,CAC1F,QAAQ,OACV;CACA,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MAAM,GAAG,MAAM,KAAK,mBAAmB;CAGnD,IAAI,KACF;;;;;;;;;OAUA,WACA,KACA,uBAAuB,QAAQ,SAAS,oCAAoC,CAC9E;AACF;;;;;;;AAQA,MAAM,0BACJ,KACA,OACA,QACS;CACT,IAAI,MAAM,SAAS,yBACjB;CAGF,MAAM,UAAU,OAAO,kBAAkB,qBAAqB,CAAC,CAAC,MAAM,OAAO;CAC7E,MAAM,YAAY,QAAQ;CAC1B,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MAAM,kCAAkC;CAEpD,IAAI,QAAQ,YAAY,KAAA,GACtB,MAAM,IAAI,MAAM,yCAAyC;CAG3D,MAAM,UAAU,OAAO,kBAAkB,yBAAyB,CAAC,CAAC,QAAQ,OAAO;CACnF,IAAI,QAAQ,cAAc,WACxB,MAAM,IAAI,MAAM,yDAAyD;CAE3E,IAAI,QAAQ,iBAAiB,QAAQ,cACnC,MAAM,IAAI,MAAM,4DAA4D;CAG9E,IAAI,KACF;;;;;;;;;OAUA,WACA,KACA,uBAAuB,SAAS,qCAAqC,CACvE;AACF;;AAGA,MAAM,gCACJ,KACA,OACA,SACS;CACT,IAAI,MAAM,SAAS,yBACjB;CAGF,MAAM,UAAU,OAAO,kBAAkB,qBAAqB,CAAC,CAAC,MAAM,OAAO;CAC7E,IAAI,QAAQ,cAAc,KAAA,GACxB,MAAM,IAAI,MAAM,kCAAkC;CAEpD,MAAM,UAAU,2BAA2B,KAAK,UAAU,KAAK,OAAO,QAAQ,SAAS,CAAC,CAAC;CACzF,IAAI,YAAY,KAAA,GACd,MAAM,IAAI,MAAM,+CAA+C,OAAO,QAAQ,SAAS,GAAG;CAE5F,IAAI,QAAQ,iBAAiB,QAAQ,cACnC,MAAM,IAAI,MAAM,kEAAkE;CAEpF,IAAI,QAAQ,2BAA2B,QAAQ,wBAC7C,MAAM,IAAI,MAAM,+DAA+D;AAEnF;;;;;;;AAQA,MAAM,2BACJ,KACA,WACA,mBAC8C;CAC9C,IAAI,mBAAmB,KAAA,GAAW;EAChC,MAAM,MAAM,IACT,KACC;;;;WAKA,cACF,CAAC,CACA,QAAQ,CAAC,CAAC;EACb,IAAI,QAAQ,KAAA,GACV,OAAO;CAEX;CAEA,IAAI,cAAc,KAAA,GAChB;CAEF,OAAO,IACJ,KACC;;;;SAKA,SACF,CAAC,CACA,QAAQ,CAAC,CAAC;AACf;AAEA,MAAM,qBAAqB,WAAmB,UAC5C,IAAI,qBAAqB,EACvB,SACE,iBAAiB,QAAQ,GAAG,UAAU,IAAI,MAAM,YAAY,GAAG,UAAU,IAAI,OAAO,KAAK,IAC7F,CAAC"}
@@ -1,12 +1,19 @@
1
- import { a as SessionOutcomeInput, i as SessionGrantRunInput, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as edaSessionRpc, t as SessionBatchInput } from "./rpc-spec-C8wknrbN.js";
2
- import { i as EDASessionControllerOptions, l as EDAWebSocketProjection } from "./session-controller-DoeFP_Ej.js";
1
+ import { a as DurableObjectTranscriptObserver, c as TranscriptAlert } from "./durable-object-storage-D3muKtpz.js";
2
+ import { a as SessionOutcomeInput, i as SessionGrantRunInput, l as edaSessionRpc, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as SessionTranscriptWindowInput, t as SessionBatchInput } from "./rpc-spec-BTVd02Rg.js";
3
+ import { d as EDAWebSocketProjection, i as EDASessionControllerOptions, l as EDATranscriptSocketOptions } from "./session-controller-D8uXDKVG.js";
3
4
  import * as Schema from "effect/Schema";
4
5
  import { CommittedDurableEvent } from "effect-durable-agent/services/session-store";
5
6
  import { EDARuntimeConfig } from "effect-durable-agent/services/runtime";
7
+ import { TranscriptMaintenanceConfig } from "effect-durable-agent/transcript";
6
8
  import { DurableObject } from "cloudflare:workers";
7
9
  //#region src/durable-object.d.ts
8
10
  /** Internal Worker-to-object header selecting an app-owned WebSocket projection. */
9
11
  declare const EDA_WEB_SOCKET_PROJECTION_HEADER = "x-eda-websocket-projection";
12
+ /**
13
+ * Upgrade query parameter selecting the socket's stream: `transcript` selects the ordered
14
+ * transcript-window stream; anything else keeps the raw event stream.
15
+ */
16
+ declare const EDA_WEB_SOCKET_STREAM_PARAM = "stream";
10
17
  /** Encoded session RPC inputs, decoded before invoking the controller. */
11
18
  type EDASessionCommandRpcInput = typeof SessionCommandInput.Encoded;
12
19
  type EDASessionGrantRunRpcInput = typeof SessionGrantRunInput.Encoded;
@@ -28,9 +35,38 @@ interface EDASessionRpcSurface {
28
35
  readonly snapshot: (input: EDASessionScopedRpcInput) => Promise<typeof edaSessionRpc.snapshot.output.Encoded>;
29
36
  readonly messages: (input: EDASessionScopedRpcInput) => Promise<typeof edaSessionRpc.messages.output.Encoded>;
30
37
  readonly destroySession: (input: EDASessionScopedRpcInput) => Promise<typeof edaSessionRpc.destroySession.output.Encoded>;
38
+ readonly transcriptStatus: (input: EDASessionScopedRpcInput) => Promise<typeof edaSessionRpc.transcriptStatus.output.Encoded>;
39
+ readonly readTranscriptWindow: (input: typeof SessionTranscriptWindowInput.Encoded) => Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded>;
40
+ }
41
+ /** Host transcript configuration of a session Durable Object. */
42
+ interface EDASessionTranscriptOptions {
43
+ /**
44
+ * The transcript definitions this release carries. Defaults to the definition with no host
45
+ * mappings. A host changing its mappings ships `current` = new, `previous` = old, then runs
46
+ * its backfill through `transcriptStatus` (see `docs/transcript-history.md` §7).
47
+ */
48
+ readonly definitions?: TranscriptMaintenanceConfig;
49
+ /**
50
+ * Adopt the host's existing log incarnation from this `ctx.storage.kv` key (Gia:
51
+ * `gia.log_incarnation`). Without it the adapter mints its own.
52
+ */
53
+ readonly adoptIncarnationKey?: string;
54
+ /** Alerts (frozen versions, missed sessions). Defaults to `console.error`. */
55
+ readonly onAlert?: (alert: TranscriptAlert) => void;
56
+ /** A rebuilt version became active. */
57
+ readonly onActivated?: DurableObjectTranscriptObserver["onActivated"];
31
58
  }
32
59
  /** Constructor options for concrete app subclasses of the EDA Durable Object base. */
33
- type EDASessionDurableObjectOptions<ProjectionState extends object = never> = Omit<EDASessionControllerOptions<ProjectionState>, "background" | "getWebSockets" | "storage">;
60
+ type EDASessionDurableObjectOptions<ProjectionState extends object = never> = Omit<EDASessionControllerOptions<ProjectionState>, "alarmStorage" | "background" | "getWebSockets" | "storage" | "transcript" | "transcriptSockets"> & {
61
+ readonly transcript?: EDASessionTranscriptOptions;
62
+ /**
63
+ * Serve transcript-window sockets (`?stream=transcript`). `transcriptStore` defaults to this
64
+ * object's own runtime-free Durable Object transcript store.
65
+ */
66
+ readonly transcriptSockets?: Omit<EDATranscriptSocketOptions, "transcriptStore"> & {
67
+ readonly transcriptStore?: EDATranscriptSocketOptions["transcriptStore"];
68
+ };
69
+ };
34
70
  /** Resolve a concrete EDA session Durable Object binding by domain session id. */
35
71
  declare const getEDASessionDurableObjectByName: <T extends Rpc.DurableObjectBranded & EDASessionRpcSurface>(namespace: DurableObjectNamespace<T>, sessionId: string) => DurableObjectStub<T>;
36
72
  /**
@@ -59,7 +95,26 @@ declare abstract class EDASessionDurableObject<EnvType extends object = object,
59
95
  webSocketClose(webSocket: WebSocket, _code: number, _reason: string, _wasClean: boolean): Promise<void>;
60
96
  webSocketError(webSocket: WebSocket, _error: unknown): Promise<void>;
61
97
  destroySession(raw: typeof SessionScopedInput.Encoded): Promise<typeof edaSessionRpc.destroySession.output.Encoded>;
98
+ /**
99
+ * Storage-only backfill entry point: advance pending transcript build work by bounded slices
100
+ * and return the transcript status. It never starts the model runtime, reducers or sinks.
101
+ */
102
+ transcriptStatus(raw: typeof SessionScopedInput.Encoded): Promise<typeof edaSessionRpc.transcriptStatus.output.Encoded>;
103
+ /** Runtime-free transcript window read for SSR and CLIs. Hosts authorize the caller. */
104
+ readTranscriptWindow(raw: typeof SessionTranscriptWindowInput.Encoded): Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded>;
105
+ /**
106
+ * The alarm is shared by the runtime heartbeat and the transcript builder. A builder wakeup
107
+ * runs storage-only slices; the runtime runs only for its own wakeup, or for an alarm neither
108
+ * owner recorded (one armed before wakeups were recorded).
109
+ */
62
110
  alarm(): Promise<void>;
111
+ private transcriptOptions;
112
+ /** This object's transcript store as the port transcript sockets read, resolved per call. */
113
+ private transcriptPort;
114
+ /** The transcript service of this object's session, created on first use. */
115
+ private transcriptFor;
116
+ /** The transcript service when the object is named by a valid session id. */
117
+ private objectTranscript;
63
118
  private parseSessionId;
64
119
  private sessionIdFromObjectName;
65
120
  }
@@ -2595,5 +2650,5 @@ declare const encodeEdaRpcSessionSnapshot: (input: {
2595
2650
  })[];
2596
2651
  };
2597
2652
  //#endregion
2598
- export { EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionEventsRpcInput, EDASessionGrantRunRpcInput, EDASessionRpcSurface, EDASessionRunRequestOutcomeRpcInput, EDASessionScopedRpcInput, EDASessionSubmitBatchRpcInput, type EDAWebSocketProjection, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
2653
+ export { EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionEventsRpcInput, EDASessionGrantRunRpcInput, EDASessionRpcSurface, EDASessionRunRequestOutcomeRpcInput, EDASessionScopedRpcInput, EDASessionSubmitBatchRpcInput, EDASessionTranscriptOptions, type EDAWebSocketProjection, EDA_WEB_SOCKET_PROJECTION_HEADER, EDA_WEB_SOCKET_STREAM_PARAM, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
2599
2654
  //# sourceMappingURL=durable-object.d.ts.map
@@ -1,207 +1,2 @@
1
- import { a as SessionOutcomeInput, f as encodeEdaRpcDurableEvent, i as SessionGrantRunInput, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as edaSessionRpc, t as SessionBatchInput } from "./rpc-spec-CkWEeWJG.js";
2
- import { t as EDASessionController } from "./session-controller-BGfz1DdS.js";
3
- import * as Effect from "effect/Effect";
4
- import { durableEventEnvelope } from "effect-durable-agent/types/events/durable";
5
- import * as Schema from "effect/Schema";
6
- import { CommandId, RunRequestId, SequenceNumber, SessionId } from "effect-durable-agent/types/core";
7
- import { EDATraceMetadata, makeEDATraceMetadataFromParent, makeRootEDATraceMetadata, parseEDATraceparent } from "effect-durable-agent/types/tracing";
8
- import { DurableObject } from "cloudflare:workers";
9
- import { EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE } from "effect-durable-agent/websocket";
10
- //#region src/durable-object.ts
11
- /** Internal Worker-to-object header selecting an app-owned WebSocket projection. */
12
- const EDA_WEB_SOCKET_PROJECTION_HEADER = "x-eda-websocket-projection";
13
- /** Resolve a concrete EDA session Durable Object binding by domain session id. */
14
- const getEDASessionDurableObjectByName = (namespace, sessionId) => namespace.getByName(sessionId);
15
- /**
16
- * Base class for raw Cloudflare Durable Object hosts of one EDA session.
17
- *
18
- * Concrete products should extend this class, pass provider/tool layers from
19
- * their own constructor, and register only that subclass in Wrangler. The base
20
- * class is deliberately not exported from `workers/app.ts` and owns no binding
21
- * name or routing convention.
22
- */
23
- var EDASessionDurableObject = class extends DurableObject {
24
- #controller;
25
- #webSocketProjectionId;
26
- constructor(ctx, env, options) {
27
- super(ctx, env);
28
- this.#webSocketProjectionId = options.webSocketProjection?.id;
29
- const storage = toEDASessionStorage(this.ctx.storage);
30
- this.#controller = new EDASessionController({
31
- ...options,
32
- background: this.ctx,
33
- getWebSockets: () => this.ctx.getWebSockets(),
34
- storage
35
- });
36
- this.ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair(EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE));
37
- this.ctx.blockConcurrencyWhile(async () => {
38
- await Effect.runPromise(EDASessionController.migrate(storage));
39
- });
40
- }
41
- async fetch(request) {
42
- if (request.headers.get("Upgrade")?.toLowerCase() !== "websocket") return new Response("Expected WebSocket upgrade.", { status: 426 });
43
- const url = new URL(request.url);
44
- const sessionIdRaw = url.searchParams.get("sessionId");
45
- if (sessionIdRaw === null) return new Response("Missing sessionId.", { status: 400 });
46
- const afterSeqRaw = url.searchParams.get("afterSeq");
47
- const afterSeq = afterSeqRaw === null ? void 0 : Number(afterSeqRaw);
48
- if (afterSeq !== void 0 && (!Number.isInteger(afterSeq) || afterSeq < 0)) return new Response("Invalid afterSeq.", { status: 400 });
49
- const projectionId = request.headers.get("x-eda-websocket-projection") ?? void 0;
50
- if (projectionId !== void 0 && projectionId !== this.#webSocketProjectionId) return new Response("Unsupported WebSocket projection.", { status: 400 });
51
- const sessionId = this.parseSessionId(sessionIdRaw);
52
- const trace = traceMetadataFromRequest(request);
53
- const prepared = await this.#controller.prepareEventWebSocket({
54
- ...afterSeq === void 0 ? {} : { afterSeq: SequenceNumber.make(afterSeq) },
55
- sessionId,
56
- trace,
57
- ...projectionId === void 0 ? {} : { projectionId }
58
- });
59
- const pair = new WebSocketPair();
60
- const client = pair[0];
61
- const server = pair[1];
62
- this.ctx.acceptWebSocket(server);
63
- await this.#controller.acceptPreparedEventWebSocket({
64
- ...prepared,
65
- webSocket: server
66
- });
67
- return new Response(null, {
68
- status: 101,
69
- webSocket: client
70
- });
71
- }
72
- async submit(raw) {
73
- const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);
74
- const committed = await this.#controller.submit({
75
- command: input.command,
76
- sessionId: this.parseSessionId(input.sessionId),
77
- trace: decodeTraceMetadata(input.trace)
78
- });
79
- return encodeEdaRpcCommittedDurableEvent(committed);
80
- }
81
- /** Reconcile lost grant replies from durable request and run facts. */
82
- async runRequestOutcome(raw) {
83
- const input = Schema.decodeUnknownSync(SessionOutcomeInput)(raw);
84
- const result = await this.#controller.runRequestOutcome({
85
- requestId: Schema.decodeUnknownSync(RunRequestId)(input.requestId),
86
- sessionId: this.parseSessionId(input.sessionId),
87
- trace: decodeTraceMetadata(input.trace)
88
- });
89
- return Schema.encodeSync(edaSessionRpc.runRequestOutcome.output)(result);
90
- }
91
- /** Trusted RPC only: the calling Worker owns scheduler authentication and authorization. */
92
- async grantRun(raw) {
93
- const input = Schema.decodeUnknownSync(SessionGrantRunInput)(raw);
94
- const command = input.command;
95
- const result = await this.#controller.grantRun({
96
- command,
97
- sessionId: this.parseSessionId(input.sessionId),
98
- trace: decodeTraceMetadata(input.trace)
99
- });
100
- return Schema.encodeSync(edaSessionRpc.grantRun.output)(result);
101
- }
102
- async submitBatch(raw) {
103
- const input = Schema.decodeUnknownSync(SessionBatchInput)(raw);
104
- return (await this.#controller.submitBatch({
105
- items: input.items,
106
- sessionId: this.parseSessionId(input.sessionId),
107
- trace: decodeTraceMetadata(input.trace)
108
- })).map(encodeEdaRpcCommittedDurableEvent);
109
- }
110
- async submitAndBlock(raw) {
111
- const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);
112
- const committed = await this.#controller.submitAndBlock({
113
- command: input.command,
114
- sessionId: this.parseSessionId(input.sessionId),
115
- trace: decodeTraceMetadata(input.trace)
116
- });
117
- return Schema.encodeSync(edaSessionRpc.submitAndBlock.output)(committed);
118
- }
119
- async blockOnCommand(raw) {
120
- const input = Schema.decodeUnknownSync(SessionBlockInput)(raw);
121
- const committed = await this.#controller.blockOnCommand({
122
- ...input.afterSeq === void 0 ? {} : { afterSeq: SequenceNumber.make(input.afterSeq) },
123
- commandId: CommandId.make(input.commandId),
124
- sessionId: this.parseSessionId(input.sessionId),
125
- trace: decodeTraceMetadata(input.trace)
126
- });
127
- return Schema.encodeSync(edaSessionRpc.blockOnCommand.output)(committed);
128
- }
129
- async snapshot(raw) {
130
- const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
131
- const snapshot = await this.#controller.snapshot({
132
- sessionId: this.parseSessionId(input.sessionId),
133
- trace: decodeTraceMetadata(input.trace)
134
- });
135
- return Schema.encodeSync(edaSessionRpc.snapshot.output)(snapshot);
136
- }
137
- async messages(raw) {
138
- const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
139
- const result = await this.#controller.messages({
140
- sessionId: this.parseSessionId(input.sessionId),
141
- trace: decodeTraceMetadata(input.trace)
142
- });
143
- return Schema.encodeSync(edaSessionRpc.messages.output)(result);
144
- }
145
- async webSocketMessage(webSocket, message) {
146
- await this.#controller.webSocketMessage(webSocket, message);
147
- }
148
- async webSocketClose(webSocket, _code, _reason, _wasClean) {
149
- this.#controller.webSocketClose(webSocket);
150
- }
151
- async webSocketError(webSocket, _error) {
152
- this.#controller.webSocketError(webSocket);
153
- }
154
- async destroySession(raw) {
155
- const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
156
- await this.#controller.destroy({
157
- sessionId: this.parseSessionId(input.sessionId),
158
- trace: decodeTraceMetadata(input.trace)
159
- });
160
- await this.ctx.storage.deleteAlarm();
161
- await this.ctx.storage.deleteAll();
162
- }
163
- async alarm() {
164
- const sessionId = this.sessionIdFromObjectName();
165
- await this.#controller.alarm(sessionId === void 0 ? void 0 : {
166
- sessionId,
167
- trace: makeRootEDATraceMetadata()
168
- });
169
- }
170
- parseSessionId(input) {
171
- const sessionId = SessionId.make(input);
172
- const objectName = this.ctx.id.name;
173
- if (objectName !== void 0 && objectName !== sessionId) throw new Error(`EDA Durable Object name ${objectName} cannot serve session ${sessionId}`);
174
- return sessionId;
175
- }
176
- sessionIdFromObjectName() {
177
- return this.ctx.id.name === void 0 ? void 0 : SessionId.make(this.ctx.id.name);
178
- }
179
- };
180
- const toEDASessionStorage = (storage) => {
181
- return storage;
182
- };
183
- const decodeTraceMetadata = (input) => Schema.decodeUnknownSync(EDATraceMetadata)(input);
184
- const traceMetadataFromRequest = (request) => {
185
- const parent = parseEDATraceparent(request.headers.get("traceparent"), request.headers.get("tracestate"));
186
- return parent === null ? makeRootEDATraceMetadata() : makeEDATraceMetadataFromParent(parent);
187
- };
188
- /** Convenience config constructor for subclasses that need only provider/model ids. */
189
- const edaRuntimeConfig = (input) => ({
190
- modelSelection: {
191
- modelId: input.modelId,
192
- provider: input.provider
193
- },
194
- ...input.maxToolCallsPerRun === void 0 ? {} : { maxToolCallsPerRun: input.maxToolCallsPerRun },
195
- ...input.systemPrompt === void 0 ? {} : { systemPrompt: input.systemPrompt }
196
- });
197
- /** Encode committed events into the existing structured-clone envelope. */
198
- const encodeEdaRpcCommittedDurableEvent = (entry) => ({
199
- position: entry.position,
200
- event: encodeEdaRpcDurableEvent(durableEventEnvelope(entry.event))
201
- });
202
- /** Encode query snapshots without asserting that encoded command values are decoded classes. */
203
- const encodeEdaRpcSessionSnapshot = Schema.encodeSync(edaSessionRpc.snapshot.output);
204
- //#endregion
205
- export { EDASessionDurableObject, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
206
-
207
- //# sourceMappingURL=durable-object.js.map
1
+ import { a as encodeEdaRpcCommittedDurableEvent, i as edaRuntimeConfig, n as EDA_WEB_SOCKET_PROJECTION_HEADER, o as encodeEdaRpcSessionSnapshot, r as EDA_WEB_SOCKET_STREAM_PARAM, s as getEDASessionDurableObjectByName, t as EDASessionDurableObject } from "./durable-object-BZJM3RyV.js";
2
+ export { EDASessionDurableObject, EDA_WEB_SOCKET_PROJECTION_HEADER, EDA_WEB_SOCKET_STREAM_PARAM, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };