effect-durable-agent-cloudflare 0.1.0-alpha.6 → 0.1.0-alpha.7

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/README.md CHANGED
@@ -30,6 +30,12 @@ Idle sockets use `ctx.acceptWebSocket`, Effect Schema attachments, and
30
30
  automatic ping responses. They own no timer or resident subscriber fiber.
31
31
  Register only the concrete application subclass in `wrangler.jsonc`.
32
32
 
33
+ Apps with an existing client wire contract may register one
34
+ `EDAWebSocketProjection`. An authenticated Worker selects it on the internal
35
+ request with `EDA_WEB_SOCKET_PROJECTION_HEADER`; the Durable Object still owns
36
+ the accepted socket and persists the app projection state through hibernation.
37
+ Do not build a Worker-side WebSocket bridge for protocol translation.
38
+
33
39
  Durable Object RPC uses structured clone. Encode Schema class instances before
34
40
  passing commands or batches across the Worker-to-object boundary with
35
41
  `encodeEdaRpcCommand` or `encodeEdaRpcSubmittables`.
@@ -1,4 +1,4 @@
1
- import { r as EDASessionControllerOptions } from "./session-controller-BSMHhS_l.js";
1
+ import { i as EDASessionControllerOptions, l as EDAWebSocketProjection } from "./session-controller-BCsOxE22.js";
2
2
  import { DurableObject } from "cloudflare:workers";
3
3
  import { CommittedCommandTerminalEvent, EDARuntimeConfig } from "effect-durable-agent/services/runtime";
4
4
  import { CommittedDurableEvent } from "effect-durable-agent/services/session-store";
@@ -6,6 +6,8 @@ import { DurableTranscriptMessage } from "effect-durable-agent/domain/message-tr
6
6
  import { EDASessionSnapshot } from "effect-durable-agent/services/session-query";
7
7
 
8
8
  //#region src/durable-object.d.ts
9
+ /** Internal Worker-to-object header selecting an app-owned WebSocket projection. */
10
+ declare const EDA_WEB_SOCKET_PROJECTION_HEADER = "x-eda-websocket-projection";
9
11
  /** Raw RPC shape decoded before admitting one session command. */
