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.
@@ -1,15 +1,71 @@
1
- import { _ as encodeEdaRpcDurableEvent, a as SessionOutcomeInput, d as DurableObjectTranscriptStore, i as SessionGrantRunInput, l as edaSessionRpc, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as SessionTranscriptWindowInput, t as SessionBatchInput, u as DurableObjectTranscriptBuilder } from "./rpc-spec-B5cL83zd.js";
2
- import { t as EDASessionController } from "./session-controller-DoUy9zR6.js";
1
+ import { S as encodeEdaRpcDurableEvent, a as SessionOutcomeInput, d as SessionTranscriptWindowInput, g as DurableObjectTranscriptStore, h as DurableObjectTranscriptBuilder, 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-BupIkBhI.js";
2
+ import { i as readDurableObjectSummary, m as resolveTranscriptSliceLimits, r as readDurableObjectCommittedEvent, s as defaultTranscriptSliceLimits } from "./durable-object-store-Ca0pvpa_.js";
3
+ import { t as EDASessionController } from "./session-controller-KWMuKhlX.js";
3
4
  import * as Effect from "effect/Effect";
4
5
  import { durableEventEnvelope } from "effect-durable-agent/types/events/durable";
5
6
  import * as Schema from "effect/Schema";
6
7
  import { CommandId, RunRequestId, SequenceNumber, SessionId } from "effect-durable-agent/types/core";
7
8
  import { EDATraceMetadata, makeEDATraceMetadataFromParent, makeRootEDATraceMetadata, parseEDATraceparent } from "effect-durable-agent/types/tracing";
8
9
  import { EDASessionStoreError } from "effect-durable-agent/services/session-store";
9
- import { defaultTranscriptWindowLimits, emptyTranscriptMappings, makeTranscriptDefinition } from "effect-durable-agent/transcript";
10
+ import { defaultTranscriptWindowLimits, emptyTranscriptMappings, makeTranscriptDefinition, resolveTranscriptBody } from "effect-durable-agent/transcript";
10
11
  import * as Result from "effect/Result";
11
12
  import { DurableObject } from "cloudflare:workers";
12
13
  import { EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE } from "effect-durable-agent/websocket";
14
+ //#region src/durable-object-alarm-handler.ts
15
+ /** Longest delay between builder retries. */
16
+ const maxBuilderRetryDelayMs = 36e5;
17
+ /**
18
+ * Handle one platform alarm shared by the runtime and the transcript builder.
19
+ *
20
+ * - The runtime runs for its own wakeup, or for an alarm no owner recorded (one armed by a
21
+ * release before wakeups were recorded). The builder runs for its wakeup even when the runtime
22
+ * failed.
23
+ * - No wakeup is consumed up front: each owner's is cleared only after its work succeeds, so a
24
+ * handler that throws or dies mid-work leaves the platform's retry attributed to every owner it
25
+ * fired for.
26
+ * - A failed builder retries with exponential backoff; its consecutive failures persist with its
27
+ * wakeup, so eviction cannot reset them, and at `maxBuilderFailures` it stops scheduling itself.
28
+ * No failure re-arms the alarm sooner than the backoff, so no object can loop on its alarm.
29
+ * - A failed runtime rethrows without re-arming the platform alarm, so the platform's own retry
30
+ * (backoff and retry cap) applies; otherwise the alarm is pointed at the earliest wakeup left.
31
+ */
32
+ const runEDASessionAlarm = async (participants) => {
33
+ const { alarms } = participants;
34
+ const now = participants.now();
35
+ const due = alarms.due(now);
36
+ let runtimeFailure;
37
+ if (due.has("runtime") || due.size === 0) try {
38
+ await participants.runRuntime();
39
+ alarms.clearThrough("runtime", due.get("runtime") ?? now);
40
+ } catch (error) {
41
+ runtimeFailure = { error };
42
+ }
43
+ const builderWakeup = due.get("transcript");
44
+ if (builderWakeup !== void 0) {
45
+ const runBuilderSlices = participants.runBuilderSlices;
46
+ if (runBuilderSlices === void 0) alarms.clear("transcript");
47
+ else try {
48
+ if (await runBuilderSlices()) alarms.retain("transcript", participants.now());
49
+ else alarms.clearThrough("transcript", builderWakeup);
50
+ } catch (error) {
51
+ const consecutiveFailures = alarms.failures("transcript") + 1;
52
+ const stopped = consecutiveFailures >= participants.maxBuilderFailures;
53
+ if (stopped) alarms.clear("transcript");
54
+ else {
55
+ const delayMs = Math.min(participants.builderRetryDelayMs * 2 ** (consecutiveFailures - 1), maxBuilderRetryDelayMs);
56
+ alarms.retain("transcript", participants.now() + delayMs, consecutiveFailures);
57
+ }
58
+ participants.onBuilderFailure({
59
+ error,
60
+ consecutiveFailures,
61
+ stopped
62
+ });
63
+ }
64
+ }
65
+ if (runtimeFailure !== void 0) throw runtimeFailure.error;
66
+ await alarms.sync();
67
+ };
68
+ //#endregion
13
69
  //#region src/durable-object-alarms.ts
14
70
  /**
15
71
  * Shares one Durable Object alarm between owners that each keep a durable wakeup.
@@ -63,8 +119,16 @@ var DurableObjectAlarmScheduler = class {
63
119
  * caller syncs once at the end, or not at all when it rethrows, which leaves the platform's own
64
120
  * retry (with its backoff and cap) in force.
65
121
  */
66
- retain(owner, atMs) {
67
- this.#write(owner, atMs);
122
+ retain(owner, atMs, failures = 0) {
123
+ this.#write(owner, atMs, failures);
124
+ }
125
+ /** Consecutive failures recorded with `owner`'s wakeup; 0 without one. */
126
+ failures(owner) {
127
+ return this.storage.sql.exec("SELECT failures FROM _eda_alarm_wakeups WHERE owner = ?", owner).toArray()[0]?.failures ?? 0;
128
+ }
129
+ /** Remove `owner`'s wakeup whatever its time; call `sync` afterwards. */
130
+ clear(owner) {
131
+ this.#write(owner, void 0);
68
132
  }
69
133
  /** Wake `owner` no later than `atMs`; an earlier wakeup it already holds is kept. */
70
134
  request(owner, atMs) {
@@ -114,13 +178,19 @@ var DurableObjectAlarmScheduler = class {
114
178
  #wakeup(owner) {
115
179
  return this.storage.sql.exec("SELECT at_ms FROM _eda_alarm_wakeups WHERE owner = ?", owner).toArray()[0]?.at_ms;
116
180
  }
117
- #write(owner, atMs) {
181
+ /** Upsert or delete `owner`'s wakeup. Without `failures`, an existing count is kept. */
182
+ #write(owner, atMs, failures) {
118
183
  if (atMs === void 0) {
119
184
  this.storage.sql.exec("DELETE FROM _eda_alarm_wakeups WHERE owner = ?", owner);
120
185
  return;
121
186
  }
122
- this.storage.sql.exec(`INSERT INTO _eda_alarm_wakeups (owner, at_ms) VALUES (?, ?)
123
- ON CONFLICT(owner) DO UPDATE SET at_ms = excluded.at_ms`, owner, atMs);
187
+ if (failures === void 0) {
188
+ this.storage.sql.exec(`INSERT INTO _eda_alarm_wakeups (owner, at_ms) VALUES (?, ?)
189
+ ON CONFLICT(owner) DO UPDATE SET at_ms = excluded.at_ms`, owner, atMs);
190
+ return;
191
+ }
192
+ this.storage.sql.exec(`INSERT INTO _eda_alarm_wakeups (owner, at_ms, failures) VALUES (?, ?, ?)
193
+ ON CONFLICT(owner) DO UPDATE SET at_ms = excluded.at_ms, failures = excluded.failures`, owner, atMs, failures);
124
194
  }
125
195
  };
126
196
  const isOwner = (owner) => owner === "runtime" || owner === "transcript";
@@ -138,6 +208,8 @@ const transcriptStatusMaxSlices = 16;
138
208
  /** Server bounds on one `readTranscriptWindow` RPC, whatever limits the caller asks for. */
139
209
  const transcriptWindowMaxRecords = 500;
140
210
  const transcriptWindowMaxBytes = 8388608;
211
+ /** First retry delay after a failed builder alarm; doubled per consecutive failure. */
212
+ const transcriptBuilderRetryDelayMs = 3e4;
141
213
  /** Slices one builder alarm runs before rescheduling itself. */
142
214
  const transcriptAlarmMaxSlices = 4;
143
215
  /** Resolve a concrete EDA session Durable Object binding by domain session id. */
@@ -156,6 +228,7 @@ var EDASessionDurableObject = class extends DurableObject {
156
228
  #alarms;
157
229
  #transcriptOptions;
158
230
  #transcript;
231
+ #transcriptEnabled;
159
232
  constructor(ctx, env, options) {
160
233
  super(ctx, env);
161
234
  this.#webSocketProjectionId = options.webSocketProjection?.id;
@@ -164,13 +237,15 @@ var EDASessionDurableObject = class extends DurableObject {
164
237
  const { transcript: transcriptHostOptions, transcriptSockets, ...controllerOptions } = options;
165
238
  const transcript = this.transcriptOptions(transcriptHostOptions);
166
239
  this.#transcriptOptions = transcript;
240
+ const enabled = transcriptHostOptions?.enabled ?? false;
241
+ this.#transcriptEnabled = typeof enabled === "function" ? enabled : () => enabled;
167
242
  this.#controller = new EDASessionController({
168
243
  ...controllerOptions,
169
244
  alarmStorage: this.#alarms.owner("runtime"),
170
245
  background: this.ctx,
171
246
  getWebSockets: () => this.ctx.getWebSockets(),
172
247
  storage,
173
- transcript,
248
+ transcript: ({ sessionId }) => this.transcriptFor(sessionId).enabled ? transcript : void 0,
174
249
  ...transcriptSockets === void 0 ? {} : { transcriptSockets: {
175
250
  ...transcriptSockets,
176
251
  transcriptStore: transcriptSockets.transcriptStore ?? this.transcriptPort()
@@ -180,7 +255,7 @@ var EDASessionDurableObject = class extends DurableObject {
180
255
  this.ctx.blockConcurrencyWhile(async () => {
181
256
  await Effect.runPromise(EDASessionController.migrate(storage));
182
257
  await this.#alarms.adoptUnrecordedAlarm();
183
- await this.objectTranscript()?.builder.start();
258
+ await this.maintainedTranscript()?.builder.start();
184
259
  });
185
260
  }
186
261
  async fetch(request) {
@@ -193,11 +268,12 @@ var EDASessionDurableObject = class extends DurableObject {
193
268
  if (afterSeq !== void 0 && (!Number.isInteger(afterSeq) || afterSeq < 0)) return new Response("Invalid afterSeq.", { status: 400 });
194
269
  const projectionId = request.headers.get("x-eda-websocket-projection") ?? void 0;
195
270
  if (projectionId !== void 0 && projectionId !== this.#webSocketProjectionId) return new Response("Unsupported WebSocket projection.", { status: 400 });
196
- const sessionId = this.parseSessionId(sessionIdRaw);
271
+ const sessionId = this.parseSessionIdOrUndefined(sessionIdRaw);
272
+ if (sessionId === void 0) return new Response("This object does not serve that session.", { status: 400 });
197
273
  const trace = traceMetadataFromRequest(request);
198
274
  if (url.searchParams.get("stream") === "transcript") {
199
275
  if (projectionId !== void 0 || !this.#controller.supportsTranscriptWebSocket) return new Response("Unsupported transcript stream.", { status: 400 });
200
- this.transcriptFor(sessionId);
276
+ if (!this.transcriptFor(sessionId).enabled) return new Response("Transcript is not enabled for this session.", { status: 409 });
201
277
  const pair = new WebSocketPair();
202
278
  this.ctx.acceptWebSocket(pair[1]);
203
279
  this.#controller.acceptTranscriptWebSocket({
@@ -328,6 +404,7 @@ var EDASessionDurableObject = class extends DurableObject {
328
404
  async transcriptStatus(raw) {
329
405
  const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
330
406
  const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));
407
+ if (!transcript.enabled) return Schema.encodeSync(edaSessionRpc.transcriptStatus.output)(transcript.store.disabledStatus());
331
408
  await transcript.builder.run(transcriptStatusMaxSlices);
332
409
  return Schema.encodeSync(edaSessionRpc.transcriptStatus.output)(transcript.store.status());
333
410
  }
@@ -335,6 +412,7 @@ var EDASessionDurableObject = class extends DurableObject {
335
412
  async readTranscriptWindow(raw) {
336
413
  const input = Schema.decodeUnknownSync(SessionTranscriptWindowInput)(raw);
337
414
  const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));
415
+ if (!transcript.enabled) return Schema.encodeSync(edaSessionRpc.readTranscriptWindow.output)({ _tag: "Disabled" });
338
416
  const limits = input.limits ?? defaultTranscriptWindowLimits;
339
417
  const window = transcript.store.readWindow(input.selector, {
340
418
  ...limits,
@@ -350,37 +428,75 @@ var EDASessionDurableObject = class extends DurableObject {
350
428
  });
351
429
  }
352
430
  /**
353
- * The alarm is shared by the runtime heartbeat and the transcript builder. A builder wakeup
354
- * runs storage-only slices; the runtime runs only for its own wakeup, or for an alarm neither
355
- * owner recorded (one armed before wakeups were recorded).
431
+ * Runtime-free read of the body a transcript `Ref` names, resolved through the immutable log
432
+ * (so it stays valid after projection rows are rebuilt). Hosts authorize the caller.
433
+ */
434
+ async readTranscriptBody(raw) {
435
+ const input = Schema.decodeUnknownSync(SessionTranscriptBodyInput)(raw);
436
+ const scope = this.transcriptReadScope(input.sessionId, input.incarnation);
437
+ if (scope._tag !== "Scope") return Schema.encodeSync(edaSessionRpc.readTranscriptBody.output)(scope);
438
+ const sessionId = scope.sessionId;
439
+ const committed = readDurableObjectCommittedEvent(toEDASessionStorage(this.ctx.storage).sql, sessionId, input.source.seq);
440
+ const resolved = committed === void 0 ? {
441
+ _tag: "Missing",
442
+ message: `no event at seq ${input.source.seq}`
443
+ } : resolveTranscriptBody(committed.event, input.source.path);
444
+ return Schema.encodeSync(edaSessionRpc.readTranscriptBody.output)(resolved._tag === "Found" ? {
445
+ _tag: "Body",
446
+ value: resolved.value
447
+ } : {
448
+ _tag: "NotFound",
449
+ message: resolved.message
450
+ });
451
+ }
452
+ /** Runtime-free read of a compaction summary's text. Hosts authorize the caller. */
453
+ async readTranscriptSummary(raw) {
454
+ const input = Schema.decodeUnknownSync(SessionTranscriptSummaryInput)(raw);
455
+ const scope = this.transcriptReadScope(input.sessionId, input.incarnation);
456
+ if (scope._tag !== "Scope") return Schema.encodeSync(edaSessionRpc.readTranscriptSummary.output)(scope);
457
+ const artifact = readDurableObjectSummary(toEDASessionStorage(this.ctx.storage).sql, input.summaryId);
458
+ return Schema.encodeSync(edaSessionRpc.readTranscriptSummary.output)(artifact === void 0 ? {
459
+ _tag: "NotFound",
460
+ message: `no summary ${input.summaryId}`
461
+ } : {
462
+ _tag: "Summary",
463
+ summary: {
464
+ compactionId: artifact.compactionId,
465
+ summaryId: artifact.summaryId,
466
+ text: artifact.text,
467
+ sourceFromSeq: artifact.sourceFromSeq,
468
+ sourceToSeq: artifact.sourceToSeq
469
+ }
470
+ });
471
+ }
472
+ /**
473
+ * The alarm is shared by the runtime heartbeat and the transcript builder; see
474
+ * `runEDASessionAlarm`.
356
475
  */
357
476
  async alarm() {
358
- const now = Date.now();
359
- const due = this.#alarms.due(now);
360
- let runtimeFailure;
361
- if (due.has("runtime") || due.size === 0) {
362
- const sessionId = this.sessionIdFromObjectName();
363
- try {
477
+ const transcript = this.maintainedTranscript();
478
+ await runEDASessionAlarm({
479
+ alarms: this.#alarms,
480
+ now: () => Date.now(),
481
+ runRuntime: async () => {
482
+ const sessionId = this.sessionIdFromObjectName();
364
483
  await this.#controller.alarm(sessionId === void 0 ? void 0 : {
365
484
  sessionId,
366
485
  trace: makeRootEDATraceMetadata()
367
486
  });
368
- this.#alarms.clearThrough("runtime", due.get("runtime") ?? now);
369
- } catch (error) {
370
- runtimeFailure = { error };
487
+ },
488
+ runBuilderSlices: transcript === void 0 ? void 0 : () => transcript.builder.runSlices(transcriptAlarmMaxSlices),
489
+ maxBuilderFailures: this.#transcriptOptions.sliceLimits?.maxSliceFailures ?? defaultTranscriptSliceLimits.maxSliceFailures,
490
+ builderRetryDelayMs: transcriptBuilderRetryDelayMs,
491
+ onBuilderFailure: ({ error, consecutiveFailures, stopped }) => {
492
+ console.error("EDA transcript builder slice failed", error);
493
+ if (stopped) transcript?.store.alert({
494
+ _tag: "BuilderStopped",
495
+ consecutiveFailures,
496
+ error: error instanceof Error ? error.message : String(error)
497
+ });
371
498
  }
372
- }
373
- const builderWakeup = due.get("transcript");
374
- if (builderWakeup !== void 0) try {
375
- const builder = this.objectTranscript()?.builder;
376
- if (builder === void 0 ? false : await builder.runSlices(transcriptAlarmMaxSlices)) this.#alarms.retain("transcript", Date.now());
377
- else this.#alarms.clearThrough("transcript", builderWakeup);
378
- } catch (error) {
379
- console.error("EDA transcript builder slice failed", error);
380
- this.#alarms.retain("transcript", Date.now() + 3e4);
381
- }
382
- if (runtimeFailure !== void 0) throw runtimeFailure.error;
383
- await this.#alarms.sync();
499
+ });
384
500
  }
385
501
  transcriptOptions(options) {
386
502
  const key = options?.adoptIncarnationKey;
@@ -390,12 +506,16 @@ var EDASessionDurableObject = class extends DurableObject {
390
506
  key,
391
507
  kv: this.ctx.storage.kv
392
508
  } },
509
+ sliceLimits: resolveTranscriptSliceLimits(options?.sliceLimits),
393
510
  observer: {
394
511
  onAlert: options?.onAlert ?? ((alert) => console.error("EDA transcript alert", JSON.stringify(alert))),
395
512
  onPendingWork: () => {
396
- const builder = this.objectTranscript()?.builder;
513
+ const builder = this.maintainedTranscript()?.builder;
397
514
  if (builder !== void 0) this.ctx.waitUntil(builder.kick());
398
515
  },
516
+ onServedChanged: () => {
517
+ this.ctx.waitUntil(this.#controller.refreshTranscriptWebSockets());
518
+ },
399
519
  onActivated: (activation) => {
400
520
  this.ctx.waitUntil(this.#controller.refreshTranscriptWebSockets());
401
521
  options?.onActivated?.(activation);
@@ -405,13 +525,29 @@ var EDASessionDurableObject = class extends DurableObject {
405
525
  }
406
526
  /** This object's transcript store as the port transcript sockets read, resolved per call. */
407
527
  transcriptPort() {
408
- const port = () => this.objectTranscript()?.store.port;
409
- const unbound = () => Effect.fail(new EDASessionStoreError({ message: "EDA transcript read before the session was named" }));
528
+ const port = () => this.maintainedTranscript()?.store.port;
529
+ const unbound = () => Effect.fail(new EDASessionStoreError({ message: this.objectTranscript()?.enabled === false ? "EDA transcript is not enabled for this session" : "EDA transcript read before the session was named" }));
410
530
  return {
411
531
  readTranscriptWindow: (selector, limits) => Effect.suspend(() => port()?.readTranscriptWindow(selector, limits) ?? unbound()),
412
532
  readTranscriptMeta: Effect.suspend(() => port()?.readTranscriptMeta ?? unbound())
413
533
  };
414
534
  }
535
+ /**
536
+ * The session and log a body or summary read may serve: pinned to the session this object's
537
+ * transcript serves, like window reads, and to the incarnation the caller's reference names.
538
+ */
539
+ transcriptReadScope(rawSessionId, incarnation) {
540
+ const transcript = this.transcriptFor(this.parseSessionId(rawSessionId));
541
+ if (!transcript.enabled) return { _tag: "Disabled" };
542
+ const current = transcript.store.incarnation();
543
+ return incarnation === current ? {
544
+ _tag: "Scope",
545
+ sessionId: transcript.sessionId
546
+ } : {
547
+ _tag: "IncarnationMismatch",
548
+ incarnation: current
549
+ };
550
+ }
415
551
  /** The transcript service of this object's session, created on first use. */
416
552
  transcriptFor(sessionId) {
417
553
  if (this.#transcript !== void 0) {
@@ -426,17 +562,31 @@ var EDASessionDurableObject = class extends DurableObject {
426
562
  const builder = new DurableObjectTranscriptBuilder(store, () => this.#alarms.request("transcript", Date.now()));
427
563
  this.#transcript = {
428
564
  sessionId,
565
+ enabled: this.#transcriptEnabled(sessionId),
429
566
  store,
430
567
  builder
431
568
  };
432
569
  return this.#transcript;
433
570
  }
571
+ /** The transcript service when this object's session is enabled for maintenance. */
572
+ maintainedTranscript() {
573
+ const transcript = this.objectTranscript();
574
+ return transcript?.enabled === true ? transcript : void 0;
575
+ }
434
576
  /** The transcript service when the object is named by a valid session id. */
435
577
  objectTranscript() {
436
578
  if (this.#transcript !== void 0) return this.#transcript;
437
579
  const name = this.ctx.id.name;
438
580
  return name !== void 0 && Schema.is(SessionId)(name) ? this.transcriptFor(SessionId.make(name)) : void 0;
439
581
  }
582
+ /** `parseSessionId` for request paths that answer a foreign session with a 400. */
583
+ parseSessionIdOrUndefined(input) {
584
+ if (!Schema.is(SessionId)(input)) return void 0;
585
+ const name = this.ctx.id.name;
586
+ if (name !== void 0 && name !== input) return void 0;
587
+ const bound = this.#transcript?.sessionId;
588
+ return bound === void 0 || bound === input ? SessionId.make(input) : void 0;
589
+ }
440
590
  parseSessionId(input) {
441
591
  const sessionId = SessionId.make(input);
442
592
  const objectName = this.ctx.id.name;
@@ -474,4 +624,4 @@ const encodeEdaRpcSessionSnapshot = Schema.encodeSync(edaSessionRpc.snapshot.out
474
624
  //#endregion
475
625
  export { encodeEdaRpcCommittedDurableEvent as a, DurableObjectAlarmScheduler as c, edaRuntimeConfig as i, EDA_WEB_SOCKET_PROJECTION_HEADER as n, encodeEdaRpcSessionSnapshot as o, EDA_WEB_SOCKET_STREAM_PARAM as r, getEDASessionDurableObjectByName as s, EDASessionDurableObject as t };
476
626
 
477
- //# sourceMappingURL=durable-object-BZJM3RyV.js.map
627
+ //# sourceMappingURL=durable-object-CkrxIOH4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-object-CkrxIOH4.js","names":["#wakeup","#write","#rows","#tail","#controller","#webSocketProjectionId","#alarms","#transcriptOptions","#transcriptEnabled","#transcript"],"sources":["../src/durable-object-alarm-handler.ts","../src/durable-object-alarms.ts","../src/durable-object.ts"],"sourcesContent":["import type { DurableObjectAlarmScheduler } from \"./durable-object-alarms\";\n\n/** What one session object's alarm fires for, and the policy bounding builder retries. */\nexport interface EDASessionAlarmParticipants {\n readonly alarms: DurableObjectAlarmScheduler;\n readonly now: () => number;\n /** The runtime's alarm work: keep-alive and run-scheduling redelivery. */\n readonly runRuntime: () => Promise<void>;\n /**\n * Bounded builder slices; resolves whether work remains. Undefined when this object's session\n * maintains no transcript (it is not enabled, or the object is unnamed).\n */\n readonly runBuilderSlices: (() => Promise<boolean>) | undefined;\n /** Consecutive failed builder alarms before the builder stops scheduling itself. */\n readonly maxBuilderFailures: number;\n /** First retry delay after a failed builder alarm; doubled per consecutive failure. */\n readonly builderRetryDelayMs: number;\n readonly onBuilderFailure: (failure: {\n readonly error: unknown;\n readonly consecutiveFailures: number;\n readonly stopped: boolean;\n }) => void;\n}\n\n/** Longest delay between builder retries. */\nconst maxBuilderRetryDelayMs = 3_600_000;\n\n/**\n * Handle one platform alarm shared by the runtime and the transcript builder.\n *\n * - The runtime runs for its own wakeup, or for an alarm no owner recorded (one armed by a\n * release before wakeups were recorded). The builder runs for its wakeup even when the runtime\n * failed.\n * - No wakeup is consumed up front: each owner's is cleared only after its work succeeds, so a\n * handler that throws or dies mid-work leaves the platform's retry attributed to every owner it\n * fired for.\n * - A failed builder retries with exponential backoff; its consecutive failures persist with its\n * wakeup, so eviction cannot reset them, and at `maxBuilderFailures` it stops scheduling itself.\n * No failure re-arms the alarm sooner than the backoff, so no object can loop on its alarm.\n * - A failed runtime rethrows without re-arming the platform alarm, so the platform's own retry\n * (backoff and retry cap) applies; otherwise the alarm is pointed at the earliest wakeup left.\n */\nexport const runEDASessionAlarm = async (participants: EDASessionAlarmParticipants) => {\n const { alarms } = participants;\n const now = participants.now();\n const due = alarms.due(now);\n let runtimeFailure: { readonly error: unknown } | undefined;\n if (due.has(\"runtime\") || due.size === 0) {\n try {\n await participants.runRuntime();\n alarms.clearThrough(\"runtime\", due.get(\"runtime\") ?? now);\n } catch (error) {\n runtimeFailure = { error };\n }\n }\n const builderWakeup = due.get(\"transcript\");\n if (builderWakeup !== undefined) {\n const runBuilderSlices = participants.runBuilderSlices;\n if (runBuilderSlices === undefined) {\n alarms.clear(\"transcript\");\n } else {\n try {\n if (await runBuilderSlices()) alarms.retain(\"transcript\", participants.now());\n else alarms.clearThrough(\"transcript\", builderWakeup);\n } catch (error) {\n const consecutiveFailures = alarms.failures(\"transcript\") + 1;\n const stopped = consecutiveFailures >= participants.maxBuilderFailures;\n if (stopped) {\n alarms.clear(\"transcript\");\n } else {\n const delayMs = Math.min(\n participants.builderRetryDelayMs * 2 ** (consecutiveFailures - 1),\n maxBuilderRetryDelayMs,\n );\n alarms.retain(\"transcript\", participants.now() + delayMs, consecutiveFailures);\n }\n participants.onBuilderFailure({ error, consecutiveFailures, stopped });\n }\n }\n }\n if (runtimeFailure !== undefined) throw runtimeFailure.error;\n await alarms.sync();\n};\n","import type { DurableObjectAlarmStorage } from \"./durable-object-keepalive\";\nimport type { DurableObjectSessionStorage } from \"./durable-object-storage\";\n\n/**\n * The independent owners of a session object's single platform alarm.\n *\n * - `runtime`: the keep-alive heartbeat and run-scheduling redelivery; its wakeup builds the model\n * runtime.\n * - `transcript`: the transcript builder; its wakeup runs storage-only slices and must never\n * build the model runtime.\n */\nexport type DurableObjectAlarmOwner = \"runtime\" | \"transcript\";\n\n/**\n * Shares one Durable Object alarm between owners that each keep a durable wakeup.\n *\n * Each owner's wakeup is a row in `_eda_alarm_wakeups`, and the platform alarm is always set to the\n * earliest row, so no owner can delete or postpone another's wakeup, and after an eviction the\n * alarm handler still knows which owners it fired for. An owner's view (`owner(...)`) has the\n * same shape as the platform alarm API, so the keep-alive heartbeat uses it unchanged.\n */\nexport class DurableObjectAlarmScheduler {\n #tail: Promise<void> = Promise.resolve();\n\n constructor(\n private readonly storage: DurableObjectSessionStorage & DurableObjectAlarmStorage,\n private readonly now: () => number = () => Date.now(),\n ) {}\n\n /**\n * One owner's alarm, behaving like the platform alarm restricted to that owner. Like the\n * platform's, it reports no alarm once its time has passed: a wakeup left behind when the\n * platform gave up retrying a failed alarm must not look armed, or its owner would never re-arm.\n */\n owner(owner: DurableObjectAlarmOwner): DurableObjectAlarmStorage {\n return {\n getAlarm: () => {\n const wakeup = this.#wakeup(owner);\n return wakeup === undefined || wakeup < this.now() ? null : wakeup;\n },\n setAlarm: (scheduledTimeMs) => {\n this.#write(owner, scheduledTimeMs);\n return this.sync();\n },\n deleteAlarm: () => {\n this.#write(owner, undefined);\n return this.sync();\n },\n };\n }\n\n /**\n * Adopt a platform alarm no owner recorded (one armed before wakeups were recorded) as the\n * runtime's, so the first wakeup another owner requests cannot replace it. Call once at startup,\n * before any owner writes a wakeup.\n */\n async adoptUnrecordedAlarm(): Promise<void> {\n if (this.#rows().length > 0) return;\n const armed = await this.storage.getAlarm();\n if (armed !== null && this.#rows().length === 0) this.#write(\"runtime\", armed);\n }\n\n /**\n * Record `owner`'s wakeup without touching the platform alarm, for use inside `alarm()`: the\n * caller syncs once at the end, or not at all when it rethrows, which leaves the platform's own\n * retry (with its backoff and cap) in force.\n */\n retain(owner: DurableObjectAlarmOwner, atMs: number, failures = 0): void {\n this.#write(owner, atMs, failures);\n }\n\n /** Consecutive failures recorded with `owner`'s wakeup; 0 without one. */\n failures(owner: DurableObjectAlarmOwner): number {\n return (\n this.storage.sql\n .exec<{ readonly failures: number }>(\n \"SELECT failures FROM _eda_alarm_wakeups WHERE owner = ?\",\n owner,\n )\n .toArray()[0]?.failures ?? 0\n );\n }\n\n /** Remove `owner`'s wakeup whatever its time; call `sync` afterwards. */\n clear(owner: DurableObjectAlarmOwner): void {\n this.#write(owner, undefined);\n }\n\n /** Wake `owner` no later than `atMs`; an earlier wakeup it already holds is kept. */\n request(owner: DurableObjectAlarmOwner, atMs: number): Promise<void> {\n const current = this.#wakeup(owner);\n if (current !== undefined && current <= atMs) return this.sync();\n this.#write(owner, atMs);\n return this.sync();\n }\n\n /**\n * Called when the platform alarm fires: the owners it fired for (every wakeup at or before now,\n * and always the earliest one) and the wakeup each held. Nothing is consumed here: each owner\n * `clearThrough`s its wakeup only after its work succeeds, so a handler that throws, or dies\n * mid-work (eviction, deploy, a resource limit), leaves the platform's retry attributed to every\n * owner it fired for. An owner's view already reports a past wakeup as no alarm, so the runtime's\n * keep-alive re-arms during its work as it did with the platform alarm.\n */\n due(nowMs: number): ReadonlyMap<DurableObjectAlarmOwner, number> {\n const rows = this.#rows();\n const earliest = rows.reduce((min, row) => Math.min(min, row.at_ms), Number.POSITIVE_INFINITY);\n const threshold = Math.max(nowMs, earliest);\n const due = new Map<DurableObjectAlarmOwner, number>();\n for (const row of rows) {\n if (row.at_ms <= threshold && isOwner(row.owner)) due.set(row.owner, row.at_ms);\n }\n return due;\n }\n\n /**\n * Remove `owner`'s wakeup if it is still at or before `atMs`, once the work it fired for has\n * succeeded. A later wakeup the owner re-armed during that work is kept.\n */\n clearThrough(owner: DurableObjectAlarmOwner, atMs: number): void {\n this.storage.sql.exec(\n \"DELETE FROM _eda_alarm_wakeups WHERE owner = ? AND at_ms <= ?\",\n owner,\n atMs,\n );\n }\n\n /** Point the platform alarm at the earliest wakeup, or clear it when none remains. */\n sync(): Promise<void> {\n this.#tail = this.#tail\n .catch(() => undefined)\n .then(async () => {\n const earliest = this.storage.sql\n .exec<{ readonly at_ms: number | null }>(\n \"SELECT MIN(at_ms) AS at_ms FROM _eda_alarm_wakeups\",\n )\n .one().at_ms;\n if (earliest === null) {\n await this.storage.deleteAlarm();\n return;\n }\n if ((await this.storage.getAlarm()) !== earliest) {\n await this.storage.setAlarm(earliest);\n }\n });\n return this.#tail;\n }\n\n #rows(): ReadonlyArray<{ readonly owner: string; readonly at_ms: number }> {\n return this.storage.sql\n .exec<{ readonly owner: string; readonly at_ms: number }>(\n \"SELECT owner, at_ms FROM _eda_alarm_wakeups\",\n )\n .toArray();\n }\n\n #wakeup(owner: DurableObjectAlarmOwner): number | undefined {\n return this.storage.sql\n .exec<{ readonly at_ms: number }>(\n \"SELECT at_ms FROM _eda_alarm_wakeups WHERE owner = ?\",\n owner,\n )\n .toArray()[0]?.at_ms;\n }\n\n /** Upsert or delete `owner`'s wakeup. Without `failures`, an existing count is kept. */\n #write(owner: DurableObjectAlarmOwner, atMs: number | undefined, failures?: number): void {\n if (atMs === undefined) {\n this.storage.sql.exec(\"DELETE FROM _eda_alarm_wakeups WHERE owner = ?\", owner);\n return;\n }\n if (failures === undefined) {\n this.storage.sql.exec(\n `INSERT INTO _eda_alarm_wakeups (owner, at_ms) VALUES (?, ?)\n ON CONFLICT(owner) DO UPDATE SET at_ms = excluded.at_ms`,\n owner,\n atMs,\n );\n return;\n }\n this.storage.sql.exec(\n `INSERT INTO _eda_alarm_wakeups (owner, at_ms, failures) VALUES (?, ?, ?)\n ON CONFLICT(owner) DO UPDATE SET at_ms = excluded.at_ms, failures = excluded.failures`,\n owner,\n atMs,\n failures,\n );\n }\n}\n\nconst isOwner = (owner: string): owner is DurableObjectAlarmOwner =>\n owner === \"runtime\" || owner === \"transcript\";\n","import type { CommittedDurableEvent } from \"effect-durable-agent/services/session-store\";\nimport { durableEventEnvelope } from \"effect-durable-agent/types/events/durable\";\nimport { encodeEdaRpcDurableEvent } from \"./rpc-codec\";\nimport {\n SessionScopedInput,\n SessionTranscriptBodyInput,\n SessionTranscriptSummaryInput,\n SessionTranscriptWindowInput,\n SessionCommandInput,\n SessionGrantRunInput,\n SessionBatchInput,\n SessionBlockInput,\n SessionOutcomeInput,\n edaSessionRpc,\n} from \"./rpc-spec\";\nimport { DurableObject } from \"cloudflare:workers\";\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\n\nimport type { EDARuntimeConfig } from \"effect-durable-agent/services/runtime\";\nimport {\n CommandId,\n RunRequestId,\n SequenceNumber,\n SessionId,\n} from \"effect-durable-agent/types/core\";\nimport {\n EDATraceMetadata,\n makeEDATraceMetadataFromParent,\n makeRootEDATraceMetadata,\n parseEDATraceparent,\n} from \"effect-durable-agent/types/tracing\";\nimport {\n EDASessionController,\n type EDASessionControllerOptions,\n type EDASessionDurableObjectStorage,\n} from \"./session-controller\";\nimport {\n EDA_WEB_SOCKET_PING_MESSAGE,\n EDA_WEB_SOCKET_PONG_MESSAGE,\n} from \"effect-durable-agent/websocket\";\nimport * as Result from \"effect/Result\";\nimport {\n defaultTranscriptWindowLimits,\n emptyTranscriptMappings,\n makeTranscriptDefinition,\n resolveTranscriptBody,\n type EDATranscriptStoreShape,\n type TranscriptLogIncarnation,\n type TranscriptMaintenanceConfig,\n} from \"effect-durable-agent/transcript\";\nimport { runEDASessionAlarm } from \"./durable-object-alarm-handler\";\nimport { DurableObjectAlarmScheduler } from \"./durable-object-alarms\";\nimport { readDurableObjectCommittedEvent, readDurableObjectSummary } from \"./durable-object-store\";\nimport type { EDATranscriptSocketOptions } from \"./websocket/transcript-sockets\";\nimport { EDASessionStoreError } from \"effect-durable-agent/services/session-store\";\nimport {\n DurableObjectTranscriptBuilder,\n DurableObjectTranscriptStore,\n} from \"./durable-object-transcript\";\nimport {\n defaultTranscriptSliceLimits,\n resolveTranscriptSliceLimits,\n type DurableObjectTranscriptObserver,\n type DurableObjectTranscriptOptions,\n type DurableObjectTranscriptSliceLimits,\n type TranscriptAlert,\n} from \"./durable-object-transcript-maintenance\";\n\nexport type { EDAWebSocketProjection } from \"./websocket/projection\";\n/** Internal Worker-to-object header selecting an app-owned WebSocket projection. */\nexport const EDA_WEB_SOCKET_PROJECTION_HEADER = \"x-eda-websocket-projection\";\n\n/**\n * Upgrade query parameter selecting the socket's stream: `transcript` selects the ordered\n * transcript-window stream; anything else keeps the raw event stream.\n */\nexport const EDA_WEB_SOCKET_STREAM_PARAM = \"stream\";\n\n/** Encoded session RPC inputs, decoded before invoking the controller. */\nexport type EDASessionCommandRpcInput = typeof SessionCommandInput.Encoded;\nexport type EDASessionGrantRunRpcInput = typeof SessionGrantRunInput.Encoded;\nexport type EDASessionSubmitBatchRpcInput = typeof SessionBatchInput.Encoded;\nexport type EDASessionScopedRpcInput = typeof SessionScopedInput.Encoded;\nexport type EDASessionEventsRpcInput = EDASessionScopedRpcInput & { readonly afterSeq?: number };\nexport type EDASessionBlockOnCommandRpcInput = typeof SessionBlockInput.Encoded;\nexport type EDASessionRunRequestOutcomeRpcInput = typeof SessionOutcomeInput.Encoded;\n\n/** EDA RPC methods required by the session namespace helper. */\nexport interface EDASessionRpcSurface {\n readonly runRequestOutcome: (\n input: EDASessionRunRequestOutcomeRpcInput,\n ) => Promise<typeof edaSessionRpc.runRequestOutcome.output.Encoded>;\n readonly grantRun: (\n input: EDASessionGrantRunRpcInput,\n ) => Promise<typeof edaSessionRpc.grantRun.output.Encoded>;\n readonly submit: (\n input: EDASessionCommandRpcInput,\n ) => Promise<typeof edaSessionRpc.submit.output.Encoded>;\n readonly submitBatch: (\n input: EDASessionSubmitBatchRpcInput,\n ) => Promise<typeof edaSessionRpc.submitBatch.output.Encoded>;\n readonly submitAndBlock: (\n input: EDASessionCommandRpcInput,\n ) => Promise<typeof edaSessionRpc.submitAndBlock.output.Encoded>;\n readonly blockOnCommand: (\n input: EDASessionBlockOnCommandRpcInput,\n ) => Promise<typeof edaSessionRpc.blockOnCommand.output.Encoded>;\n readonly snapshot: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.snapshot.output.Encoded>;\n readonly messages: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.messages.output.Encoded>;\n readonly destroySession: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.destroySession.output.Encoded>;\n readonly transcriptStatus: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.transcriptStatus.output.Encoded>;\n readonly readTranscriptWindow: (\n input: typeof SessionTranscriptWindowInput.Encoded,\n ) => Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded>;\n readonly readTranscriptBody: (\n input: typeof SessionTranscriptBodyInput.Encoded,\n ) => Promise<typeof edaSessionRpc.readTranscriptBody.output.Encoded>;\n readonly readTranscriptSummary: (\n input: typeof SessionTranscriptSummaryInput.Encoded,\n ) => Promise<typeof edaSessionRpc.readTranscriptSummary.output.Encoded>;\n}\n\n/** Host transcript configuration of a session Durable Object. */\nexport interface EDASessionTranscriptOptions {\n /**\n * Which sessions maintain a transcript; default **off**. A disabled session gets no transcript\n * writes, builder slices or wakeups: `readTranscriptWindow` answers `Disabled`,\n * `transcriptStatus` reports `Disabled` without writing, and transcript sockets are\n * refused. Enabling a session takes the first-introduction path (a build from the log, then\n * activation). Rollout rings use a deterministic predicate (for example a hash of the session\n * id under a percentage); disabling leaves a session's rows untouched, and re-enabling catches\n * an active version up to the head before it is served as current. Evaluated once per object\n * instance, so a change takes effect when the object next starts.\n */\n readonly enabled?: boolean | ((sessionId: SessionId) => boolean);\n /**\n * Builder bounds: events per slice, rows deleted per slice, and `maxSliceFailures` (default 5),\n * the consecutive failures after which a build freezes as failed and a failing builder alarm\n * stops scheduling itself.\n */\n readonly sliceLimits?: Partial<DurableObjectTranscriptSliceLimits>;\n /**\n * The transcript definitions this release carries. Defaults to the definition with no host\n * mappings. A host changing its mappings ships `current` = new, `previous` = old, then runs\n * its backfill through `transcriptStatus` (see `docs/transcript-history.md` §7).\n */\n readonly definitions?: TranscriptMaintenanceConfig;\n /**\n * Adopt the host's existing log incarnation from this `ctx.storage.kv` key (Gia:\n * `gia.log_incarnation`). Without it the adapter mints its own.\n */\n readonly adoptIncarnationKey?: string;\n /** Alerts (frozen versions, missed sessions). Defaults to `console.error`. */\n readonly onAlert?: (alert: TranscriptAlert) => void;\n /** A rebuilt version became active. */\n readonly onActivated?: DurableObjectTranscriptObserver[\"onActivated\"];\n}\n\n/** Constructor options for concrete app subclasses of the EDA Durable Object base. */\nexport type EDASessionDurableObjectOptions<ProjectionState extends object = never> = Omit<\n EDASessionControllerOptions<ProjectionState>,\n \"alarmStorage\" | \"background\" | \"getWebSockets\" | \"storage\" | \"transcript\" | \"transcriptSockets\"\n> & {\n readonly transcript?: EDASessionTranscriptOptions;\n /**\n * Serve transcript-window sockets (`?stream=transcript`). `transcriptStore` defaults to this\n * object's own runtime-free Durable Object transcript store.\n */\n readonly transcriptSockets?: Omit<EDATranscriptSocketOptions, \"transcriptStore\"> & {\n readonly transcriptStore?: EDATranscriptSocketOptions[\"transcriptStore\"];\n };\n};\n\n/** Slices a backfill `transcriptStatus` call may run before it returns. */\nconst transcriptStatusMaxSlices = 16;\n/** Server bounds on one `readTranscriptWindow` RPC, whatever limits the caller asks for. */\nconst transcriptWindowMaxRecords = 500;\nconst transcriptWindowMaxBytes = 8 * 1_048_576;\n/** First retry delay after a failed builder alarm; doubled per consecutive failure. */\nconst transcriptBuilderRetryDelayMs = 30_000;\n/** Slices one builder alarm runs before rescheduling itself. */\nconst transcriptAlarmMaxSlices = 4;\n\n/** Resolve a concrete EDA session Durable Object binding by domain session id. */\nexport const getEDASessionDurableObjectByName = <\n T extends Rpc.DurableObjectBranded & EDASessionRpcSurface,\n>(\n namespace: DurableObjectNamespace<T>,\n sessionId: string,\n): DurableObjectStub<T> => namespace.getByName(sessionId);\n\n/**\n * Base class for raw Cloudflare Durable Object hosts of one EDA session.\n *\n * Concrete products should extend this class, pass provider/tool layers from\n * their own constructor, and register only that subclass in Wrangler. The base\n * class is deliberately not exported from `workers/app.ts` and owns no binding\n * name or routing convention.\n */\nexport abstract class EDASessionDurableObject<\n EnvType extends object = object,\n ProjectionState extends object = never,\n> extends DurableObject<EnvType> {\n readonly #controller: EDASessionController<ProjectionState>;\n readonly #webSocketProjectionId: string | undefined;\n readonly #alarms: DurableObjectAlarmScheduler;\n readonly #transcriptOptions: DurableObjectTranscriptOptions;\n #transcript:\n | {\n readonly sessionId: SessionId;\n /** Whether the host enabled transcript maintenance for this session. */\n readonly enabled: boolean;\n readonly store: DurableObjectTranscriptStore;\n readonly builder: DurableObjectTranscriptBuilder;\n }\n | undefined;\n readonly #transcriptEnabled: (sessionId: SessionId) => boolean;\n\n protected constructor(\n ctx: DurableObjectState,\n env: EnvType,\n options: EDASessionDurableObjectOptions<ProjectionState>,\n ) {\n super(ctx, env);\n this.#webSocketProjectionId = options.webSocketProjection?.id;\n const storage = toEDASessionStorage(this.ctx.storage);\n this.#alarms = new DurableObjectAlarmScheduler(storage);\n const { transcript: transcriptHostOptions, transcriptSockets, ...controllerOptions } = options;\n const transcript = this.transcriptOptions(transcriptHostOptions);\n this.#transcriptOptions = transcript;\n const enabled = transcriptHostOptions?.enabled ?? false;\n this.#transcriptEnabled = typeof enabled === \"function\" ? enabled : () => enabled;\n this.#controller = new EDASessionController({\n ...controllerOptions,\n alarmStorage: this.#alarms.owner(\"runtime\"),\n background: this.ctx,\n getWebSockets: () => this.ctx.getWebSockets(),\n storage,\n // The runtime's store maintains the transcript only for an enabled session.\n transcript: ({ sessionId }) =>\n this.transcriptFor(sessionId).enabled ? transcript : undefined,\n ...(transcriptSockets === undefined\n ? {}\n : {\n transcriptSockets: {\n ...transcriptSockets,\n transcriptStore: transcriptSockets.transcriptStore ?? this.transcriptPort(),\n },\n }),\n });\n\n // Answer client liveness pings at the runtime layer so idle sockets never\n // wake a hibernated object.\n this.ctx.setWebSocketAutoResponse(\n new WebSocketRequestResponsePair(EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE),\n );\n\n this.ctx.blockConcurrencyWhile(async () => {\n await Effect.runPromise(EDASessionController.migrate(storage));\n // Keep an alarm armed by an earlier release for the runtime, then resume any builder\n // work an earlier instance left (or a new release created).\n await this.#alarms.adoptUnrecordedAlarm();\n await this.maintainedTranscript()?.builder.start();\n });\n }\n\n async fetch(request: Request): Promise<Response> {\n const upgrade = request.headers.get(\"Upgrade\");\n if (upgrade?.toLowerCase() !== \"websocket\") {\n return new Response(\"Expected WebSocket upgrade.\", { status: 426 });\n }\n\n const url = new URL(request.url);\n const sessionIdRaw = url.searchParams.get(\"sessionId\");\n if (sessionIdRaw === null) {\n return new Response(\"Missing sessionId.\", { status: 400 });\n }\n const afterSeqRaw = url.searchParams.get(\"afterSeq\");\n const afterSeq = afterSeqRaw === null ? undefined : Number(afterSeqRaw);\n if (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n return new Response(\"Invalid afterSeq.\", { status: 400 });\n }\n const projectionId = request.headers.get(EDA_WEB_SOCKET_PROJECTION_HEADER) ?? undefined;\n if (projectionId !== undefined && projectionId !== this.#webSocketProjectionId) {\n return new Response(\"Unsupported WebSocket projection.\", { status: 400 });\n }\n\n const sessionId = this.parseSessionIdOrUndefined(sessionIdRaw);\n if (sessionId === undefined) {\n return new Response(\"This object does not serve that session.\", { status: 400 });\n }\n const trace = traceMetadataFromRequest(request);\n\n if (url.searchParams.get(EDA_WEB_SOCKET_STREAM_PARAM) === \"transcript\") {\n if (projectionId !== undefined || !this.#controller.supportsTranscriptWebSocket) {\n return new Response(\"Unsupported transcript stream.\", { status: 400 });\n }\n if (!this.transcriptFor(sessionId).enabled) {\n return new Response(\"Transcript is not enabled for this session.\", { status: 409 });\n }\n const pair = new WebSocketPair();\n this.ctx.acceptWebSocket(pair[1]);\n this.#controller.acceptTranscriptWebSocket({ sessionId, trace, webSocket: pair[1] });\n return new Response(null, { status: 101, webSocket: pair[0] });\n }\n\n const prepared = await this.#controller.prepareEventWebSocket({\n ...(afterSeq === undefined ? {} : { afterSeq: SequenceNumber.make(afterSeq) }),\n sessionId,\n trace,\n ...(projectionId === undefined ? {} : { projectionId }),\n });\n\n const pair = new WebSocketPair();\n const client = pair[0];\n const server = pair[1];\n this.ctx.acceptWebSocket(server);\n await this.#controller.acceptPreparedEventWebSocket({\n ...prepared,\n webSocket: server,\n });\n return new Response(null, { status: 101, webSocket: client });\n }\n\n async submit(\n raw: typeof SessionCommandInput.Encoded,\n ): Promise<typeof edaSessionRpc.submit.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);\n const committed = await this.#controller.submit({\n command: input.command,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcCommittedDurableEvent(committed);\n }\n\n /** Reconcile lost grant replies from durable request and run facts. */\n async runRequestOutcome(\n raw: typeof SessionOutcomeInput.Encoded,\n ): Promise<typeof edaSessionRpc.runRequestOutcome.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionOutcomeInput)(raw);\n const result = await this.#controller.runRequestOutcome({\n requestId: Schema.decodeUnknownSync(RunRequestId)(input.requestId),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.runRequestOutcome.output)(result);\n }\n\n /** Trusted RPC only: the calling Worker owns scheduler authentication and authorization. */\n async grantRun(\n raw: typeof SessionGrantRunInput.Encoded,\n ): Promise<typeof edaSessionRpc.grantRun.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionGrantRunInput)(raw);\n const command = input.command;\n const result = await this.#controller.grantRun({\n command,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.grantRun.output)(result);\n }\n\n async submitBatch(\n raw: typeof SessionBatchInput.Encoded,\n ): Promise<typeof edaSessionRpc.submitBatch.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionBatchInput)(raw);\n const committed = await this.#controller.submitBatch({\n items: input.items,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return committed.map(encodeEdaRpcCommittedDurableEvent);\n }\n\n async submitAndBlock(\n raw: typeof SessionCommandInput.Encoded,\n ): Promise<typeof edaSessionRpc.submitAndBlock.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);\n const committed = await this.#controller.submitAndBlock({\n command: input.command,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.submitAndBlock.output)(committed);\n }\n\n async blockOnCommand(\n raw: typeof SessionBlockInput.Encoded,\n ): Promise<typeof edaSessionRpc.blockOnCommand.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionBlockInput)(raw);\n const committed = await this.#controller.blockOnCommand({\n ...(input.afterSeq === undefined ? {} : { afterSeq: SequenceNumber.make(input.afterSeq) }),\n commandId: CommandId.make(input.commandId),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.blockOnCommand.output)(committed);\n }\n\n async snapshot(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.snapshot.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n const snapshot = await this.#controller.snapshot({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.snapshot.output)(snapshot);\n }\n\n async messages(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.messages.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n const result = await this.#controller.messages({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.messages.output)(result);\n }\n\n async webSocketMessage(webSocket: WebSocket, message: string | ArrayBuffer): Promise<void> {\n await this.#controller.webSocketMessage(webSocket, message);\n }\n\n async webSocketClose(\n webSocket: WebSocket,\n _code: number,\n _reason: string,\n _wasClean: boolean,\n ): Promise<void> {\n this.#controller.webSocketClose(webSocket);\n }\n\n async webSocketError(webSocket: WebSocket, _error: unknown): Promise<void> {\n this.#controller.webSocketError(webSocket);\n }\n\n async destroySession(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.destroySession.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n await this.#controller.destroy({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n await this.ctx.storage.deleteAlarm();\n await this.ctx.storage.deleteAll();\n // The wiped storage is a brand-new log: recreate the tables storage-only entry points read,\n // synchronously, so no other work observes the object without them.\n Effect.runSync(EDASessionController.migrate(toEDASessionStorage(this.ctx.storage)));\n }\n\n /**\n * Storage-only backfill entry point: advance pending transcript build work by bounded slices\n * and return the transcript status. It never starts the model runtime, reducers or sinks.\n */\n async transcriptStatus(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.transcriptStatus.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));\n if (!transcript.enabled) {\n return Schema.encodeSync(edaSessionRpc.transcriptStatus.output)(\n transcript.store.disabledStatus(),\n );\n }\n await transcript.builder.run(transcriptStatusMaxSlices);\n return Schema.encodeSync(edaSessionRpc.transcriptStatus.output)(transcript.store.status());\n }\n\n /** Runtime-free transcript window read for SSR and CLIs. Hosts authorize the caller. */\n async readTranscriptWindow(\n raw: typeof SessionTranscriptWindowInput.Encoded,\n ): Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionTranscriptWindowInput)(raw);\n const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));\n if (!transcript.enabled) {\n return Schema.encodeSync(edaSessionRpc.readTranscriptWindow.output)({ _tag: \"Disabled\" });\n }\n const limits = input.limits ?? defaultTranscriptWindowLimits;\n const window = transcript.store.readWindow(input.selector, {\n ...limits,\n maxRecords: Math.min(limits.maxRecords, transcriptWindowMaxRecords),\n maxBytes: Math.min(limits.maxBytes, transcriptWindowMaxBytes),\n });\n return Schema.encodeSync(edaSessionRpc.readTranscriptWindow.output)(\n Result.isSuccess(window)\n ? { _tag: \"Window\", window: window.success }\n : { _tag: \"CursorMismatch\", message: window.failure.message },\n );\n }\n\n /**\n * Runtime-free read of the body a transcript `Ref` names, resolved through the immutable log\n * (so it stays valid after projection rows are rebuilt). Hosts authorize the caller.\n */\n async readTranscriptBody(\n raw: typeof SessionTranscriptBodyInput.Encoded,\n ): Promise<typeof edaSessionRpc.readTranscriptBody.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionTranscriptBodyInput)(raw);\n const scope = this.transcriptReadScope(input.sessionId, input.incarnation);\n if (scope._tag !== \"Scope\") {\n return Schema.encodeSync(edaSessionRpc.readTranscriptBody.output)(scope);\n }\n const sessionId = scope.sessionId;\n const committed = readDurableObjectCommittedEvent(\n toEDASessionStorage(this.ctx.storage).sql,\n sessionId,\n input.source.seq,\n );\n const resolved =\n committed === undefined\n ? ({ _tag: \"Missing\", message: `no event at seq ${input.source.seq}` } as const)\n : resolveTranscriptBody(committed.event, input.source.path);\n return Schema.encodeSync(edaSessionRpc.readTranscriptBody.output)(\n resolved._tag === \"Found\"\n ? { _tag: \"Body\", value: resolved.value }\n : { _tag: \"NotFound\", message: resolved.message },\n );\n }\n\n /** Runtime-free read of a compaction summary's text. Hosts authorize the caller. */\n async readTranscriptSummary(\n raw: typeof SessionTranscriptSummaryInput.Encoded,\n ): Promise<typeof edaSessionRpc.readTranscriptSummary.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionTranscriptSummaryInput)(raw);\n const scope = this.transcriptReadScope(input.sessionId, input.incarnation);\n if (scope._tag !== \"Scope\") {\n return Schema.encodeSync(edaSessionRpc.readTranscriptSummary.output)(scope);\n }\n const artifact = readDurableObjectSummary(\n toEDASessionStorage(this.ctx.storage).sql,\n input.summaryId,\n );\n return Schema.encodeSync(edaSessionRpc.readTranscriptSummary.output)(\n artifact === undefined\n ? { _tag: \"NotFound\", message: `no summary ${input.summaryId}` }\n : {\n _tag: \"Summary\",\n summary: {\n compactionId: artifact.compactionId,\n summaryId: artifact.summaryId,\n text: artifact.text,\n sourceFromSeq: artifact.sourceFromSeq,\n sourceToSeq: artifact.sourceToSeq,\n },\n },\n );\n }\n\n /**\n * The alarm is shared by the runtime heartbeat and the transcript builder; see\n * `runEDASessionAlarm`.\n */\n async alarm(): Promise<void> {\n const transcript = this.maintainedTranscript();\n await runEDASessionAlarm({\n alarms: this.#alarms,\n now: () => Date.now(),\n runRuntime: async () => {\n const sessionId = this.sessionIdFromObjectName();\n await this.#controller.alarm(\n sessionId === undefined ? undefined : { sessionId, trace: makeRootEDATraceMetadata() },\n );\n },\n runBuilderSlices:\n transcript === undefined\n ? undefined\n : () => transcript.builder.runSlices(transcriptAlarmMaxSlices),\n maxBuilderFailures:\n this.#transcriptOptions.sliceLimits?.maxSliceFailures ??\n defaultTranscriptSliceLimits.maxSliceFailures,\n builderRetryDelayMs: transcriptBuilderRetryDelayMs,\n onBuilderFailure: ({ error, consecutiveFailures, stopped }) => {\n console.error(\"EDA transcript builder slice failed\", error);\n if (stopped) {\n transcript?.store.alert({\n _tag: \"BuilderStopped\",\n consecutiveFailures,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n },\n });\n }\n\n private transcriptOptions(\n options: EDASessionTranscriptOptions | undefined,\n ): DurableObjectTranscriptOptions {\n const key = options?.adoptIncarnationKey;\n return {\n definitions: options?.definitions ?? {\n current: Effect.runSync(makeTranscriptDefinition(emptyTranscriptMappings)),\n },\n ...(key === undefined ? {} : { adoptIncarnation: { key, kv: this.ctx.storage.kv } }),\n // Validated here so a misconfigured host fails at construction, not on a failing slice.\n sliceLimits: resolveTranscriptSliceLimits(options?.sliceLimits),\n observer: {\n onAlert:\n options?.onAlert ??\n ((alert) => console.error(\"EDA transcript alert\", JSON.stringify(alert))),\n onPendingWork: () => {\n const builder = this.maintainedTranscript()?.builder;\n if (builder !== undefined) this.ctx.waitUntil(builder.kick());\n },\n onServedChanged: () => {\n // A behind active version reached the head, or the active version froze: sockets re-read.\n this.ctx.waitUntil(this.#controller.refreshTranscriptWebSockets());\n },\n onActivated: (activation) => {\n // Connected transcript sockets get one complete replacement in the new version.\n this.ctx.waitUntil(this.#controller.refreshTranscriptWebSockets());\n options?.onActivated?.(activation);\n },\n },\n };\n }\n\n /** This object's transcript store as the port transcript sockets read, resolved per call. */\n private transcriptPort(): EDATranscriptStoreShape {\n const port = () => this.maintainedTranscript()?.store.port;\n const unbound = () =>\n Effect.fail(\n new EDASessionStoreError({\n message:\n this.objectTranscript()?.enabled === false\n ? \"EDA transcript is not enabled for this session\"\n : \"EDA transcript read before the session was named\",\n }),\n );\n return {\n readTranscriptWindow: (selector, limits) =>\n Effect.suspend(() => port()?.readTranscriptWindow(selector, limits) ?? unbound()),\n readTranscriptMeta: Effect.suspend(() => port()?.readTranscriptMeta ?? unbound()),\n };\n }\n\n /**\n * The session and log a body or summary read may serve: pinned to the session this object's\n * transcript serves, like window reads, and to the incarnation the caller's reference names.\n */\n private transcriptReadScope(\n rawSessionId: string,\n incarnation: TranscriptLogIncarnation,\n ):\n | { readonly _tag: \"Scope\"; readonly sessionId: SessionId }\n | { readonly _tag: \"Disabled\" }\n | { readonly _tag: \"IncarnationMismatch\"; readonly incarnation: TranscriptLogIncarnation } {\n const transcript = this.transcriptFor(this.parseSessionId(rawSessionId));\n // Outside the rollout nothing is initialized or minted, and no reference was ever served.\n if (!transcript.enabled) return { _tag: \"Disabled\" };\n const current = transcript.store.incarnation();\n return incarnation === current\n ? { _tag: \"Scope\", sessionId: transcript.sessionId }\n : { _tag: \"IncarnationMismatch\", incarnation: current };\n }\n\n /** The transcript service of this object's session, created on first use. */\n private transcriptFor(sessionId: SessionId) {\n if (this.#transcript !== undefined) {\n if (this.#transcript.sessionId !== sessionId) {\n throw new Error(\n `EDA transcript is scoped to session ${this.#transcript.sessionId}; received ${sessionId}`,\n );\n }\n return this.#transcript;\n }\n const store = new DurableObjectTranscriptStore({\n sessionId,\n storage: toEDASessionStorage(this.ctx.storage),\n transcript: this.#transcriptOptions,\n });\n const builder = new DurableObjectTranscriptBuilder(store, () =>\n this.#alarms.request(\"transcript\", Date.now()),\n );\n this.#transcript = { sessionId, enabled: this.#transcriptEnabled(sessionId), store, builder };\n return this.#transcript;\n }\n\n /** The transcript service when this object's session is enabled for maintenance. */\n private maintainedTranscript() {\n const transcript = this.objectTranscript();\n return transcript?.enabled === true ? transcript : undefined;\n }\n\n /** The transcript service when the object is named by a valid session id. */\n private objectTranscript() {\n if (this.#transcript !== undefined) return this.#transcript;\n const name = this.ctx.id.name;\n return name !== undefined && Schema.is(SessionId)(name)\n ? this.transcriptFor(SessionId.make(name))\n : undefined;\n }\n\n /** `parseSessionId` for request paths that answer a foreign session with a 400. */\n private parseSessionIdOrUndefined(input: string): SessionId | undefined {\n if (!Schema.is(SessionId)(input)) return undefined;\n const name = this.ctx.id.name;\n if (name !== undefined && name !== input) return undefined;\n const bound = this.#transcript?.sessionId;\n return bound === undefined || bound === input ? SessionId.make(input) : undefined;\n }\n\n private parseSessionId(input: string): SessionId {\n const sessionId = SessionId.make(input);\n const objectName = this.ctx.id.name;\n if (objectName !== undefined && objectName !== sessionId) {\n throw new Error(`EDA Durable Object name ${objectName} cannot serve session ${sessionId}`);\n }\n return sessionId;\n }\n\n private sessionIdFromObjectName(): SessionId | undefined {\n return this.ctx.id.name === undefined ? undefined : SessionId.make(this.ctx.id.name);\n }\n}\n\nconst toEDASessionStorage = (storage: DurableObjectStorage): EDASessionDurableObjectStorage => {\n // SAFETY: the adapter interface is the exact SQL, transaction, and alarm subset\n // of DurableObjectStorage; its looser row generic also supports test implementations.\n return storage as EDASessionDurableObjectStorage;\n};\n\nconst decodeTraceMetadata = (input: unknown): EDATraceMetadata =>\n Schema.decodeUnknownSync(EDATraceMetadata)(input);\n\nconst traceMetadataFromRequest = (request: Request): EDATraceMetadata => {\n const parent = parseEDATraceparent(\n request.headers.get(\"traceparent\"),\n request.headers.get(\"tracestate\"),\n );\n return parent === null ? makeRootEDATraceMetadata() : makeEDATraceMetadataFromParent(parent);\n};\n\n/** Convenience config constructor for subclasses that need only provider/model ids. */\nexport const edaRuntimeConfig = (input: {\n readonly maxToolCallsPerRun?: number;\n readonly modelId: string;\n readonly provider: string;\n readonly systemPrompt?: string;\n}): EDARuntimeConfig => ({\n modelSelection: { modelId: input.modelId, provider: input.provider },\n ...(input.maxToolCallsPerRun === undefined\n ? {}\n : { maxToolCallsPerRun: input.maxToolCallsPerRun }),\n ...(input.systemPrompt === undefined ? {} : { systemPrompt: input.systemPrompt }),\n});\n\n/** Encode committed events into the existing structured-clone envelope. */\nexport const encodeEdaRpcCommittedDurableEvent = (\n entry: CommittedDurableEvent,\n): typeof edaSessionRpc.submit.output.Encoded => ({\n position: entry.position,\n event: encodeEdaRpcDurableEvent(durableEventEnvelope(entry.event)),\n});\n/** Encode query snapshots without asserting that encoded command values are decoded classes. */\nexport const encodeEdaRpcSessionSnapshot = Schema.encodeSync(edaSessionRpc.snapshot.output);\n"],"mappings":";;;;;;;;;;;;;;;AAyBA,MAAM,yBAAyB;;;;;;;;;;;;;;;;AAiB/B,MAAa,qBAAqB,OAAO,iBAA8C;CACrF,MAAM,EAAE,WAAW;CACnB,MAAM,MAAM,aAAa,IAAI;CAC7B,MAAM,MAAM,OAAO,IAAI,GAAG;CAC1B,IAAI;CACJ,IAAI,IAAI,IAAI,SAAS,KAAK,IAAI,SAAS,GACrC,IAAI;EACF,MAAM,aAAa,WAAW;EAC9B,OAAO,aAAa,WAAW,IAAI,IAAI,SAAS,KAAK,GAAG;CAC1D,SAAS,OAAO;EACd,iBAAiB,EAAE,MAAM;CAC3B;CAEF,MAAM,gBAAgB,IAAI,IAAI,YAAY;CAC1C,IAAI,kBAAkB,KAAA,GAAW;EAC/B,MAAM,mBAAmB,aAAa;EACtC,IAAI,qBAAqB,KAAA,GACvB,OAAO,MAAM,YAAY;OAEzB,IAAI;GACF,IAAI,MAAM,iBAAiB,GAAG,OAAO,OAAO,cAAc,aAAa,IAAI,CAAC;QACvE,OAAO,aAAa,cAAc,aAAa;EACtD,SAAS,OAAO;GACd,MAAM,sBAAsB,OAAO,SAAS,YAAY,IAAI;GAC5D,MAAM,UAAU,uBAAuB,aAAa;GACpD,IAAI,SACF,OAAO,MAAM,YAAY;QACpB;IACL,MAAM,UAAU,KAAK,IACnB,aAAa,sBAAsB,MAAM,sBAAsB,IAC/D,sBACF;IACA,OAAO,OAAO,cAAc,aAAa,IAAI,IAAI,SAAS,mBAAmB;GAC/E;GACA,aAAa,iBAAiB;IAAE;IAAO;IAAqB;GAAQ,CAAC;EACvE;CAEJ;CACA,IAAI,mBAAmB,KAAA,GAAW,MAAM,eAAe;CACvD,MAAM,OAAO,KAAK;AACpB;;;;;;;;;;;AC7DA,IAAa,8BAAb,MAAyC;CAIpB;CACA;CAJnB,QAAuB,QAAQ,QAAQ;CAEvC,YACE,SACA,YAA2C,KAAK,IAAI,GACpD;EAFiB,KAAA,UAAA;EACA,KAAA,MAAA;CAChB;;;;;;CAOH,MAAM,OAA2D;EAC/D,OAAO;GACL,gBAAgB;IACd,MAAM,SAAS,KAAKA,QAAQ,KAAK;IACjC,OAAO,WAAW,KAAA,KAAa,SAAS,KAAK,IAAI,IAAI,OAAO;GAC9D;GACA,WAAW,oBAAoB;IAC7B,KAAKC,OAAO,OAAO,eAAe;IAClC,OAAO,KAAK,KAAK;GACnB;GACA,mBAAmB;IACjB,KAAKA,OAAO,OAAO,KAAA,CAAS;IAC5B,OAAO,KAAK,KAAK;GACnB;EACF;CACF;;;;;;CAOA,MAAM,uBAAsC;EAC1C,IAAI,KAAKC,MAAM,CAAC,CAAC,SAAS,GAAG;EAC7B,MAAM,QAAQ,MAAM,KAAK,QAAQ,SAAS;EAC1C,IAAI,UAAU,QAAQ,KAAKA,MAAM,CAAC,CAAC,WAAW,GAAG,KAAKD,OAAO,WAAW,KAAK;CAC/E;;;;;;CAOA,OAAO,OAAgC,MAAc,WAAW,GAAS;EACvE,KAAKA,OAAO,OAAO,MAAM,QAAQ;CACnC;;CAGA,SAAS,OAAwC;EAC/C,OACE,KAAK,QAAQ,IACV,KACC,2DACA,KACF,CAAC,CACA,QAAQ,CAAC,CAAC,EAAE,EAAE,YAAY;CAEjC;;CAGA,MAAM,OAAsC;EAC1C,KAAKA,OAAO,OAAO,KAAA,CAAS;CAC9B;;CAGA,QAAQ,OAAgC,MAA6B;EACnE,MAAM,UAAU,KAAKD,QAAQ,KAAK;EAClC,IAAI,YAAY,KAAA,KAAa,WAAW,MAAM,OAAO,KAAK,KAAK;EAC/D,KAAKC,OAAO,OAAO,IAAI;EACvB,OAAO,KAAK,KAAK;CACnB;;;;;;;;;CAUA,IAAI,OAA6D;EAC/D,MAAM,OAAO,KAAKC,MAAM;EACxB,MAAM,WAAW,KAAK,QAAQ,KAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,OAAO,iBAAiB;EAC7F,MAAM,YAAY,KAAK,IAAI,OAAO,QAAQ;EAC1C,MAAM,sBAAM,IAAI,IAAqC;EACrD,KAAK,MAAM,OAAO,MAChB,IAAI,IAAI,SAAS,aAAa,QAAQ,IAAI,KAAK,GAAG,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK;EAEhF,OAAO;CACT;;;;;CAMA,aAAa,OAAgC,MAAoB;EAC/D,KAAK,QAAQ,IAAI,KACf,iEACA,OACA,IACF;CACF;;CAGA,OAAsB;EACpB,KAAKC,QAAQ,KAAKA,MACf,YAAY,KAAA,CAAS,CAAC,CACtB,KAAK,YAAY;GAChB,MAAM,WAAW,KAAK,QAAQ,IAC3B,KACC,oDACF,CAAC,CACA,IAAI,CAAC,CAAC;GACT,IAAI,aAAa,MAAM;IACrB,MAAM,KAAK,QAAQ,YAAY;IAC/B;GACF;GACA,IAAK,MAAM,KAAK,QAAQ,SAAS,MAAO,UACtC,MAAM,KAAK,QAAQ,SAAS,QAAQ;EAExC,CAAC;EACH,OAAO,KAAKA;CACd;CAEA,QAA2E;EACzE,OAAO,KAAK,QAAQ,IACjB,KACC,6CACF,CAAC,CACA,QAAQ;CACb;CAEA,QAAQ,OAAoD;EAC1D,OAAO,KAAK,QAAQ,IACjB,KACC,wDACA,KACF,CAAC,CACA,QAAQ,CAAC,CAAC,EAAE,EAAE;CACnB;;CAGA,OAAO,OAAgC,MAA0B,UAAyB;EACxF,IAAI,SAAS,KAAA,GAAW;GACtB,KAAK,QAAQ,IAAI,KAAK,kDAAkD,KAAK;GAC7E;EACF;EACA,IAAI,aAAa,KAAA,GAAW;GAC1B,KAAK,QAAQ,IAAI,KACf;kEAEA,OACA,IACF;GACA;EACF;EACA,KAAK,QAAQ,IAAI,KACf;8FAEA,OACA,MACA,QACF;CACF;AACF;AAEA,MAAM,WAAW,UACf,UAAU,aAAa,UAAU;;;;ACxHnC,MAAa,mCAAmC;;;;;AAMhD,MAAa,8BAA8B;;AA0G3C,MAAM,4BAA4B;;AAElC,MAAM,6BAA6B;AACnC,MAAM,2BAA2B;;AAEjC,MAAM,gCAAgC;;AAEtC,MAAM,2BAA2B;;AAGjC,MAAa,oCAGX,WACA,cACyB,UAAU,UAAU,SAAS;;;;;;;;;AAUxD,IAAsB,0BAAtB,cAGU,cAAuB;CAC/B;CACA;CACA;CACA;CACA;CASA;CAEA,YACE,KACA,KACA,SACA;EACA,MAAM,KAAK,GAAG;EACd,KAAKE,yBAAyB,QAAQ,qBAAqB;EAC3D,MAAM,UAAU,oBAAoB,KAAK,IAAI,OAAO;EACpD,KAAKC,UAAU,IAAI,4BAA4B,OAAO;EACtD,MAAM,EAAE,YAAY,uBAAuB,mBAAmB,GAAG,sBAAsB;EACvF,MAAM,aAAa,KAAK,kBAAkB,qBAAqB;EAC/D,KAAKC,qBAAqB;EAC1B,MAAM,UAAU,uBAAuB,WAAW;EAClD,KAAKC,qBAAqB,OAAO,YAAY,aAAa,gBAAgB;EAC1E,KAAKJ,cAAc,IAAI,qBAAqB;GAC1C,GAAG;GACH,cAAc,KAAKE,QAAQ,MAAM,SAAS;GAC1C,YAAY,KAAK;GACjB,qBAAqB,KAAK,IAAI,cAAc;GAC5C;GAEA,aAAa,EAAE,gBACb,KAAK,cAAc,SAAS,CAAC,CAAC,UAAU,aAAa,KAAA;GACvD,GAAI,sBAAsB,KAAA,IACtB,CAAC,IACD,EACE,mBAAmB;IACjB,GAAG;IACH,iBAAiB,kBAAkB,mBAAmB,KAAK,eAAe;GAC5E,EACF;EACN,CAAC;EAID,KAAK,IAAI,yBACP,IAAI,6BAA6B,6BAA6B,2BAA2B,CAC3F;EAEA,KAAK,IAAI,sBAAsB,YAAY;GACzC,MAAM,OAAO,WAAW,qBAAqB,QAAQ,OAAO,CAAC;GAG7D,MAAM,KAAKA,QAAQ,qBAAqB;GACxC,MAAM,KAAK,qBAAqB,CAAC,EAAE,QAAQ,MAAM;EACnD,CAAC;CACH;CAEA,MAAM,MAAM,SAAqC;EAE/C,IADgB,QAAQ,QAAQ,IAAI,SAC1B,CAAC,EAAE,YAAY,MAAM,aAC7B,OAAO,IAAI,SAAS,+BAA+B,EAAE,QAAQ,IAAI,CAAC;EAGpE,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;EAC/B,MAAM,eAAe,IAAI,aAAa,IAAI,WAAW;EACrD,IAAI,iBAAiB,MACnB,OAAO,IAAI,SAAS,sBAAsB,EAAE,QAAQ,IAAI,CAAC;EAE3D,MAAM,cAAc,IAAI,aAAa,IAAI,UAAU;EACnD,MAAM,WAAW,gBAAgB,OAAO,KAAA,IAAY,OAAO,WAAW;EACtE,IAAI,aAAa,KAAA,MAAc,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,IACvE,OAAO,IAAI,SAAS,qBAAqB,EAAE,QAAQ,IAAI,CAAC;EAE1D,MAAM,eAAe,QAAQ,QAAQ,IAAA,4BAAoC,KAAK,KAAA;EAC9E,IAAI,iBAAiB,KAAA,KAAa,iBAAiB,KAAKD,wBACtD,OAAO,IAAI,SAAS,qCAAqC,EAAE,QAAQ,IAAI,CAAC;EAG1E,MAAM,YAAY,KAAK,0BAA0B,YAAY;EAC7D,IAAI,cAAc,KAAA,GAChB,OAAO,IAAI,SAAS,4CAA4C,EAAE,QAAQ,IAAI,CAAC;EAEjF,MAAM,QAAQ,yBAAyB,OAAO;EAE9C,IAAI,IAAI,aAAa,IAAA,QAA+B,MAAM,cAAc;GACtE,IAAI,iBAAiB,KAAA,KAAa,CAAC,KAAKD,YAAY,6BAClD,OAAO,IAAI,SAAS,kCAAkC,EAAE,QAAQ,IAAI,CAAC;GAEvE,IAAI,CAAC,KAAK,cAAc,SAAS,CAAC,CAAC,SACjC,OAAO,IAAI,SAAS,+CAA+C,EAAE,QAAQ,IAAI,CAAC;GAEpF,MAAM,OAAO,IAAI,cAAc;GAC/B,KAAK,IAAI,gBAAgB,KAAK,EAAE;GAChC,KAAKA,YAAY,0BAA0B;IAAE;IAAW;IAAO,WAAW,KAAK;GAAG,CAAC;GACnF,OAAO,IAAI,SAAS,MAAM;IAAE,QAAQ;IAAK,WAAW,KAAK;GAAG,CAAC;EAC/D;EAEA,MAAM,WAAW,MAAM,KAAKA,YAAY,sBAAsB;GAC5D,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,eAAe,KAAK,QAAQ,EAAE;GAC5E;GACA;GACA,GAAI,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa;EACvD,CAAC;EAED,MAAM,OAAO,IAAI,cAAc;EAC/B,MAAM,SAAS,KAAK;EACpB,MAAM,SAAS,KAAK;EACpB,KAAK,IAAI,gBAAgB,MAAM;EAC/B,MAAM,KAAKA,YAAY,6BAA6B;GAClD,GAAG;GACH,WAAW;EACb,CAAC;EACD,OAAO,IAAI,SAAS,MAAM;GAAE,QAAQ;GAAK,WAAW;EAAO,CAAC;CAC9D;CAEA,MAAM,OACJ,KACqD;EACrD,MAAM,QAAQ,OAAO,kBAAkB,mBAAmB,CAAC,CAAC,GAAG;EAC/D,MAAM,YAAY,MAAM,KAAKA,YAAY,OAAO;GAC9C,SAAS,MAAM;GACf,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,OAAO,kCAAkC,SAAS;CACpD;;CAGA,MAAM,kBACJ,KACgE;EAChE,MAAM,QAAQ,OAAO,kBAAkB,mBAAmB,CAAC,CAAC,GAAG;EAC/D,MAAM,SAAS,MAAM,KAAKA,YAAY,kBAAkB;GACtD,WAAW,OAAO,kBAAkB,YAAY,CAAC,CAAC,MAAM,SAAS;GACjE,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,OAAO,OAAO,WAAW,cAAc,kBAAkB,MAAM,CAAC,CAAC,MAAM;CACzE;;CAGA,MAAM,SACJ,KACuD;EACvD,MAAM,QAAQ,OAAO,kBAAkB,oBAAoB,CAAC,CAAC,GAAG;EAChE,MAAM,UAAU,MAAM;EACtB,MAAM,SAAS,MAAM,KAAKA,YAAY,SAAS;GAC7C;GACA,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,OAAO,OAAO,WAAW,cAAc,SAAS,MAAM,CAAC,CAAC,MAAM;CAChE;CAEA,MAAM,YACJ,KAC0D;EAC1D,MAAM,QAAQ,OAAO,kBAAkB,iBAAiB,CAAC,CAAC,GAAG;EAM7D,QAAO,MALiB,KAAKA,YAAY,YAAY;GACnD,OAAO,MAAM;GACb,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC,EAAA,CACgB,IAAI,iCAAiC;CACxD;CAEA,MAAM,eACJ,KAC6D;EAC7D,MAAM,QAAQ,OAAO,kBAAkB,mBAAmB,CAAC,CAAC,GAAG;EAC/D,MAAM,YAAY,MAAM,KAAKA,YAAY,eAAe;GACtD,SAAS,MAAM;GACf,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,OAAO,OAAO,WAAW,cAAc,eAAe,MAAM,CAAC,CAAC,SAAS;CACzE;CAEA,MAAM,eACJ,KAC6D;EAC7D,MAAM,QAAQ,OAAO,kBAAkB,iBAAiB,CAAC,CAAC,GAAG;EAC7D,MAAM,YAAY,MAAM,KAAKA,YAAY,eAAe;GACtD,GAAI,MAAM,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,eAAe,KAAK,MAAM,QAAQ,EAAE;GACxF,WAAW,UAAU,KAAK,MAAM,SAAS;GACzC,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,OAAO,OAAO,WAAW,cAAc,eAAe,MAAM,CAAC,CAAC,SAAS;CACzE;CAEA,MAAM,SACJ,KACuD;EACvD,MAAM,QAAQ,OAAO,kBAAkB,kBAAkB,CAAC,CAAC,GAAG;EAC9D,MAAM,WAAW,MAAM,KAAKA,YAAY,SAAS;GAC/C,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,OAAO,OAAO,WAAW,cAAc,SAAS,MAAM,CAAC,CAAC,QAAQ;CAClE;CAEA,MAAM,SACJ,KACuD;EACvD,MAAM,QAAQ,OAAO,kBAAkB,kBAAkB,CAAC,CAAC,GAAG;EAC9D,MAAM,SAAS,MAAM,KAAKA,YAAY,SAAS;GAC7C,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,OAAO,OAAO,WAAW,cAAc,SAAS,MAAM,CAAC,CAAC,MAAM;CAChE;CAEA,MAAM,iBAAiB,WAAsB,SAA8C;EACzF,MAAM,KAAKA,YAAY,iBAAiB,WAAW,OAAO;CAC5D;CAEA,MAAM,eACJ,WACA,OACA,SACA,WACe;EACf,KAAKA,YAAY,eAAe,SAAS;CAC3C;CAEA,MAAM,eAAe,WAAsB,QAAgC;EACzE,KAAKA,YAAY,eAAe,SAAS;CAC3C;CAEA,MAAM,eACJ,KAC6D;EAC7D,MAAM,QAAQ,OAAO,kBAAkB,kBAAkB,CAAC,CAAC,GAAG;EAC9D,MAAM,KAAKA,YAAY,QAAQ;GAC7B,WAAW,KAAK,eAAe,MAAM,SAAS;GAC9C,OAAO,oBAAoB,MAAM,KAAK;EACxC,CAAC;EACD,MAAM,KAAK,IAAI,QAAQ,YAAY;EACnC,MAAM,KAAK,IAAI,QAAQ,UAAU;EAGjC,OAAO,QAAQ,qBAAqB,QAAQ,oBAAoB,KAAK,IAAI,OAAO,CAAC,CAAC;CACpF;;;;;CAMA,MAAM,iBACJ,KAC+D;EAC/D,MAAM,QAAQ,OAAO,kBAAkB,kBAAkB,CAAC,CAAC,GAAG;EAC9D,MAAM,aAAa,KAAK,cAAc,KAAK,eAAe,MAAM,SAAS,CAAC;EAC1E,IAAI,CAAC,WAAW,SACd,OAAO,OAAO,WAAW,cAAc,iBAAiB,MAAM,CAAC,CAC7D,WAAW,MAAM,eAAe,CAClC;EAEF,MAAM,WAAW,QAAQ,IAAI,yBAAyB;EACtD,OAAO,OAAO,WAAW,cAAc,iBAAiB,MAAM,CAAC,CAAC,WAAW,MAAM,OAAO,CAAC;CAC3F;;CAGA,MAAM,qBACJ,KACmE;EACnE,MAAM,QAAQ,OAAO,kBAAkB,4BAA4B,CAAC,CAAC,GAAG;EACxE,MAAM,aAAa,KAAK,cAAc,KAAK,eAAe,MAAM,SAAS,CAAC;EAC1E,IAAI,CAAC,WAAW,SACd,OAAO,OAAO,WAAW,cAAc,qBAAqB,MAAM,CAAC,CAAC,EAAE,MAAM,WAAW,CAAC;EAE1F,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,SAAS,WAAW,MAAM,WAAW,MAAM,UAAU;GACzD,GAAG;GACH,YAAY,KAAK,IAAI,OAAO,YAAY,0BAA0B;GAClE,UAAU,KAAK,IAAI,OAAO,UAAU,wBAAwB;EAC9D,CAAC;EACD,OAAO,OAAO,WAAW,cAAc,qBAAqB,MAAM,CAAC,CACjE,OAAO,UAAU,MAAM,IACnB;GAAE,MAAM;GAAU,QAAQ,OAAO;EAAQ,IACzC;GAAE,MAAM;GAAkB,SAAS,OAAO,QAAQ;EAAQ,CAChE;CACF;;;;;CAMA,MAAM,mBACJ,KACiE;EACjE,MAAM,QAAQ,OAAO,kBAAkB,0BAA0B,CAAC,CAAC,GAAG;EACtE,MAAM,QAAQ,KAAK,oBAAoB,MAAM,WAAW,MAAM,WAAW;EACzE,IAAI,MAAM,SAAS,SACjB,OAAO,OAAO,WAAW,cAAc,mBAAmB,MAAM,CAAC,CAAC,KAAK;EAEzE,MAAM,YAAY,MAAM;EACxB,MAAM,YAAY,gCAChB,oBAAoB,KAAK,IAAI,OAAO,CAAC,CAAC,KACtC,WACA,MAAM,OAAO,GACf;EACA,MAAM,WACJ,cAAc,KAAA,IACT;GAAE,MAAM;GAAW,SAAS,mBAAmB,MAAM,OAAO;EAAM,IACnE,sBAAsB,UAAU,OAAO,MAAM,OAAO,IAAI;EAC9D,OAAO,OAAO,WAAW,cAAc,mBAAmB,MAAM,CAAC,CAC/D,SAAS,SAAS,UACd;GAAE,MAAM;GAAQ,OAAO,SAAS;EAAM,IACtC;GAAE,MAAM;GAAY,SAAS,SAAS;EAAQ,CACpD;CACF;;CAGA,MAAM,sBACJ,KACoE;EACpE,MAAM,QAAQ,OAAO,kBAAkB,6BAA6B,CAAC,CAAC,GAAG;EACzE,MAAM,QAAQ,KAAK,oBAAoB,MAAM,WAAW,MAAM,WAAW;EACzE,IAAI,MAAM,SAAS,SACjB,OAAO,OAAO,WAAW,cAAc,sBAAsB,MAAM,CAAC,CAAC,KAAK;EAE5E,MAAM,WAAW,yBACf,oBAAoB,KAAK,IAAI,OAAO,CAAC,CAAC,KACtC,MAAM,SACR;EACA,OAAO,OAAO,WAAW,cAAc,sBAAsB,MAAM,CAAC,CAClE,aAAa,KAAA,IACT;GAAE,MAAM;GAAY,SAAS,cAAc,MAAM;EAAY,IAC7D;GACE,MAAM;GACN,SAAS;IACP,cAAc,SAAS;IACvB,WAAW,SAAS;IACpB,MAAM,SAAS;IACf,eAAe,SAAS;IACxB,aAAa,SAAS;GACxB;EACF,CACN;CACF;;;;;CAMA,MAAM,QAAuB;EAC3B,MAAM,aAAa,KAAK,qBAAqB;EAC7C,MAAM,mBAAmB;GACvB,QAAQ,KAAKE;GACb,WAAW,KAAK,IAAI;GACpB,YAAY,YAAY;IACtB,MAAM,YAAY,KAAK,wBAAwB;IAC/C,MAAM,KAAKF,YAAY,MACrB,cAAc,KAAA,IAAY,KAAA,IAAY;KAAE;KAAW,OAAO,yBAAyB;IAAE,CACvF;GACF;GACA,kBACE,eAAe,KAAA,IACX,KAAA,UACM,WAAW,QAAQ,UAAU,wBAAwB;GACjE,oBACE,KAAKG,mBAAmB,aAAa,oBACrC,6BAA6B;GAC/B,qBAAqB;GACrB,mBAAmB,EAAE,OAAO,qBAAqB,cAAc;IAC7D,QAAQ,MAAM,uCAAuC,KAAK;IAC1D,IAAI,SACF,YAAY,MAAM,MAAM;KACtB,MAAM;KACN;KACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC9D,CAAC;GAEL;EACF,CAAC;CACH;CAEA,kBACE,SACgC;EAChC,MAAM,MAAM,SAAS;EACrB,OAAO;GACL,aAAa,SAAS,eAAe,EACnC,SAAS,OAAO,QAAQ,yBAAyB,uBAAuB,CAAC,EAC3E;GACA,GAAI,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,kBAAkB;IAAE;IAAK,IAAI,KAAK,IAAI,QAAQ;GAAG,EAAE;GAElF,aAAa,6BAA6B,SAAS,WAAW;GAC9D,UAAU;IACR,SACE,SAAS,aACP,UAAU,QAAQ,MAAM,wBAAwB,KAAK,UAAU,KAAK,CAAC;IACzE,qBAAqB;KACnB,MAAM,UAAU,KAAK,qBAAqB,CAAC,EAAE;KAC7C,IAAI,YAAY,KAAA,GAAW,KAAK,IAAI,UAAU,QAAQ,KAAK,CAAC;IAC9D;IACA,uBAAuB;KAErB,KAAK,IAAI,UAAU,KAAKH,YAAY,4BAA4B,CAAC;IACnE;IACA,cAAc,eAAe;KAE3B,KAAK,IAAI,UAAU,KAAKA,YAAY,4BAA4B,CAAC;KACjE,SAAS,cAAc,UAAU;IACnC;GACF;EACF;CACF;;CAGA,iBAAkD;EAChD,MAAM,aAAa,KAAK,qBAAqB,CAAC,EAAE,MAAM;EACtD,MAAM,gBACJ,OAAO,KACL,IAAI,qBAAqB,EACvB,SACE,KAAK,iBAAiB,CAAC,EAAE,YAAY,QACjC,mDACA,mDACR,CAAC,CACH;EACF,OAAO;GACL,uBAAuB,UAAU,WAC/B,OAAO,cAAc,KAAK,CAAC,EAAE,qBAAqB,UAAU,MAAM,KAAK,QAAQ,CAAC;GAClF,oBAAoB,OAAO,cAAc,KAAK,CAAC,EAAE,sBAAsB,QAAQ,CAAC;EAClF;CACF;;;;;CAMA,oBACE,cACA,aAI2F;EAC3F,MAAM,aAAa,KAAK,cAAc,KAAK,eAAe,YAAY,CAAC;EAEvE,IAAI,CAAC,WAAW,SAAS,OAAO,EAAE,MAAM,WAAW;EACnD,MAAM,UAAU,WAAW,MAAM,YAAY;EAC7C,OAAO,gBAAgB,UACnB;GAAE,MAAM;GAAS,WAAW,WAAW;EAAU,IACjD;GAAE,MAAM;GAAuB,aAAa;EAAQ;CAC1D;;CAGA,cAAsB,WAAsB;EAC1C,IAAI,KAAKK,gBAAgB,KAAA,GAAW;GAClC,IAAI,KAAKA,YAAY,cAAc,WACjC,MAAM,IAAI,MACR,uCAAuC,KAAKA,YAAY,UAAU,aAAa,WACjF;GAEF,OAAO,KAAKA;EACd;EACA,MAAM,QAAQ,IAAI,6BAA6B;GAC7C;GACA,SAAS,oBAAoB,KAAK,IAAI,OAAO;GAC7C,YAAY,KAAKF;EACnB,CAAC;EACD,MAAM,UAAU,IAAI,+BAA+B,aACjD,KAAKD,QAAQ,QAAQ,cAAc,KAAK,IAAI,CAAC,CAC/C;EACA,KAAKG,cAAc;GAAE;GAAW,SAAS,KAAKD,mBAAmB,SAAS;GAAG;GAAO;EAAQ;EAC5F,OAAO,KAAKC;CACd;;CAGA,uBAA+B;EAC7B,MAAM,aAAa,KAAK,iBAAiB;EACzC,OAAO,YAAY,YAAY,OAAO,aAAa,KAAA;CACrD;;CAGA,mBAA2B;EACzB,IAAI,KAAKA,gBAAgB,KAAA,GAAW,OAAO,KAAKA;EAChD,MAAM,OAAO,KAAK,IAAI,GAAG;EACzB,OAAO,SAAS,KAAA,KAAa,OAAO,GAAG,SAAS,CAAC,CAAC,IAAI,IAClD,KAAK,cAAc,UAAU,KAAK,IAAI,CAAC,IACvC,KAAA;CACN;;CAGA,0BAAkC,OAAsC;EACtE,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,KAAK,GAAG,OAAO,KAAA;EACzC,MAAM,OAAO,KAAK,IAAI,GAAG;EACzB,IAAI,SAAS,KAAA,KAAa,SAAS,OAAO,OAAO,KAAA;EACjD,MAAM,QAAQ,KAAKA,aAAa;EAChC,OAAO,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,KAAK,KAAK,IAAI,KAAA;CAC1E;CAEA,eAAuB,OAA0B;EAC/C,MAAM,YAAY,UAAU,KAAK,KAAK;EACtC,MAAM,aAAa,KAAK,IAAI,GAAG;EAC/B,IAAI,eAAe,KAAA,KAAa,eAAe,WAC7C,MAAM,IAAI,MAAM,2BAA2B,WAAW,wBAAwB,WAAW;EAE3F,OAAO;CACT;CAEA,0BAAyD;EACvD,OAAO,KAAK,IAAI,GAAG,SAAS,KAAA,IAAY,KAAA,IAAY,UAAU,KAAK,KAAK,IAAI,GAAG,IAAI;CACrF;AACF;AAEA,MAAM,uBAAuB,YAAkE;CAG7F,OAAO;AACT;AAEA,MAAM,uBAAuB,UAC3B,OAAO,kBAAkB,gBAAgB,CAAC,CAAC,KAAK;AAElD,MAAM,4BAA4B,YAAuC;CACvE,MAAM,SAAS,oBACb,QAAQ,QAAQ,IAAI,aAAa,GACjC,QAAQ,QAAQ,IAAI,YAAY,CAClC;CACA,OAAO,WAAW,OAAO,yBAAyB,IAAI,+BAA+B,MAAM;AAC7F;;AAGA,MAAa,oBAAoB,WAKR;CACvB,gBAAgB;EAAE,SAAS,MAAM;EAAS,UAAU,MAAM;CAAS;CACnE,GAAI,MAAM,uBAAuB,KAAA,IAC7B,CAAC,IACD,EAAE,oBAAoB,MAAM,mBAAmB;CACnD,GAAI,MAAM,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,MAAM,aAAa;AACjF;;AAGA,MAAa,qCACX,WACgD;CAChD,UAAU,MAAM;CAChB,OAAO,yBAAyB,qBAAqB,MAAM,KAAK,CAAC;AACnE;;AAEA,MAAa,8BAA8B,OAAO,WAAW,cAAc,SAAS,MAAM"}
@@ -24,6 +24,10 @@ interface AdoptedLogIncarnation {
24
24
  * active version keeps serving and the backfill reports it.
25
25
  * - `MissedSession`: the active version is one this release no longer carries, so its history is
26
26
  * frozen behind the log and `current` is being built at once (§7 safety net).
27
+ * - `BuilderStopped`: the builder alarm failed `consecutiveFailures` times in a row, typically
28
+ * for a reason no build is charged for (cleanup or reconciliation, or a failure record storage
29
+ * refused), so the builder stopped scheduling itself. A later object start, `transcriptStatus`
30
+ * call or pending-work kick tries again, bounded the same way, and may raise it again.
27
31
  */
28
32
  type TranscriptAlert = {
29
33
  readonly _tag: "ProjectionFailed";
@@ -35,6 +39,10 @@ type TranscriptAlert = {
35
39
  readonly _tag: "MissedSession";
36
40
  readonly activeVersion: TranscriptVersion;
37
41
  readonly currentVersion: TranscriptVersion;
42
+ } | {
43
+ readonly _tag: "BuilderStopped";
44
+ readonly consecutiveFailures: number;
45
+ readonly error: string;
38
46
  };
39
47
  /**
40
48
  * Host hooks for transcript maintenance. Every hook runs only after the transaction that caused
@@ -49,6 +57,12 @@ interface DurableObjectTranscriptObserver {
49
57
  }) => void;
50
58
  /** Bounded builder or cleanup work is pending; the host schedules a slice. */
51
59
  readonly onPendingWork?: () => void;
60
+ /**
61
+ * What reads serve changed without a publication, so connected clients need a re-read: an
62
+ * active version that was behind the head (a re-enabled session) reached it (`UpdatingHistory`
63
+ * becomes `Ready`), or the active version froze (it becomes `Degraded`).
64
+ */
65
+ readonly onServedChanged?: () => void;
52
66
  }
53
67
  /** Bounds on one builder slice. */
54
68
  interface DurableObjectTranscriptSliceLimits {
@@ -58,6 +72,12 @@ interface DurableObjectTranscriptSliceLimits {
58
72
  readonly pageEvents: number;
59
73
  /** Rows of retired versions deleted per slice. */
60
74
  readonly maxDeletedRows: number;
75
+ /**
76
+ * Consecutive slices that may throw while advancing one build target before it is frozen as
77
+ * failed (and so never retried). The session object also stops its builder alarm after this
78
+ * many consecutive failed alarms.
79
+ */
80
+ readonly maxSliceFailures: number;
61
81
  }
62
82
  /** Transcript maintenance configuration of one session store. */
63
83
  interface DurableObjectTranscriptOptions {
@@ -112,4 +132,4 @@ interface DurableObjectSessionStoreOptions {
112
132
  }
113
133
  //#endregion
114
134
  export { DurableObjectTranscriptObserver as a, TranscriptAlert as c, DurableObjectSqlStorage as i, AdoptedLogIncarnation as l, DurableObjectSessionStoreOptions as n, DurableObjectTranscriptOptions as o, DurableObjectSqlCursor as r, DurableObjectTranscriptSliceLimits as s, DurableObjectSessionStorage as t };
115
- //# sourceMappingURL=durable-object-storage-D3muKtpz.d.ts.map
135
+ //# sourceMappingURL=durable-object-storage-BVsu5oAV.d.ts.map