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.
- package/CHANGELOG.md +14 -0
- package/README.md +2 -0
- package/dist/AiGateway.d.mts +86 -0
- package/dist/AiGateway.mjs +178 -0
- package/dist/AnalyticsEngine.d.mts +170 -0
- package/dist/AnalyticsEngine.mjs +275 -0
- package/dist/{Artifacts-B3r3RuTB.d.mts → Artifacts.d.mts} +8 -5
- package/dist/{Artifacts-CBxWGeZB.mjs → Artifacts.mjs} +9 -5
- package/dist/Binding.d.mts +45 -0
- package/dist/{Binding-C82jRhdr.mjs → Binding.mjs} +8 -4
- package/dist/BrowserRendering.d.mts +85 -0
- package/dist/BrowserRendering.mjs +81 -0
- package/dist/Cache.d.mts +40 -0
- package/dist/Cache.mjs +51 -0
- package/dist/CloudflareOtlp.d.mts +95 -0
- package/dist/CloudflareOtlp.mjs +125 -0
- package/dist/CloudflareTracer.d.mts +20 -0
- package/dist/CloudflareTracer.mjs +69 -0
- package/dist/ComputerArtifacts.d.mts +2 -2
- package/dist/ComputerArtifacts.mjs +3 -2
- package/dist/ComputerWorkspace.d.mts +36 -31
- package/dist/ComputerWorkspace.mjs +8 -3
- package/dist/ComputerWorkspaceHost.d.mts +1 -1
- package/dist/ComputerWorkspaceHost.mjs +1 -1
- package/dist/{ContainerNamespace-DbLaeFhN.d.mts → ContainerNamespace.d.mts} +16 -12
- package/dist/ContainerNamespace.mjs +165 -0
- package/dist/D1.d.mts +33 -0
- package/dist/D1.mjs +32 -0
- package/dist/DurableObject.d.mts +103 -0
- package/dist/DurableObject.mjs +77 -0
- package/dist/DurableObjectAlarm.d.mts +187 -0
- package/dist/DurableObjectAlarm.mjs +344 -0
- package/dist/DurableObjectDefinition.d.mts +87 -0
- package/dist/DurableObjectDefinition.mjs +125 -0
- package/dist/DurableObjectNamespace.d.mts +154 -0
- package/dist/DurableObjectNamespace.mjs +144 -0
- package/dist/DurableObjectRpcWebSocket.d.mts +112 -0
- package/dist/DurableObjectRpcWebSocket.mjs +547 -0
- package/dist/DurableObjectSqlite.d.mts +11 -0
- package/dist/DurableObjectSqlite.mjs +16 -0
- package/dist/DurableObjectState.d.mts +65 -0
- package/dist/DurableObjectState.mjs +47 -0
- package/dist/DurableObjectStorage.d.mts +112 -0
- package/dist/{DurableObjectState-DLL0YgBd.mjs → DurableObjectStorage.mjs} +19 -157
- package/dist/DurableObjectWebSocket.d.mts +83 -0
- package/dist/DurableObjectWebSocket.mjs +120 -0
- package/dist/Email.d.mts +106 -0
- package/dist/Email.mjs +247 -0
- package/dist/Environment.d.mts +59 -0
- package/dist/{ErrorMessage-Byx2OgNd.mjs → Environment.mjs} +7 -18
- package/dist/{Hyperdrive-HrwFlZ6x.d.mts → Hyperdrive.d.mts} +8 -5
- package/dist/Hyperdrive.mjs +32 -0
- package/dist/HyperdrivePg.d.mts +4 -3
- package/dist/HyperdrivePg.mjs +3 -1
- package/dist/Images.d.mts +191 -0
- package/dist/Images.mjs +112 -0
- package/dist/Kv.d.mts +84 -0
- package/dist/Kv.mjs +132 -0
- package/dist/Mcp.d.mts +5 -3
- package/dist/Mcp.mjs +13 -4
- package/dist/Queue.d.mts +64 -0
- package/dist/Queue.mjs +52 -0
- package/dist/QueueBinding.d.mts +42 -0
- package/dist/QueueBinding.mjs +69 -0
- package/dist/QueueDefinition.d.mts +48 -0
- package/dist/QueueDefinition.mjs +63 -0
- package/dist/R2.d.mts +89 -0
- package/dist/R2.mjs +117 -0
- package/dist/Rpc.d.mts +29 -0
- package/dist/Rpc.mjs +28 -0
- package/dist/RpcDefinition.d.mts +116 -0
- package/dist/RpcDefinition.mjs +184 -0
- package/dist/RpcTracing.d.mts +52 -0
- package/dist/RpcTracing.mjs +77 -0
- package/dist/Sandbox.d.mts +10 -5
- package/dist/Sandbox.mjs +9 -3
- package/dist/ServiceBinding.d.mts +112 -0
- package/dist/ServiceBinding.mjs +145 -0
- package/dist/Vectorize.d.mts +68 -0
- package/dist/Vectorize.mjs +76 -0
- package/dist/Vitest.d.mts +6 -4
- package/dist/Vitest.mjs +8 -4
- package/dist/WebTransport.d.mts +66 -0
- package/dist/WebTransport.mjs +63 -0
- package/dist/Worker.d.mts +139 -0
- package/dist/Worker.mjs +141 -0
- package/dist/WorkerDefinition.d.mts +100 -0
- package/dist/WorkerDefinition.mjs +103 -0
- package/dist/WorkersAi.d.mts +84 -0
- package/dist/WorkersAi.mjs +84 -0
- package/dist/Workflow.d.mts +86 -0
- package/dist/Workflow.mjs +137 -0
- package/dist/{WorkflowBinding-DtVykUCz.d.mts → WorkflowBinding.d.mts} +14 -10
- package/dist/WorkflowBinding.mjs +100 -0
- package/dist/WorkflowDefinition.d.mts +51 -0
- package/dist/WorkflowDefinition.mjs +69 -0
- package/dist/{rolldown-runtime-D7D4PA-g.mjs → _virtual/_rolldown/runtime.mjs} +1 -1
- package/dist/index.d.mts +40 -1839
- package/dist/index.mjs +40 -3161
- package/dist/{ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs → internal/ComputerWorkspaceHostRegistry.mjs} +1 -1
- package/dist/internal/Entrypoint.mjs +37 -0
- package/dist/internal/ErrorMessage.mjs +17 -0
- package/dist/internal/NativeCallback.mjs +33 -0
- package/dist/internal/RpcInvocation.d.mts +13 -0
- package/dist/internal/RpcInvocation.mjs +34 -0
- package/dist/internal/Runtime.mjs +31 -0
- package/dist/internal/Telemetry.mjs +20 -0
- package/dist/{WorkerContext-Yobnfw-K.mjs → internal/WorkerContext.mjs} +4 -31
- package/package.json +1 -1
- package/src/AiGateway.ts +5 -1
- package/src/AnalyticsEngine.ts +14 -19
- package/src/Artifacts.ts +6 -1
- package/src/Binding.ts +5 -1
- package/src/BrowserRendering.ts +5 -1
- package/src/Cache.ts +5 -1
- package/src/CloudflareOtlp.ts +12 -10
- package/src/CloudflareTracer.ts +7 -1
- package/src/ComputerArtifacts.ts +2 -1
- package/src/ComputerWorkspace.ts +7 -1
- package/src/ContainerNamespace.ts +6 -1
- package/src/D1.ts +4 -1
- package/src/DurableObject.ts +4 -1
- package/src/DurableObjectAlarm.ts +10 -12
- package/src/DurableObjectDefinition.ts +3 -1
- package/src/DurableObjectNamespace.ts +4 -1
- package/src/DurableObjectRpcWebSocket.ts +7 -1
- package/src/DurableObjectSqlite.ts +2 -1
- package/src/DurableObjectState.ts +4 -1
- package/src/DurableObjectStorage.ts +11 -13
- package/src/DurableObjectWebSocket.ts +5 -1
- package/src/Email.ts +5 -1
- package/src/Environment.ts +6 -1
- package/src/Hyperdrive.ts +4 -1
- package/src/HyperdrivePg.ts +3 -1
- package/src/Images.ts +7 -1
- package/src/Kv.ts +7 -1
- package/src/Mcp.ts +13 -13
- package/src/Queue.ts +5 -11
- package/src/QueueBinding.ts +5 -1
- package/src/QueueDefinition.ts +4 -1
- package/src/R2.ts +7 -1
- package/src/Rpc.ts +4 -1
- package/src/RpcDefinition.ts +4 -1
- package/src/RpcTracing.ts +9 -1
- package/src/Sandbox.ts +7 -1
- package/src/ServiceBinding.ts +6 -1
- package/src/Vectorize.ts +7 -1
- package/src/Vitest.ts +5 -1
- package/src/WebTransport.ts +6 -1
- package/src/Worker.ts +10 -16
- package/src/WorkerDefinition.ts +3 -1
- package/src/WorkersAi.ts +7 -1
- package/src/Workflow.ts +10 -25
- package/src/WorkflowBinding.ts +6 -1
- package/src/WorkflowDefinition.ts +4 -1
- package/src/internal/Entrypoint.ts +3 -1
- package/src/internal/ErrorMessage.ts +1 -1
- package/src/internal/NativeCallback.ts +3 -1
- package/src/internal/RpcInvocation.ts +5 -1
- package/src/internal/Runtime.ts +5 -1
- package/src/internal/Telemetry.ts +4 -3
- package/src/internal/WorkerContext.ts +3 -1
- package/dist/Binding-DKcLrQCM.d.mts +0 -94
- package/dist/DurableObjectState-DJ0K-zyd.d.mts +0 -244
- package/dist/Worker-XsGJsCJX.mjs +0 -885
- 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 };
|