effect-durable-agent-cloudflare 0.1.0-alpha.24 → 0.1.0-alpha.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{durable-object-BZJM3RyV.js → durable-object-CkrxIOH4.js} +190 -40
- package/dist/durable-object-CkrxIOH4.js.map +1 -0
- package/dist/{durable-object-storage-D3muKtpz.d.ts → durable-object-storage-BVsu5oAV.d.ts} +21 -1
- package/dist/{durable-object-store-Dct3N6rk.js → durable-object-store-Ca0pvpa_.js} +100 -17
- package/dist/durable-object-store-Ca0pvpa_.js.map +1 -0
- package/dist/durable-object.d.ts +41 -6
- package/dist/durable-object.js +1 -1
- package/dist/index.d.ts +54 -13
- package/dist/index.js +5 -5
- package/dist/{rpc-spec-B5cL83zd.js → rpc-spec-BupIkBhI.js} +125 -17
- package/dist/rpc-spec-BupIkBhI.js.map +1 -0
- package/dist/{rpc-spec-BTVd02Rg.d.ts → rpc-spec-CwehaLCd.d.ts} +191 -7
- package/dist/rpc.d.ts +2 -2
- package/dist/rpc.js +2 -2
- package/dist/{session-controller-D8uXDKVG.d.ts → session-controller-D0PxLJJ9.d.ts} +9 -4
- package/dist/{session-controller-DoUy9zR6.js → session-controller-KWMuKhlX.js} +3 -3
- package/dist/session-controller-KWMuKhlX.js.map +1 -0
- package/dist/session-controller.d.ts +1 -1
- package/dist/session-controller.js +1 -1
- package/dist/storage.d.ts +1 -1
- package/package.json +2 -2
- package/dist/durable-object-BZJM3RyV.js.map +0 -1
- package/dist/durable-object-store-Dct3N6rk.js.map +0 -1
- package/dist/rpc-spec-B5cL83zd.js.map +0 -1
- package/dist/session-controller-DoUy9zR6.js.map +0 -1
|
@@ -87,6 +87,11 @@ const transcriptTableStatements = [
|
|
|
87
87
|
at_ms INTEGER NOT NULL
|
|
88
88
|
)`
|
|
89
89
|
];
|
|
90
|
+
/**
|
|
91
|
+
* Migration 3: consecutive failed builder slices of a slot (a build freezes after the configured
|
|
92
|
+
* limit), and consecutive failures of an alarm owner's work (an owner stops after the limit).
|
|
93
|
+
*/
|
|
94
|
+
const builderFailureColumnStatements = ["ALTER TABLE _eda_transcript_meta ADD COLUMN slice_failures INTEGER NOT NULL DEFAULT 0", "ALTER TABLE _eda_alarm_wakeups ADD COLUMN failures INTEGER NOT NULL DEFAULT 0"];
|
|
90
95
|
const decodeVersion = Schema.decodeUnknownSync(TranscriptVersion);
|
|
91
96
|
const decodeSlot = (row) => {
|
|
92
97
|
if (row.role !== "active" && row.role !== "building" && row.role !== "retired") throw new Error(`transcript slot ${row.slot} has unknown role ${row.role}`);
|
|
@@ -96,6 +101,7 @@ const decodeSlot = (row) => {
|
|
|
96
101
|
version: decodeVersion(row.version),
|
|
97
102
|
role: row.role,
|
|
98
103
|
cursor: SequenceNumber.make(row.cursor),
|
|
104
|
+
sliceFailures: row.slice_failures,
|
|
99
105
|
status: row.status === "failed" ? {
|
|
100
106
|
_tag: "Failed",
|
|
101
107
|
failedAtSeq: SequenceNumber.make(row.failed_at_seq ?? 0),
|
|
@@ -104,7 +110,7 @@ const decodeSlot = (row) => {
|
|
|
104
110
|
};
|
|
105
111
|
};
|
|
106
112
|
/** Every stored slot, in creation order. */
|
|
107
|
-
const readTranscriptSlots = (sql) => sql.exec("SELECT slot, version, role, cursor, status, failed_at_seq, error FROM _eda_transcript_meta ORDER BY slot").toArray().map(decodeSlot);
|
|
113
|
+
const readTranscriptSlots = (sql) => sql.exec("SELECT slot, version, role, cursor, status, failed_at_seq, error, slice_failures FROM _eda_transcript_meta ORDER BY slot").toArray().map(decodeSlot);
|
|
108
114
|
/** The port's view of a slot; retired slots have none. */
|
|
109
115
|
const transcriptVersionMetaOf = (slot) => slot.role === "retired" ? void 0 : {
|
|
110
116
|
version: slot.version,
|
|
@@ -118,6 +124,10 @@ const insertTranscriptSlot = (sql, version, role) => {
|
|
|
118
124
|
const setTranscriptSlotRole = (sql, slot, role) => {
|
|
119
125
|
sql.exec("UPDATE _eda_transcript_meta SET role = ? WHERE slot = ?", role, slot);
|
|
120
126
|
};
|
|
127
|
+
/** Record how many consecutive builder slices threw while targeting a slot. */
|
|
128
|
+
const setTranscriptSliceFailures = (sql, slot, failures) => {
|
|
129
|
+
sql.exec("UPDATE _eda_transcript_meta SET slice_failures = ? WHERE slot = ?", failures, slot);
|
|
130
|
+
};
|
|
121
131
|
/** Freeze a slot at its unchanged cursor. A failed slot is never written again. */
|
|
122
132
|
const markTranscriptSlotFailed = (sql, slot, failedAtSeq, error) => {
|
|
123
133
|
sql.exec("UPDATE _eda_transcript_meta SET status = 'failed', failed_at_seq = ?, error = ? WHERE slot = ?", failedAtSeq, error, slot);
|
|
@@ -254,6 +264,13 @@ const makeTranscriptWindowSource = (sql, incarnation, slot, carried) => {
|
|
|
254
264
|
const mintUuidV7 = () => Effect.runSync(Effect.gen(function* () {
|
|
255
265
|
return yield* (yield* IdGenerator).makeCorrelationId();
|
|
256
266
|
}).pipe(Effect.provide(IdGenerator.Live)));
|
|
267
|
+
/** Read this log's incarnation (or the host's adoptable value) without minting one. */
|
|
268
|
+
const readLogIncarnation = (sql, adopt) => {
|
|
269
|
+
const row = sql.exec("SELECT incarnation FROM _eda_log_incarnation WHERE id = 1").toArray()[0];
|
|
270
|
+
if (row !== void 0) return TranscriptLogIncarnation.make(row.incarnation);
|
|
271
|
+
const adopted = adopt?.kv.get(adopt.key);
|
|
272
|
+
return typeof adopted === "string" && adopted.length > 0 ? TranscriptLogIncarnation.make(adopted) : void 0;
|
|
273
|
+
};
|
|
257
274
|
/**
|
|
258
275
|
* Read this log's incarnation, minting one on first need. The caller runs it inside a
|
|
259
276
|
* `transactionSync`, so read-or-mint is atomic; storage wipes delete the row and so mint anew.
|
|
@@ -272,7 +289,17 @@ const readOrMintLogIncarnation = (sql, adopt) => {
|
|
|
272
289
|
const defaultTranscriptSliceLimits = {
|
|
273
290
|
maxEvents: 512,
|
|
274
291
|
pageEvents: 16,
|
|
275
|
-
maxDeletedRows: 2e3
|
|
292
|
+
maxDeletedRows: 2e3,
|
|
293
|
+
maxSliceFailures: 5
|
|
294
|
+
};
|
|
295
|
+
/** Merge host limits over the defaults; every limit must be a positive integer. */
|
|
296
|
+
const resolveTranscriptSliceLimits = (limits) => {
|
|
297
|
+
const resolved = {
|
|
298
|
+
...defaultTranscriptSliceLimits,
|
|
299
|
+
...Object.fromEntries(Object.entries(limits ?? {}).filter(([, value]) => value !== void 0))
|
|
300
|
+
};
|
|
301
|
+
for (const [name, value] of Object.entries(resolved)) if (!Number.isInteger(value) || value < 1) throw new Error(`transcript slice limit ${name} must be a positive integer; got ${value}`);
|
|
302
|
+
return resolved;
|
|
276
303
|
};
|
|
277
304
|
const emptyTranscriptEffects = () => ({
|
|
278
305
|
alerts: [],
|
|
@@ -293,6 +320,7 @@ const publishTranscriptEffects = (observer, effects) => {
|
|
|
293
320
|
for (const alert of effects.alerts) notify(() => observer?.onAlert?.(alert));
|
|
294
321
|
const activated = effects.activated;
|
|
295
322
|
if (activated !== void 0) notify(() => observer?.onActivated?.(activated));
|
|
323
|
+
if (effects.servedChanged === true) notify(() => observer?.onServedChanged?.());
|
|
296
324
|
if (effects.pendingWork) notify(() => observer?.onPendingWork?.());
|
|
297
325
|
};
|
|
298
326
|
/** The carried definition for a stored version, if this release still carries it. */
|
|
@@ -353,6 +381,7 @@ const supportsNestedTransactions = (storage) => {
|
|
|
353
381
|
const freezeSlot = (storage, slot, failedAtSeq, cause, effects) => {
|
|
354
382
|
const error = cause instanceof Error ? cause.message : String(cause);
|
|
355
383
|
markTranscriptSlotFailed(storage.sql, slot.slot, failedAtSeq, error);
|
|
384
|
+
if (slot.role === "active") effects.servedChanged = true;
|
|
356
385
|
if (slot.role !== "retired") effects.alerts.push({
|
|
357
386
|
_tag: "ProjectionFailed",
|
|
358
387
|
version: slot.version,
|
|
@@ -466,18 +495,24 @@ const runTranscriptSlice = (storage, config, log, limits, effects) => {
|
|
|
466
495
|
const definition = carriedDefinition(config, target.version);
|
|
467
496
|
let slot = target;
|
|
468
497
|
let remaining = limits.maxEvents;
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
498
|
+
try {
|
|
499
|
+
while (definition !== void 0 && slot.status._tag === "Ok" && slot.cursor < head && remaining > 0) {
|
|
500
|
+
let page;
|
|
501
|
+
try {
|
|
502
|
+
page = log.after(slot.cursor, Math.min(limits.pageEvents, remaining));
|
|
503
|
+
} catch (cause) {
|
|
504
|
+
slot = freezeSlot(storage, slot, SequenceNumber.make(slot.cursor + 1), cause, effects);
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
if (page.length === 0) break;
|
|
508
|
+
remaining -= page.length;
|
|
509
|
+
slot = advanceSlot(storage, slot, definition, page, effects);
|
|
476
510
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
slot = advanceSlot(storage, slot, definition, page, effects);
|
|
511
|
+
} catch (cause) {
|
|
512
|
+
throw new TranscriptBuildSliceError(cause);
|
|
480
513
|
}
|
|
514
|
+
if (target.role === "active" && target.cursor < head && slot.status._tag === "Ok" && slot.cursor === log.head()) effects.servedChanged = true;
|
|
515
|
+
if (target.sliceFailures > 0) setTranscriptSliceFailures(sql, target.slot, 0);
|
|
481
516
|
if (slot.role === "building" && slot.status._tag === "Ok" && slot.cursor === log.head()) {
|
|
482
517
|
const previous = slots.find((candidate) => candidate.role === "active");
|
|
483
518
|
if (previous !== void 0) setTranscriptSlotRole(sql, previous.slot, "retired");
|
|
@@ -495,6 +530,37 @@ const runTranscriptSlice = (storage, config, log, limits, effects) => {
|
|
|
495
530
|
}
|
|
496
531
|
return hasPendingTranscriptWork(storage, config, log.head());
|
|
497
532
|
};
|
|
533
|
+
/** A builder slice threw while advancing its build target; the cause is the original error. */
|
|
534
|
+
var TranscriptBuildSliceError = class extends Error {
|
|
535
|
+
cause;
|
|
536
|
+
name = "TranscriptBuildSliceError";
|
|
537
|
+
constructor(cause) {
|
|
538
|
+
super(cause instanceof Error ? cause.message : String(cause), { cause });
|
|
539
|
+
this.cause = cause;
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
/**
|
|
543
|
+
* Record a builder slice that threw while advancing its build target (its own transaction rolled
|
|
544
|
+
* back), in a new transaction.
|
|
545
|
+
*
|
|
546
|
+
* The slice's build target counts the failure; at `maxSliceFailures` consecutive failures it is
|
|
547
|
+
* frozen as failed at its cursor and alerted, so it is never retried, as the design requires of a
|
|
548
|
+
* failed build. Returns whether a version was frozen.
|
|
549
|
+
*/
|
|
550
|
+
const recordTranscriptSliceFailure = (storage, config, log, limits, cause, effects) => {
|
|
551
|
+
const head = log.head();
|
|
552
|
+
reconcileTranscriptSlots(storage, config, head, effects);
|
|
553
|
+
const target = buildTarget(config, liveSlots(storage), head);
|
|
554
|
+
if (target === void 0) return false;
|
|
555
|
+
const failures = target.sliceFailures + 1;
|
|
556
|
+
if (failures < limits.maxSliceFailures) {
|
|
557
|
+
setTranscriptSliceFailures(storage.sql, target.slot, failures);
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
setTranscriptSliceFailures(storage.sql, target.slot, failures);
|
|
561
|
+
freezeSlot(storage, target, SequenceNumber.make(target.cursor + 1), cause, effects);
|
|
562
|
+
return true;
|
|
563
|
+
};
|
|
498
564
|
//#endregion
|
|
499
565
|
//#region src/durable-object-store.ts
|
|
500
566
|
const ProjectionPayload = Schema.Record(Schema.String, Schema.Unknown);
|
|
@@ -506,6 +572,8 @@ const AdmittedCommandProjection = Schema.Struct({
|
|
|
506
572
|
const durableObjectSessionStoreSchemaVersion = 1;
|
|
507
573
|
/** Forward migration adding the transcript projection, log incarnation and alarm wakeups. */
|
|
508
574
|
const durableObjectTranscriptSchemaVersion = 2;
|
|
575
|
+
/** Forward migration adding the consecutive-failure counts that bound builder retries. */
|
|
576
|
+
const durableObjectBuilderFailuresSchemaVersion = 3;
|
|
509
577
|
/**
|
|
510
578
|
* Bound one synchronous DO SQLite event-log read/decode to a small CPU and memory slice.
|
|
511
579
|
*
|
|
@@ -634,6 +702,10 @@ const migrateDurableObjectSessionStore = (storage) => Effect.try({
|
|
|
634
702
|
for (const statement of transcriptTableStatements) sql.exec(statement);
|
|
635
703
|
sql.exec("INSERT INTO _eda_schema_migrations (id) VALUES (?)", durableObjectTranscriptSchemaVersion);
|
|
636
704
|
}
|
|
705
|
+
if (currentVersion < durableObjectBuilderFailuresSchemaVersion) {
|
|
706
|
+
for (const statement of builderFailureColumnStatements) sql.exec(statement);
|
|
707
|
+
sql.exec("INSERT INTO _eda_schema_migrations (id) VALUES (?)", durableObjectBuilderFailuresSchemaVersion);
|
|
708
|
+
}
|
|
637
709
|
}),
|
|
638
710
|
catch: (error) => durableStoreError("migrating DurableObjectSessionStore", error)
|
|
639
711
|
});
|
|
@@ -844,13 +916,24 @@ const readMessagePayloadByContextSeq = (sql, contextSeq) => {
|
|
|
844
916
|
if (message === void 0) throw new Error(`Context message at seq ${contextSeq} missing from _eda_context_messages`);
|
|
845
917
|
return message;
|
|
846
918
|
};
|
|
847
|
-
|
|
919
|
+
/**
|
|
920
|
+
* One committed event by seq, or `undefined` when the log has none there. Storage-only: hosts
|
|
921
|
+
* resolve transcript body references through it without starting the runtime.
|
|
922
|
+
*/
|
|
923
|
+
const readDurableObjectCommittedEvent = (sql, sessionId, seq) => {
|
|
848
924
|
const row = sql.exec(`
|
|
849
925
|
SELECT seq, event_id, namespace, type, schema_version, created_at_ms, trace_json, fact_json
|
|
850
926
|
FROM _eda_event_log
|
|
851
927
|
WHERE seq = ?
|
|
852
|
-
`, seq).
|
|
853
|
-
return rowToCommittedDurableEvent(sql, row, sessionId);
|
|
928
|
+
`, seq).toArray()[0];
|
|
929
|
+
return row === void 0 ? void 0 : rowToCommittedDurableEvent(sql, row, sessionId);
|
|
930
|
+
};
|
|
931
|
+
/** One compaction summary artifact by id, or `undefined`. Storage-only. */
|
|
932
|
+
const readDurableObjectSummary = (sql, summaryId) => readSummaryPayloadOptional(sql, summaryId);
|
|
933
|
+
const readCommittedBySeq = (sql, sessionId, seq) => {
|
|
934
|
+
const committed = readDurableObjectCommittedEvent(sql, sessionId, seq);
|
|
935
|
+
if (committed === void 0) throw new Error(`no committed event at seq ${seq}`);
|
|
936
|
+
return committed;
|
|
854
937
|
};
|
|
855
938
|
const rowToCommittedDurableEvent = (sql, row, sessionId) => ({
|
|
856
939
|
position: durablePosition(SequenceNumber.make(row.seq)),
|
|
@@ -1143,6 +1226,6 @@ const findCommandAdmissionRow = (sql, commandId, idempotencyKey) => {
|
|
|
1143
1226
|
};
|
|
1144
1227
|
const durableStoreError = (operation, cause) => new EDASessionStoreError({ message: cause instanceof Error ? `${operation}: ${cause.message}` : `${operation}: ${String(cause)}` });
|
|
1145
1228
|
//#endregion
|
|
1146
|
-
export {
|
|
1229
|
+
export { makeTranscriptWindowSource as _, TranscriptBuildSliceError as a, readTranscriptSlots as b, emptyTranscriptEffects as c, publishTranscriptEffects as d, reconcileTranscriptSlots as f, TranscriptRowDecodeError as g, runTranscriptSlice as h, readDurableObjectSummary as i, hasPendingTranscriptWork as l, resolveTranscriptSliceLimits as m, makeDurableObjectEventLog as n, carriedDefinition as o, recordTranscriptSliceFailure as p, readDurableObjectCommittedEvent as r, defaultTranscriptSliceLimits as s, DurableObjectSessionStore as t, missedSessionAlert as u, readLogIncarnation as v, transcriptVersionMetaOf as x, readOrMintLogIncarnation as y };
|
|
1147
1230
|
|
|
1148
|
-
//# sourceMappingURL=durable-object-store-
|
|
1231
|
+
//# sourceMappingURL=durable-object-store-Ca0pvpa_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"durable-object-store-Ca0pvpa_.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/**\n * Migration 3: consecutive failed builder slices of a slot (a build freezes after the configured\n * limit), and consecutive failures of an alarm owner's work (an owner stops after the limit).\n */\nexport const builderFailureColumnStatements: ReadonlyArray<string> = [\n \"ALTER TABLE _eda_transcript_meta ADD COLUMN slice_failures INTEGER NOT NULL DEFAULT 0\",\n \"ALTER TABLE _eda_alarm_wakeups ADD COLUMN failures INTEGER NOT NULL DEFAULT 0\",\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 /** Consecutive builder slices that threw while this slot was their target. */\n readonly sliceFailures: number;\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 readonly slice_failures: number;\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 sliceFailures: row.slice_failures,\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, slice_failures 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/** Record how many consecutive builder slices threw while targeting a slot. */\nexport const setTranscriptSliceFailures = (\n sql: DurableObjectSqlStorage,\n slot: number,\n failures: number,\n): void => {\n sql.exec(\"UPDATE _eda_transcript_meta SET slice_failures = ? WHERE slot = ?\", failures, 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/** Read this log's incarnation (or the host's adoptable value) without minting one. */\nexport const readLogIncarnation = (\n sql: DurableObjectSqlStorage,\n adopt: AdoptedLogIncarnation | undefined,\n): TranscriptLogIncarnation | undefined => {\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 return typeof adopted === \"string\" && adopted.length > 0\n ? TranscriptLogIncarnation.make(adopted)\n : undefined;\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 setTranscriptSliceFailures,\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 * - `BuilderStopped`: the builder alarm failed `consecutiveFailures` times in a row, typically\n * for a reason no build is charged for (cleanup or reconciliation, or a failure record storage\n * refused), so the builder stopped scheduling itself. A later object start, `transcriptStatus`\n * call or pending-work kick tries again, bounded the same way, and may raise it again.\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 readonly _tag: \"BuilderStopped\";\n readonly consecutiveFailures: number;\n readonly error: string;\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 * What reads serve changed without a publication, so connected clients need a re-read: an\n * active version that was behind the head (a re-enabled session) reached it (`UpdatingHistory`\n * becomes `Ready`), or the active version froze (it becomes `Degraded`).\n */\n readonly onServedChanged?: () => 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 * Consecutive slices that may throw while advancing one build target before it is frozen as\n * failed (and so never retried). The session object also stops its builder alarm after this\n * many consecutive failed alarms.\n */\n readonly maxSliceFailures: number;\n}\n\nexport const defaultTranscriptSliceLimits: DurableObjectTranscriptSliceLimits = {\n maxEvents: 512,\n pageEvents: 16,\n maxDeletedRows: 2_000,\n maxSliceFailures: 5,\n};\n\n/** Merge host limits over the defaults; every limit must be a positive integer. */\nexport const resolveTranscriptSliceLimits = (\n limits: Partial<DurableObjectTranscriptSliceLimits> | undefined,\n): DurableObjectTranscriptSliceLimits => {\n // An explicit `undefined` keeps the default, as the optional type promises.\n const resolved = {\n ...defaultTranscriptSliceLimits,\n ...Object.fromEntries(Object.entries(limits ?? {}).filter(([, value]) => value !== undefined)),\n };\n for (const [name, value] of Object.entries(resolved)) {\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`transcript slice limit ${name} must be a positive integer; got ${value}`);\n }\n }\n return resolved;\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 /** What reads serve changed without a publication (see `onServedChanged`). */\n servedChanged?: boolean;\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.servedChanged === true) notify(() => observer?.onServedChanged?.());\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 // A frozen active version reads as degraded from now on.\n if (slot.role === \"active\") effects.servedChanged = true;\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 try {\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 } catch (cause) {\n // Only a failure while advancing the target is charged to it (see\n // `recordTranscriptSliceFailure`); reconciliation and cleanup failures are not.\n throw new TranscriptBuildSliceError(cause);\n }\n if (\n target.role === \"active\" &&\n target.cursor < head &&\n slot.status._tag === \"Ok\" &&\n slot.cursor === log.head()\n ) {\n // An active version behind the head (a re-enabled session) is current again.\n effects.servedChanged = true;\n }\n // A slice that completes resets its target's consecutive failures.\n if (target.sliceFailures > 0) setTranscriptSliceFailures(sql, target.slot, 0);\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\n/** A builder slice threw while advancing its build target; the cause is the original error. */\nexport class TranscriptBuildSliceError extends Error {\n override readonly name = \"TranscriptBuildSliceError\";\n constructor(override readonly cause: unknown) {\n super(cause instanceof Error ? cause.message : String(cause), { cause });\n }\n}\n\n/**\n * Record a builder slice that threw while advancing its build target (its own transaction rolled\n * back), in a new transaction.\n *\n * The slice's build target counts the failure; at `maxSliceFailures` consecutive failures it is\n * frozen as failed at its cursor and alerted, so it is never retried, as the design requires of a\n * failed build. Returns whether a version was frozen.\n */\nexport const recordTranscriptSliceFailure = (\n storage: DurableObjectSessionStorage,\n config: TranscriptMaintenanceConfig,\n log: TranscriptEventLog,\n limits: DurableObjectTranscriptSliceLimits,\n cause: unknown,\n effects: TranscriptEffects,\n): boolean => {\n // The failed slice's own reconciliation rolled back with it; redo it so its target exists.\n const head = log.head();\n reconcileTranscriptSlots(storage, config, head, effects);\n const target = buildTarget(config, liveSlots(storage), head);\n if (target === undefined) return false;\n const failures = target.sliceFailures + 1;\n if (failures < limits.maxSliceFailures) {\n setTranscriptSliceFailures(storage.sql, target.slot, failures);\n return false;\n }\n setTranscriptSliceFailures(storage.sql, target.slot, failures);\n freezeSlot(storage, target, SequenceNumber.make(target.cursor + 1), cause, effects);\n return true;\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 {\n builderFailureColumnStatements,\n transcriptTableStatements,\n} 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/** Forward migration adding the consecutive-failure counts that bound builder retries. */\nconst durableObjectBuilderFailuresSchemaVersion = 3;\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 if (currentVersion < durableObjectBuilderFailuresSchemaVersion) {\n for (const statement of builderFailureColumnStatements) sql.exec(statement);\n sql.exec(\n \"INSERT INTO _eda_schema_migrations (id) VALUES (?)\",\n durableObjectBuilderFailuresSchemaVersion,\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\n/**\n * One committed event by seq, or `undefined` when the log has none there. Storage-only: hosts\n * resolve transcript body references through it without starting the runtime.\n */\nexport const readDurableObjectCommittedEvent = (\n sql: DurableObjectSqlStorage,\n sessionId: SessionId,\n seq: number,\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 seq = ?\n `,\n seq,\n )\n .toArray()[0];\n return row === undefined ? undefined : rowToCommittedDurableEvent(sql, row, sessionId);\n};\n\n/** One compaction summary artifact by id, or `undefined`. Storage-only. */\nexport const readDurableObjectSummary = (\n sql: DurableObjectSqlStorage,\n summaryId: SummaryId,\n): CompactionSummaryArtifact | undefined => readSummaryPayloadOptional(sql, summaryId);\n\nconst readCommittedBySeq = (\n sql: DurableObjectSqlStorage,\n sessionId: SessionId,\n seq: number,\n): CommittedDurableEvent => {\n const committed = readDurableObjectCommittedEvent(sql, sessionId, seq);\n if (committed === undefined) throw new Error(`no committed event at seq ${seq}`);\n return committed;\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;;;;;AAMA,MAAa,iCAAwD,CACnE,yFACA,+EACF;AA2BA,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,eAAe,IAAI;EACnB,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,0HACF,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,8BACX,KACA,MACA,aACS;CACT,IAAI,KAAK,qEAAqE,UAAU,IAAI;AAC9F;;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;;AAGF,MAAa,sBACX,KACA,UACyC;CACzC,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,OAAO,OAAO,YAAY,YAAY,QAAQ,SAAS,IACnD,yBAAyB,KAAK,OAAO,IACrC,KAAA;AACN;;;;;AAMA,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;;;ACncA,MAAa,+BAAmE;CAC9E,WAAW;CACX,YAAY;CACZ,gBAAgB;CAChB,kBAAkB;AACpB;;AAGA,MAAa,gCACX,WACuC;CAEvC,MAAM,WAAW;EACf,GAAG;EACH,GAAG,OAAO,YAAY,OAAO,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,CAAC;CAC/F;CACA,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,QAAQ,GACjD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,MAAM,IAAI,MAAM,0BAA0B,KAAK,mCAAmC,OAAO;CAG7F,OAAO;AACT;AA+BA,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,kBAAkB,MAAM,aAAa,UAAU,kBAAkB,CAAC;CAC9E,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;CAEnE,IAAI,KAAK,SAAS,UAAU,QAAQ,gBAAgB;CACpD,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,IAAI;GACF,OACE,eAAe,KAAA,KACf,KAAK,OAAO,SAAS,QACrB,KAAK,SAAS,QACd,YAAY,GACZ;IACA,IAAI;IACJ,IAAI;KACF,OAAO,IAAI,MAAM,KAAK,QAAQ,KAAK,IAAI,OAAO,YAAY,SAAS,CAAC;IACtE,SAAS,OAAO;KAGd,OAAO,WAAW,SAAS,MAAM,eAAe,KAAK,KAAK,SAAS,CAAC,GAAG,OAAO,OAAO;KACrF;IACF;IACA,IAAI,KAAK,WAAW,GAAG;IACvB,aAAa,KAAK;IAClB,OAAO,YAAY,SAAS,MAAM,YAAY,MAAM,OAAO;GAC7D;EACF,SAAS,OAAO;GAGd,MAAM,IAAI,0BAA0B,KAAK;EAC3C;EACA,IACE,OAAO,SAAS,YAChB,OAAO,SAAS,QAChB,KAAK,OAAO,SAAS,QACrB,KAAK,WAAW,IAAI,KAAK,GAGzB,QAAQ,gBAAgB;EAG1B,IAAI,OAAO,gBAAgB,GAAG,2BAA2B,KAAK,OAAO,MAAM,CAAC;EAC5E,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;;AAGA,IAAa,4BAAb,cAA+C,MAAM;CAErB;CAD9B,OAAyB;CACzB,YAAY,OAAkC;EAC5C,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,EAAE,MAAM,CAAC;EAD3C,KAAA,QAAA;CAE9B;AACF;;;;;;;;;AAUA,MAAa,gCACX,SACA,QACA,KACA,QACA,OACA,YACY;CAEZ,MAAM,OAAO,IAAI,KAAK;CACtB,yBAAyB,SAAS,QAAQ,MAAM,OAAO;CACvD,MAAM,SAAS,YAAY,QAAQ,UAAU,OAAO,GAAG,IAAI;CAC3D,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,MAAM,WAAW,OAAO,gBAAgB;CACxC,IAAI,WAAW,OAAO,kBAAkB;EACtC,2BAA2B,QAAQ,KAAK,OAAO,MAAM,QAAQ;EAC7D,OAAO;CACT;CACA,2BAA2B,QAAQ,KAAK,OAAO,MAAM,QAAQ;CAC7D,WAAW,SAAS,QAAQ,eAAe,KAAK,OAAO,SAAS,CAAC,GAAG,OAAO,OAAO;CAClF,OAAO;AACT;;;AC3bA,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;;AAE7C,MAAM,4CAA4C;;;;;;;;;AAUlD,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;EAEA,IAAI,iBAAiB,2CAA2C;GAC9D,KAAK,MAAM,aAAa,gCAAgC,IAAI,KAAK,SAAS;GAC1E,IAAI,KACF,sDACA,yCACF;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;;;;;AAMA,MAAa,mCACX,KACA,WACA,QACsC;CACtC,MAAM,MAAM,IACT,KACC;;;;SAKA,GACF,CAAC,CACA,QAAQ,CAAC,CAAC;CACb,OAAO,QAAQ,KAAA,IAAY,KAAA,IAAY,2BAA2B,KAAK,KAAK,SAAS;AACvF;;AAGA,MAAa,4BACX,KACA,cAC0C,2BAA2B,KAAK,SAAS;AAErF,MAAM,sBACJ,KACA,WACA,QAC0B;CAC1B,MAAM,YAAY,gCAAgC,KAAK,WAAW,GAAG;CACrE,IAAI,cAAc,KAAA,GAAW,MAAM,IAAI,MAAM,6BAA6B,KAAK;CAC/E,OAAO;AACT;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"}
|
package/dist/durable-object.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { a as DurableObjectTranscriptObserver, c as TranscriptAlert } from "./durable-object-storage-
|
|
2
|
-
import { a as SessionOutcomeInput, i as SessionGrantRunInput, l as edaSessionRpc, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as
|
|
3
|
-
import { d as EDAWebSocketProjection, i as EDASessionControllerOptions, l as EDATranscriptSocketOptions } from "./session-controller-
|
|
1
|
+
import { a as DurableObjectTranscriptObserver, c as TranscriptAlert, s as DurableObjectTranscriptSliceLimits } from "./durable-object-storage-BVsu5oAV.js";
|
|
2
|
+
import { a as SessionOutcomeInput, d as SessionTranscriptWindowInput, i as SessionGrantRunInput, l as SessionTranscriptSummaryInput, m as edaSessionRpc, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as SessionTranscriptBodyInput, t as SessionBatchInput } from "./rpc-spec-CwehaLCd.js";
|
|
3
|
+
import { d as EDAWebSocketProjection, i as EDASessionControllerOptions, l as EDATranscriptSocketOptions } from "./session-controller-D0PxLJJ9.js";
|
|
4
4
|
import * as Schema from "effect/Schema";
|
|
5
|
+
import { SessionId } from "effect-durable-agent/types/core";
|
|
5
6
|
import { CommittedDurableEvent } from "effect-durable-agent/services/session-store";
|
|
6
7
|
import { EDARuntimeConfig } from "effect-durable-agent/services/runtime";
|
|
7
8
|
import { TranscriptMaintenanceConfig } from "effect-durable-agent/transcript";
|
|
@@ -37,9 +38,28 @@ interface EDASessionRpcSurface {
|
|
|
37
38
|
readonly destroySession: (input: EDASessionScopedRpcInput) => Promise<typeof edaSessionRpc.destroySession.output.Encoded>;
|
|
38
39
|
readonly transcriptStatus: (input: EDASessionScopedRpcInput) => Promise<typeof edaSessionRpc.transcriptStatus.output.Encoded>;
|
|
39
40
|
readonly readTranscriptWindow: (input: typeof SessionTranscriptWindowInput.Encoded) => Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded>;
|
|
41
|
+
readonly readTranscriptBody: (input: typeof SessionTranscriptBodyInput.Encoded) => Promise<typeof edaSessionRpc.readTranscriptBody.output.Encoded>;
|
|
42
|
+
readonly readTranscriptSummary: (input: typeof SessionTranscriptSummaryInput.Encoded) => Promise<typeof edaSessionRpc.readTranscriptSummary.output.Encoded>;
|
|
40
43
|
}
|
|
41
44
|
/** Host transcript configuration of a session Durable Object. */
|
|
42
45
|
interface EDASessionTranscriptOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Which sessions maintain a transcript; default **off**. A disabled session gets no transcript
|
|
48
|
+
* writes, builder slices or wakeups: `readTranscriptWindow` answers `Disabled`,
|
|
49
|
+
* `transcriptStatus` reports `Disabled` without writing, and transcript sockets are
|
|
50
|
+
* refused. Enabling a session takes the first-introduction path (a build from the log, then
|
|
51
|
+
* activation). Rollout rings use a deterministic predicate (for example a hash of the session
|
|
52
|
+
* id under a percentage); disabling leaves a session's rows untouched, and re-enabling catches
|
|
53
|
+
* an active version up to the head before it is served as current. Evaluated once per object
|
|
54
|
+
* instance, so a change takes effect when the object next starts.
|
|
55
|
+
*/
|
|
56
|
+
readonly enabled?: boolean | ((sessionId: SessionId) => boolean);
|
|
57
|
+
/**
|
|
58
|
+
* Builder bounds: events per slice, rows deleted per slice, and `maxSliceFailures` (default 5),
|
|
59
|
+
* the consecutive failures after which a build freezes as failed and a failing builder alarm
|
|
60
|
+
* stops scheduling itself.
|
|
61
|
+
*/
|
|
62
|
+
readonly sliceLimits?: Partial<DurableObjectTranscriptSliceLimits>;
|
|
43
63
|
/**
|
|
44
64
|
* The transcript definitions this release carries. Defaults to the definition with no host
|
|
45
65
|
* mappings. A host changing its mappings ships `current` = new, `previous` = old, then runs
|
|
@@ -103,18 +123,33 @@ declare abstract class EDASessionDurableObject<EnvType extends object = object,
|
|
|
103
123
|
/** Runtime-free transcript window read for SSR and CLIs. Hosts authorize the caller. */
|
|
104
124
|
readTranscriptWindow(raw: typeof SessionTranscriptWindowInput.Encoded): Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded>;
|
|
105
125
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
|
|
126
|
+
* Runtime-free read of the body a transcript `Ref` names, resolved through the immutable log
|
|
127
|
+
* (so it stays valid after projection rows are rebuilt). Hosts authorize the caller.
|
|
128
|
+
*/
|
|
129
|
+
readTranscriptBody(raw: typeof SessionTranscriptBodyInput.Encoded): Promise<typeof edaSessionRpc.readTranscriptBody.output.Encoded>;
|
|
130
|
+
/** Runtime-free read of a compaction summary's text. Hosts authorize the caller. */
|
|
131
|
+
readTranscriptSummary(raw: typeof SessionTranscriptSummaryInput.Encoded): Promise<typeof edaSessionRpc.readTranscriptSummary.output.Encoded>;
|
|
132
|
+
/**
|
|
133
|
+
* The alarm is shared by the runtime heartbeat and the transcript builder; see
|
|
134
|
+
* `runEDASessionAlarm`.
|
|
109
135
|
*/
|
|
110
136
|
alarm(): Promise<void>;
|
|
111
137
|
private transcriptOptions;
|
|
112
138
|
/** This object's transcript store as the port transcript sockets read, resolved per call. */
|
|
113
139
|
private transcriptPort;
|
|
140
|
+
/**
|
|
141
|
+
* The session and log a body or summary read may serve: pinned to the session this object's
|
|
142
|
+
* transcript serves, like window reads, and to the incarnation the caller's reference names.
|
|
143
|
+
*/
|
|
144
|
+
private transcriptReadScope;
|
|
114
145
|
/** The transcript service of this object's session, created on first use. */
|
|
115
146
|
private transcriptFor;
|
|
147
|
+
/** The transcript service when this object's session is enabled for maintenance. */
|
|
148
|
+
private maintainedTranscript;
|
|
116
149
|
/** The transcript service when the object is named by a valid session id. */
|
|
117
150
|
private objectTranscript;
|
|
151
|
+
/** `parseSessionId` for request paths that answer a foreign session with a 400. */
|
|
152
|
+
private parseSessionIdOrUndefined;
|
|
118
153
|
private parseSessionId;
|
|
119
154
|
private sessionIdFromObjectName;
|
|
120
155
|
}
|
package/dist/durable-object.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-CkrxIOH4.js";
|
|
2
2
|
export { EDASessionDurableObject, EDA_WEB_SOCKET_PROJECTION_HEADER, EDA_WEB_SOCKET_STREAM_PARAM, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
|