effect-cf 0.40.0 → 0.40.2

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.
Files changed (166) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +2 -0
  3. package/dist/AiGateway.d.mts +86 -0
  4. package/dist/AiGateway.mjs +178 -0
  5. package/dist/AnalyticsEngine.d.mts +170 -0
  6. package/dist/AnalyticsEngine.mjs +275 -0
  7. package/dist/{Artifacts-B3r3RuTB.d.mts → Artifacts.d.mts} +8 -5
  8. package/dist/{Artifacts-CBxWGeZB.mjs → Artifacts.mjs} +9 -5
  9. package/dist/Binding.d.mts +45 -0
  10. package/dist/{Binding-C82jRhdr.mjs → Binding.mjs} +8 -4
  11. package/dist/BrowserRendering.d.mts +85 -0
  12. package/dist/BrowserRendering.mjs +81 -0
  13. package/dist/Cache.d.mts +40 -0
  14. package/dist/Cache.mjs +51 -0
  15. package/dist/CloudflareOtlp.d.mts +95 -0
  16. package/dist/CloudflareOtlp.mjs +125 -0
  17. package/dist/CloudflareTracer.d.mts +20 -0
  18. package/dist/CloudflareTracer.mjs +69 -0
  19. package/dist/ComputerArtifacts.d.mts +2 -2
  20. package/dist/ComputerArtifacts.mjs +3 -2
  21. package/dist/ComputerWorkspace.d.mts +36 -31
  22. package/dist/ComputerWorkspace.mjs +8 -3
  23. package/dist/ComputerWorkspaceHost.d.mts +1 -1
  24. package/dist/ComputerWorkspaceHost.mjs +1 -1
  25. package/dist/{ContainerNamespace-DbLaeFhN.d.mts → ContainerNamespace.d.mts} +16 -12
  26. package/dist/ContainerNamespace.mjs +165 -0
  27. package/dist/D1.d.mts +33 -0
  28. package/dist/D1.mjs +32 -0
  29. package/dist/DurableObject.d.mts +103 -0
  30. package/dist/DurableObject.mjs +77 -0
  31. package/dist/DurableObjectAlarm.d.mts +187 -0
  32. package/dist/DurableObjectAlarm.mjs +344 -0
  33. package/dist/DurableObjectDefinition.d.mts +87 -0
  34. package/dist/DurableObjectDefinition.mjs +125 -0
  35. package/dist/DurableObjectNamespace.d.mts +154 -0
  36. package/dist/DurableObjectNamespace.mjs +144 -0
  37. package/dist/DurableObjectRpcWebSocket.d.mts +112 -0
  38. package/dist/DurableObjectRpcWebSocket.mjs +547 -0
  39. package/dist/DurableObjectSqlite.d.mts +11 -0
  40. package/dist/DurableObjectSqlite.mjs +16 -0
  41. package/dist/DurableObjectState.d.mts +65 -0
  42. package/dist/DurableObjectState.mjs +47 -0
  43. package/dist/DurableObjectStorage.d.mts +112 -0
  44. package/dist/{DurableObjectState-DLL0YgBd.mjs → DurableObjectStorage.mjs} +19 -157
  45. package/dist/DurableObjectWebSocket.d.mts +83 -0
  46. package/dist/DurableObjectWebSocket.mjs +120 -0
  47. package/dist/Email.d.mts +106 -0
  48. package/dist/Email.mjs +247 -0
  49. package/dist/Environment.d.mts +59 -0
  50. package/dist/{ErrorMessage-Byx2OgNd.mjs → Environment.mjs} +7 -18
  51. package/dist/{Hyperdrive-HrwFlZ6x.d.mts → Hyperdrive.d.mts} +8 -5
  52. package/dist/Hyperdrive.mjs +32 -0
  53. package/dist/HyperdrivePg.d.mts +4 -3
  54. package/dist/HyperdrivePg.mjs +3 -1
  55. package/dist/Images.d.mts +191 -0
  56. package/dist/Images.mjs +112 -0
  57. package/dist/Kv.d.mts +84 -0
  58. package/dist/Kv.mjs +132 -0
  59. package/dist/Mcp.d.mts +5 -3
  60. package/dist/Mcp.mjs +13 -4
  61. package/dist/Queue.d.mts +64 -0
  62. package/dist/Queue.mjs +52 -0
  63. package/dist/QueueBinding.d.mts +42 -0
  64. package/dist/QueueBinding.mjs +69 -0
  65. package/dist/QueueDefinition.d.mts +48 -0
  66. package/dist/QueueDefinition.mjs +63 -0
  67. package/dist/R2.d.mts +89 -0
  68. package/dist/R2.mjs +117 -0
  69. package/dist/Rpc.d.mts +29 -0
  70. package/dist/Rpc.mjs +28 -0
  71. package/dist/RpcDefinition.d.mts +116 -0
  72. package/dist/RpcDefinition.mjs +184 -0
  73. package/dist/RpcTracing.d.mts +52 -0
  74. package/dist/RpcTracing.mjs +77 -0
  75. package/dist/Sandbox.d.mts +10 -5
  76. package/dist/Sandbox.mjs +9 -3
  77. package/dist/ServiceBinding.d.mts +112 -0
  78. package/dist/ServiceBinding.mjs +145 -0
  79. package/dist/Vectorize.d.mts +68 -0
  80. package/dist/Vectorize.mjs +76 -0
  81. package/dist/Vitest.d.mts +6 -4
  82. package/dist/Vitest.mjs +8 -4
  83. package/dist/WebTransport.d.mts +66 -0
  84. package/dist/WebTransport.mjs +63 -0
  85. package/dist/Worker.d.mts +139 -0
  86. package/dist/Worker.mjs +141 -0
  87. package/dist/WorkerDefinition.d.mts +100 -0
  88. package/dist/WorkerDefinition.mjs +103 -0
  89. package/dist/WorkersAi.d.mts +84 -0
  90. package/dist/WorkersAi.mjs +84 -0
  91. package/dist/Workflow.d.mts +86 -0
  92. package/dist/Workflow.mjs +137 -0
  93. package/dist/{WorkflowBinding-DtVykUCz.d.mts → WorkflowBinding.d.mts} +14 -10
  94. package/dist/WorkflowBinding.mjs +100 -0
  95. package/dist/WorkflowDefinition.d.mts +51 -0
  96. package/dist/WorkflowDefinition.mjs +69 -0
  97. package/dist/{rolldown-runtime-D7D4PA-g.mjs → _virtual/_rolldown/runtime.mjs} +1 -1
  98. package/dist/index.d.mts +40 -1839
  99. package/dist/index.mjs +40 -3161
  100. package/dist/{ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs → internal/ComputerWorkspaceHostRegistry.mjs} +1 -1
  101. package/dist/internal/Entrypoint.mjs +37 -0
  102. package/dist/internal/ErrorMessage.mjs +17 -0
  103. package/dist/internal/NativeCallback.mjs +33 -0
  104. package/dist/internal/RpcInvocation.d.mts +13 -0
  105. package/dist/internal/RpcInvocation.mjs +34 -0
  106. package/dist/internal/Runtime.mjs +31 -0
  107. package/dist/internal/Telemetry.mjs +20 -0
  108. package/dist/{WorkerContext-Yobnfw-K.mjs → internal/WorkerContext.mjs} +4 -31
  109. package/package.json +1 -1
  110. package/src/AiGateway.ts +5 -1
  111. package/src/AnalyticsEngine.ts +14 -19
  112. package/src/Artifacts.ts +6 -1
  113. package/src/Binding.ts +5 -1
  114. package/src/BrowserRendering.ts +5 -1
  115. package/src/Cache.ts +5 -1
  116. package/src/CloudflareOtlp.ts +12 -10
  117. package/src/CloudflareTracer.ts +7 -1
  118. package/src/ComputerArtifacts.ts +2 -1
  119. package/src/ComputerWorkspace.ts +7 -1
  120. package/src/ContainerNamespace.ts +6 -1
  121. package/src/D1.ts +4 -1
  122. package/src/DurableObject.ts +4 -1
  123. package/src/DurableObjectAlarm.ts +10 -12
  124. package/src/DurableObjectDefinition.ts +3 -1
  125. package/src/DurableObjectNamespace.ts +4 -1
  126. package/src/DurableObjectRpcWebSocket.ts +7 -1
  127. package/src/DurableObjectSqlite.ts +2 -1
  128. package/src/DurableObjectState.ts +4 -1
  129. package/src/DurableObjectStorage.ts +11 -13
  130. package/src/DurableObjectWebSocket.ts +5 -1
  131. package/src/Email.ts +5 -1
  132. package/src/Environment.ts +6 -1
  133. package/src/Hyperdrive.ts +4 -1
  134. package/src/HyperdrivePg.ts +3 -1
  135. package/src/Images.ts +7 -1
  136. package/src/Kv.ts +7 -1
  137. package/src/Mcp.ts +13 -13
  138. package/src/Queue.ts +5 -11
  139. package/src/QueueBinding.ts +5 -1
  140. package/src/QueueDefinition.ts +4 -1
  141. package/src/R2.ts +7 -1
  142. package/src/Rpc.ts +4 -1
  143. package/src/RpcDefinition.ts +4 -1
  144. package/src/RpcTracing.ts +9 -1
  145. package/src/Sandbox.ts +7 -1
  146. package/src/ServiceBinding.ts +6 -1
  147. package/src/Vectorize.ts +7 -1
  148. package/src/Vitest.ts +5 -1
  149. package/src/WebTransport.ts +6 -1
  150. package/src/Worker.ts +10 -16
  151. package/src/WorkerDefinition.ts +3 -1
  152. package/src/WorkersAi.ts +7 -1
  153. package/src/Workflow.ts +10 -25
  154. package/src/WorkflowBinding.ts +6 -1
  155. package/src/WorkflowDefinition.ts +4 -1
  156. package/src/internal/Entrypoint.ts +3 -1
  157. package/src/internal/ErrorMessage.ts +1 -1
  158. package/src/internal/NativeCallback.ts +3 -1
  159. package/src/internal/RpcInvocation.ts +5 -1
  160. package/src/internal/Runtime.ts +5 -1
  161. package/src/internal/Telemetry.ts +4 -3
  162. package/src/internal/WorkerContext.ts +3 -1
  163. package/dist/Binding-DKcLrQCM.d.mts +0 -94
  164. package/dist/DurableObjectState-DJ0K-zyd.d.mts +0 -244
  165. package/dist/Worker-XsGJsCJX.mjs +0 -885
  166. package/dist/Worker-gV4mDqIs.d.mts +0 -641