10
12
  interface EDASessionCommandRpcInput {
11
13
  readonly command: unknown;
@@ -36,10 +38,20 @@ interface EDASessionBlockOnCommandRpcInput {
36
38
  readonly sessionId: string;
37
39
  readonly trace: unknown;
38
40
  }
41
+ /** EDA RPC methods required by the session namespace helper. */
42
+ interface EDASessionRpcSurface {
43
+ readonly submit: (input: EDASessionCommandRpcInput) => Promise<CommittedDurableEvent>;
44
+ readonly submitBatch: (input: EDASessionSubmitBatchRpcInput) => Promise<ReadonlyArray<CommittedDurableEvent>>;
45
+ readonly submitAndBlock: (input: EDASessionCommandRpcInput) => Promise<CommittedCommandTerminalEvent>;
46
+ readonly blockOnCommand: (input: EDASessionBlockOnCommandRpcInput) => Promise<CommittedCommandTerminalEvent>;
47
+ readonly snapshot: (input: EDASessionScopedRpcInput) => Promise<EDASessionSnapshot>;
48
+ readonly messages: (input: EDASessionScopedRpcInput) => Promise<ReadonlyArray<DurableTranscriptMessage>>;
49
+ readonly destroySession: (input: EDASessionScopedRpcInput) => Promise<void>;
50
+ }
39
51
  /** Constructor options for concrete app subclasses of the EDA Durable Object base. */
40
- type EDASessionDurableObjectOptions = Omit<EDASessionControllerOptions, "background" | "getWebSockets" | "storage">;
52
+ type EDASessionDurableObjectOptions<ProjectionState extends object = never> = Omit<EDASessionControllerOptions<ProjectionState>, "background" | "getWebSockets" | "storage">;
41
53
  /** Resolve a concrete EDA session Durable Object binding by domain session id. */
42
- declare const getEDASessionDurableObjectByName: <T extends EDASessionDurableObject<object>>(namespace: DurableObjectNamespace<T>, sessionId: string) => DurableObjectStub<T>;
54
+ declare const getEDASessionDurableObjectByName: <T extends Rpc.DurableObjectBranded & EDASessionRpcSurface>(namespace: DurableObjectNamespace<T>, sessionId: string) => DurableObjectStub<T>;
43
55
  /**
44
56
  * Base class for raw Cloudflare Durable Object hosts of one EDA session.
45
57
  *
@@ -48,9 +60,9 @@ declare const getEDASessionDurableObjectByName: <T extends EDASessionDurableObje
48
60
  * class is deliberately not exported from `workers/app.ts` and owns no binding
49
61
  * name or routing convention.
50
62
  */
51
- declare abstract class EDASessionDurableObject<EnvType extends object = object> extends DurableObject<EnvType> {
63
+ declare abstract class EDASessionDurableObject<EnvType extends object = object, ProjectionState extends object = never> extends DurableObject<EnvType> {
52
64
  #private;
53
- protected constructor(ctx: DurableObjectState, env: EnvType, options: EDASessionDurableObjectOptions);
65
+ protected constructor(ctx: DurableObjectState, env: EnvType, options: EDASessionDurableObjectOptions<ProjectionState>);
54
66
  fetch(request: Request): Promise<Response>;
55
67
  submit(input: EDASessionCommandRpcInput): Promise<CommittedDurableEvent>;
56
68
  submitBatch(input: EDASessionSubmitBatchRpcInput): Promise<ReadonlyArray<CommittedDurableEvent>>;
@@ -78,5 +90,5 @@ declare const encodeEdaRpcCommittedDurableEvent: (event: CommittedDurableEvent)
78
90
  /** Encode runtime snapshots into structured-clone-safe Durable Object RPC payloads. */
79
91
  declare const encodeEdaRpcSessionSnapshot: (snapshot: EDASessionSnapshot) => EDASessionSnapshot;
80
92
  //#endregion
81
- export { EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionEventsRpcInput, EDASessionScopedRpcInput, EDASessionSubmitBatchRpcInput, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
93
+ export { EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionEventsRpcInput, EDASessionRpcSurface, EDASessionScopedRpcInput, EDASessionSubmitBatchRpcInput, type EDAWebSocketProjection, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
82
94
  //# sourceMappingURL=durable-object.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { decodeEdaRpcCommand, decodeEdaRpcSubmittables, encodeEdaRpcDurableEvent } from "./rpc.js";
2
- import { t as EDASessionController } from "./session-controller-Bo7DyydT.js";
2
+ import { t as EDASessionController } from "./session-controller-CMbW7vgf.js";
3
3
  import { DurableObject } from "cloudflare:workers";
4
4
  import * as Effect from "effect/Effect";
5
5
  import * as Schema from "effect/Schema";
@@ -8,6 +8,8 @@ import { CommandId, SequenceNumber, SessionId } from "effect-durable-agent/types
8
8
  import { EDATraceMetadata, makeEDATraceMetadataFromParent, makeRootEDATraceMetadata, parseEDATraceparent } from "effect-durable-agent/types/tracing";
9
9
  import { EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE } from "effect-durable-agent/websocket";
10
10
  //#region src/durable-object.ts
11
+ /** Internal Worker-to-object header selecting an app-owned WebSocket projection. */
12
+ const EDA_WEB_SOCKET_PROJECTION_HEADER = "x-eda-websocket-projection";
11
13
  /** Resolve a concrete EDA session Durable Object binding by domain session id. */
12
14
  const getEDASessionDurableObjectByName = (namespace, sessionId) => namespace.getByName(sessionId);
13
15
  /**
@@ -20,8 +22,10 @@ const getEDASessionDurableObjectByName = (namespace, sessionId) => namespace.get
20
22
  */
21
23
  var EDASessionDurableObject = class extends DurableObject {
22
24
  #controller;
25
+ #webSocketProjectionId;
23
26
  constructor(ctx, env, options) {
24
27
  super(ctx, env);
28
+ this.#webSocketProjectionId = options.webSocketProjection?.id;
25
29
  const storage = toEDASessionStorage(this.ctx.storage);
26
30
  this.#controller = new EDASessionController({
27
31
  ...options,
@@ -39,16 +43,25 @@ var EDASessionDurableObject = class extends DurableObject {
39
43
  const url = new URL(request.url);
40
44
  const sessionIdRaw = url.searchParams.get("sessionId");
41
45
  if (sessionIdRaw === null) return new Response("Missing sessionId.", { status: 400 });
42
- const afterSeq = Number(url.searchParams.get("afterSeq") ?? "0");
43
- if (!Number.isInteger(afterSeq) || afterSeq < 0) return new Response("Invalid afterSeq.", { status: 400 });
46
+ const afterSeqRaw = url.searchParams.get("afterSeq");
47
+ const afterSeq = afterSeqRaw === null ? void 0 : Number(afterSeqRaw);
48
+ if (afterSeq !== void 0 && (!Number.isInteger(afterSeq) || afterSeq < 0)) return new Response("Invalid afterSeq.", { status: 400 });
49
+ const projectionId = request.headers.get("x-eda-websocket-projection") ?? void 0;
50
+ if (projectionId !== void 0 && projectionId !== this.#webSocketProjectionId) return new Response("Unsupported WebSocket projection.", { status: 400 });
51
+ const sessionId = this.parseSessionId(sessionIdRaw);
52
+ const trace = traceMetadataFromRequest(request);
53
+ const prepared = await this.#controller.prepareEventWebSocket({
54
+ ...afterSeq === void 0 ? {} : { afterSeq: SequenceNumber.make(afterSeq) },
55
+ sessionId,
56
+ trace,
57
+ ...projectionId === void 0 ? {} : { projectionId }
58
+ });
44
59
  const pair = new WebSocketPair();
45
60
  const client = pair[0];
46
61
  const server = pair[1];
47
62
  this.ctx.acceptWebSocket(server);
48
- await this.#controller.acceptEventWebSocket({
49
- afterSeq: SequenceNumber.make(afterSeq),
50
- sessionId: this.parseSessionId(sessionIdRaw),
51
- trace: traceMetadataFromRequest(request),
63
+ await this.#controller.acceptPreparedEventWebSocket({
64
+ ...prepared,
52
65
  webSocket: server
53
66
  });
54
67
  return new Response(null, {
@@ -175,6 +188,6 @@ const encodeCommandCarrierForRpc = (value) => value.command === void 0 ? value :
175
188
  const decodeCommand = (input) => Effect.runPromise(decodeEdaRpcCommand(input));
176
189
  const decodeSubmittables = (input) => Effect.runPromise(decodeEdaRpcSubmittables(input));
177
190
  //#endregion
178
- export { EDASessionDurableObject, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
191
+ export { EDASessionDurableObject, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName };
179
192
 
180
193
  //# sourceMappingURL=durable-object.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"durable-object.js","names":["#controller"],"sources":["../src/durable-object.ts"],"sourcesContent":["import { DurableObject } from \"cloudflare:workers\";\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\n\nimport type { DurableTranscriptMessage } from \"effect-durable-agent/domain/message-transcript\";\nimport {\n decodeEdaRpcCommand,\n decodeEdaRpcSubmittables,\n encodeEdaRpcDurableEvent,\n} from \"./rpc-codec\";\nimport type { EDASessionSnapshot } from \"effect-durable-agent/services/session-query\";\nimport type { CommittedDurableEvent as CommittedDurableEventValue } from \"effect-durable-agent/services/session-store\";\nimport type {\n CommittedCommandTerminalEvent,\n EDARuntimeConfig,\n} from \"effect-durable-agent/services/runtime\";\nimport {\n EDACommand,\n type EDACommand as EDACommandValue,\n} from \"effect-durable-agent/types/commands\";\nimport type { EDASubmittable } from \"effect-durable-agent/services/session-state\";\nimport { CommandId, SequenceNumber, SessionId } 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\";\n\n/** Raw RPC shape decoded before admitting one session command. */\nexport interface EDASessionCommandRpcInput {\n readonly command: unknown;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape decoded before admitting a durable command/app-event batch. */\nexport interface EDASessionSubmitBatchRpcInput {\n readonly items: ReadonlyArray<unknown>;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape for read/destroy operations that only need a session id. */\nexport interface EDASessionScopedRpcInput {\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape for WebSocket event-stream upgrades with a resume cursor. */\nexport interface EDASessionEventsRpcInput {\n readonly afterSeq?: number;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape decoded before blocking on one command terminal event. */\nexport interface EDASessionBlockOnCommandRpcInput {\n readonly afterSeq?: number;\n readonly commandId: string;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Constructor options for concrete app subclasses of the EDA Durable Object base. */\nexport type EDASessionDurableObjectOptions = Omit<\n EDASessionControllerOptions,\n \"background\" | \"getWebSockets\" | \"storage\"\n>;\n\n/** Resolve a concrete EDA session Durable Object binding by domain session id. */\nexport const getEDASessionDurableObjectByName = <T extends EDASessionDurableObject<object>>(\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> extends DurableObject<EnvType> {\n readonly #controller: EDASessionController;\n\n protected constructor(\n ctx: DurableObjectState,\n env: EnvType,\n options: EDASessionDurableObjectOptions,\n ) {\n super(ctx, env);\n const storage = toEDASessionStorage(this.ctx.storage);\n this.#controller = new EDASessionController({\n ...options,\n background: this.ctx,\n getWebSockets: () => this.ctx.getWebSockets(),\n storage,\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 });\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 afterSeq = Number(url.searchParams.get(\"afterSeq\") ?? \"0\");\n if (!Number.isInteger(afterSeq) || afterSeq < 0) {\n return new Response(\"Invalid afterSeq.\", { status: 400 });\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.acceptEventWebSocket({\n afterSeq: SequenceNumber.make(afterSeq),\n sessionId: this.parseSessionId(sessionIdRaw),\n trace: traceMetadataFromRequest(request),\n webSocket: server,\n });\n return new Response(null, { status: 101, webSocket: client });\n }\n\n async submit(input: EDASessionCommandRpcInput): Promise<CommittedDurableEventValue> {\n const committed = await this.#controller.submit({\n command: await decodeCommand(input.command),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcCommittedDurableEvent(committed);\n }\n\n async submitBatch(\n input: EDASessionSubmitBatchRpcInput,\n ): Promise<ReadonlyArray<CommittedDurableEventValue>> {\n const committed = await this.#controller.submitBatch({\n items: await decodeSubmittables(input.items),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return committed.map(encodeEdaRpcCommittedDurableEvent);\n }\n\n async submitAndBlock(input: EDASessionCommandRpcInput): Promise<CommittedCommandTerminalEvent> {\n const committed = await this.#controller.submitAndBlock({\n command: await decodeCommand(input.command),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcCommittedDurableEvent(committed) as CommittedCommandTerminalEvent;\n }\n\n async blockOnCommand(\n input: EDASessionBlockOnCommandRpcInput,\n ): Promise<CommittedCommandTerminalEvent> {\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 encodeEdaRpcCommittedDurableEvent(committed) as CommittedCommandTerminalEvent;\n }\n\n async snapshot(input: EDASessionScopedRpcInput): Promise<EDASessionSnapshot> {\n const snapshot = await this.#controller.snapshot({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcSessionSnapshot(snapshot);\n }\n\n async messages(\n input: EDASessionScopedRpcInput,\n ): Promise<ReadonlyArray<DurableTranscriptMessage>> {\n return await this.#controller.messages({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\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(input: EDASessionScopedRpcInput): Promise<void> {\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 }\n\n async alarm(): Promise<void> {\n const sessionId = this.sessionIdFromObjectName();\n await this.#controller.alarm(\n sessionId === undefined ? undefined : { sessionId, trace: makeRootEDATraceMetadata() },\n );\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 structured-clone-safe Durable Object RPC payloads. */\nexport const encodeEdaRpcCommittedDurableEvent = (\n event: CommittedDurableEventValue,\n): CommittedDurableEventValue => ({\n position: event.position,\n event: encodeEdaRpcDurableEvent(event.event),\n});\n\n/** Encode runtime snapshots into structured-clone-safe Durable Object RPC payloads. */\nexport const encodeEdaRpcSessionSnapshot = (snapshot: EDASessionSnapshot): EDASessionSnapshot => ({\n ...snapshot,\n reducerStates: new Map(snapshot.reducerStates),\n state: {\n ...snapshot.state,\n commands: new Map(\n Array.from(snapshot.state.commands, ([commandId, record]) => [\n commandId,\n encodeCommandCarrierForRpc(record),\n ]),\n ),\n commandQueues: {\n ...snapshot.state.commandQueues,\n activeControlCommands: snapshot.state.commandQueues.activeControlCommands.map(\n encodeCommandCarrierForRpc,\n ),\n pendingCommands: snapshot.state.commandQueues.pendingCommands.map(encodeCommandCarrierForRpc),\n queuedCommands: snapshot.state.commandQueues.queuedCommands.map(encodeCommandCarrierForRpc),\n },\n },\n});\n\nconst encodeCommandCarrierForRpc = <A extends { readonly command?: EDACommandValue }>(\n value: A,\n): A =>\n value.command === undefined\n ? value\n : {\n ...value,\n command: Schema.encodeSync(EDACommand)(value.command) as EDACommandValue,\n };\n\nconst decodeCommand = (input: unknown): Promise<EDACommandValue> =>\n Effect.runPromise(decodeEdaRpcCommand(input));\n\nconst decodeSubmittables = (\n input: ReadonlyArray<unknown>,\n): Promise<ReadonlyArray<EDASubmittable>> => Effect.runPromise(decodeEdaRpcSubmittables(input));\n"],"mappings":"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"}
1
+ {"version":3,"file":"durable-object.js","names":["#controller","#webSocketProjectionId"],"sources":["../src/durable-object.ts"],"sourcesContent":["import { DurableObject } from \"cloudflare:workers\";\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\n\nimport type { DurableTranscriptMessage } from \"effect-durable-agent/domain/message-transcript\";\nimport {\n decodeEdaRpcCommand,\n decodeEdaRpcSubmittables,\n encodeEdaRpcDurableEvent,\n} from \"./rpc-codec\";\nimport type { EDASessionSnapshot } from \"effect-durable-agent/services/session-query\";\nimport type { CommittedDurableEvent as CommittedDurableEventValue } from \"effect-durable-agent/services/session-store\";\nimport type {\n CommittedCommandTerminalEvent,\n EDARuntimeConfig,\n} from \"effect-durable-agent/services/runtime\";\nimport {\n EDACommand,\n type EDACommand as EDACommandValue,\n} from \"effect-durable-agent/types/commands\";\nimport type { EDASubmittable } from \"effect-durable-agent/services/session-state\";\nimport { CommandId, SequenceNumber, SessionId } 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\";\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/** Raw RPC shape decoded before admitting one session command. */\nexport interface EDASessionCommandRpcInput {\n readonly command: unknown;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape decoded before admitting a durable command/app-event batch. */\nexport interface EDASessionSubmitBatchRpcInput {\n readonly items: ReadonlyArray<unknown>;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape for read/destroy operations that only need a session id. */\nexport interface EDASessionScopedRpcInput {\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape for WebSocket event-stream upgrades with a resume cursor. */\nexport interface EDASessionEventsRpcInput {\n readonly afterSeq?: number;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** Raw RPC shape decoded before blocking on one command terminal event. */\nexport interface EDASessionBlockOnCommandRpcInput {\n readonly afterSeq?: number;\n readonly commandId: string;\n readonly sessionId: string;\n readonly trace: unknown;\n}\n\n/** EDA RPC methods required by the session namespace helper. */\nexport interface EDASessionRpcSurface {\n readonly submit: (input: EDASessionCommandRpcInput) => Promise<CommittedDurableEventValue>;\n readonly submitBatch: (\n input: EDASessionSubmitBatchRpcInput,\n ) => Promise<ReadonlyArray<CommittedDurableEventValue>>;\n readonly submitAndBlock: (\n input: EDASessionCommandRpcInput,\n ) => Promise<CommittedCommandTerminalEvent>;\n readonly blockOnCommand: (\n input: EDASessionBlockOnCommandRpcInput,\n ) => Promise<CommittedCommandTerminalEvent>;\n readonly snapshot: (input: EDASessionScopedRpcInput) => Promise<EDASessionSnapshot>;\n readonly messages: (\n input: EDASessionScopedRpcInput,\n ) => Promise<ReadonlyArray<DurableTranscriptMessage>>;\n readonly destroySession: (input: EDASessionScopedRpcInput) => Promise<void>;\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 \"background\" | \"getWebSockets\" | \"storage\"\n>;\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\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.#controller = new EDASessionController({\n ...options,\n background: this.ctx,\n getWebSockets: () => this.ctx.getWebSockets(),\n storage,\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 });\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.parseSessionId(sessionIdRaw);\n const trace = traceMetadataFromRequest(request);\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(input: EDASessionCommandRpcInput): Promise<CommittedDurableEventValue> {\n const committed = await this.#controller.submit({\n command: await decodeCommand(input.command),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcCommittedDurableEvent(committed);\n }\n\n async submitBatch(\n input: EDASessionSubmitBatchRpcInput,\n ): Promise<ReadonlyArray<CommittedDurableEventValue>> {\n const committed = await this.#controller.submitBatch({\n items: await decodeSubmittables(input.items),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return committed.map(encodeEdaRpcCommittedDurableEvent);\n }\n\n async submitAndBlock(input: EDASessionCommandRpcInput): Promise<CommittedCommandTerminalEvent> {\n const committed = await this.#controller.submitAndBlock({\n command: await decodeCommand(input.command),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcCommittedDurableEvent(committed) as CommittedCommandTerminalEvent;\n }\n\n async blockOnCommand(\n input: EDASessionBlockOnCommandRpcInput,\n ): Promise<CommittedCommandTerminalEvent> {\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 encodeEdaRpcCommittedDurableEvent(committed) as CommittedCommandTerminalEvent;\n }\n\n async snapshot(input: EDASessionScopedRpcInput): Promise<EDASessionSnapshot> {\n const snapshot = await this.#controller.snapshot({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcSessionSnapshot(snapshot);\n }\n\n async messages(\n input: EDASessionScopedRpcInput,\n ): Promise<ReadonlyArray<DurableTranscriptMessage>> {\n return await this.#controller.messages({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\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(input: EDASessionScopedRpcInput): Promise<void> {\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 }\n\n async alarm(): Promise<void> {\n const sessionId = this.sessionIdFromObjectName();\n await this.#controller.alarm(\n sessionId === undefined ? undefined : { sessionId, trace: makeRootEDATraceMetadata() },\n );\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 structured-clone-safe Durable Object RPC payloads. */\nexport const encodeEdaRpcCommittedDurableEvent = (\n event: CommittedDurableEventValue,\n): CommittedDurableEventValue => ({\n position: event.position,\n event: encodeEdaRpcDurableEvent(event.event),\n});\n\n/** Encode runtime snapshots into structured-clone-safe Durable Object RPC payloads. */\nexport const encodeEdaRpcSessionSnapshot = (snapshot: EDASessionSnapshot): EDASessionSnapshot => ({\n ...snapshot,\n reducerStates: new Map(snapshot.reducerStates),\n state: {\n ...snapshot.state,\n commands: new Map(\n Array.from(snapshot.state.commands, ([commandId, record]) => [\n commandId,\n encodeCommandCarrierForRpc(record),\n ]),\n ),\n commandQueues: {\n ...snapshot.state.commandQueues,\n activeControlCommands: snapshot.state.commandQueues.activeControlCommands.map(\n encodeCommandCarrierForRpc,\n ),\n pendingCommands: snapshot.state.commandQueues.pendingCommands.map(encodeCommandCarrierForRpc),\n queuedCommands: snapshot.state.commandQueues.queuedCommands.map(encodeCommandCarrierForRpc),\n },\n },\n});\n\nconst encodeCommandCarrierForRpc = <A extends { readonly command?: EDACommandValue }>(\n value: A,\n): A =>\n value.command === undefined\n ? value\n : {\n ...value,\n command: Schema.encodeSync(EDACommand)(value.command) as EDACommandValue,\n };\n\nconst decodeCommand = (input: unknown): Promise<EDACommandValue> =>\n Effect.runPromise(decodeEdaRpcCommand(input));\n\nconst decodeSubmittables = (\n input: ReadonlyArray<unknown>,\n): Promise<ReadonlyArray<EDASubmittable>> => Effect.runPromise(decodeEdaRpcSubmittables(input));\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { i as DurableObjectSqlStorage, n as DurableObjectSessionStoreOptions, r as DurableObjectSqlCursor, t as DurableObjectSessionStorage } from "./durable-object-storage-DCL2IyUe.js";
2
- import { a as EDASessionScopedInput, c as EDADurableObjectRuntimeLayerOptions, i as EDASessionEventsInput, l as EDASessionDurableObjectStorage, n as EDASessionController, o as EDASessionSubmitBatchInput, r as EDASessionControllerOptions, s as EDASessionSubmitInput, t as EDASessionBlockOnCommandInput, u as makeEDADurableObjectRuntimeLayer } from "./session-controller-BSMHhS_l.js";
3
- import { EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionEventsRpcInput, EDASessionScopedRpcInput, EDASessionSubmitBatchRpcInput, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName } from "./durable-object.js";
2
+ import { a as EDASessionEventsInput, c as EDASessionSubmitInput, d as EDAWebSocketProjectionInitial, f as EDAWebSocketProjectionResult, h as makeEDADurableObjectRuntimeLayer, i as EDASessionControllerOptions, l as EDAWebSocketProjection, m as EDASessionDurableObjectStorage, n as EDASessionBlockOnCommandInput, o as EDASessionScopedInput, p as EDADurableObjectRuntimeLayerOptions, r as EDASessionController, s as EDASessionSubmitBatchInput, t as EDAPreparedEventWebSocket, u as EDAWebSocketProjectionId } from "./session-controller-BCsOxE22.js";
3
+ import { EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionEventsRpcInput, EDASessionRpcSurface, EDASessionScopedRpcInput, EDASessionSubmitBatchRpcInput, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName } from "./durable-object.js";
4
4
  import { EDAOpenAiModelConfig, makeEDADurableObjectOpenAiModelLayer } from "./openai.js";
5
5
  import { decodeEdaRpcCommand, decodeEdaRpcSubmittables, encodeEdaRpcCommand, encodeEdaRpcDurableEvent, encodeEdaRpcSubmittables } from "./rpc.js";
6
- export { DurableObjectSessionStorage, DurableObjectSessionStoreOptions, DurableObjectSqlCursor, DurableObjectSqlStorage, EDADurableObjectRuntimeLayerOptions, EDAOpenAiModelConfig, EDASessionBlockOnCommandInput, EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionController, EDASessionControllerOptions, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionDurableObjectStorage, EDASessionEventsInput, EDASessionEventsRpcInput, EDASessionScopedInput, EDASessionScopedRpcInput, EDASessionSubmitBatchInput, EDASessionSubmitBatchRpcInput, EDASessionSubmitInput, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectRuntimeLayer };
6
+ export { DurableObjectSessionStorage, DurableObjectSessionStoreOptions, DurableObjectSqlCursor, DurableObjectSqlStorage, EDADurableObjectRuntimeLayerOptions, EDAOpenAiModelConfig, EDAPreparedEventWebSocket, EDASessionBlockOnCommandInput, EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionController, EDASessionControllerOptions, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionDurableObjectStorage, EDASessionEventsInput, EDASessionEventsRpcInput, EDASessionRpcSurface, EDASessionScopedInput, EDASessionScopedRpcInput, EDASessionSubmitBatchInput, EDASessionSubmitBatchRpcInput, EDASessionSubmitInput, EDAWebSocketProjection, EDAWebSocketProjectionId, EDAWebSocketProjectionInitial, EDAWebSocketProjectionResult, EDA_WEB_SOCKET_PROJECTION_HEADER, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectRuntimeLayer };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { decodeEdaRpcCommand, decodeEdaRpcSubmittables, encodeEdaRpcCommand, encodeEdaRpcDurableEvent, encodeEdaRpcSubmittables } from "./rpc.js";
2
- import { n as makeEDADurableObjectRuntimeLayer, t as EDASessionController } from "./session-controller-Bo7DyydT.js";
3
- import { EDASessionDurableObject, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName } from "./durable-object.js";
2
+ import { n as EDAWebSocketProjectionId, r as makeEDADurableObjectRuntimeLayer, t as EDASessionController } from "./session-controller-CMbW7vgf.js";
3
+ import { EDASessionDurableObject, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName } from "./durable-object.js";
4
4
  import "./storage.js";
5
5
  import { makeEDADurableObjectOpenAiModelLayer } from "./openai.js";
6
- export { EDASessionController, EDASessionDurableObject, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectRuntimeLayer };
6
+ export { EDASessionController, EDASessionDurableObject, EDAWebSocketProjectionId, EDA_WEB_SOCKET_PROJECTION_HEADER, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectRuntimeLayer };
@@ -1,5 +1,6 @@
1
1
  import { t as DurableObjectSessionStorage } from "./durable-object-storage-DCL2IyUe.js";
2
2
  import * as Effect from "effect/Effect";
3
+ import * as Schema from "effect/Schema";
3
4
  import { EDACommand } from "effect-durable-agent/types/commands";
4
5
  import { CommandId, SequenceNumber, SessionId } from "effect-durable-agent/types/core";
5
6
  import { EDATraceMetadata } from "effect-durable-agent/types/tracing";
@@ -10,7 +11,7 @@ import { CompactionExecutor, CompactionPolicy } from "effect-durable-agent/servi
10
11
  import { EDAPromptProjector } from "effect-durable-agent/services/prompt-projector";
11
12
  import { EDAReducer } from "effect-durable-agent/services/reducer-registry";
12
13
  import { SessionEventObserver } from "effect-durable-agent/services/session-event-observer";
13
- import { EDAWebSocketServerFrameEncoder } from "effect-durable-agent/websocket";
14
+ import { EDAWebSocketClientFrame, EDAWebSocketServerFrameEncoder, EDAWebSocketServerFrameInput } from "effect-durable-agent/websocket";
14
15
  import { DurableTranscriptMessage } from "effect-durable-agent/domain/message-transcript";
15
16
  import { EDASessionSnapshot } from "effect-durable-agent/services/session-query";
16
17
  import { EDASubmittable, SessionCommandAdmissionError } from "effect-durable-agent/services/session-state";
@@ -165,10 +166,54 @@ interface EDASessionRuntimeOptions {
165
166
  readonly tracer?: Tracer.Tracer | EDATracerFactory;
166
167
  }
167
168
  //#endregion
169
+ //#region src/websocket/projection.d.ts
170
+ /** Stable non-empty identity persisted with an app WebSocket projection. */
171
+ declare const EDAWebSocketProjectionId: Schema.brand<Schema.NonEmptyString, "EDAWebSocketProjectionId">;
172
+ type EDAWebSocketProjectionId = typeof EDAWebSocketProjectionId.Type;
173
+ /** Initial state and cursor selected when an app-projected WebSocket is accepted. */
174
+ interface EDAWebSocketProjectionInitial<State extends object> {
175
+ readonly afterSeq: SequenceNumber;
176
+ readonly state: State;
177
+ }
178
+ /** App projection decision for one EDA delivery frame. */
179
+ type EDAWebSocketProjectionResult<State extends object> = {
180
+ readonly _tag: "Send";
181
+ readonly frame: string;
182
+ readonly state: State;
183
+ } | {
184
+ /** Suppress an internal-only events frame and advance its ACK in the host. */readonly _tag: "SuppressAndAck";
185
+ readonly state: State;
186
+ };
187
+ /**
188
+ * App-owned wire projection hosted directly by the EDA Durable Object.
189
+ *
190
+ * The host persists `State` beside EDA delivery state, so an app can retain a
191
+ * stable public protocol without placing a resident WebSocket bridge in front
192
+ * of the hibernating object.
193
+ */
194
+ interface EDAWebSocketProjection<State extends object> {
195
+ /** Stable identifier persisted in WebSocket attachments. */
196
+ readonly id: EDAWebSocketProjectionId;
197
+ /** Decode one app-protocol client message into EDA's delivery ACK protocol. */
198
+ readonly decodeClientMessage: (message: string) => Effect.Effect<EDAWebSocketClientFrame, unknown>;
199
+ /** Restore app-owned connection state after isolate eviction. */
200
+ readonly decodeState: (encoded: unknown) => Effect.Effect<State, unknown>;
201
+ /** Encode app-owned connection state for Cloudflare's attachment boundary. */
202
+ readonly encodeState: (state: State) => unknown;
203
+ /** Project one EDA server frame while updating app-owned connection state. */
204
+ readonly encodeServerFrame: (frame: EDAWebSocketServerFrameInput, state: State) => EDAWebSocketProjectionResult<State>;
205
+ /** Seed the projection and select its default replay cursor from a durable snapshot. */
206
+ readonly initialize: (input: {
207
+ readonly requestedAfterSeq?: SequenceNumber;
208
+ readonly snapshot: EDASessionSnapshot;
209
+ }) => EDAWebSocketProjectionInitial<State>;
210
+ }
211
+ //#endregion
168
212
  //#region src/session-controller.d.ts
169
213
  /** Composition options for the session use cases and Cloudflare adapters. */
170
- interface EDASessionControllerOptions extends Omit<EDASessionRuntimeOptions, "sessionEventObserverLayer"> {
214
+ interface EDASessionControllerOptions<ProjectionState extends object = never> extends Omit<EDASessionRuntimeOptions, "sessionEventObserverLayer"> {
171
215
  readonly getWebSockets?: () => ReadonlyArray<WebSocket>;
216
+ readonly webSocketProjection?: EDAWebSocketProjection<ProjectionState>;
172
217
  readonly webSocketProtocol?: EDAWebSocketServerFrameEncoder;
173
218
  }
174
219
  interface EDASessionSubmitInput {
@@ -196,16 +241,23 @@ interface EDASessionEventsInput {
196
241
  readonly sessionId: SessionId;
197
242
  readonly trace?: EDATraceMetadata;
198
243
  }
244
+ /** Prepared acceptance state created before a Cloudflare socket is registered. */
245
+ interface EDAPreparedEventWebSocket<ProjectionState extends object = never> {
246
+ readonly afterSeq: SequenceNumber;
247
+ readonly sessionId: SessionId;
248
+ readonly trace: EDATraceMetadata;
249
+ readonly projectionState?: ProjectionState;
250
+ }
199
251
  /**
200
252
  * Public application-facing use cases for one EDA session.
201
253
  *
202
254
  * Runtime lifecycle belongs to EDASessionRuntime; WebSocket transport belongs
203
255
  * to EDAWebSocketConnectionManager. This class only coordinates them.
204
256
  */
205
- declare class EDASessionController {
257
+ declare class EDASessionController<ProjectionState extends object = never> {
206
258
  private readonly runtime;
207
259
  private readonly webSockets;
208
- constructor(options: EDASessionControllerOptions);
260
+ constructor(options: EDASessionControllerOptions<ProjectionState>);
209
261
  static readonly migrate: (storage: EDASessionDurableObjectStorage) => Effect.Effect<void, import("effect-durable-agent/services/session-store").EDASessionStoreError>;
210
262
  submit(input: EDASessionSubmitInput): Promise<CommittedDurableEvent>;
211
263
  submitBatch(input: EDASessionSubmitBatchInput): Promise<ReadonlyArray<CommittedDurableEvent>>;
@@ -214,6 +266,14 @@ declare class EDASessionController {
214
266
  snapshot(input: EDASessionScopedInput): Promise<EDASessionSnapshot>;
215
267
  messages(input: EDASessionScopedInput): Promise<ReadonlyArray<DurableTranscriptMessage>>;
216
268
  acceptEventWebSocket(input: EDASessionEventsInput & {
269
+ readonly projectionId?: string;
270
+ readonly webSocket: WebSocket;
271
+ }): Promise<void>;
272
+ private acceptEventWebSocketUnhosted;
273
+ prepareEventWebSocket(input: EDASessionEventsInput & {
274
+ readonly projectionId?: string;
275
+ }): Promise<EDAPreparedEventWebSocket<ProjectionState>>;
276
+ acceptPreparedEventWebSocket(input: EDAPreparedEventWebSocket<ProjectionState> & {
217
277
  readonly webSocket: WebSocket;
218
278
  }): Promise<void>;
219
279
  webSocketMessage(webSocket: WebSocket, message: string | ArrayBuffer): Promise<void>;
@@ -227,5 +287,5 @@ declare class EDASessionController {
227
287
  private run;
228
288
  }
229
289
  //#endregion
230
- export { EDASessionScopedInput as a, EDADurableObjectRuntimeLayerOptions as c, EDASessionEventsInput as i, EDASessionDurableObjectStorage as l, EDASessionController as n, EDASessionSubmitBatchInput as o, EDASessionControllerOptions as r, EDASessionSubmitInput as s, EDASessionBlockOnCommandInput as t, makeEDADurableObjectRuntimeLayer as u };
231
- //# sourceMappingURL=session-controller-BSMHhS_l.d.ts.map
290
+ export { EDASessionEventsInput as a, EDASessionSubmitInput as c, EDAWebSocketProjectionInitial as d, EDAWebSocketProjectionResult as f, makeEDADurableObjectRuntimeLayer as h, EDASessionControllerOptions as i, EDAWebSocketProjection as l, EDASessionDurableObjectStorage as m, EDASessionBlockOnCommandInput as n, EDASessionScopedInput as o, EDADurableObjectRuntimeLayerOptions as p, EDASessionController as r, EDASessionSubmitBatchInput as s, EDAPreparedEventWebSocket as t, EDAWebSocketProjectionId as u };
291
+ //# sourceMappingURL=session-controller-BCsOxE22.d.ts.map