@@ -0,0 +1,547 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
2
+ import { DurableWebSocketAttachmentError, fromWebSocket } from "./DurableObjectWebSocket.mjs";
3
+ import { DurableObjectState } from "./DurableObjectState.mjs";
4
+ import * as Context from "effect/Context";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Schema from "effect/Schema";
7
+ import * as Layer from "effect/Layer";
8
+ import * as Predicate from "effect/Predicate";
9
+ import * as Option from "effect/Option";
10
+ import * as Queue from "effect/Queue";
11
+ import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
12
+ import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
13
+ import * as RpcServer from "effect/unstable/rpc/RpcServer";
14
+ //#region src/DurableObjectRpcWebSocket.ts
15
+ var DurableObjectRpcWebSocket_exports = /* @__PURE__ */ __exportAll({
16
+ DurableObjectRpcWebSocket: () => DurableObjectRpcWebSocket,
17
+ layer: () => layer,
18
+ resumableStream: () => resumableStream
19
+ });
20
+ const defaultAttachmentKey = "effectCloudflareRpcClientId";
21
+ const defaultTag = "effect-cf-rpc";
22
+ const legacyAttachmentVersion = 1;
23
+ const resumableAttachmentVersion = 2;
24
+ const serviceRestartCode = 1012;
25
+ const serviceRestartReason = "Durable Object RPC activation reset";
26
+ /** Declares an explicitly resumable RPC stream. */
27
+ const resumableStream = (declaration) => declaration;
28
+ const PersistedPendingBatchSchema = Schema.Struct({ checkpointTokens: Schema.Array(Schema.String) });
29
+ const PersistedSubscriptionSchema = Schema.Struct({
30
+ definitionId: Schema.String,
31
+ subscriptionKey: Schema.String,
32
+ requestId: Schema.Union([Schema.String, Schema.Finite]),
33
+ rpcTag: Schema.String,
34
+ resumeDescriptor: Schema.Unknown,
35
+ acknowledgedCheckpoint: Schema.Unknown,
36
+ pending: Schema.optionalKey(PersistedPendingBatchSchema)
37
+ });
38
+ const ResumableAttachmentMetadataSchema = Schema.Struct({
39
+ version: Schema.Literal(resumableAttachmentVersion),
40
+ clientId: Schema.Finite,
41
+ hasPendingRequests: Schema.Boolean,
42
+ hasNonResumableRequests: Schema.Boolean,
43
+ subscriptions: Schema.Array(PersistedSubscriptionSchema)
44
+ });
45
+ const decodeResumableAttachment = Schema.decodeUnknownOption(ResumableAttachmentMetadataSchema);
46
+ var DurableObjectRpcWebSocket = class extends Context.Service()("effect-cf/DurableObjectRpcWebSocket") {};
47
+ /**
48
+ * Builds a hibernation-aware transport that bridges Durable Object websocket
49
+ * events to `RpcServer.Protocol`.
50
+ *
51
+ * The layer restores idle tagged sockets and explicitly declared resumable
52
+ * streams after constructor recreation. A socket that lost any other in-flight
53
+ * request is closed with code 1012, which the stock Effect socket protocol
54
+ * reports as an `RpcClientError` containing `SocketCloseError`.
55
+ */
56
+ const layer = (options = {}) => Layer.effectContext(Effect.gen(function* () {
57
+ const tag = options.tag ?? defaultTag;
58
+ const attachmentKey = options.attachmentKey ?? defaultAttachmentKey;
59
+ const heartbeatPolicy = options.heartbeat ?? "auto-response";
60
+ const declarations = options.resumableStreams ?? [];
61
+ const durableObjectState = yield* DurableObjectState;
62
+ const serialization = yield* RpcSerialization.RpcSerialization;
63
+ const encodeDefect = Schema.encodeSync(serialization.codecFor(Schema.Defect()));
64
+ const disconnects = yield* Queue.make();
65
+ const connectionsBySocket = /* @__PURE__ */ new Map();
66
+ const connectionsById = /* @__PURE__ */ new Map();
67
+ const resetSockets = /* @__PURE__ */ new WeakSet();
68
+ const declarationsById = /* @__PURE__ */ new Map();
69
+ const declarationsByTag = /* @__PURE__ */ new Map();
70
+ const replayRequests = [];
71
+ let nextClientId = 0;
72
+ let activeNonResumableRequestCount = 0;
73
+ let writeRequest;
74
+ for (const declaration of declarations) {
75
+ if (declaration.id.length === 0 || declaration.rpcTag.length === 0) return yield* Effect.die(/* @__PURE__ */ new Error("Resumable RPC stream declaration ids and tags must be non-empty"));
76
+ if (declarationsById.has(declaration.id)) return yield* Effect.die(/* @__PURE__ */ new Error(`Duplicate resumable RPC stream declaration id: ${declaration.id}`));
77
+ if (declarationsByTag.has(declaration.rpcTag)) return yield* Effect.die(/* @__PURE__ */ new Error(`Duplicate resumable RPC stream tag: ${declaration.rpcTag}`));
78
+ declarationsById.set(declaration.id, declaration);
79
+ declarationsByTag.set(declaration.rpcTag, declaration);
80
+ }
81
+ const reserveClientId = (socket) => {
82
+ const id = nextClientId++;
83
+ const created = {
84
+ version: legacyAttachmentVersion,
85
+ clientId: id,
86
+ hasPendingRequests: false
87
+ };
88
+ writeAttachment(socket.raw, attachmentKey, created);
89
+ return created;
90
+ };
91
+ const addSubscription = (connection, subscription) => {
92
+ if (connection.subscriptionsByRequestId.has(subscription.requestId)) return false;
93
+ let byKey = connection.subscriptionsByDefinition.get(subscription.definitionId);
94
+ if (byKey?.has(subscription.subscriptionKey) === true) return false;
95
+ if (byKey === void 0) {
96
+ byKey = /* @__PURE__ */ new Map();
97
+ connection.subscriptionsByDefinition.set(subscription.definitionId, byKey);
98
+ }
99
+ byKey.set(subscription.subscriptionKey, subscription);
100
+ connection.subscriptionsByRequestId.set(subscription.requestId, subscription);
101
+ connection.requestIds.add(subscription.requestId);
102
+ connection.metadataVersion = resumableAttachmentVersion;
103
+ return true;
104
+ };
105
+ const removeSubscription = (connection, requestId) => {
106
+ const subscription = connection.subscriptionsByRequestId.get(requestId);
107
+ if (subscription === void 0) return;
108
+ connection.subscriptionsByRequestId.delete(requestId);
109
+ const byKey = connection.subscriptionsByDefinition.get(subscription.definitionId);
110
+ byKey?.delete(subscription.subscriptionKey);
111
+ if (byKey?.size === 0) connection.subscriptionsByDefinition.delete(subscription.definitionId);
112
+ return subscription;
113
+ };
114
+ const register = (socket, restoredMetadata, restoredSubscriptions = []) => {
115
+ const existing = connectionsBySocket.get(socket.raw);
116
+ if (existing !== void 0) return existing;
117
+ const metadata = restoredMetadata ?? reserveClientId(socket);
118
+ const connection = {
119
+ id: metadata.clientId,
120
+ socket,
121
+ parser: serialization.makeUnsafe(),
122
+ requestIds: /* @__PURE__ */ new Set(),
123
+ nonResumableRequestIds: /* @__PURE__ */ new Set(),
124
+ subscriptionsByRequestId: /* @__PURE__ */ new Map(),
125
+ subscriptionsByDefinition: /* @__PURE__ */ new Map(),
126
+ suppressedAckRequestIds: /* @__PURE__ */ new Set(),
127
+ currentPendingRequestIds: /* @__PURE__ */ new Set(),
128
+ metadataVersion: metadata.version
129
+ };
130
+ if (connectionsById.has(connection.id)) throw new Error(`Duplicate Durable Object RPC websocket client id: ${connection.id}`);
131
+ for (const subscription of restoredSubscriptions) if (!addSubscription(connection, subscription)) throw new Error("Duplicate restored resumable RPC stream subscription identity");
132
+ connectionsBySocket.set(socket.raw, connection);
133
+ connectionsById.set(connection.id, connection);
134
+ nextClientId = Math.max(nextClientId, connection.id + 1);
135
+ return connection;
136
+ };
137
+ const heartbeat = yield* makeHeartbeatController(durableObjectState, serialization, heartbeatPolicy);
138
+ const syncHeartbeat = () => heartbeat.setEnabled(connectionsBySocket.size > 0 && activeNonResumableRequestCount === 0);
139
+ const persistConnection = Effect.fn("DurableObjectRpcWebSocket.persistConnection")(function* (connection) {
140
+ return yield* Effect.try({
141
+ try: () => {
142
+ if (connection.metadataVersion === legacyAttachmentVersion) {
143
+ writeAttachment(connection.socket.raw, attachmentKey, {
144
+ version: legacyAttachmentVersion,
145
+ clientId: connection.id,
146
+ hasPendingRequests: connection.requestIds.size > 0
147
+ });
148
+ return;
149
+ }
150
+ const subscriptions = Array.from(connection.subscriptionsByRequestId.values()).map(({ declaration: _, ...subscription }) => subscription);
151
+ writeAttachment(connection.socket.raw, attachmentKey, {
152
+ version: resumableAttachmentVersion,
153
+ clientId: connection.id,
154
+ hasPendingRequests: connection.requestIds.size > 0,
155
+ hasNonResumableRequests: connection.nonResumableRequestIds.size > 0,
156
+ subscriptions
157
+ });
158
+ },
159
+ catch: (cause) => new DurableWebSocketAttachmentError({
160
+ operation: "serialize",
161
+ cause
162
+ })
163
+ });
164
+ });
165
+ const unregister = Effect.fn("DurableObjectRpcWebSocket.unregister")(function* (socket) {
166
+ const connection = connectionsBySocket.get(socket.raw);
167
+ if (connection === void 0) return;
168
+ connectionsBySocket.delete(socket.raw);
169
+ connectionsById.delete(connection.id);
170
+ activeNonResumableRequestCount -= connection.nonResumableRequestIds.size;
171
+ connection.requestIds.clear();
172
+ connection.nonResumableRequestIds.clear();
173
+ connection.subscriptionsByRequestId.clear();
174
+ connection.subscriptionsByDefinition.clear();
175
+ connection.suppressedAckRequestIds.clear();
176
+ connection.currentPendingRequestIds.clear();
177
+ Queue.offerUnsafe(disconnects, connection.id);
178
+ yield* syncHeartbeat();
179
+ });
180
+ const resetSocket = Effect.fn("DurableObjectRpcWebSocket.resetSocket")(function* (socket, cause) {
181
+ resetSockets.add(socket.raw);
182
+ yield* unregister(socket).pipe(Effect.catchCause((unregisterCause) => Effect.logDebug("Failed to unregister Durable Object RPC websocket", unregisterCause)));
183
+ if (cause !== void 0) yield* Effect.logDebug("Resetting Durable Object RPC websocket", cause);
184
+ yield* socket.close(serviceRestartCode, serviceRestartReason).pipe(Effect.catch((closeError) => Effect.logDebug("Failed to close Durable Object RPC websocket", closeError)));
185
+ });
186
+ const persistOrReset = Effect.fn("DurableObjectRpcWebSocket.persistOrReset")(function* (connection) {
187
+ return yield* persistConnection(connection).pipe(Effect.as(true), Effect.catch((cause) => resetSocket(connection.socket, cause).pipe(Effect.as(false))));
188
+ });
189
+ const trackRequest = Effect.fn("DurableObjectRpcWebSocket.trackRequest")(function* (connection, request) {
190
+ if (connection.requestIds.has(request.id)) return true;
191
+ const declaration = declarationsByTag.get(request.tag);
192
+ const identified = declaration === void 0 ? Option.none() : yield* Effect.sync(() => declaration.identify(request));
193
+ if (declaration !== void 0 && Option.isSome(identified)) {
194
+ if (!addSubscription(connection, {
195
+ declaration,
196
+ definitionId: declaration.id,
197
+ subscriptionKey: identified.value.subscriptionKey,
198
+ requestId: request.id,
199
+ rpcTag: declaration.rpcTag,
200
+ resumeDescriptor: identified.value.resumeDescriptor,
201
+ acknowledgedCheckpoint: identified.value.acknowledgedCheckpoint
202
+ })) {
203
+ yield* resetSocket(connection.socket, /* @__PURE__ */ new Error(`Duplicate resumable RPC stream subscription: ${declaration.id}`));
204
+ return false;
205
+ }
206
+ } else {
207
+ connection.requestIds.add(request.id);
208
+ connection.nonResumableRequestIds.add(request.id);
209
+ activeNonResumableRequestCount++;
210
+ }
211
+ if (!(yield* persistOrReset(connection))) return false;
212
+ yield* syncHeartbeat();
213
+ return true;
214
+ });
215
+ const completeRequest = Effect.fn("DurableObjectRpcWebSocket.completeRequest")(function* (connection, requestId, preserveAckFilter = false) {
216
+ if (connection.requestIds.delete(requestId)) {
217
+ if (connection.nonResumableRequestIds.delete(requestId)) activeNonResumableRequestCount--;
218
+ const subscription = removeSubscription(connection, requestId);
219
+ connection.currentPendingRequestIds.delete(requestId);
220
+ if (preserveAckFilter && subscription !== void 0) connection.suppressedAckRequestIds.add(requestId);
221
+ if (!(yield* persistOrReset(connection))) return;
222
+ }
223
+ if (!preserveAckFilter) connection.suppressedAckRequestIds.delete(requestId);
224
+ yield* syncHeartbeat();
225
+ });
226
+ const completeAllRequests = Effect.fn("DurableObjectRpcWebSocket.completeAllRequests")(function* (connection) {
227
+ const hadRequests = connection.requestIds.size > 0;
228
+ if (connection.requestIds.size > 0) activeNonResumableRequestCount -= connection.nonResumableRequestIds.size;
229
+ connection.requestIds.clear();
230
+ connection.nonResumableRequestIds.clear();
231
+ connection.subscriptionsByRequestId.clear();
232
+ connection.subscriptionsByDefinition.clear();
233
+ connection.suppressedAckRequestIds.clear();
234
+ connection.currentPendingRequestIds.clear();
235
+ if (hadRequests && !(yield* persistOrReset(connection))) return;
236
+ yield* syncHeartbeat();
237
+ });
238
+ const restoredAttachments = (yield* durableObjectState.getWebSockets(tag)).map((socket) => ({
239
+ socket,
240
+ attachment: readAttachment(socket.raw, attachmentKey)
241
+ }));
242
+ for (const { attachment, socket } of restoredAttachments) {
243
+ if (attachment._tag === "Invalid") {
244
+ yield* resetSocket(socket);
245
+ continue;
246
+ }
247
+ if (attachment._tag === "Missing") {
248
+ yield* resetSocket(socket);
249
+ continue;
250
+ }
251
+ const metadata = attachment.metadata;
252
+ if (metadata.version === legacyAttachmentVersion) {
253
+ if (metadata.hasPendingRequests) yield* resetSocket(socket);
254
+ else if (connectionsById.has(metadata.clientId)) yield* resetSocket(socket);
255
+ else yield* persistOrReset(register(socket, metadata));
256
+ continue;
257
+ }
258
+ const prepared = yield* Effect.sync(() => {
259
+ try {
260
+ if (metadata.hasNonResumableRequests || metadata.hasPendingRequests !== (metadata.hasNonResumableRequests || metadata.subscriptions.length > 0)) throw new Error("Dirty resumable RPC websocket attachment metadata");
261
+ const requestIds = /* @__PURE__ */ new Set();
262
+ const subscriptionKeys = /* @__PURE__ */ new Map();
263
+ const subscriptions = [];
264
+ const requests = [];
265
+ for (const persisted of metadata.subscriptions) {
266
+ const declaration = declarationsById.get(persisted.definitionId);
267
+ if (declaration === void 0 || declaration.rpcTag !== persisted.rpcTag) throw new Error("Missing resumable RPC stream declaration");
268
+ let keys = subscriptionKeys.get(persisted.definitionId);
269
+ if (keys === void 0) {
270
+ keys = /* @__PURE__ */ new Set();
271
+ subscriptionKeys.set(persisted.definitionId, keys);
272
+ }
273
+ if (requestIds.has(persisted.requestId) || keys.has(persisted.subscriptionKey)) throw new Error("Duplicate persisted resumable RPC stream subscription");
274
+ requestIds.add(persisted.requestId);
275
+ keys.add(persisted.subscriptionKey);
276
+ if (persisted.pending !== void 0) {
277
+ const { checkpointTokens } = persisted.pending;
278
+ if (checkpointTokens.length === 0 || checkpointTokens.some((token) => token.length === 0) || new Set(checkpointTokens).size !== checkpointTokens.length) throw new Error("Invalid persisted resumable RPC stream pending batch");
279
+ }
280
+ const resumeDescriptor = Schema.decodeUnknownOption(declaration.resumeDescriptorSchema)(persisted.resumeDescriptor);
281
+ const acknowledgedCheckpoint = Schema.decodeUnknownOption(declaration.checkpointSchema)(persisted.acknowledgedCheckpoint);
282
+ if (Option.isNone(resumeDescriptor) || Option.isNone(acknowledgedCheckpoint)) throw new Error("Invalid persisted resumable RPC stream state");
283
+ const rebuilt = declaration.rebuild({
284
+ subscriptionKey: persisted.subscriptionKey,
285
+ resumeDescriptor: resumeDescriptor.value,
286
+ acknowledgedCheckpoint: acknowledgedCheckpoint.value
287
+ });
288
+ const request = {
289
+ _tag: "Request",
290
+ id: persisted.requestId,
291
+ tag: declaration.rpcTag,
292
+ payload: rebuilt.payload,
293
+ headers: rebuilt.headers?.map(([name, value]) => [name, value]) ?? []
294
+ };
295
+ if (rebuilt.traceId !== void 0) Object.assign(request, { traceId: rebuilt.traceId });
296
+ if (rebuilt.spanId !== void 0) Object.assign(request, { spanId: rebuilt.spanId });
297
+ if (rebuilt.sampled !== void 0) Object.assign(request, { sampled: rebuilt.sampled });
298
+ subscriptions.push({
299
+ ...persisted,
300
+ resumeDescriptor: resumeDescriptor.value,
301
+ acknowledgedCheckpoint: acknowledgedCheckpoint.value,
302
+ declaration
303
+ });
304
+ requests.push(request);
305
+ }
306
+ return {
307
+ _tag: "Success",
308
+ requests,
309
+ subscriptions
310
+ };
311
+ } catch (cause) {
312
+ return {
313
+ _tag: "Failure",
314
+ cause
315
+ };
316
+ }
317
+ });
318
+ if (prepared._tag === "Failure") {
319
+ yield* Effect.logDebug("Invalid resumable RPC websocket attachment", prepared.cause);
320
+ yield* resetSocket(socket);
321
+ continue;
322
+ }
323
+ if (connectionsById.has(metadata.clientId)) {
324
+ yield* resetSocket(socket);
325
+ continue;
326
+ }
327
+ const connection = register(socket, metadata, prepared.subscriptions);
328
+ for (const request of prepared.requests) replayRequests.push({
329
+ clientId: connection.id,
330
+ request
331
+ });
332
+ }
333
+ yield* syncHeartbeat();
334
+ const send = (connection, response) => Effect.gen(function* () {
335
+ let delivered = response;
336
+ if (response._tag === "Chunk") {
337
+ const subscription = connection.subscriptionsByRequestId.get(response.requestId);
338
+ if (subscription !== void 0) {
339
+ subscription.pending = { checkpointTokens: yield* Effect.sync(() => {
340
+ const tokens = [];
341
+ for (const value of response.values) {
342
+ const checkpoint = subscription.declaration.checkpointFromValue(value);
343
+ if (Option.isNone(checkpoint)) throw new Error(`Resumable RPC stream ${subscription.definitionId} did not identify a checkpoint`);
344
+ const token = subscription.declaration.checkpointToken(checkpoint.value);
345
+ if (token.length === 0 || tokens.includes(token)) throw new Error(`Resumable RPC stream ${subscription.definitionId} produced invalid checkpoint tokens`);
346
+ tokens.push(token);
347
+ }
348
+ if (tokens.length === 0) throw new Error("Resumable RPC stream chunks must contain checkpointed values");
349
+ return tokens;
350
+ }) };
351
+ connection.currentPendingRequestIds.add(subscription.requestId);
352
+ if (!(yield* persistOrReset(connection))) return;
353
+ }
354
+ }
355
+ if (!(yield* Effect.sync(() => {
356
+ try {
357
+ const encoded = connection.parser.encode(response);
358
+ if (encoded === void 0) return false;
359
+ connection.socket.raw.send(encoded);
360
+ return true;
361
+ } catch (cause) {
362
+ delivered = RpcMessage.ResponseDefectEncoded(encodeDefect(cause));
363
+ const encoded = connection.parser.encode(delivered);
364
+ if (encoded === void 0) return false;
365
+ connection.socket.raw.send(encoded);
366
+ return true;
367
+ }
368
+ }).pipe(Effect.catchCause((cause) => Effect.logDebug("Durable Object RPC websocket send failed", cause).pipe(Effect.as(false)))))) {
369
+ resetSockets.add(connection.socket.raw);
370
+ yield* connection.socket.close(serviceRestartCode, serviceRestartReason).pipe(Effect.ignore);
371
+ yield* unregister(connection.socket);
372
+ return;
373
+ }
374
+ if (delivered._tag === "Exit") yield* completeRequest(connection, delivered.requestId);
375
+ else if (delivered._tag === "Defect" || delivered._tag === "ClientProtocolError") yield* completeAllRequests(connection);
376
+ });
377
+ const protocol = yield* RpcServer.Protocol.make((writeRequest_) => {
378
+ writeRequest = writeRequest_;
379
+ return Effect.succeed({
380
+ disconnects,
381
+ send: (clientId, response) => {
382
+ const connection = connectionsById.get(clientId);
383
+ return connection === void 0 ? Effect.void : send(connection, response);
384
+ },
385
+ end: (clientId) => Effect.sync(() => {
386
+ connectionsById.get(clientId)?.socket.raw.close();
387
+ }),
388
+ clientIds: Effect.sync(() => new Set(connectionsById.keys())),
389
+ initialMessage: Effect.succeedNone,
390
+ supportsAck: true,
391
+ supportsTransferables: false,
392
+ supportsSpanPropagation: true,
393
+ supportsNotifications: true,
394
+ codecFor: serialization.codecFor
395
+ });
396
+ });
397
+ const replay = writeRequest;
398
+ if (replay === void 0) return yield* Effect.die(/* @__PURE__ */ new Error("RPC server protocol did not install its request writer"));
399
+ for (const restoredRequest of replayRequests) yield* replay(restoredRequest.clientId, restoredRequest.request);
400
+ const checkpoint = Effect.fn("DurableObjectRpcWebSocket.checkpoint")(function* (declaration, checkpointOptions) {
401
+ const connection = connectionsById.get(checkpointOptions.clientId);
402
+ const configured = declarationsById.get(declaration.id);
403
+ const subscription = connection?.subscriptionsByDefinition.get(declaration.id)?.get(checkpointOptions.subscriptionKey);
404
+ if (connection === void 0 || configured === void 0 || configured.rpcTag !== declaration.rpcTag || subscription === void 0 || subscription.pending === void 0) return false;
405
+ const token = configured.checkpointToken(checkpointOptions.checkpoint);
406
+ const checkpointIndex = subscription.pending.checkpointTokens.indexOf(token);
407
+ if (token.length === 0 || checkpointIndex < 0) return false;
408
+ const pending = subscription.pending;
409
+ const isFinal = checkpointIndex === pending.checkpointTokens.length - 1;
410
+ const shouldAck = isFinal && connection.currentPendingRequestIds.has(subscription.requestId);
411
+ return yield* Effect.uninterruptible(Effect.gen(function* () {
412
+ subscription.acknowledgedCheckpoint = checkpointOptions.checkpoint;
413
+ if (isFinal) {
414
+ connection.currentPendingRequestIds.delete(subscription.requestId);
415
+ delete subscription.pending;
416
+ } else subscription.pending = { checkpointTokens: pending.checkpointTokens.slice(checkpointIndex + 1) };
417
+ yield* persistConnection(connection).pipe(Effect.catch((cause) => Effect.gen(function* () {
418
+ yield* resetSocket(connection.socket, cause);
419
+ return yield* cause;
420
+ })));
421
+ if (shouldAck) {
422
+ const run = writeRequest;
423
+ if (run === void 0) return yield* Effect.die(/* @__PURE__ */ new Error("RPC server is not ready to accept a checkpoint Ack"));
424
+ yield* run(connection.id, {
425
+ _tag: "Ack",
426
+ requestId: subscription.requestId
427
+ });
428
+ }
429
+ return true;
430
+ }));
431
+ });
432
+ const service = DurableObjectRpcWebSocket.of({
433
+ accept: (socket, tags = []) => Effect.gen(function* () {
434
+ register(socket);
435
+ yield* durableObjectState.acceptWebSocket(socket, Array.from(/* @__PURE__ */ new Set([tag, ...tags])));
436
+ yield* syncHeartbeat();
437
+ }),
438
+ acceptUpgrade: (upgradeOptions = {}) => Effect.gen(function* () {
439
+ const pair = new WebSocketPair();
440
+ const client = pair[0];
441
+ const server = fromWebSocket(pair[1]);
442
+ if (upgradeOptions.attachment !== void 0) yield* server.serializeAttachment(upgradeOptions.attachment);
443
+ yield* service.accept(server, upgradeOptions.tags);
444
+ return {
445
+ client,
446
+ server,
447
+ response: new Response(null, {
448
+ status: 101,
449
+ webSocket: client
450
+ })
451
+ };
452
+ }),
453
+ message: (socket, message) => Effect.gen(function* () {
454
+ if (resetSockets.has(socket.raw)) return;
455
+ const connection = register(socket);
456
+ const decoded = yield* Effect.try({
457
+ try: () => connection.parser.decode(normalizeMessage(message)),
458
+ catch: (cause) => cause
459
+ });
460
+ const run = writeRequest;
461
+ if (run === void 0) {
462
+ yield* send(connection, RpcMessage.ResponseDefectEncoded(encodeDefect("RPC server is not ready")));
463
+ return;
464
+ }
465
+ for (const current of decoded) {
466
+ const request = current;
467
+ if (request._tag === "Request" && request.isNotification !== true) {
468
+ if (!(yield* trackRequest(connection, request))) return;
469
+ }
470
+ if (request._tag === "Ack" && (connection.subscriptionsByRequestId.has(request.requestId) || connection.suppressedAckRequestIds.has(request.requestId))) continue;
471
+ if (request._tag === "Interrupt" && connection.subscriptionsByRequestId.has(request.requestId)) yield* completeRequest(connection, request.requestId, true);
472
+ yield* run(connection.id, request);
473
+ if (request._tag === "Interrupt" && !connection.suppressedAckRequestIds.has(request.requestId)) yield* completeRequest(connection, request.requestId);
474
+ }
475
+ }).pipe(Effect.catch((cause) => {
476
+ const connection = register(socket);
477
+ return Predicate.isTagged(cause, "MaxBufferSizeExceeded") ? Effect.ignore(connection.socket.close(1009, String(cause))) : send(connection, RpcMessage.ResponseDefectEncoded(encodeDefect(cause)));
478
+ })),
479
+ close: unregister,
480
+ error: resetSocket,
481
+ checkpoint
482
+ });
483
+ return Context.mergeAll(Context.make(RpcServer.Protocol, protocol), Context.make(DurableObjectRpcWebSocket, service));
484
+ }));
485
+ const normalizeMessage = (message) => Predicate.isString(message) ? message : new Uint8Array(message);
486
+ const readAttachment = (socket, key) => {
487
+ const value = socket.deserializeAttachment();
488
+ if (value === null || value === void 0) return { _tag: "Missing" };
489
+ if (!Predicate.isObject(value)) return { _tag: "Invalid" };
490
+ if (!Predicate.hasProperty(value, key)) return { _tag: "Missing" };
491
+ const metadata = value[key];
492
+ if (Predicate.isNumber(metadata) && isClientId(metadata)) return {
493
+ _tag: "Valid",
494
+ metadata: {
495
+ version: legacyAttachmentVersion,
496
+ clientId: metadata,
497
+ hasPendingRequests: false
498
+ }
499
+ };
500
+ if (!Predicate.isObject(metadata)) return { _tag: "Invalid" };
501
+ if (Predicate.hasProperty(metadata, "version") && metadata.version === resumableAttachmentVersion) {
502
+ const decoded = decodeResumableAttachment(metadata);
503
+ return Option.isSome(decoded) && isClientId(decoded.value.clientId) ? {
504
+ _tag: "Valid",
505
+ metadata: decoded.value
506
+ } : { _tag: "Invalid" };
507
+ }
508
+ const hasPendingRequests = Predicate.hasProperty(metadata, "hasPendingRequests") ? metadata.hasPendingRequests : false;
509
+ if ((!Predicate.hasProperty(metadata, "version") || metadata.version === legacyAttachmentVersion) && Predicate.hasProperty(metadata, "clientId") && Predicate.isNumber(metadata.clientId) && isClientId(metadata.clientId) && Predicate.isBoolean(hasPendingRequests)) return {
510
+ _tag: "Valid",
511
+ metadata: {
512
+ version: legacyAttachmentVersion,
513
+ clientId: metadata.clientId,
514
+ hasPendingRequests
515
+ }
516
+ };
517
+ return { _tag: "Invalid" };
518
+ };
519
+ const isClientId = (value) => Number.isSafeInteger(value) && value >= 0;
520
+ const writeAttachment = (socket, key, metadata) => {
521
+ const current = socket.deserializeAttachment();
522
+ if (current !== null && current !== void 0 && !Predicate.isObject(current)) throw new Error("DurableObjectRpcWebSocket requires object-shaped websocket attachments so adapter metadata can preserve application fields");
523
+ const attachment = Predicate.isObject(current) ? current : {};
524
+ socket.serializeAttachment({
525
+ ...attachment,
526
+ [key]: metadata
527
+ });
528
+ };
529
+ const makeHeartbeatController = (state, serialization, policy) => Effect.gen(function* () {
530
+ if (policy === "passthrough") return { setEnabled: () => Effect.void };
531
+ const parser = serialization.makeUnsafe();
532
+ const request = parser.encode(RpcMessage.constPing);
533
+ const response = parser.encode(RpcMessage.constPong);
534
+ if (!Predicate.isString(request) || !Predicate.isString(response)) return yield* Effect.die(/* @__PURE__ */ new Error("DurableObjectRpcWebSocket heartbeat auto-response requires a text RPC serialization; use heartbeat: \"passthrough\" to manage heartbeats externally"));
535
+ const configured = yield* state.getWebSocketAutoResponse;
536
+ if (configured !== null && (configured.request !== request || configured.response !== response)) return yield* Effect.die(/* @__PURE__ */ new Error("DurableObjectRpcWebSocket cannot replace the application WebSocket auto-response; use heartbeat: \"passthrough\" to preserve it"));
537
+ const pair = new WebSocketRequestResponsePair(request, response);
538
+ let enabled = configured !== null;
539
+ return { setEnabled: (nextEnabled) => {
540
+ if (enabled === nextEnabled) return Effect.void;
541
+ return state.setWebSocketAutoResponse(nextEnabled ? pair : void 0).pipe(Effect.tap(() => Effect.sync(() => {
542
+ enabled = nextEnabled;
543
+ })));
544
+ } };
545
+ });
546
+ //#endregion
547
+ export { DurableObjectRpcWebSocket, DurableObjectRpcWebSocket_exports, layer, resumableStream };
@@ -0,0 +1,11 @@
1
+ import { DurableObjectState } from "./DurableObjectState.mjs";
2
+ import * as Layer from "effect/Layer";
3
+ import { SqliteClient } from "@effect/sql-sqlite-do";
4
+ import { SqlClient } from "effect/unstable/sql";
5
+ declare namespace DurableObjectSqlite_d_exports {
6
+ export { SqliteLayerOptions, layer };
7
+ }
8
+ type SqliteLayerOptions = Omit<SqliteClient.SqliteClientConfig, "db" | "storage">;
9
+ declare const layer: (options?: SqliteLayerOptions) => Layer.Layer<SqliteClient.SqliteClient | SqlClient.SqlClient, never, DurableObjectState>;
10
+ //#endregion
11
+ export { DurableObjectSqlite_d_exports, SqliteLayerOptions, layer };
@@ -0,0 +1,16 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
2
+ import { DurableObjectState } from "./DurableObjectState.mjs";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Layer from "effect/Layer";
5
+ import { SqliteClient } from "@effect/sql-sqlite-do";
6
+ //#region src/DurableObjectSqlite.ts
7
+ var DurableObjectSqlite_exports = /* @__PURE__ */ __exportAll({ layer: () => layer });
8
+ const layer = (options) => Layer.unwrap(Effect.gen(function* () {
9
+ const state = yield* DurableObjectState;
10
+ return SqliteClient.layer({
11
+ ...options,
12
+ storage: state.raw.storage
13
+ });
14
+ }));
15
+ //#endregion
16
+ export { DurableObjectSqlite_exports, layer };
@@ -0,0 +1,65 @@
1
+ import { DurableObjectStorage } from "./DurableObjectStorage.mjs";
2
+ import { DurableWebSocket } from "./DurableObjectWebSocket.mjs";
3
+ import { WorkerContextWaitUntilOptions } from "./Worker.mjs";
4
+ import * as Context from "effect/Context";
5
+ import * as Effect from "effect/Effect";
6
+ declare namespace DurableObjectState_d_exports {
7
+ export { DurableObjectState, DurableObjectStateService, fromDurableObjectState };
8
+ }
9
+ /**
10
+ * Effect-friendly wrapper around Cloudflare `DurableObjectState`.
11
+ */
12
+ interface DurableObjectStateService {
13
+ readonly raw: globalThis.DurableObjectState;
14
+ readonly id: globalThis.DurableObjectId;
15
+ readonly storage: DurableObjectStorage;
16
+ waitUntil(promise: Promise<unknown>): Effect.Effect<void>;
17
+ /**
18
+ * Runs a background Effect via Cloudflare's `waitUntil` with the caller's
19
+ * Effect context, mirroring `WorkerContext.waitUntil` failure modes:
20
+ * `"observe"` (default) logs or routes failures to `onFailure`, while
21
+ * `"propagate"` also rejects the native `waitUntil` promise.
22
+ */
23
+ waitUntil<A, E, R, R2 = never>(effect: Effect.Effect<A, E, R>, options?: WorkerContextWaitUntilOptions<E, R2>): Effect.Effect<void, never, R | R2>;
24
+ /**
25
+ * Runs an Effect inside Cloudflare's `blockConcurrencyWhile` gate.
26
+ *
27
+ * Cloudflare resets a Durable Object if the callback throws/rejects, or if the
28
+ * callback exceeds the platform timeout (currently documented as 30 seconds).
29
+ * This safe default resolves the callback with the Effect `Exit` for typed
30
+ * Effect failures and resumes that `Exit` afterward, so typed failures remain
31
+ * ordinary Effect failures instead of resetting the Durable Object. Defects
32
+ * and interruptions still reject the callback.
33
+ */
34
+ blockConcurrencyWhile<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>;
35
+ /**
36
+ * Runs an Effect inside Cloudflare's `blockConcurrencyWhile` gate and lets
37
+ * Effect failures reject the callback.
38
+ *
39
+ * Use this only when Cloudflare's reset-on-throw behavior is intentional. The
40
+ * platform also resets the Durable Object if the callback exceeds the
41
+ * documented timeout (currently 30 seconds).
42
+ */
43
+ blockConcurrencyWhileOrReset<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>;
44
+ acceptWebSocket(ws: DurableWebSocket, tags?: Array<string>): Effect.Effect<void>;
45
+ getWebSockets(tag?: string): Effect.Effect<Array<DurableWebSocket>>;
46
+ setWebSocketAutoResponse(pair?: WebSocketRequestResponsePair): Effect.Effect<void>;
47
+ getWebSocketAutoResponse: Effect.Effect<WebSocketRequestResponsePair | null>;
48
+ getWebSocketAutoResponseTimestamp(ws: DurableWebSocket): Effect.Effect<Date | null>;
49
+ setHibernatableWebSocketEventTimeout(timeoutMs?: number): Effect.Effect<void>;
50
+ getHibernatableWebSocketEventTimeout: Effect.Effect<number | null>;
51
+ getTags(ws: DurableWebSocket): Effect.Effect<Array<string>>;
52
+ /**
53
+ * Forcibly resets the Durable Object. Cloudflare logs an uncaught Error using
54
+ * the optional reason, and the method is not available in `wrangler dev` local
55
+ * development according to the Durable Object State docs. Set
56
+ * `retryAlarm: false` to prevent the current alarm invocation from retrying;
57
+ * this option has no effect outside an alarm handler.
58
+ */
59
+ abort(reason?: string, options?: globalThis.DurableObjectAbortOptions): Effect.Effect<void>;
60
+ }
61
+ declare const DurableObjectState_base: Context.ServiceClass<DurableObjectState, "effect-cf/DurableObjectState", DurableObjectStateService>;
62
+ declare class DurableObjectState extends DurableObjectState_base {}
63
+ declare const fromDurableObjectState: (state: globalThis.DurableObjectState) => DurableObjectStateService;
64
+ //#endregion
65
+ export { DurableObjectState, DurableObjectStateService, DurableObjectState_d_exports, fromDurableObjectState };