effect-cf 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3,1192 +3,1168 @@ import { a as WorkerConfig, i as layer$10, n as Binding_exports, o as WorkerEnvi
3
3
  import { Cause, Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Layer, ManagedRuntime, Option, Queue, Schema } from "effect";
4
4
  import { FetchHttpClient, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
5
5
  import { Otlp, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
6
- import { DurableObject, RpcStub, RpcTarget, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
7
6
  import { D1Client } from "@effect/sql-d1";
7
+ import { DurableObject, RpcStub, RpcTarget, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
8
8
  import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
9
9
  import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
10
10
  import * as RpcServer from "effect/unstable/rpc/RpcServer";
11
11
  import { SqliteClient } from "@effect/sql-sqlite-do";
12
- //#region src/QueueBinding.ts
13
- var QueueBinding_exports = /* @__PURE__ */ __exportAll({
14
- QueueOperationError: () => QueueOperationError,
15
- isQueue: () => isQueue,
16
- layer: () => layer$9,
17
- makeClient: () => makeClient$6
12
+ //#region src/DurableObjectStorage.ts
13
+ var DurableObjectStorage_exports = /* @__PURE__ */ __exportAll({
14
+ StorageOperationError: () => StorageOperationError,
15
+ fromDurableObjectStorage: () => fromDurableObjectStorage
18
16
  });
19
- const expectedQueueProducer = "Queue producer binding with send(); optional sendBatch()/metrics()";
20
- var QueueOperationError = class extends Data.TaggedError("QueueOperationError") {};
21
- const tryQueuePromise = (binding, operation, evaluate) => Effect.tryPromise({
17
+ /** Error type used when a storage operation throws or rejects. */
18
+ var StorageOperationError = class extends Data.TaggedError("StorageOperationError") {};
19
+ const storageError = (operation, cause) => new StorageOperationError({
20
+ operation,
21
+ cause
22
+ });
23
+ const tryStorageSync = (operation, evaluate) => Effect.try({
22
24
  try: evaluate,
23
- catch: (cause) => new QueueOperationError({
24
- binding,
25
- operation,
26
- cause,
27
- message: `Cloudflare queue binding "${binding}" operation "${operation}" failed`
28
- })
25
+ catch: (cause) => storageError(operation, cause)
29
26
  });
30
- const isQueue = (value) => {
31
- if (typeof value !== "object" || value === null) return false;
32
- return typeof value.send === "function";
33
- };
34
- const makeClient$6 = (definition) => {
35
- const encodeMessage = Schema.encodeEffect(definition.message);
36
- return (queue) => ({
37
- send: Effect.fnUntraced(function* (message, options) {
38
- const encoded = yield* encodeMessage(message);
39
- yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
27
+ const tryStoragePromise = (operation, evaluate) => Effect.tryPromise({
28
+ try: evaluate,
29
+ catch: (cause) => storageError(operation, cause)
30
+ });
31
+ const fromSqlCursor = (cursor) => ({
32
+ next: () => tryStorageSync("sql.next", () => cursor.next()),
33
+ toArray: () => tryStorageSync("sql.toArray", () => cursor.toArray()),
34
+ one: () => tryStorageSync("sql.one", () => cursor.one()),
35
+ raw: () => tryStorageSync("sql.raw", () => cursor.raw()),
36
+ get columnNames() {
37
+ return cursor.columnNames;
38
+ },
39
+ rowsRead: tryStorageSync("sql.rowsRead", () => cursor.rowsRead),
40
+ rowsWritten: tryStorageSync("sql.rowsWritten", () => cursor.rowsWritten)
41
+ });
42
+ const fromSqlStorage = (sql) => ({
43
+ exec: (query, ...bindings) => tryStorageSync("sql.exec", () => fromSqlCursor(sql.exec(query, ...bindings))),
44
+ get databaseSize() {
45
+ return sql.databaseSize;
46
+ }
47
+ });
48
+ const schemaBackedSyncKvStorage = (kv, definition) => {
49
+ const encodeKey = Schema.encodeEffect(definition.key);
50
+ const decodeKey = Schema.decodeUnknownEffect(definition.key);
51
+ const encodeValue = Schema.encodeEffect(definition.value);
52
+ const decodeValue = Schema.decodeUnknownEffect(definition.value);
53
+ return {
54
+ get: (key) => Effect.gen(function* () {
55
+ const encodedKey = yield* encodeKey(key);
56
+ const encodedValue = yield* tryStorageSync("kv.get", () => kv.get(encodedKey));
57
+ if (encodedValue === void 0) return Option.none();
58
+ return yield* decodeValue(encodedValue).pipe(Effect.map(Option.some));
40
59
  }),
41
- sendBatch: Effect.fnUntraced(function* (messages, options) {
42
- const encodedMessages = [];
43
- for (const message of messages) encodedMessages.push({
44
- ...message,
45
- body: yield* encodeMessage(message.body)
46
- });
47
- const sendBatch = queue.sendBatch;
48
- if (sendBatch !== void 0) {
49
- yield* tryQueuePromise(definition.binding, "sendBatch", () => sendBatch.call(queue, encodedMessages, options));
50
- return;
51
- }
52
- yield* tryQueuePromise(definition.binding, "sendBatch", async () => {
53
- for (const message of encodedMessages) await queue.send(message.body, {
54
- contentType: message.contentType,
55
- delaySeconds: message.delaySeconds ?? options?.delaySeconds
56
- });
57
- });
60
+ put: (key, value) => Effect.gen(function* () {
61
+ const encodedKey = yield* encodeKey(key);
62
+ const encodedValue = yield* encodeValue(value);
63
+ yield* tryStorageSync("kv.put", () => kv.put(encodedKey, encodedValue));
58
64
  }),
59
- metrics: () => {
60
- const metrics = queue.metrics;
61
- if (metrics === void 0) return Effect.fail(new QueueOperationError({
62
- binding: definition.binding,
63
- operation: "metrics",
64
- cause: /* @__PURE__ */ new Error(`Queue binding "${definition.binding}" does not provide metrics()`),
65
- message: `Cloudflare queue binding "${definition.binding}" does not provide metrics()`
66
- }));
67
- return tryQueuePromise(definition.binding, "metrics", () => metrics.call(queue));
68
- },
69
- unsafeRaw: Effect.succeed(queue)
70
- });
71
- };
72
- const layer$9 = (tag, definition) => layer$10(tag, definition.binding, (value) => isQueue(value), makeClient$6(definition), { expected: expectedQueueProducer });
73
- //#endregion
74
- //#region src/QueueDefinition.ts
75
- var QueueDefinition_exports = /* @__PURE__ */ __exportAll({
76
- Queue: () => Queue$1,
77
- Tag: () => Tag$10,
78
- implement: () => implement$7,
79
- make: () => make$10
80
- });
81
- const makeDefinition$4 = (id, definition) => {
82
- const queueDefinition = {
83
- id,
84
- message: definition.message
65
+ delete: (key) => Effect.gen(function* () {
66
+ const encodedKey = yield* encodeKey(key);
67
+ return yield* tryStorageSync("kv.delete", () => kv.delete(encodedKey));
68
+ }),
69
+ list: (options) => Effect.gen(function* () {
70
+ const entries = Array.from(yield* tryStorageSync("kv.list", () => kv.list(options)));
71
+ const decoded = [];
72
+ for (const [key, value] of entries) decoded.push([yield* decodeKey(key), yield* decodeValue(value)]);
73
+ return decoded;
74
+ })
85
75
  };
86
- return Object.assign(queueDefinition, { make: (layer, options) => make$7(layer, {
87
- ...options,
88
- queue: wrapHandler$1(queueDefinition, options.queue)
89
- }) });
90
- };
91
- const make$10 = (id, definition) => Tag$10()(id, definition);
92
- const Tag$10 = () => (id, definition) => {
93
- const queueDefinition = makeDefinition$4(id, definition);
94
- const tag = Context.Service()(id);
95
- const layer = (binding) => layer$9(tag, {
96
- ...binding,
97
- message: definition.message
98
- });
99
- const send = Effect.fnUntraced(function* (message, options) {
100
- yield* (yield* tag).send(message, options);
101
- });
102
- const sendBatch = Effect.fnUntraced(function* (messages, options) {
103
- yield* (yield* tag).sendBatch(messages, options);
104
- });
105
- const metrics = Effect.fnUntraced(function* () {
106
- return yield* (yield* tag).metrics();
107
- });
108
- const unsafeRaw = Effect.fnUntraced(function* () {
109
- return yield* (yield* tag).unsafeRaw;
110
- });
111
- return Object.assign(tag, {
112
- id: queueDefinition.id,
113
- message: queueDefinition.message,
114
- make: queueDefinition.make,
115
- layer,
116
- send,
117
- sendBatch,
118
- metrics,
119
- unsafeRaw
120
- });
121
- };
122
- const Queue$1 = Tag$10;
123
- const wrapHandler$1 = (definition, handler) => {
124
- const decodeBody = Schema.decodeUnknownEffect(definition.message);
125
- return (batch) => Effect.gen(function* () {
126
- yield* handler(yield* decodeBatch(batch.raw, decodeBody));
127
- });
128
76
  };
129
- const implement$7 = (_definition, handler) => handler;
130
- //#endregion
131
- //#region src/Queue.ts
132
- var Queue_exports = /* @__PURE__ */ __exportAll({
133
- QueueMessageDecodeError: () => QueueMessageDecodeError,
134
- Tag: () => Tag$9,
135
- decodeBatch: () => decodeBatch,
136
- fromMessage: () => fromMessage,
137
- fromMessageBatch: () => fromMessageBatch,
138
- implement: () => implement$6
77
+ const fromSyncKvStorage = (kv) => ({
78
+ get: (key) => tryStorageSync("kv.get", () => kv.get(key)),
79
+ put: (key, value) => tryStorageSync("kv.put", () => kv.put(key, value)),
80
+ delete: (key) => tryStorageSync("kv.delete", () => kv.delete(key)),
81
+ list: (options) => tryStorageSync("kv.list", () => Array.from(kv.list(options))),
82
+ schema: (definition) => schemaBackedSyncKvStorage(kv, definition)
139
83
  });
140
- var QueueMessageDecodeError = class extends Data.TaggedError("QueueMessageDecodeError") {};
141
- const fromMessage = (message, body) => ({
142
- raw: message,
143
- id: message.id,
144
- timestamp: message.timestamp,
145
- body,
146
- attempts: message.attempts,
147
- ack: Effect.sync(() => message.ack()),
148
- retry: (options) => Effect.sync(() => message.retry(options))
84
+ const fromDurableObjectTransaction = (txn) => ({
85
+ get: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)) : tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)),
86
+ list: (options) => tryStoragePromise("transaction.list", () => txn.list(options)),
87
+ put: (keyOrEntries, valueOrOptions, maybeOptions) => tryStoragePromise("transaction.put", () => typeof keyOrEntries === "string" ? txn.put(keyOrEntries, valueOrOptions, maybeOptions) : txn.put(keyOrEntries, valueOrOptions)),
88
+ delete: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)) : tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)),
89
+ rollback: () => tryStorageSync("transaction.rollback", () => txn.rollback()),
90
+ getAlarm: (options) => tryStoragePromise("transaction.getAlarm", () => txn.getAlarm(options)),
91
+ setAlarm: (scheduledTime, options) => tryStoragePromise("transaction.setAlarm", () => txn.setAlarm(scheduledTime, options)),
92
+ deleteAlarm: (options) => tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options))
149
93
  });
150
- const fromMessageBatch = (batch, messages) => ({
151
- raw: batch,
152
- messages,
153
- queue: batch.queue,
154
- metadata: batch.metadata,
155
- ackAll: Effect.sync(() => batch.ackAll()),
156
- retryAll: (options) => Effect.sync(() => batch.retryAll(options))
94
+ /**
95
+ * Wraps native Cloudflare storage APIs as Effect-returning helpers.
96
+ */
97
+ const fromDurableObjectStorage = (storage) => ({
98
+ get: (key, options) => tryStoragePromise("get", () => storage.get(key, options)),
99
+ put: (key, value, options) => tryStoragePromise("put", () => storage.put(key, value, options)),
100
+ delete: (key, options) => tryStoragePromise("delete", () => storage.delete(key, options)),
101
+ deleteAll: (options) => tryStoragePromise("deleteAll", () => storage.deleteAll(options)),
102
+ getAlarm: (options) => tryStoragePromise("getAlarm", () => storage.getAlarm(options)),
103
+ setAlarm: (scheduledTime, options) => tryStoragePromise("setAlarm", () => storage.setAlarm(scheduledTime, options)),
104
+ deleteAlarm: (options) => tryStoragePromise("deleteAlarm", () => storage.deleteAlarm(options)),
105
+ transactionSync: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.suspend(() => {
106
+ try {
107
+ return Effect.succeed(storage.transactionSync(() => {
108
+ const exit = Effect.runSyncExitWith(context)(closure());
109
+ if (Exit.isSuccess(exit)) return exit.value;
110
+ throw exit;
111
+ }));
112
+ } catch (cause) {
113
+ if (Exit.isExit(cause) && Exit.isFailure(cause)) return Effect.failCause(cause.cause);
114
+ return Effect.fail(storageError("transactionSync", cause));
115
+ }
116
+ }))),
117
+ transaction: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.callback((resume) => {
118
+ storage.transaction(async (txn) => {
119
+ const exit = await Effect.runPromiseExitWith(context)(closure(fromDurableObjectTransaction(txn)));
120
+ if (Exit.isSuccess(exit)) return exit.value;
121
+ throw exit;
122
+ }).then((value) => resume(Effect.succeed(value)), (cause) => {
123
+ if (Exit.isExit(cause) && Exit.isFailure(cause)) resume(Effect.failCause(cause.cause));
124
+ else resume(Effect.fail(storageError("transaction", cause)));
125
+ });
126
+ }))),
127
+ sync: () => tryStoragePromise("sync", () => storage.sync()),
128
+ getCurrentBookmark: () => tryStoragePromise("getCurrentBookmark", () => storage.getCurrentBookmark()),
129
+ onNextSessionRestoreBookmark: (bookmark) => tryStoragePromise("onNextSessionRestoreBookmark", () => storage.onNextSessionRestoreBookmark(bookmark)),
130
+ sql: fromSqlStorage(storage.sql),
131
+ kv: fromSyncKvStorage(storage.kv)
157
132
  });
158
- const decodeBatch = (batch, decodeBody) => Effect.gen(function* () {
159
- const messages = [];
160
- for (let index = 0; index < batch.messages.length; index++) {
161
- const message = batch.messages[index];
162
- const body = yield* decodeBody(message.body).pipe(Effect.mapError((cause) => new QueueMessageDecodeError({
163
- queue: batch.queue,
164
- messageId: message.id,
165
- index,
166
- cause
167
- })));
168
- messages.push(fromMessage(message, body));
169
- }
170
- return fromMessageBatch(batch, messages);
171
- });
172
- const Tag$9 = Tag$10;
173
- const implement$6 = implement$7;
174
133
  //#endregion
175
- //#region src/RpcDefinition.ts
176
- var RpcDefinition_exports = /* @__PURE__ */ __exportAll({
177
- ReservedMethodNameError: () => ReservedMethodNameError,
178
- RpcArgumentCountError: () => RpcArgumentCountError,
179
- RpcArgumentDecodeError: () => RpcArgumentDecodeError,
180
- RpcArgumentEncodeError: () => RpcArgumentEncodeError,
181
- RpcReservedMethodNameError: () => RpcReservedMethodNameError,
182
- RpcSuccessDecodeError: () => RpcSuccessDecodeError,
183
- RpcSuccessEncodeError: () => RpcSuccessEncodeError,
184
- assertNoReservedMethodNames: () => assertNoReservedMethodNames,
185
- assertNoReservedMethods: () => assertNoReservedMethods,
186
- decodeArgs: () => decodeArgs,
187
- decodeSuccess: () => decodeSuccess,
188
- encodeArgs: () => encodeArgs,
189
- encodeSuccess: () => encodeSuccess,
190
- make: () => make$9,
191
- method: () => method$4,
192
- reservedMethodNames: () => reservedMethodNames$4
134
+ //#region src/DurableObjectWebSocket.ts
135
+ var DurableObjectWebSocket_exports = /* @__PURE__ */ __exportAll({
136
+ DurableWebSocketAttachmentError: () => DurableWebSocketAttachmentError,
137
+ DurableWebSocketCloseError: () => DurableWebSocketCloseError,
138
+ DurableWebSocketSendError: () => DurableWebSocketSendError,
139
+ acceptUpgrade: () => acceptUpgrade,
140
+ attachment: () => attachment,
141
+ fromWebSocket: () => fromWebSocket,
142
+ handlers: () => handlers
193
143
  });
194
- var RpcReservedMethodNameError = class extends Data.TaggedError("RpcReservedMethodNameError") {};
195
- var RpcArgumentCountError = class extends Data.TaggedError("RpcArgumentCountError") {};
196
- var RpcArgumentDecodeError = class extends Data.TaggedError("RpcArgumentDecodeError") {};
197
- var RpcArgumentEncodeError = class extends Data.TaggedError("RpcArgumentEncodeError") {};
198
- var RpcSuccessDecodeError = class extends Data.TaggedError("RpcSuccessDecodeError") {};
199
- var RpcSuccessEncodeError = class extends Data.TaggedError("RpcSuccessEncodeError") {};
200
- const reservedMethodNames$4 = new Set([
201
- "constructor",
202
- "fetch",
203
- "connect",
204
- "alarm",
205
- "webSocketMessage",
206
- "webSocketClose",
207
- "webSocketError",
208
- "then",
209
- "dup",
210
- "dispose",
211
- "serialize",
212
- "deserialize"
213
- ]);
214
- var ReservedMethodNameError = class extends Error {
215
- method;
216
- target;
217
- constructor(target, method) {
218
- super(`${target} RPC method "${method}" is reserved by Cloudflare Workers RPC`);
219
- this.name = "ReservedMethodNameError";
220
- this.target = target;
221
- this.method = method;
222
- }
223
- };
224
- const assertNoReservedMethods = (target, methods, reserved) => {
225
- for (const method of Object.keys(methods)) if (reserved.has(method)) throw new ReservedMethodNameError(target, method);
144
+ /** Error raised when sending on a Durable Object websocket fails. */
145
+ var DurableWebSocketSendError = class extends Data.TaggedError("DurableWebSocketSendError") {};
146
+ /** Error raised when closing a Durable Object websocket fails. */
147
+ var DurableWebSocketCloseError = class extends Data.TaggedError("DurableWebSocketCloseError") {};
148
+ /** Error raised when serializing or deserializing a websocket attachment fails. */
149
+ var DurableWebSocketAttachmentError = class extends Data.TaggedError("DurableWebSocketAttachmentError") {};
150
+ const wrappers = /* @__PURE__ */ new WeakMap();
151
+ /** Wraps a native Cloudflare websocket in the Effect-native Durable Object API. */
152
+ const fromWebSocket = (raw) => {
153
+ const existing = wrappers.get(raw);
154
+ if (existing !== void 0) return existing;
155
+ const socket = {
156
+ raw,
157
+ send: (data) => Effect.try({
158
+ try: () => raw.send(data),
159
+ catch: (cause) => new DurableWebSocketSendError({ cause })
160
+ }),
161
+ close: (code, reason) => Effect.try({
162
+ try: () => raw.close(code, reason),
163
+ catch: (cause) => new DurableWebSocketCloseError({ cause })
164
+ }),
165
+ serializeAttachment: (value) => Effect.try({
166
+ try: () => raw.serializeAttachment(value),
167
+ catch: (cause) => new DurableWebSocketAttachmentError({
168
+ operation: "serialize",
169
+ cause
170
+ })
171
+ }),
172
+ deserializeAttachment: Effect.try({
173
+ try: () => raw.deserializeAttachment(),
174
+ catch: (cause) => new DurableWebSocketAttachmentError({
175
+ operation: "deserialize",
176
+ cause
177
+ })
178
+ })
179
+ };
180
+ wrappers.set(raw, socket);
181
+ return socket;
226
182
  };
227
- function method$4(definition) {
183
+ /**
184
+ * Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * const response = yield* DurableObjectWebSocket.acceptUpgrade({
189
+ * tags: ["room:general"],
190
+ * });
191
+ *
192
+ * return response.response;
193
+ * ```
194
+ */
195
+ const acceptUpgrade = (options = {}) => Effect.gen(function* () {
196
+ const state = yield* DurableObjectState;
197
+ const pair = new WebSocketPair();
198
+ const client = pair[0];
199
+ const server = fromWebSocket(pair[1]);
200
+ if (options.attachment !== void 0) server.raw.serializeAttachment(options.attachment);
201
+ yield* state.acceptWebSocket(server, options.tags === void 0 ? void 0 : [...options.tags]);
228
202
  return {
229
- args: definition.args ?? [],
230
- success: definition.success
203
+ client,
204
+ server,
205
+ response: new Response(null, {
206
+ status: 101,
207
+ webSocket: client
208
+ })
231
209
  };
232
- }
233
- const assertNoReservedMethodNames = (definition) => Effect.forEach(Object.keys(definition.methods), (method) => reservedMethodNames$4.has(method) ? Effect.fail(new RpcReservedMethodNameError({
234
- definition: definition.id,
235
- method
236
- })) : Effect.void).pipe(Effect.asVoid);
237
- const decodeArgs = (definition, methodName, args) => Effect.gen(function* () {
238
- const methodDefinition = definition.methods[methodName];
239
- if (args.length !== methodDefinition.args.length) return yield* Effect.fail(new RpcArgumentCountError({
240
- definition: definition.id,
241
- method: methodName,
242
- expected: methodDefinition.args.length,
243
- actual: args.length
244
- }));
245
- const decoded = [];
246
- for (let index = 0; index < methodDefinition.args.length; index++) {
247
- const schema = methodDefinition.args[index];
248
- decoded.push(yield* Schema.decodeUnknownEffect(schema)(args[index]).pipe(Effect.mapError((cause) => new RpcArgumentDecodeError({
249
- definition: definition.id,
250
- method: methodName,
251
- index,
252
- cause
253
- }))));
254
- }
255
- return decoded;
256
210
  });
257
- const encodeArgs = (definition, methodName, args) => Effect.gen(function* () {
258
- const methodDefinition = definition.methods[methodName];
259
- if (args.length !== methodDefinition.args.length) return yield* Effect.fail(new RpcArgumentCountError({
260
- definition: definition.id,
261
- method: methodName,
262
- expected: methodDefinition.args.length,
263
- actual: args.length
264
- }));
265
- const encoded = [];
266
- for (let index = 0; index < methodDefinition.args.length; index++) {
267
- const schema = methodDefinition.args[index];
268
- encoded.push(yield* Schema.encodeEffect(schema)(args[index]).pipe(Effect.mapError((cause) => new RpcArgumentEncodeError({
269
- definition: definition.id,
270
- method: methodName,
271
- index,
211
+ /** Creates typed attachment helpers for accepted and rehydrated sockets. */
212
+ const attachment = (schema) => {
213
+ const serialize = (socket, value) => Schema.encodeEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
214
+ operation: "serialize",
215
+ cause
216
+ })), Effect.flatMap((encoded) => socket.serializeAttachment(encoded)));
217
+ const deserialize = (socket) => Effect.gen(function* () {
218
+ const value = yield* socket.deserializeAttachment;
219
+ if (value == null) return Option.none();
220
+ return Option.some(yield* Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
221
+ operation: "deserialize",
272
222
  cause
273
223
  }))));
274
- }
275
- return encoded;
276
- });
277
- const encodeSuccess = (definition, methodName, value) => {
278
- const methodDefinition = definition.methods[methodName];
279
- return Schema.encodeEffect(methodDefinition.success)(value).pipe(Effect.mapError((cause) => new RpcSuccessEncodeError({
280
- definition: definition.id,
281
- method: methodName,
282
- cause
283
- })));
284
- };
285
- const decodeSuccess = (definition, methodName, value) => {
286
- const methodDefinition = definition.methods[methodName];
287
- return Schema.decodeUnknownEffect(methodDefinition.success)(value).pipe(Effect.mapError((cause) => new RpcSuccessDecodeError({
288
- definition: definition.id,
289
- method: methodName,
290
- cause
291
- })));
292
- };
293
- const make$9 = (id, methods) => {
294
- const definition = {
295
- id,
296
- methods
297
- };
298
- const reserved = Object.keys(definition.methods).find((methodName) => reservedMethodNames$4.has(methodName));
299
- if (reserved !== void 0) throw new RpcReservedMethodNameError({
300
- definition: id,
301
- method: reserved
302
224
  });
303
- return definition;
225
+ const rehydrate = (options = {}) => Effect.gen(function* () {
226
+ const sockets = yield* (yield* DurableObjectState).getWebSockets(options.tag);
227
+ const restored = [];
228
+ const onInvalid = options.onInvalid ?? "ignore";
229
+ for (const socket of sockets) {
230
+ const decoded = yield* deserialize(socket).pipe(Effect.match({
231
+ onFailure: (error) => ({
232
+ _tag: "Failure",
233
+ error
234
+ }),
235
+ onSuccess: (value) => ({
236
+ _tag: "Success",
237
+ value
238
+ })
239
+ }));
240
+ if (decoded._tag === "Success" && Option.isSome(decoded.value)) {
241
+ restored.push({
242
+ socket,
243
+ attachment: decoded.value.value
244
+ });
245
+ continue;
246
+ }
247
+ if (decoded._tag === "Failure" && onInvalid === "fail") return yield* Effect.fail(decoded.error);
248
+ if (decoded._tag === "Failure" && onInvalid === "ignore-and-close") yield* socket.close(1008, "invalid websocket attachment").pipe(Effect.ignore);
249
+ }
250
+ return restored;
251
+ });
252
+ return {
253
+ serialize,
254
+ deserialize,
255
+ rehydrate,
256
+ schema
257
+ };
304
258
  };
305
- //#endregion
306
- //#region src/Rpc.ts
307
- var Rpc_exports = /* @__PURE__ */ __exportAll({
308
- RpcStub: () => RpcStub,
309
- RpcTarget: () => RpcTarget,
310
- dispose: () => dispose,
311
- isDisposable: () => isDisposable,
312
- resolve: () => resolve,
313
- scoped: () => scoped
314
- });
315
- const isDisposable = (value) => (typeof value === "object" || typeof value === "function") && value !== null && Symbol.dispose in value && typeof value[Symbol.dispose] === "function";
316
- const dispose = (value) => Effect.sync(() => {
317
- if (isDisposable(value)) value[Symbol.dispose]();
318
- });
319
- const resolve = (value) => isPromiseLike(value) ? Effect.tryPromise({
320
- try: () => value,
321
- catch: (cause) => cause
322
- }) : Effect.sync(() => value);
323
- const scoped = (value) => Effect.acquireRelease(resolve(value), (resolved) => dispose(resolved));
324
- const isPromiseLike = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
325
- //#endregion
326
- //#region src/internal/RpcInvocation.ts
327
- const isPropertyTarget = (value) => (typeof value === "object" || typeof value === "function") && value !== null;
328
- const lookupRpcMethod = (target, method, makeError) => Effect.try({
329
- try: () => {
330
- if (!isPropertyTarget(target)) throw new TypeError(`RPC target is not object-like`);
331
- const value = Reflect.get(target, method);
332
- if (typeof value !== "function") throw new TypeError(`RPC method "${String(method)}" is not callable`);
333
- return ((...args) => Reflect.apply(value, target, args));
334
- },
335
- catch: makeError
336
- });
337
- const invokeRpcMethod = (target, method, args, makeError) => Effect.gen(function* () {
338
- const fn = yield* lookupRpcMethod(target, method, makeError);
339
- return yield* Effect.try({
340
- try: () => fn(...args),
341
- catch: makeError
342
- });
259
+ /** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
260
+ const handlers = (options) => ({
261
+ webSocketMessage: options.message,
262
+ webSocketClose: options.close,
263
+ webSocketError: options.error
343
264
  });
344
265
  //#endregion
345
- //#region src/ServiceBinding.ts
346
- var ServiceBinding_exports = /* @__PURE__ */ __exportAll({
347
- Service: () => Service$1,
348
- ServiceBindingFetchError: () => ServiceBindingFetchError,
349
- ServiceBindingRpcError: () => ServiceBindingRpcError,
350
- isServiceBindingClient: () => isServiceBindingClient,
351
- layer: () => layer$8,
352
- makeClient: () => makeClient$5,
353
- makeDirectMethods: () => makeDirectMethods$1
266
+ //#region src/DurableObjectState.ts
267
+ var DurableObjectState_exports = /* @__PURE__ */ __exportAll({
268
+ DurableObjectState: () => DurableObjectState,
269
+ fromDurableObjectState: () => fromDurableObjectState
354
270
  });
355
- const TypeId$2 = "effect-cf/ServiceBinding";
356
- const expectedServiceBinding = "Worker service binding with fetch()";
357
271
  /**
358
- * Failure raised when calling `fetch` on a service binding.
272
+ * Context tag for accessing the current Durable Object state service.
359
273
  */
360
- var ServiceBindingFetchError = class extends Data.TaggedError("ServiceBindingFetchError") {};
274
+ var DurableObjectState = class extends Context.Service()("effect-cf/DurableObjectState") {};
361
275
  /**
362
- * Failure raised when invoking an RPC method on a service binding.
276
+ * Wraps a native Cloudflare `DurableObjectState` as a {@link DurableObjectStateService}.
363
277
  */
364
- var ServiceBindingRpcError = class extends Data.TaggedError("ServiceBindingRpcError") {};
365
- const isServiceBindingClient = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "fetch") === "function";
366
- const makeClient$5 = (definition) => {
367
- return (service) => {
368
- const fetch = (input, init) => Effect.tryPromise({
369
- try: () => service.fetch(input, init),
370
- catch: (cause) => new ServiceBindingFetchError({
371
- binding: definition.binding,
372
- cause
373
- })
374
- });
375
- const rpc = (method, ...args) => Effect.gen(function* () {
376
- const methodName = String(method);
377
- return yield* invokeRpcMethod(service, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
378
- binding: definition.binding,
379
- method: methodName,
380
- cause
381
- }))), (cause) => new ServiceBindingRpcError({
382
- binding: definition.binding,
383
- method: methodName,
384
- cause
385
- }));
386
- });
387
- const decodeSuccess$2 = (methodName, value) => Effect.gen(function* () {
388
- if (definition.definition === void 0) return value;
389
- return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
390
- binding: definition.binding,
391
- method: methodName,
392
- cause
393
- })));
394
- });
395
- const call = (method, ...args) => Effect.gen(function* () {
396
- const methodName = String(method);
397
- return yield* decodeSuccess$2(methodName, yield* resolve(yield* rpc(method, ...args)).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
398
- binding: definition.binding,
399
- method: methodName,
400
- cause
401
- }))));
402
- });
403
- const scopedCall = (method, ...args) => Effect.gen(function* () {
404
- return yield* decodeSuccess$2(String(method), yield* scoped(yield* rpc(method, ...args)));
405
- });
406
- const directMethods = makeDirectMethods$1(definition.definition, call);
407
- return Object.assign(directMethods, {
408
- fetch,
409
- rpc,
410
- call,
411
- scopedCall
412
- });
413
- };
278
+ const fromDurableObjectState = (state) => ({
279
+ raw: state,
280
+ id: state.id,
281
+ storage: fromDurableObjectStorage(state.storage),
282
+ waitUntil: (promise) => Effect.sync(() => state.waitUntil(promise)),
283
+ blockConcurrencyWhile: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => runPromiseExitPreservingTypedFailures(Effect.provideContext(effect, context))))), Effect.flatten),
284
+ blockConcurrencyWhileOrReset: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => Effect.runPromise(Effect.provideContext(effect, context)))))),
285
+ acceptWebSocket: (ws, tags) => Effect.sync(() => state.acceptWebSocket(ws.raw, tags)),
286
+ getWebSockets: (tag) => Effect.sync(() => state.getWebSockets(tag).map((socket) => fromWebSocket(socket))),
287
+ setWebSocketAutoResponse: (pair) => Effect.sync(() => state.setWebSocketAutoResponse(pair)),
288
+ getWebSocketAutoResponse: Effect.sync(() => state.getWebSocketAutoResponse()),
289
+ getWebSocketAutoResponseTimestamp: (ws) => Effect.sync(() => state.getWebSocketAutoResponseTimestamp(ws.raw)),
290
+ setHibernatableWebSocketEventTimeout: (timeoutMs) => Effect.sync(() => state.setHibernatableWebSocketEventTimeout(timeoutMs)),
291
+ getHibernatableWebSocketEventTimeout: Effect.sync(() => state.getHibernatableWebSocketEventTimeout()),
292
+ getTags: (ws) => Effect.sync(() => state.getTags(ws.raw)),
293
+ abort: (reason) => Effect.sync(() => state.abort(reason))
294
+ });
295
+ const runPromiseExitPreservingTypedFailures = async (effect) => {
296
+ const exit = await Effect.runPromiseExit(effect);
297
+ if (Exit.isFailure(exit) && (Cause.hasDies(exit.cause) || Cause.hasInterrupts(exit.cause))) throw Cause.squash(exit.cause);
298
+ return exit;
414
299
  };
415
- const layer$8 = (tag, definition) => layer$10(tag, definition.binding, (value) => isServiceBindingClient(value), makeClient$5(definition), { expected: expectedServiceBinding });
300
+ //#endregion
301
+ //#region src/CloudflareOtlp.ts
302
+ var CloudflareOtlp_exports = /* @__PURE__ */ __exportAll({
303
+ CloudflareOtlpSettings: () => CloudflareOtlpSettings,
304
+ durableObjectLayer: () => durableObjectLayer,
305
+ layer: () => layer$9,
306
+ layerJson: () => layerJson,
307
+ layerProtobuf: () => layerProtobuf,
308
+ settingsConfig: () => settingsConfig,
309
+ settingsLayer: () => settingsLayer,
310
+ workerLayer: () => workerLayer
311
+ });
416
312
  /**
417
- * Creates a typed Effect service for a Worker service binding.
313
+ * Supported OpenTelemetry environment configuration for Cloudflare OTLP export.
418
314
  *
419
- * Returned value includes:
420
- * - a Context tag for dependency injection
421
- * - `fetch(...)` for raw HTTP forwarding
422
- * - `rpc(...)` for raw Cloudflare RPC results
423
- * - `call(...)` for resolved and decoded RPC results
424
- * - `scopedCall(...)` for scoped and decoded disposable RPC results
425
- * - direct RPC methods when `definition` is provided
315
+ * This config intentionally uses the conventional `OTEL_*` variable names so
316
+ * deployments can share the same settings used by other OpenTelemetry SDKs.
317
+ * It covers the OTLP HTTP settings supported by the Effect OTLP layers:
426
318
  *
427
- * @example
428
- * ```ts
429
- * const Counter = WorkerDefinition.make("Counter", {
430
- * increment: WorkerDefinition.method({
431
- * args: [Schema.Number],
432
- * success: Schema.Number,
433
- * }),
434
- * });
319
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT`
320
+ * - `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`
321
+ * - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`
322
+ * - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`
323
+ * - `OTEL_EXPORTER_OTLP_HEADERS`
324
+ * - `OTEL_EXPORTER_OTLP_LOGS_HEADERS`
325
+ * - `OTEL_EXPORTER_OTLP_TRACES_HEADERS`
326
+ * - `OTEL_EXPORTER_OTLP_METRICS_HEADERS`
327
+ * - `OTEL_SERVICE_NAME`
328
+ * - `OTEL_RESOURCE_ATTRIBUTES`
435
329
  *
436
- * const CounterLive = Counter.layer({ binding: "COUNTER" });
330
+ * `OTEL_SERVICE_VERSION` is also accepted as an effect-cf convenience alias.
331
+ * The standard OpenTelemetry way to configure service version is
332
+ * `OTEL_RESOURCE_ATTRIBUTES=service.version=...`.
437
333
  *
438
- * const program = Effect.gen(function* () {
439
- * const counter = yield* Counter;
440
- * const next = yield* counter.increment(1);
441
- * return next;
442
- * });
443
- * ```
334
+ * Consumers with non-standard binding names should map those names into
335
+ * {@link CloudflareOtlpSettings} rather than changing this config globally.
444
336
  */
445
- const Service$1 = () => (id, definition) => {
446
- const tag = Service$2()(id, definition.binding, (value) => isServiceBindingClient(value), makeClient$5(definition));
447
- const fetch = (input, init) => Effect.gen(function* () {
448
- return yield* (yield* tag).fetch(input, init);
449
- });
450
- const rpc = (method, ...args) => Effect.gen(function* () {
451
- return yield* (yield* tag).rpc(method, ...args);
452
- });
453
- const call = (method, ...args) => Effect.gen(function* () {
454
- return yield* (yield* tag).call(method, ...args);
455
- });
456
- const scopedCall = (method, ...args) => Effect.gen(function* () {
457
- return yield* (yield* tag).scopedCall(method, ...args);
458
- });
459
- const directMethods = makeDirectMethods$1(definition.definition, call);
460
- return Object.assign(tag, directMethods, {
461
- [TypeId$2]: TypeId$2,
462
- definition,
463
- fetch,
464
- rpc,
465
- call,
466
- scopedCall
467
- });
468
- };
469
- const makeDirectMethods$1 = (rpcDefinition, call) => {
470
- const methods = {};
471
- if (rpcDefinition !== void 0) for (const methodName of Object.keys(rpcDefinition.methods)) methods[methodName] = (...args) => call(methodName, ...args);
472
- return methods;
473
- };
474
- //#endregion
475
- //#region src/WorkerDefinition.ts
476
- var WorkerDefinition_exports = /* @__PURE__ */ __exportAll({
477
- Tag: () => Tag$8,
478
- Worker: () => Worker,
479
- implement: () => implement$5,
480
- make: () => make$8,
481
- method: () => method$3
337
+ const settingsConfig = Config.all({
338
+ endpoint: Config.string("OTEL_EXPORTER_OTLP_ENDPOINT").pipe(Config.option),
339
+ logsEndpoint: Config.string("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT").pipe(Config.option),
340
+ tracesEndpoint: Config.string("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT").pipe(Config.option),
341
+ metricsEndpoint: Config.string("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT").pipe(Config.option),
342
+ headers: Config.string("OTEL_EXPORTER_OTLP_HEADERS").pipe(Config.option),
343
+ logsHeaders: Config.string("OTEL_EXPORTER_OTLP_LOGS_HEADERS").pipe(Config.option),
344
+ tracesHeaders: Config.string("OTEL_EXPORTER_OTLP_TRACES_HEADERS").pipe(Config.option),
345
+ metricsHeaders: Config.string("OTEL_EXPORTER_OTLP_METRICS_HEADERS").pipe(Config.option),
346
+ serviceName: Config.string("OTEL_SERVICE_NAME").pipe(Config.option),
347
+ serviceVersion: Config.string("OTEL_SERVICE_VERSION").pipe(Config.option),
348
+ resourceAttributes: Config.schema(Config.Record(Schema.String, Schema.String), "OTEL_RESOURCE_ATTRIBUTES").pipe(Config.option)
482
349
  });
483
- const reservedMethodNames$3 = new Set([
484
- "constructor",
485
- "dup",
486
- "fetch",
487
- "connect",
488
- "queue",
489
- "scheduled",
490
- "tail",
491
- "tailStream",
492
- "test",
493
- "trace",
494
- "alarm",
495
- "webSocketMessage",
496
- "webSocketClose",
497
- "webSocketError"
498
- ]);
499
- /**
500
- * Defines a single RPC method schema in a worker definition.
501
- */
502
- const method$3 = method$4;
503
350
  /**
504
- * Creates a typed worker RPC definition plus helpers for implementation and bindings.
351
+ * Service carrying already-resolved Cloudflare OTLP settings.
352
+ *
353
+ * Provide this service directly when an application needs to map custom
354
+ * Cloudflare binding names, compute settings dynamically, or override settings
355
+ * in tests. When this service is present, the OTLP layers use it instead of
356
+ * reading {@link settingsConfig}.
505
357
  *
506
358
  * @example
507
359
  * ```ts
508
- * const CounterWorker = WorkerDefinition.make("CounterWorker", {
509
- * increment: WorkerDefinition.method({
510
- * args: [Schema.Number],
511
- * success: Schema.Number,
512
- * }),
513
- * });
514
- * ```
515
- */
516
- const makeDefinition$3 = (id, methods) => {
517
- assertNoReservedMethods("Worker", methods, reservedMethodNames$3);
518
- const definition = make$9(id, methods);
519
- return Object.assign(definition, { make: (layer, options) => make$7(layer, {
520
- ...options,
521
- rpc: wrapHandlers$1(definition, options.rpc)
522
- }) });
523
- };
524
- const make$8 = (id, methods) => Tag$8()(id, methods);
525
- const Tag$8 = () => (id, methods) => {
526
- const definition = makeDefinition$3(id, methods);
527
- const tag = Context.Service()(id);
528
- const bindingDefinition = (binding) => ({
529
- ...binding,
530
- definition
531
- });
532
- const layer = (binding) => layer$8(tag, bindingDefinition(binding));
533
- const fetch = (input, init) => Effect.gen(function* () {
534
- return yield* (yield* tag).fetch(input, init);
535
- });
536
- const rpc = (method, ...args) => Effect.gen(function* () {
537
- return yield* (yield* tag).rpc(method, ...args);
538
- });
539
- const call = (method, ...args) => Effect.gen(function* () {
540
- return yield* (yield* tag).call(method, ...args);
541
- });
542
- const scopedCall = (method, ...args) => Effect.gen(function* () {
543
- return yield* (yield* tag).scopedCall(method, ...args);
544
- });
545
- const directMethods = makeDirectMethods$1(definition, call);
546
- return Object.assign(tag, directMethods, {
547
- id: definition.id,
548
- methods: definition.methods,
549
- make: definition.make,
550
- layer,
551
- fetch,
552
- rpc,
553
- call,
554
- scopedCall
555
- });
556
- };
557
- const Worker = Tag$8;
558
- const wrapHandlers$1 = (definition, handlers) => {
559
- const wrapped = {};
560
- for (const key of Object.keys(definition.methods)) {
561
- const handler = handlers[key];
562
- wrapped[key] = (...args) => Effect.gen(function* () {
563
- return yield* encodeSuccess(definition, key, yield* handler(...yield* decodeArgs(definition, key, args)));
564
- });
565
- }
566
- return wrapped;
567
- };
360
+ * const CustomOtlpSettings = Layer.effect(
361
+ * CloudflareOtlp.CloudflareOtlpSettings,
362
+ * Config.all({
363
+ * ...CloudflareOtlp.settingsConfig,
364
+ * endpoint: Config.string("MY_OTLP_ENDPOINT").pipe(Config.option),
365
+ * }),
366
+ * ).pipe(Layer.provide(WorkerConfig.layer));
367
+ * ```
368
+ */
369
+ var CloudflareOtlpSettings = class extends Context.Service()("effect-cf/CloudflareOtlpSettings") {};
370
+ const allSignals = [
371
+ "logs",
372
+ "traces",
373
+ "metrics"
374
+ ];
375
+ const optionToUndefined = (option) => Option.isSome(option) ? option.value : void 0;
376
+ const nonEmptyStringOption = (option) => Option.flatMap(option, (value) => {
377
+ const trimmed = value.trim();
378
+ return trimmed === "" ? Option.none() : Option.some(trimmed);
379
+ });
380
+ const nonEmptyRecordOption = (option) => Option.filter(option, (value) => Object.keys(value).length > 0);
381
+ const normalizeSettings = (settings) => ({
382
+ endpoint: nonEmptyStringOption(settings.endpoint),
383
+ logsEndpoint: nonEmptyStringOption(settings.logsEndpoint),
384
+ tracesEndpoint: nonEmptyStringOption(settings.tracesEndpoint),
385
+ metricsEndpoint: nonEmptyStringOption(settings.metricsEndpoint),
386
+ headers: nonEmptyStringOption(settings.headers),
387
+ logsHeaders: nonEmptyStringOption(settings.logsHeaders),
388
+ tracesHeaders: nonEmptyStringOption(settings.tracesHeaders),
389
+ metricsHeaders: nonEmptyStringOption(settings.metricsHeaders),
390
+ serviceName: nonEmptyStringOption(settings.serviceName),
391
+ serviceVersion: nonEmptyStringOption(settings.serviceVersion),
392
+ resourceAttributes: nonEmptyRecordOption(settings.resourceAttributes)
393
+ });
568
394
  /**
569
- * Helper for implementing handlers with the exact method shape of a definition.
395
+ * Layer that reads standard OpenTelemetry settings from the current Cloudflare
396
+ * `env` object.
397
+ *
398
+ * The layer depends on {@link WorkerEnvironment} and installs a
399
+ * Cloudflare-backed Effect `ConfigProvider`, so `settingsConfig` reads from
400
+ * Worker vars/secrets instead of Node process environment variables.
570
401
  */
571
- const implement$5 = (_definition, handlers) => handlers;
572
- //#endregion
573
- //#region src/internal/Entrypoint.ts
574
- const provideEntrypointServices = (layer, services) => layer.pipe(Layer.provideMerge(services));
575
- const defineEntrypointRpcMethods = (target, prototype, rpc, reservedMethodNames, run) => {
576
- const methods = rpc ?? {};
577
- assertNoReservedMethods(target, methods, reservedMethodNames);
578
- for (const [key, method] of Object.entries(methods)) Object.defineProperty(prototype, key, {
579
- enumerable: true,
580
- value(...args) {
581
- return run(this, Effect.suspend(() => method(...args)));
582
- }
583
- });
402
+ const settingsLayer = Layer.effect(CloudflareOtlpSettings, settingsConfig.pipe(Config.map(normalizeSettings))).pipe(Layer.provide(WorkerConfig.layer));
403
+ const selectedSignals = (signals) => new Set(signals ?? allSignals);
404
+ const withDefinedAttributes = (attributes) => {
405
+ const out = {};
406
+ for (const [key, value] of Object.entries(attributes)) if (value !== void 0) out[key] = value;
407
+ return out;
584
408
  };
585
- const assumeEntrypointClass = (entrypoint) => entrypoint;
586
- //#endregion
587
- //#region src/internal/WorkerContext.ts
588
- const causeError = (cause) => new Error(Cause.pretty(cause));
589
- const failureHandler = (cause, options) => (options?.onFailure?.(cause) ?? Effect.logError("WorkerContext.waitUntil failed", Cause.pretty(cause))).pipe(Effect.catchCause((handlerCause) => Effect.logError("WorkerContext.waitUntil failure handler failed", Cause.pretty(cause), Cause.pretty(handlerCause))));
590
- const fromExecutionContext = (ctx, runPromiseExit) => {
591
- const schedule = (effect, options, mode) => Effect.context().pipe(Effect.flatMap((context) => Effect.sync(() => {
592
- const runHandler = (cause) => runPromiseExit(Effect.scoped(Effect.provideContext(failureHandler(cause, options), context))).then((exit) => {
593
- if (Exit.isFailure(exit)) console.error("WorkerContext.waitUntil failure handler failed", Cause.pretty(exit.cause));
594
- });
595
- ctx.waitUntil(runPromiseExit(Effect.scoped(Effect.provideContext(effect, context))).then(async (exit) => {
596
- if (Exit.isSuccess(exit)) return;
597
- await runHandler(exit.cause);
598
- if (mode === "propagate") throw causeError(exit.cause);
599
- }));
600
- })));
409
+ const parseHeaders = (input) => {
410
+ if (Option.isNone(input) || input.value.trim() === "") return;
411
+ const headers = {};
412
+ for (const part of input.value.split(",")) {
413
+ const index = part.indexOf("=");
414
+ if (index <= 0) continue;
415
+ const key = part.slice(0, index).trim();
416
+ const value = part.slice(index + 1).trim();
417
+ if (key !== "") headers[decodeHeaderComponent(key)] = decodeHeaderComponent(value);
418
+ }
419
+ return headers;
420
+ };
421
+ const mergeHeaders = (common, signalSpecific) => {
422
+ const commonHeaders = parseHeaders(common);
423
+ const signalHeaders = parseHeaders(signalSpecific);
424
+ if (commonHeaders === void 0 && signalHeaders === void 0) return;
601
425
  return {
602
- raw: ctx,
603
- waitUntil: (effect, options) => schedule(effect, options, options?.mode ?? "observe"),
604
- waitUntilPropagating: (effect, options) => schedule(effect, options, "propagate"),
605
- passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
426
+ ...commonHeaders,
427
+ ...signalHeaders
606
428
  };
607
429
  };
608
- //#endregion
609
- //#region src/Worker.ts
610
- var Worker_exports = /* @__PURE__ */ __exportAll({
611
- ExecutionContext: () => ExecutionContext,
612
- NativeRequest: () => NativeRequest,
613
- Tag: () => Tag$7,
614
- WorkerContext: () => WorkerContext,
615
- implement: () => implement$4,
616
- isWebSocketUpgrade: () => isWebSocketUpgrade,
617
- make: () => make$7,
618
- makeFetchHandler: () => makeFetchHandler,
619
- method: () => method$2,
620
- renderHttpResponse: () => renderHttpResponse
621
- });
622
- var ExecutionContext = class extends Context.Service()("effect-cf/ExecutionContext") {};
623
- var WorkerContext = class extends Context.Service()("effect-cf/WorkerContext") {};
624
- var NativeRequest = class extends Context.Service()("effect-cf/NativeRequest") {};
625
- const isWebSocketUpgrade = (request) => request.headers.get("Upgrade")?.toLowerCase() === "websocket";
626
- const reservedMethodNames$2 = new Set([
627
- "constructor",
628
- "dup",
629
- "fetch",
630
- "connect",
631
- "queue",
632
- "scheduled",
633
- "tail",
634
- "tailStream",
635
- "test",
636
- "trace",
637
- "alarm",
638
- "webSocketMessage",
639
- "webSocketClose",
640
- "webSocketError"
641
- ]);
642
- const RunSymbol$1 = Symbol.for("effect-cf/Worker/run");
643
- const renderHttpResponse = (effect) => Effect.flatMap(effect, (response) => Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
644
- const renderFetchSuccess = (effect) => Effect.flatMap(effect, (response) => response instanceof Response ? Effect.succeed(response) : Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
645
- const isWorkerOptions = (options) => typeof options === "object" && options !== null && ("fetch" in options || "queue" in options || "rpc" in options);
646
- function make$7(layer, optionsOrFetch) {
647
- const options = isWorkerOptions(optionsOrFetch) ? optionsOrFetch : { fetch: optionsOrFetch };
648
- class EffectWorker extends WorkerEntrypoint {
649
- runtime;
650
- constructor(ctx, env) {
651
- super(ctx, env);
652
- let runWaitUntilEffect = () => Promise.reject(/* @__PURE__ */ new Error("WorkerContext runtime is not initialized"));
653
- const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(ExecutionContext, ctx), ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env))), Layer.succeed(WorkerContext, fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect))), Layer.succeed(WorkerEnvironment, env)));
654
- this.runtime = ManagedRuntime.make(runtimeLayer);
655
- runWaitUntilEffect = (effect) => this.runtime.runPromiseExit(effect);
656
- }
657
- [RunSymbol$1](effect) {
658
- return this.runtime.runPromise(Effect.scoped(effect));
659
- }
660
- fetch(request) {
661
- const fetchHandler = options.fetch;
662
- if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
663
- const requestServices = Layer.mergeAll(Layer.succeed(NativeRequest, request), Layer.succeed(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromWeb(request)));
664
- return this[RunSymbol$1](renderFetchSuccess(fetchHandler).pipe(Effect.provide(requestServices)));
665
- }
666
- queue(batch) {
667
- const queueHandler = options.queue;
668
- if (queueHandler === void 0) return Promise.resolve();
669
- const messages = batch.messages.map((message) => fromMessage(message, message.body));
670
- return this[RunSymbol$1](queueHandler(fromMessageBatch(batch, messages)));
671
- }
430
+ const decodeHeaderComponent = (value) => {
431
+ try {
432
+ return decodeURIComponent(value);
433
+ } catch {
434
+ return value;
672
435
  }
673
- defineEntrypointRpcMethods("Worker", EffectWorker.prototype, options.rpc, reservedMethodNames$2, (self, effect) => self[RunSymbol$1](effect));
674
- return assumeEntrypointClass(EffectWorker);
675
- }
676
- const makeFetchHandler = (layer, options) => {
677
- const WorkerClass = make$7(layer, options);
678
- return { fetch: (request, env, ctx) => Promise.resolve(new WorkerClass(ctx, env).fetch(request)) };
679
436
  };
680
- const Tag$7 = Tag$8;
681
- const method$2 = method$3;
682
- const implement$4 = implement$5;
683
- //#endregion
684
- //#region src/DurableObjectStorage.ts
685
- var DurableObjectStorage_exports = /* @__PURE__ */ __exportAll({
686
- StorageOperationError: () => StorageOperationError,
687
- fromDurableObjectStorage: () => fromDurableObjectStorage
688
- });
689
- /** Error type used when a storage operation throws or rejects. */
690
- var StorageOperationError = class extends Data.TaggedError("StorageOperationError") {};
691
- const storageError = (operation, cause) => new StorageOperationError({
692
- operation,
693
- cause
437
+ const appendOtlpPath = (baseUrl, path) => `${baseUrl.replace(/\/+$/, "")}${path}`;
438
+ const makeResource = (settings, options, runtimeAttributes) => ({
439
+ serviceName: options.serviceName ?? optionToUndefined(settings.serviceName),
440
+ serviceVersion: options.serviceVersion ?? optionToUndefined(settings.serviceVersion),
441
+ attributes: {
442
+ ...optionToUndefined(settings.resourceAttributes),
443
+ ...withDefinedAttributes(runtimeAttributes),
444
+ ...options.attributes
445
+ }
694
446
  });
695
- const tryStorageSync = (operation, evaluate) => Effect.try({
696
- try: evaluate,
697
- catch: (cause) => storageError(operation, cause)
447
+ const commonOtlpOptions = (settings, options, runtimeAttributes) => ({
448
+ resource: makeResource(settings, options, runtimeAttributes),
449
+ maxBatchSize: options.maxBatchSize,
450
+ loggerExportInterval: options.loggerExportInterval,
451
+ loggerExcludeLogSpans: options.loggerExcludeLogSpans,
452
+ loggerMergeWithExisting: options.loggerMergeWithExisting,
453
+ tracerExportInterval: options.tracerExportInterval,
454
+ tracerContext: options.tracerContext,
455
+ metricsExportInterval: options.metricsExportInterval,
456
+ metricsTemporality: options.metricsTemporality,
457
+ shutdownTimeout: options.shutdownTimeout
698
458
  });
699
- const tryStoragePromise = (operation, evaluate) => Effect.tryPromise({
700
- try: evaluate,
701
- catch: (cause) => storageError(operation, cause)
702
- });
703
- const fromSqlCursor = (cursor) => ({
704
- next: () => tryStorageSync("sql.next", () => cursor.next()),
705
- toArray: () => tryStorageSync("sql.toArray", () => cursor.toArray()),
706
- one: () => tryStorageSync("sql.one", () => cursor.one()),
707
- raw: () => tryStorageSync("sql.raw", () => cursor.raw()),
708
- get columnNames() {
709
- return cursor.columnNames;
710
- },
711
- rowsRead: tryStorageSync("sql.rowsRead", () => cursor.rowsRead),
712
- rowsWritten: tryStorageSync("sql.rowsWritten", () => cursor.rowsWritten)
713
- });
714
- const fromSqlStorage = (sql) => ({
715
- exec: (query, ...bindings) => tryStorageSync("sql.exec", () => fromSqlCursor(sql.exec(query, ...bindings))),
716
- get databaseSize() {
717
- return sql.databaseSize;
718
- }
459
+ const serializationLayer = (serialization) => serialization === "json" ? OtlpSerialization.layerJson : OtlpSerialization.layerProtobuf;
460
+ const resolveSettings = Effect.gen(function* () {
461
+ const settings = yield* Effect.serviceOption(CloudflareOtlpSettings);
462
+ if (Option.isSome(settings)) return normalizeSettings(settings.value);
463
+ const env = yield* Effect.serviceOption(WorkerEnvironment);
464
+ if (Option.isSome(env)) return normalizeSettings(yield* settingsConfig.pipe(Effect.provide(ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env.value))))));
465
+ return normalizeSettings(yield* settingsConfig);
719
466
  });
720
- const schemaBackedSyncKvStorage = (kv, definition) => {
721
- const encodeKey = Schema.encodeEffect(definition.key);
722
- const decodeKey = Schema.decodeUnknownEffect(definition.key);
723
- const encodeValue = Schema.encodeEffect(definition.value);
724
- const decodeValue = Schema.decodeUnknownEffect(definition.value);
725
- return {
726
- get: (key) => Effect.gen(function* () {
727
- const encodedKey = yield* encodeKey(key);
728
- const encodedValue = yield* tryStorageSync("kv.get", () => kv.get(encodedKey));
729
- if (encodedValue === void 0) return Option.none();
730
- return yield* decodeValue(encodedValue).pipe(Effect.map(Option.some));
731
- }),
732
- put: (key, value) => Effect.gen(function* () {
733
- const encodedKey = yield* encodeKey(key);
734
- const encodedValue = yield* encodeValue(value);
735
- yield* tryStorageSync("kv.put", () => kv.put(encodedKey, encodedValue));
736
- }),
737
- delete: (key) => Effect.gen(function* () {
738
- const encodedKey = yield* encodeKey(key);
739
- return yield* tryStorageSync("kv.delete", () => kv.delete(encodedKey));
740
- }),
741
- list: (options) => Effect.gen(function* () {
742
- const entries = Array.from(yield* tryStorageSync("kv.list", () => kv.list(options)));
743
- const decoded = [];
744
- for (const [key, value] of entries) decoded.push([yield* decodeKey(key), yield* decodeValue(value)]);
745
- return decoded;
746
- })
747
- };
467
+ const mergeSignalLayers = (layers) => {
468
+ if (layers.length === 0) return Layer.empty;
469
+ let merged = layers[0];
470
+ for (let index = 1; index < layers.length; index++) merged = Layer.mergeAll(merged, layers[index]);
471
+ return merged;
748
472
  };
749
- const fromSyncKvStorage = (kv) => ({
750
- get: (key) => tryStorageSync("kv.get", () => kv.get(key)),
751
- put: (key, value) => tryStorageSync("kv.put", () => kv.put(key, value)),
752
- delete: (key) => tryStorageSync("kv.delete", () => kv.delete(key)),
753
- list: (options) => tryStorageSync("kv.list", () => Array.from(kv.list(options))),
754
- schema: (definition) => schemaBackedSyncKvStorage(kv, definition)
473
+ const emptyLayer = Layer.empty;
474
+ const makeLayerFromSettings = (options = {}, runtimeAttributes = {}) => Layer.unwrap(Effect.map(resolveSettings, (settings) => {
475
+ const signals = selectedSignals(options.signals);
476
+ const endpoint = optionToUndefined(settings.endpoint);
477
+ const logsEndpoint = optionToUndefined(settings.logsEndpoint);
478
+ const tracesEndpoint = optionToUndefined(settings.tracesEndpoint);
479
+ const metricsEndpoint = optionToUndefined(settings.metricsEndpoint);
480
+ const hasSpecificEndpoint = logsEndpoint !== void 0 || tracesEndpoint !== void 0 || metricsEndpoint !== void 0;
481
+ const hasSpecificHeaders = Option.isSome(settings.logsHeaders) || Option.isSome(settings.tracesHeaders) || Option.isSome(settings.metricsHeaders);
482
+ const common = commonOtlpOptions(settings, options, runtimeAttributes);
483
+ if (endpoint !== void 0 && !hasSpecificEndpoint && !hasSpecificHeaders && signals.size === 3) return Otlp.layer({
484
+ baseUrl: endpoint,
485
+ headers: parseHeaders(settings.headers),
486
+ ...common
487
+ }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer));
488
+ const layers = [];
489
+ if (signals.has("logs")) {
490
+ const url = logsEndpoint ?? (endpoint === void 0 ? void 0 : appendOtlpPath(endpoint, "/v1/logs"));
491
+ if (url !== void 0) layers.push(OtlpLogger.layer({
492
+ url,
493
+ resource: common.resource,
494
+ headers: mergeHeaders(settings.headers, settings.logsHeaders),
495
+ exportInterval: common.loggerExportInterval,
496
+ maxBatchSize: common.maxBatchSize,
497
+ shutdownTimeout: common.shutdownTimeout,
498
+ excludeLogSpans: common.loggerExcludeLogSpans,
499
+ mergeWithExisting: common.loggerMergeWithExisting
500
+ }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer)));
501
+ }
502
+ if (signals.has("traces")) {
503
+ const url = tracesEndpoint ?? (endpoint === void 0 ? void 0 : appendOtlpPath(endpoint, "/v1/traces"));
504
+ if (url !== void 0) layers.push(OtlpTracer.layer({
505
+ url,
506
+ resource: common.resource,
507
+ headers: mergeHeaders(settings.headers, settings.tracesHeaders),
508
+ exportInterval: common.tracerExportInterval,
509
+ maxBatchSize: common.maxBatchSize,
510
+ context: common.tracerContext,
511
+ shutdownTimeout: common.shutdownTimeout
512
+ }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer)));
513
+ }
514
+ if (signals.has("metrics")) {
515
+ const url = metricsEndpoint ?? (endpoint === void 0 ? void 0 : appendOtlpPath(endpoint, "/v1/metrics"));
516
+ if (url !== void 0) layers.push(OtlpMetrics.layer({
517
+ url,
518
+ resource: common.resource,
519
+ headers: mergeHeaders(settings.headers, settings.metricsHeaders),
520
+ exportInterval: common.metricsExportInterval,
521
+ shutdownTimeout: common.shutdownTimeout,
522
+ temporality: common.metricsTemporality
523
+ }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer)));
524
+ }
525
+ return mergeSignalLayers(layers);
526
+ }).pipe(Effect.catch((error) => Effect.logWarning("CloudflareOtlp disabled because OTLP configuration is invalid", { error: String(error) }).pipe(Effect.as(emptyLayer)))));
527
+ const makeLayer = (options = {}, runtimeAttributes = {}) => makeLayerFromSettings(options, runtimeAttributes);
528
+ /**
529
+ * Base OTLP telemetry layer for Cloudflare-compatible runtimes.
530
+ *
531
+ * The layer reads {@link CloudflareOtlpSettings} when provided. Otherwise it
532
+ * reads standard OpenTelemetry config from `WorkerEnvironment` when available,
533
+ * then falls back to the ambient Effect `ConfigProvider`.
534
+ *
535
+ * When only `OTEL_EXPORTER_OTLP_ENDPOINT` is configured, per-signal paths are
536
+ * derived by appending `/v1/logs`, `/v1/traces`, and `/v1/metrics`. Signal
537
+ * specific endpoints are used as-is, matching the OpenTelemetry OTLP exporter
538
+ * convention.
539
+ */
540
+ const layer$9 = (options = {}) => makeLayer(options);
541
+ /** Base OTLP telemetry layer forced to JSON serialization. */
542
+ const layerJson = (options = {}) => layer$9({
543
+ ...options,
544
+ serialization: "json"
755
545
  });
756
- const fromDurableObjectTransaction = (txn) => ({
757
- get: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)) : tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)),
758
- list: (options) => tryStoragePromise("transaction.list", () => txn.list(options)),
759
- put: (keyOrEntries, valueOrOptions, maybeOptions) => tryStoragePromise("transaction.put", () => typeof keyOrEntries === "string" ? txn.put(keyOrEntries, valueOrOptions, maybeOptions) : txn.put(keyOrEntries, valueOrOptions)),
760
- delete: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)) : tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)),
761
- rollback: () => tryStorageSync("transaction.rollback", () => txn.rollback()),
762
- getAlarm: (options) => tryStoragePromise("transaction.getAlarm", () => txn.getAlarm(options)),
763
- setAlarm: (scheduledTime, options) => tryStoragePromise("transaction.setAlarm", () => txn.setAlarm(scheduledTime, options)),
764
- deleteAlarm: (options) => tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options))
546
+ /** Base OTLP telemetry layer forced to protobuf serialization. */
547
+ const layerProtobuf = (options = {}) => layer$9({
548
+ ...options,
549
+ serialization: "protobuf"
765
550
  });
766
551
  /**
767
- * Wraps native Cloudflare storage APIs as Effect-returning helpers.
552
+ * OTLP layer with Cloudflare Worker resource attributes.
553
+ *
554
+ * Provide this layer at runtime scope for long-lived metrics aggregation, or at
555
+ * handler scope when traces/logs should flush as the Cloudflare event finishes.
768
556
  */
769
- const fromDurableObjectStorage = (storage) => ({
770
- get: (key, options) => tryStoragePromise("get", () => storage.get(key, options)),
771
- put: (key, value, options) => tryStoragePromise("put", () => storage.put(key, value, options)),
772
- delete: (key, options) => tryStoragePromise("delete", () => storage.delete(key, options)),
773
- deleteAll: (options) => tryStoragePromise("deleteAll", () => storage.deleteAll(options)),
774
- getAlarm: (options) => tryStoragePromise("getAlarm", () => storage.getAlarm(options)),
775
- setAlarm: (scheduledTime, options) => tryStoragePromise("setAlarm", () => storage.setAlarm(scheduledTime, options)),
776
- deleteAlarm: (options) => tryStoragePromise("deleteAlarm", () => storage.deleteAlarm(options)),
777
- transactionSync: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.suspend(() => {
778
- try {
779
- return Effect.succeed(storage.transactionSync(() => {
780
- const exit = Effect.runSyncExitWith(context)(closure());
781
- if (Exit.isSuccess(exit)) return exit.value;
782
- throw exit;
783
- }));
784
- } catch (cause) {
785
- if (Exit.isExit(cause) && Exit.isFailure(cause)) return Effect.failCause(cause.cause);
786
- return Effect.fail(storageError("transactionSync", cause));
787
- }
788
- }))),
789
- transaction: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.callback((resume) => {
790
- storage.transaction(async (txn) => {
791
- const exit = await Effect.runPromiseExitWith(context)(closure(fromDurableObjectTransaction(txn)));
792
- if (Exit.isSuccess(exit)) return exit.value;
793
- throw exit;
794
- }).then((value) => resume(Effect.succeed(value)), (cause) => {
795
- if (Exit.isExit(cause) && Exit.isFailure(cause)) resume(Effect.failCause(cause.cause));
796
- else resume(Effect.fail(storageError("transaction", cause)));
797
- });
798
- }))),
799
- sync: () => tryStoragePromise("sync", () => storage.sync()),
800
- getCurrentBookmark: () => tryStoragePromise("getCurrentBookmark", () => storage.getCurrentBookmark()),
801
- onNextSessionRestoreBookmark: (bookmark) => tryStoragePromise("onNextSessionRestoreBookmark", () => storage.onNextSessionRestoreBookmark(bookmark)),
802
- sql: fromSqlStorage(storage.sql),
803
- kv: fromSyncKvStorage(storage.kv)
557
+ const workerLayer = (options = {}) => makeLayer(options, {
558
+ "cloudflare.resource_type": "worker",
559
+ "cloudflare.worker.name": options.workerName
804
560
  });
561
+ /**
562
+ * OTLP layer with Cloudflare Durable Object resource attributes.
563
+ *
564
+ * The layer reads {@link DurableObjectState} so it can optionally include the
565
+ * Durable Object id. Prefer leaving `includeObjectId` disabled unless the
566
+ * backend can tolerate high-cardinality resource attributes.
567
+ */
568
+ const durableObjectLayer = (options = {}) => Layer.unwrap(Effect.map(DurableObjectState, (state) => makeLayer(options, {
569
+ "cloudflare.resource_type": "durable_object",
570
+ "cloudflare.durable_object.class": options.className,
571
+ "cloudflare.durable_object.id": options.includeObjectId ? state.id.toString() : void 0
572
+ })));
805
573
  //#endregion
806
- //#region src/DurableObjectWebSocket.ts
807
- var DurableObjectWebSocket_exports = /* @__PURE__ */ __exportAll({
808
- DurableWebSocketAttachmentError: () => DurableWebSocketAttachmentError,
809
- DurableWebSocketCloseError: () => DurableWebSocketCloseError,
810
- DurableWebSocketSendError: () => DurableWebSocketSendError,
811
- acceptUpgrade: () => acceptUpgrade,
812
- attachment: () => attachment,
813
- fromWebSocket: () => fromWebSocket,
814
- handlers: () => handlers
574
+ //#region src/D1.ts
575
+ var D1_exports = /* @__PURE__ */ __exportAll({
576
+ Service: () => Service$1,
577
+ make: () => make$10
815
578
  });
816
- /** Error raised when sending on a Durable Object websocket fails. */
817
- var DurableWebSocketSendError = class extends Data.TaggedError("DurableWebSocketSendError") {};
818
- /** Error raised when closing a Durable Object websocket fails. */
819
- var DurableWebSocketCloseError = class extends Data.TaggedError("DurableWebSocketCloseError") {};
820
- /** Error raised when serializing or deserializing a websocket attachment fails. */
821
- var DurableWebSocketAttachmentError = class extends Data.TaggedError("DurableWebSocketAttachmentError") {};
822
- const wrappers = /* @__PURE__ */ new WeakMap();
823
- /** Wraps a native Cloudflare websocket in the Effect-native Durable Object API. */
824
- const fromWebSocket = (raw) => {
825
- const existing = wrappers.get(raw);
826
- if (existing !== void 0) return existing;
827
- const socket = {
828
- raw,
829
- send: (data) => Effect.try({
830
- try: () => raw.send(data),
831
- catch: (cause) => new DurableWebSocketSendError({ cause })
832
- }),
833
- close: (code, reason) => Effect.try({
834
- try: () => raw.close(code, reason),
835
- catch: (cause) => new DurableWebSocketCloseError({ cause })
836
- }),
837
- serializeAttachment: (value) => Effect.try({
838
- try: () => raw.serializeAttachment(value),
839
- catch: (cause) => new DurableWebSocketAttachmentError({
840
- operation: "serialize",
841
- cause
842
- })
843
- }),
844
- deserializeAttachment: Effect.try({
845
- try: () => raw.deserializeAttachment(),
846
- catch: (cause) => new DurableWebSocketAttachmentError({
847
- operation: "deserialize",
848
- cause
849
- })
850
- })
851
- };
852
- wrappers.set(raw, socket);
853
- return socket;
579
+ const TypeId$2 = "effect-cf/D1";
580
+ const expectedD1Database = "D1 database binding with prepare(), batch(), and exec()";
581
+ const isD1Database = (value) => {
582
+ if (typeof value !== "object" || value === null) return false;
583
+ const resource = value;
584
+ return typeof resource.prepare === "function" && typeof resource.batch === "function" && typeof resource.exec === "function";
854
585
  };
855
586
  /**
856
- * Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
587
+ * Creates a typed D1 service tag plus Effect helpers.
588
+ */
589
+ const make$10 = (id, definition) => Service$1()(id, definition);
590
+ /**
591
+ * Builds a D1 service around a Cloudflare D1 database binding.
592
+ *
593
+ * The returned service exposes the raw `D1Database` binding and `sqlLayer(...)`
594
+ * for providing `effect/unstable/sql` via `@effect/sql-d1`.
857
595
  *
858
596
  * @example
859
597
  * ```ts
860
- * const response = yield* DurableObjectWebSocket.acceptUpgrade({
861
- * tags: ["room:general"],
862
- * });
598
+ * class TodoDatabase extends D1.Service<TodoDatabase>()("TodoDatabase", {
599
+ * binding: "TODO_DB",
600
+ * }) {}
863
601
  *
864
- * return response.response;
602
+ * const SqlLive = TodoDatabase.sqlLayer();
865
603
  * ```
866
604
  */
867
- const acceptUpgrade = (options = {}) => Effect.gen(function* () {
868
- const state = yield* DurableObjectState;
869
- const pair = new WebSocketPair();
870
- const client = pair[0];
871
- const server = fromWebSocket(pair[1]);
872
- if (options.attachment !== void 0) server.raw.serializeAttachment(options.attachment);
873
- yield* state.acceptWebSocket(server, options.tags === void 0 ? void 0 : [...options.tags]);
874
- return {
875
- client,
876
- server,
877
- response: new Response(null, {
878
- status: 101,
879
- webSocket: client
880
- })
881
- };
882
- });
883
- /** Creates typed attachment helpers for accepted and rehydrated sockets. */
884
- const attachment = (schema) => {
885
- const serialize = (socket, value) => Schema.encodeEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
886
- operation: "serialize",
887
- cause
888
- })), Effect.flatMap((encoded) => socket.serializeAttachment(encoded)));
889
- const deserialize = (socket) => Effect.gen(function* () {
890
- const value = yield* socket.deserializeAttachment;
891
- if (value == null) return Option.none();
892
- return Option.some(yield* Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
893
- operation: "deserialize",
894
- cause
895
- }))));
605
+ const Service$1 = () => (id, definition) => {
606
+ const tag = Service$2()(id, definition.binding, isD1Database, void 0, { expected: expectedD1Database });
607
+ const sqlLayer = (options) => Layer.unwrap(Effect.gen(function* () {
608
+ const db = yield* tag;
609
+ return D1Client.layer({
610
+ ...options,
611
+ db
612
+ });
613
+ })).pipe(Layer.provide(tag.layer));
614
+ return Object.assign(tag, {
615
+ [TypeId$2]: TypeId$2,
616
+ definition,
617
+ sqlLayer
896
618
  });
897
- const rehydrate = (options = {}) => Effect.gen(function* () {
898
- const sockets = yield* (yield* DurableObjectState).getWebSockets(options.tag);
899
- const restored = [];
900
- const onInvalid = options.onInvalid ?? "ignore";
901
- for (const socket of sockets) {
902
- const decoded = yield* deserialize(socket).pipe(Effect.match({
903
- onFailure: (error) => ({
904
- _tag: "Failure",
905
- error
906
- }),
907
- onSuccess: (value) => ({
908
- _tag: "Success",
909
- value
910
- })
911
- }));
912
- if (decoded._tag === "Success" && Option.isSome(decoded.value)) {
913
- restored.push({
914
- socket,
915
- attachment: decoded.value.value
916
- });
917
- continue;
619
+ };
620
+ //#endregion
621
+ //#region src/QueueBinding.ts
622
+ var QueueBinding_exports = /* @__PURE__ */ __exportAll({
623
+ QueueOperationError: () => QueueOperationError,
624
+ isQueue: () => isQueue,
625
+ layer: () => layer$8,
626
+ makeClient: () => makeClient$6
627
+ });
628
+ const expectedQueueProducer = "Queue producer binding with send(); optional sendBatch()/metrics()";
629
+ var QueueOperationError = class extends Data.TaggedError("QueueOperationError") {};
630
+ const tryQueuePromise = (binding, operation, evaluate) => Effect.tryPromise({
631
+ try: evaluate,
632
+ catch: (cause) => new QueueOperationError({
633
+ binding,
634
+ operation,
635
+ cause,
636
+ message: `Cloudflare queue binding "${binding}" operation "${operation}" failed`
637
+ })
638
+ });
639
+ const isQueue = (value) => {
640
+ if (typeof value !== "object" || value === null) return false;
641
+ return typeof value.send === "function";
642
+ };
643
+ const makeClient$6 = (definition) => {
644
+ const encodeMessage = Schema.encodeEffect(definition.message);
645
+ return (queue) => ({
646
+ send: Effect.fnUntraced(function* (message, options) {
647
+ const encoded = yield* encodeMessage(message);
648
+ yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
649
+ }),
650
+ sendBatch: Effect.fnUntraced(function* (messages, options) {
651
+ const encodedMessages = [];
652
+ for (const message of messages) encodedMessages.push({
653
+ ...message,
654
+ body: yield* encodeMessage(message.body)
655
+ });
656
+ const sendBatch = queue.sendBatch;
657
+ if (sendBatch !== void 0) {
658
+ yield* tryQueuePromise(definition.binding, "sendBatch", () => sendBatch.call(queue, encodedMessages, options));
659
+ return;
918
660
  }
919
- if (decoded._tag === "Failure" && onInvalid === "fail") return yield* Effect.fail(decoded.error);
920
- if (decoded._tag === "Failure" && onInvalid === "ignore-and-close") yield* socket.close(1008, "invalid websocket attachment").pipe(Effect.ignore);
921
- }
922
- return restored;
661
+ yield* tryQueuePromise(definition.binding, "sendBatch", async () => {
662
+ for (const message of encodedMessages) await queue.send(message.body, {
663
+ contentType: message.contentType,
664
+ delaySeconds: message.delaySeconds ?? options?.delaySeconds
665
+ });
666
+ });
667
+ }),
668
+ metrics: () => {
669
+ const metrics = queue.metrics;
670
+ if (metrics === void 0) return Effect.fail(new QueueOperationError({
671
+ binding: definition.binding,
672
+ operation: "metrics",
673
+ cause: /* @__PURE__ */ new Error(`Queue binding "${definition.binding}" does not provide metrics()`),
674
+ message: `Cloudflare queue binding "${definition.binding}" does not provide metrics()`
675
+ }));
676
+ return tryQueuePromise(definition.binding, "metrics", () => metrics.call(queue));
677
+ },
678
+ unsafeRaw: Effect.succeed(queue)
923
679
  });
924
- return {
925
- serialize,
926
- deserialize,
927
- rehydrate,
928
- schema
929
- };
930
680
  };
931
- /** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
932
- const handlers = (options) => ({
933
- webSocketMessage: options.message,
934
- webSocketClose: options.close,
935
- webSocketError: options.error
936
- });
681
+ const layer$8 = (tag, definition) => layer$10(tag, definition.binding, (value) => isQueue(value), makeClient$6(definition), { expected: expectedQueueProducer });
937
682
  //#endregion
938
- //#region src/DurableObjectState.ts
939
- var DurableObjectState_exports = /* @__PURE__ */ __exportAll({
940
- DurableObjectState: () => DurableObjectState,
941
- fromDurableObjectState: () => fromDurableObjectState
942
- });
943
- /**
944
- * Context tag for accessing the current Durable Object state service.
945
- */
946
- var DurableObjectState = class extends Context.Service()("effect-cf/DurableObjectState") {};
947
- /**
948
- * Wraps a native Cloudflare `DurableObjectState` as a {@link DurableObjectStateService}.
949
- */
950
- const fromDurableObjectState = (state) => ({
951
- raw: state,
952
- id: state.id,
953
- storage: fromDurableObjectStorage(state.storage),
954
- waitUntil: (promise) => Effect.sync(() => state.waitUntil(promise)),
955
- blockConcurrencyWhile: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => runPromiseExitPreservingTypedFailures(Effect.provideContext(effect, context))))), Effect.flatten),
956
- blockConcurrencyWhileOrReset: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => Effect.runPromise(Effect.provideContext(effect, context)))))),
957
- acceptWebSocket: (ws, tags) => Effect.sync(() => state.acceptWebSocket(ws.raw, tags)),
958
- getWebSockets: (tag) => Effect.sync(() => state.getWebSockets(tag).map((socket) => fromWebSocket(socket))),
959
- setWebSocketAutoResponse: (pair) => Effect.sync(() => state.setWebSocketAutoResponse(pair)),
960
- getWebSocketAutoResponse: Effect.sync(() => state.getWebSocketAutoResponse()),
961
- getWebSocketAutoResponseTimestamp: (ws) => Effect.sync(() => state.getWebSocketAutoResponseTimestamp(ws.raw)),
962
- setHibernatableWebSocketEventTimeout: (timeoutMs) => Effect.sync(() => state.setHibernatableWebSocketEventTimeout(timeoutMs)),
963
- getHibernatableWebSocketEventTimeout: Effect.sync(() => state.getHibernatableWebSocketEventTimeout()),
964
- getTags: (ws) => Effect.sync(() => state.getTags(ws.raw)),
965
- abort: (reason) => Effect.sync(() => state.abort(reason))
683
+ //#region src/QueueDefinition.ts
684
+ var QueueDefinition_exports = /* @__PURE__ */ __exportAll({
685
+ Queue: () => Queue$1,
686
+ Tag: () => Tag$10,
687
+ implement: () => implement$7,
688
+ make: () => make$9
966
689
  });
967
- const runPromiseExitPreservingTypedFailures = async (effect) => {
968
- const exit = await Effect.runPromiseExit(effect);
969
- if (Exit.isFailure(exit) && (Cause.hasDies(exit.cause) || Cause.hasInterrupts(exit.cause))) throw Cause.squash(exit.cause);
970
- return exit;
690
+ const makeDefinition$4 = (id, definition) => {
691
+ const queueDefinition = {
692
+ id,
693
+ message: definition.message
694
+ };
695
+ return Object.assign(queueDefinition, { make: (layer, options) => make$6(layer, {
696
+ ...options,
697
+ queue: wrapHandler$1(queueDefinition, options.queue)
698
+ }) });
699
+ };
700
+ const make$9 = (id, definition) => Tag$10()(id, definition);
701
+ const Tag$10 = () => (id, definition) => {
702
+ const queueDefinition = makeDefinition$4(id, definition);
703
+ const tag = Context.Service()(id);
704
+ const layer = (binding) => layer$8(tag, {
705
+ ...binding,
706
+ message: definition.message
707
+ });
708
+ const send = Effect.fnUntraced(function* (message, options) {
709
+ yield* (yield* tag).send(message, options);
710
+ });
711
+ const sendBatch = Effect.fnUntraced(function* (messages, options) {
712
+ yield* (yield* tag).sendBatch(messages, options);
713
+ });
714
+ const metrics = Effect.fnUntraced(function* () {
715
+ return yield* (yield* tag).metrics();
716
+ });
717
+ const unsafeRaw = Effect.fnUntraced(function* () {
718
+ return yield* (yield* tag).unsafeRaw;
719
+ });
720
+ return Object.assign(tag, {
721
+ id: queueDefinition.id,
722
+ message: queueDefinition.message,
723
+ make: queueDefinition.make,
724
+ layer,
725
+ send,
726
+ sendBatch,
727
+ metrics,
728
+ unsafeRaw
729
+ });
730
+ };
731
+ const Queue$1 = Tag$10;
732
+ const wrapHandler$1 = (definition, handler) => {
733
+ const decodeBody = Schema.decodeUnknownEffect(definition.message);
734
+ return (batch) => Effect.gen(function* () {
735
+ yield* handler(yield* decodeBatch(batch.raw, decodeBody));
736
+ });
971
737
  };
738
+ const implement$7 = (_definition, handler) => handler;
972
739
  //#endregion
973
- //#region src/DurableObjectNamespace.ts
974
- var DurableObjectNamespace_exports = /* @__PURE__ */ __exportAll({
975
- DurableObjectFetchError: () => DurableObjectFetchError,
976
- DurableObjectRpcError: () => DurableObjectRpcError,
977
- isDurableObjectNamespaceClient: () => isDurableObjectNamespaceClient,
978
- layer: () => layer$7,
979
- makeClient: () => makeClient$4,
980
- makeDirectMethods: () => makeDirectMethods
740
+ //#region src/Queue.ts
741
+ var Queue_exports = /* @__PURE__ */ __exportAll({
742
+ QueueMessageDecodeError: () => QueueMessageDecodeError,
743
+ Tag: () => Tag$9,
744
+ decodeBatch: () => decodeBatch,
745
+ fromMessage: () => fromMessage,
746
+ fromMessageBatch: () => fromMessageBatch,
747
+ implement: () => implement$6
981
748
  });
982
- const expectedDurableObjectNamespace = "Durable Object namespace binding with getByName(), get(), idFromName(), idFromString(), newUniqueId(), and jurisdiction()";
983
- /**
984
- * Failure raised when invoking an RPC method on a Durable Object stub.
985
- */
986
- var DurableObjectRpcError = class extends Data.TaggedError("DurableObjectRpcError") {};
749
+ var QueueMessageDecodeError = class extends Data.TaggedError("QueueMessageDecodeError") {};
750
+ const fromMessage = (message, body) => ({
751
+ raw: message,
752
+ id: message.id,
753
+ timestamp: message.timestamp,
754
+ body,
755
+ attempts: message.attempts,
756
+ ack: Effect.sync(() => message.ack()),
757
+ retry: (options) => Effect.sync(() => message.retry(options))
758
+ });
759
+ const fromMessageBatch = (batch, messages) => ({
760
+ raw: batch,
761
+ messages,
762
+ queue: batch.queue,
763
+ metadata: batch.metadata,
764
+ ackAll: Effect.sync(() => batch.ackAll()),
765
+ retryAll: (options) => Effect.sync(() => batch.retryAll(options))
766
+ });
767
+ const decodeBatch = (batch, decodeBody) => Effect.gen(function* () {
768
+ const messages = [];
769
+ for (let index = 0; index < batch.messages.length; index++) {
770
+ const message = batch.messages[index];
771
+ const body = yield* decodeBody(message.body).pipe(Effect.mapError((cause) => new QueueMessageDecodeError({
772
+ queue: batch.queue,
773
+ messageId: message.id,
774
+ index,
775
+ cause
776
+ })));
777
+ messages.push(fromMessage(message, body));
778
+ }
779
+ return fromMessageBatch(batch, messages);
780
+ });
781
+ const Tag$9 = Tag$10;
782
+ const implement$6 = implement$7;
783
+ //#endregion
784
+ //#region src/RpcDefinition.ts
785
+ var RpcDefinition_exports = /* @__PURE__ */ __exportAll({
786
+ ReservedMethodNameError: () => ReservedMethodNameError,
787
+ RpcArgumentCountError: () => RpcArgumentCountError,
788
+ RpcArgumentDecodeError: () => RpcArgumentDecodeError,
789
+ RpcArgumentEncodeError: () => RpcArgumentEncodeError,
790
+ RpcReservedMethodNameError: () => RpcReservedMethodNameError,
791
+ RpcSuccessDecodeError: () => RpcSuccessDecodeError,
792
+ RpcSuccessEncodeError: () => RpcSuccessEncodeError,
793
+ assertNoReservedMethodNames: () => assertNoReservedMethodNames,
794
+ assertNoReservedMethods: () => assertNoReservedMethods,
795
+ decodeArgs: () => decodeArgs,
796
+ decodeSuccess: () => decodeSuccess,
797
+ encodeArgs: () => encodeArgs,
798
+ encodeSuccess: () => encodeSuccess,
799
+ make: () => make$8,
800
+ method: () => method$4,
801
+ reservedMethodNames: () => reservedMethodNames$4
802
+ });
803
+ var RpcReservedMethodNameError = class extends Data.TaggedError("RpcReservedMethodNameError") {};
804
+ var RpcArgumentCountError = class extends Data.TaggedError("RpcArgumentCountError") {};
805
+ var RpcArgumentDecodeError = class extends Data.TaggedError("RpcArgumentDecodeError") {};
806
+ var RpcArgumentEncodeError = class extends Data.TaggedError("RpcArgumentEncodeError") {};
807
+ var RpcSuccessDecodeError = class extends Data.TaggedError("RpcSuccessDecodeError") {};
808
+ var RpcSuccessEncodeError = class extends Data.TaggedError("RpcSuccessEncodeError") {};
809
+ const reservedMethodNames$4 = new Set([
810
+ "constructor",
811
+ "fetch",
812
+ "connect",
813
+ "alarm",
814
+ "webSocketMessage",
815
+ "webSocketClose",
816
+ "webSocketError",
817
+ "then",
818
+ "dup",
819
+ "dispose",
820
+ "serialize",
821
+ "deserialize"
822
+ ]);
823
+ var ReservedMethodNameError = class extends Error {
824
+ method;
825
+ target;
826
+ constructor(target, method) {
827
+ super(`${target} RPC method "${method}" is reserved by Cloudflare Workers RPC`);
828
+ this.name = "ReservedMethodNameError";
829
+ this.target = target;
830
+ this.method = method;
831
+ }
832
+ };
833
+ const assertNoReservedMethods = (target, methods, reserved) => {
834
+ for (const method of Object.keys(methods)) if (reserved.has(method)) throw new ReservedMethodNameError(target, method);
835
+ };
836
+ function method$4(definition) {
837
+ return {
838
+ args: definition.args ?? [],
839
+ success: definition.success
840
+ };
841
+ }
842
+ const assertNoReservedMethodNames = (definition) => Effect.forEach(Object.keys(definition.methods), (method) => reservedMethodNames$4.has(method) ? Effect.fail(new RpcReservedMethodNameError({
843
+ definition: definition.id,
844
+ method
845
+ })) : Effect.void).pipe(Effect.asVoid);
846
+ const decodeArgs = (definition, methodName, args) => Effect.gen(function* () {
847
+ const methodDefinition = definition.methods[methodName];
848
+ if (args.length !== methodDefinition.args.length) return yield* Effect.fail(new RpcArgumentCountError({
849
+ definition: definition.id,
850
+ method: methodName,
851
+ expected: methodDefinition.args.length,
852
+ actual: args.length
853
+ }));
854
+ const decoded = [];
855
+ for (let index = 0; index < methodDefinition.args.length; index++) {
856
+ const schema = methodDefinition.args[index];
857
+ decoded.push(yield* Schema.decodeUnknownEffect(schema)(args[index]).pipe(Effect.mapError((cause) => new RpcArgumentDecodeError({
858
+ definition: definition.id,
859
+ method: methodName,
860
+ index,
861
+ cause
862
+ }))));
863
+ }
864
+ return decoded;
865
+ });
866
+ const encodeArgs = (definition, methodName, args) => Effect.gen(function* () {
867
+ const methodDefinition = definition.methods[methodName];
868
+ if (args.length !== methodDefinition.args.length) return yield* Effect.fail(new RpcArgumentCountError({
869
+ definition: definition.id,
870
+ method: methodName,
871
+ expected: methodDefinition.args.length,
872
+ actual: args.length
873
+ }));
874
+ const encoded = [];
875
+ for (let index = 0; index < methodDefinition.args.length; index++) {
876
+ const schema = methodDefinition.args[index];
877
+ encoded.push(yield* Schema.encodeEffect(schema)(args[index]).pipe(Effect.mapError((cause) => new RpcArgumentEncodeError({
878
+ definition: definition.id,
879
+ method: methodName,
880
+ index,
881
+ cause
882
+ }))));
883
+ }
884
+ return encoded;
885
+ });
886
+ const encodeSuccess = (definition, methodName, value) => {
887
+ const methodDefinition = definition.methods[methodName];
888
+ return Schema.encodeEffect(methodDefinition.success)(value).pipe(Effect.mapError((cause) => new RpcSuccessEncodeError({
889
+ definition: definition.id,
890
+ method: methodName,
891
+ cause
892
+ })));
893
+ };
894
+ const decodeSuccess = (definition, methodName, value) => {
895
+ const methodDefinition = definition.methods[methodName];
896
+ return Schema.decodeUnknownEffect(methodDefinition.success)(value).pipe(Effect.mapError((cause) => new RpcSuccessDecodeError({
897
+ definition: definition.id,
898
+ method: methodName,
899
+ cause
900
+ })));
901
+ };
902
+ const make$8 = (id, methods) => {
903
+ const definition = {
904
+ id,
905
+ methods
906
+ };
907
+ const reserved = Object.keys(definition.methods).find((methodName) => reservedMethodNames$4.has(methodName));
908
+ if (reserved !== void 0) throw new RpcReservedMethodNameError({
909
+ definition: id,
910
+ method: reserved
911
+ });
912
+ return definition;
913
+ };
914
+ //#endregion
915
+ //#region src/Rpc.ts
916
+ var Rpc_exports = /* @__PURE__ */ __exportAll({
917
+ RpcStub: () => RpcStub,
918
+ RpcTarget: () => RpcTarget,
919
+ dispose: () => dispose,
920
+ isDisposable: () => isDisposable,
921
+ resolve: () => resolve,
922
+ scoped: () => scoped
923
+ });
924
+ const isDisposable = (value) => (typeof value === "object" || typeof value === "function") && value !== null && Symbol.dispose in value && typeof value[Symbol.dispose] === "function";
925
+ const dispose = (value) => Effect.sync(() => {
926
+ if (isDisposable(value)) value[Symbol.dispose]();
927
+ });
928
+ const resolve = (value) => isPromiseLike(value) ? Effect.tryPromise({
929
+ try: () => value,
930
+ catch: (cause) => cause
931
+ }) : Effect.sync(() => value);
932
+ const scoped = (value) => Effect.acquireRelease(resolve(value), (resolved) => dispose(resolved));
933
+ const isPromiseLike = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
934
+ //#endregion
935
+ //#region src/internal/RpcInvocation.ts
936
+ const isPropertyTarget = (value) => (typeof value === "object" || typeof value === "function") && value !== null;
937
+ const lookupRpcMethod = (target, method, makeError) => Effect.try({
938
+ try: () => {
939
+ if (!isPropertyTarget(target)) throw new TypeError(`RPC target is not object-like`);
940
+ const value = Reflect.get(target, method);
941
+ if (typeof value !== "function") throw new TypeError(`RPC method "${String(method)}" is not callable`);
942
+ return ((...args) => Reflect.apply(value, target, args));
943
+ },
944
+ catch: makeError
945
+ });
946
+ const invokeRpcMethod = (target, method, args, makeError) => Effect.gen(function* () {
947
+ const fn = yield* lookupRpcMethod(target, method, makeError);
948
+ return yield* Effect.try({
949
+ try: () => fn(...args),
950
+ catch: makeError
951
+ });
952
+ });
953
+ //#endregion
954
+ //#region src/ServiceBinding.ts
955
+ var ServiceBinding_exports = /* @__PURE__ */ __exportAll({
956
+ Service: () => Service,
957
+ ServiceBindingFetchError: () => ServiceBindingFetchError,
958
+ ServiceBindingRpcError: () => ServiceBindingRpcError,
959
+ isServiceBindingClient: () => isServiceBindingClient,
960
+ layer: () => layer$7,
961
+ makeClient: () => makeClient$5,
962
+ makeDirectMethods: () => makeDirectMethods$1
963
+ });
964
+ const TypeId$1 = "effect-cf/ServiceBinding";
965
+ const expectedServiceBinding = "Worker service binding with fetch()";
987
966
  /**
988
- * Failure raised when forwarding a request to a Durable Object stub.
967
+ * Failure raised when calling `fetch` on a service binding.
989
968
  */
990
- var DurableObjectFetchError = class extends Data.TaggedError("DurableObjectFetchError") {};
991
- const hasFunction$1 = (value, key) => typeof Reflect.get(value, key) === "function";
992
- const isDurableObjectNamespaceClient = (value) => typeof value === "object" && value !== null && hasFunction$1(value, "getByName") && hasFunction$1(value, "get") && hasFunction$1(value, "idFromName") && hasFunction$1(value, "idFromString") && hasFunction$1(value, "newUniqueId") && hasFunction$1(value, "jurisdiction");
993
- const makeClient$4 = (definition) => {
994
- return (namespace) => {
995
- const newUniqueId = (options) => Effect.sync(() => namespace.newUniqueId(options));
996
- const idFromName = (name) => Effect.sync(() => namespace.idFromName(name));
997
- const idFromString = (id) => Effect.sync(() => namespace.idFromString(id));
998
- const get = (id, options) => Effect.sync(() => namespace.get(id, options));
999
- const getByName = (name, options) => Effect.sync(() => namespace.getByName(name, options));
1000
- const jurisdiction = (value) => Effect.sync(() => namespace.jurisdiction(value));
1001
- const fetch = (stub, input, init) => Effect.tryPromise({
1002
- try: () => stub.fetch(input, init),
1003
- catch: (cause) => new DurableObjectFetchError({
969
+ var ServiceBindingFetchError = class extends Data.TaggedError("ServiceBindingFetchError") {};
970
+ /**
971
+ * Failure raised when invoking an RPC method on a service binding.
972
+ */
973
+ var ServiceBindingRpcError = class extends Data.TaggedError("ServiceBindingRpcError") {};
974
+ const isServiceBindingClient = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "fetch") === "function";
975
+ const makeClient$5 = (definition) => {
976
+ return (service) => {
977
+ const fetch = (input, init) => Effect.tryPromise({
978
+ try: () => service.fetch(input, init),
979
+ catch: (cause) => new ServiceBindingFetchError({
1004
980
  binding: definition.binding,
1005
981
  cause
1006
982
  })
1007
983
  });
1008
- const rpc = (stub, method, ...args) => Effect.gen(function* () {
984
+ const rpc = (method, ...args) => Effect.gen(function* () {
1009
985
  const methodName = String(method);
1010
- return yield* invokeRpcMethod(stub, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
986
+ return yield* invokeRpcMethod(service, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
1011
987
  binding: definition.binding,
1012
988
  method: methodName,
1013
989
  cause
1014
- }))), (cause) => new DurableObjectRpcError({
990
+ }))), (cause) => new ServiceBindingRpcError({
1015
991
  binding: definition.binding,
1016
992
  method: methodName,
1017
993
  cause
1018
994
  }));
1019
995
  });
1020
- const decodeSuccess$1 = (methodName, value) => Effect.gen(function* () {
996
+ const decodeSuccess$2 = (methodName, value) => Effect.gen(function* () {
1021
997
  if (definition.definition === void 0) return value;
1022
- return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
998
+ return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
1023
999
  binding: definition.binding,
1024
1000
  method: methodName,
1025
1001
  cause
1026
1002
  })));
1027
1003
  });
1028
- const call = (stub, method, ...args) => Effect.gen(function* () {
1004
+ const call = (method, ...args) => Effect.gen(function* () {
1029
1005
  const methodName = String(method);
1030
- return yield* decodeSuccess$1(methodName, yield* resolve(yield* rpc(stub, method, ...args)).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1006
+ return yield* decodeSuccess$2(methodName, yield* resolve(yield* rpc(method, ...args)).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
1031
1007
  binding: definition.binding,
1032
1008
  method: methodName,
1033
1009
  cause
1034
1010
  }))));
1035
1011
  });
1036
- const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1037
- return yield* decodeSuccess$1(String(method), yield* scoped(yield* rpc(stub, method, ...args)));
1038
- });
1039
- const directMethods = makeDirectMethods(definition.definition, {
1040
- call,
1041
- fetch,
1042
- get,
1043
- getByName
1012
+ const scopedCall = (method, ...args) => Effect.gen(function* () {
1013
+ return yield* decodeSuccess$2(String(method), yield* scoped(yield* rpc(method, ...args)));
1044
1014
  });
1015
+ const directMethods = makeDirectMethods$1(definition.definition, call);
1045
1016
  return Object.assign(directMethods, {
1046
- newUniqueId,
1047
- idFromName,
1048
- idFromString,
1049
- get,
1050
- getByName,
1051
- jurisdiction,
1052
1017
  fetch,
1053
1018
  rpc,
1054
1019
  call,
1055
- scopedCall,
1056
- unsafeRaw: Effect.succeed(namespace)
1020
+ scopedCall
1057
1021
  });
1058
1022
  };
1059
1023
  };
1060
- const layer$7 = (tag, definition) => layer$10(tag, definition.binding, (value) => isDurableObjectNamespaceClient(value), makeClient$4(definition), { expected: expectedDurableObjectNamespace });
1061
- const makeDirectMethods = (rpcDefinition, helpers) => {
1024
+ const layer$7 = (tag, definition) => layer$10(tag, definition.binding, (value) => isServiceBindingClient(value), makeClient$5(definition), { expected: expectedServiceBinding });
1025
+ /**
1026
+ * Creates a typed Effect service for a Worker service binding.
1027
+ *
1028
+ * Returned value includes:
1029
+ * - a Context tag for dependency injection
1030
+ * - `fetch(...)` for raw HTTP forwarding
1031
+ * - `rpc(...)` for raw Cloudflare RPC results
1032
+ * - `call(...)` for resolved and decoded RPC results
1033
+ * - `scopedCall(...)` for scoped and decoded disposable RPC results
1034
+ * - direct RPC methods when `definition` is provided
1035
+ *
1036
+ * @example
1037
+ * ```ts
1038
+ * const Counter = WorkerDefinition.make("Counter", {
1039
+ * increment: WorkerDefinition.method({
1040
+ * args: [Schema.Number],
1041
+ * success: Schema.Number,
1042
+ * }),
1043
+ * });
1044
+ *
1045
+ * const CounterLive = Counter.layer({ binding: "COUNTER" });
1046
+ *
1047
+ * const program = Effect.gen(function* () {
1048
+ * const counter = yield* Counter;
1049
+ * const next = yield* counter.increment(1);
1050
+ * return next;
1051
+ * });
1052
+ * ```
1053
+ */
1054
+ const Service = () => (id, definition) => {
1055
+ const tag = Service$2()(id, definition.binding, (value) => isServiceBindingClient(value), makeClient$5(definition));
1056
+ const fetch = (input, init) => Effect.gen(function* () {
1057
+ return yield* (yield* tag).fetch(input, init);
1058
+ });
1059
+ const rpc = (method, ...args) => Effect.gen(function* () {
1060
+ return yield* (yield* tag).rpc(method, ...args);
1061
+ });
1062
+ const call = (method, ...args) => Effect.gen(function* () {
1063
+ return yield* (yield* tag).call(method, ...args);
1064
+ });
1065
+ const scopedCall = (method, ...args) => Effect.gen(function* () {
1066
+ return yield* (yield* tag).scopedCall(method, ...args);
1067
+ });
1068
+ const directMethods = makeDirectMethods$1(definition.definition, call);
1069
+ return Object.assign(tag, directMethods, {
1070
+ [TypeId$1]: TypeId$1,
1071
+ definition,
1072
+ fetch,
1073
+ rpc,
1074
+ call,
1075
+ scopedCall
1076
+ });
1077
+ };
1078
+ const makeDirectMethods$1 = (rpcDefinition, call) => {
1062
1079
  const methods = {};
1063
- if (rpcDefinition !== void 0) {
1064
- for (const methodName of Object.keys(rpcDefinition.methods)) methods[methodName] = (stub, ...args) => helpers.call(stub, methodName, ...args);
1065
- const makeClient = (getStub) => {
1066
- const client = { fetch: (input, init) => Effect.gen(function* () {
1067
- const stub = yield* getStub();
1068
- return yield* helpers.fetch(stub, input, init);
1069
- }) };
1070
- for (const methodName of Object.keys(rpcDefinition.methods)) client[methodName] = (...args) => Effect.gen(function* () {
1071
- const stub = yield* getStub();
1072
- return yield* helpers.call(stub, methodName, ...args);
1073
- });
1074
- return client;
1075
- };
1076
- methods.byName = (name, options) => makeClient(() => helpers.getByName(name, options));
1077
- methods.byId = (id, options) => makeClient(() => helpers.get(id, options));
1078
- }
1080
+ if (rpcDefinition !== void 0) for (const methodName of Object.keys(rpcDefinition.methods)) methods[methodName] = (...args) => call(methodName, ...args);
1079
1081
  return methods;
1080
1082
  };
1081
1083
  //#endregion
1082
- //#region src/DurableObjectDefinition.ts
1083
- var DurableObjectDefinition_exports = /* @__PURE__ */ __exportAll({
1084
- DurableObject: () => DurableObject$1,
1085
- Tag: () => Tag$6,
1086
- implement: () => implement$3,
1087
- make: () => make$6,
1088
- method: () => method$1
1084
+ //#region src/WorkerDefinition.ts
1085
+ var WorkerDefinition_exports = /* @__PURE__ */ __exportAll({
1086
+ Tag: () => Tag$8,
1087
+ Worker: () => Worker,
1088
+ implement: () => implement$5,
1089
+ make: () => make$7,
1090
+ method: () => method$3
1089
1091
  });
1090
- const reservedMethodNames$1 = new Set([
1092
+ const reservedMethodNames$3 = new Set([
1091
1093
  "constructor",
1092
1094
  "dup",
1093
1095
  "fetch",
1096
+ "connect",
1097
+ "queue",
1098
+ "scheduled",
1099
+ "tail",
1100
+ "tailStream",
1101
+ "test",
1102
+ "trace",
1094
1103
  "alarm",
1095
1104
  "webSocketMessage",
1096
1105
  "webSocketClose",
1097
1106
  "webSocketError"
1098
1107
  ]);
1099
1108
  /**
1100
- * Defines a single RPC method schema in a Durable Object definition.
1109
+ * Defines a single RPC method schema in a worker definition.
1101
1110
  */
1102
- const method$1 = method$4;
1111
+ const method$3 = method$4;
1103
1112
  /**
1104
- * Creates a Durable Object RPC definition plus implementation/binding helpers.
1113
+ * Creates a typed worker RPC definition plus helpers for implementation and bindings.
1105
1114
  *
1106
1115
  * @example
1107
1116
  * ```ts
1108
- * const ChatRoom = DurableObjectDefinition.make("ChatRoom", {
1109
- * postMessage: DurableObjectDefinition.method({
1110
- * args: [Schema.String],
1111
- * success: Schema.Void,
1117
+ * const CounterWorker = WorkerDefinition.make("CounterWorker", {
1118
+ * increment: WorkerDefinition.method({
1119
+ * args: [Schema.Number],
1120
+ * success: Schema.Number,
1112
1121
  * }),
1113
1122
  * });
1114
1123
  * ```
1115
1124
  */
1116
- const makeDefinition$2 = (id, methods) => {
1117
- assertNoReservedMethods("Durable Object", methods, reservedMethodNames$1);
1118
- const definition = make$9(id, methods);
1119
- return Object.assign(definition, { make: (layer, options) => make$5(layer, {
1125
+ const makeDefinition$3 = (id, methods) => {
1126
+ assertNoReservedMethods("Worker", methods, reservedMethodNames$3);
1127
+ const definition = make$8(id, methods);
1128
+ return Object.assign(definition, { make: (layer, options) => make$6(layer, {
1120
1129
  ...options,
1121
- rpc: wrapHandlers(definition, options.rpc)
1130
+ rpc: wrapHandlers$1(definition, options.rpc)
1122
1131
  }) });
1123
1132
  };
1124
- const make$6 = (id, methods) => Tag$6()(id, methods);
1125
- const Tag$6 = () => (id, methods) => {
1126
- const definition = makeDefinition$2(id, methods);
1133
+ const make$7 = (id, methods) => Tag$8()(id, methods);
1134
+ const Tag$8 = () => (id, methods) => {
1135
+ const definition = makeDefinition$3(id, methods);
1127
1136
  const tag = Context.Service()(id);
1128
1137
  const bindingDefinition = (binding) => ({
1129
1138
  ...binding,
1130
1139
  definition
1131
1140
  });
1132
1141
  const layer = (binding) => layer$7(tag, bindingDefinition(binding));
1133
- const newUniqueId = Effect.fnUntraced(function* (options) {
1134
- return yield* (yield* tag).newUniqueId(options);
1135
- });
1136
- const idFromName = Effect.fnUntraced(function* (name) {
1137
- return yield* (yield* tag).idFromName(name);
1138
- });
1139
- const idFromString = Effect.fnUntraced(function* (value) {
1140
- return yield* (yield* tag).idFromString(value);
1141
- });
1142
- const get = Effect.fnUntraced(function* (objectId, options) {
1143
- return yield* (yield* tag).get(objectId, options);
1144
- });
1145
- const getByName = Effect.fnUntraced(function* (name, options) {
1146
- return yield* (yield* tag).getByName(name, options);
1147
- });
1148
- const jurisdiction = Effect.fnUntraced(function* (value) {
1149
- return yield* (yield* tag).jurisdiction(value);
1150
- });
1151
- const fetch = (stub, input, init) => Effect.gen(function* () {
1152
- return yield* (yield* tag).fetch(stub, input, init);
1153
- });
1154
- const rpc = (stub, method, ...args) => Effect.gen(function* () {
1155
- return yield* (yield* tag).rpc(stub, method, ...args);
1156
- });
1157
- const call = (stub, method, ...args) => Effect.gen(function* () {
1158
- return yield* (yield* tag).call(stub, method, ...args);
1142
+ const fetch = (input, init) => Effect.gen(function* () {
1143
+ return yield* (yield* tag).fetch(input, init);
1159
1144
  });
1160
- const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1161
- return yield* (yield* tag).scopedCall(stub, method, ...args);
1145
+ const rpc = (method, ...args) => Effect.gen(function* () {
1146
+ return yield* (yield* tag).rpc(method, ...args);
1162
1147
  });
1163
- const unsafeRaw = Effect.fnUntraced(function* () {
1164
- return yield* (yield* tag).unsafeRaw;
1148
+ const call = (method, ...args) => Effect.gen(function* () {
1149
+ return yield* (yield* tag).call(method, ...args);
1165
1150
  });
1166
- const directMethods = makeDirectMethods(definition, {
1167
- call,
1168
- fetch,
1169
- get,
1170
- getByName
1151
+ const scopedCall = (method, ...args) => Effect.gen(function* () {
1152
+ return yield* (yield* tag).scopedCall(method, ...args);
1171
1153
  });
1154
+ const directMethods = makeDirectMethods$1(definition, call);
1172
1155
  return Object.assign(tag, directMethods, {
1173
1156
  id: definition.id,
1174
1157
  methods: definition.methods,
1175
1158
  make: definition.make,
1176
1159
  layer,
1177
- newUniqueId,
1178
- idFromName,
1179
- idFromString,
1180
- get,
1181
- getByName,
1182
- jurisdiction,
1183
1160
  fetch,
1184
1161
  rpc,
1185
1162
  call,
1186
- scopedCall,
1187
- unsafeRaw
1163
+ scopedCall
1188
1164
  });
1189
1165
  };
1190
- const DurableObject$1 = Tag$6;
1191
- const wrapHandlers = (definition, handlers) => {
1166
+ const Worker = Tag$8;
1167
+ const wrapHandlers$1 = (definition, handlers) => {
1192
1168
  const wrapped = {};
1193
1169
  for (const key of Object.keys(definition.methods)) {
1194
1170
  const handler = handlers[key];
@@ -1201,444 +1177,418 @@ const wrapHandlers = (definition, handlers) => {
1201
1177
  /**
1202
1178
  * Helper for implementing handlers with the exact method shape of a definition.
1203
1179
  */
1204
- const implement$3 = (_definition, handlers) => handlers;
1180
+ const implement$5 = (_definition, handlers) => handlers;
1205
1181
  //#endregion
1206
- //#region src/DurableObject.ts
1207
- var DurableObject_exports = /* @__PURE__ */ __exportAll({
1208
- Tag: () => Tag$5,
1209
- implement: () => implement$2,
1210
- make: () => make$5,
1211
- method: () => method
1212
- });
1213
- const reservedMethodNames = new Set([
1214
- "constructor",
1215
- "dup",
1216
- "fetch",
1217
- "alarm",
1218
- "webSocketMessage",
1219
- "webSocketClose",
1220
- "webSocketError"
1221
- ]);
1222
- const RunSymbol = Symbol.for("effect-cf/DurableObject/run");
1223
- /**
1224
- * Creates a Durable Object class backed by a single managed Effect runtime.
1225
- */
1226
- const make$5 = (layer, options = {}) => {
1227
- class EffectDurableObject extends DurableObject {
1228
- runtime;
1229
- constructor(state, env) {
1230
- super(state, env);
1231
- const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(DurableObjectState, fromDurableObjectState(state)), Layer.succeed(WorkerEnvironment, env)));
1232
- this.runtime = ManagedRuntime.make(runtimeLayer);
1233
- const initialize = options.initialize;
1234
- if (initialize !== void 0) state.waitUntil(this[RunSymbol](initialize));
1235
- }
1236
- [RunSymbol](effect) {
1237
- return this.runtime.runPromise(Effect.scoped(effect));
1238
- }
1239
- fetch(request) {
1240
- const fetchHandler = options.fetch;
1241
- if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
1242
- return this[RunSymbol](Effect.provideService(fetchHandler, NativeRequest, request));
1243
- }
1244
- alarm(alarmInfo) {
1245
- const logicalAlarms = options.alarms?.pipe(Effect.asVoid);
1246
- const rawAlarm = options.alarm?.(alarmInfo);
1247
- if (logicalAlarms !== void 0 && rawAlarm !== void 0) return this[RunSymbol](Effect.gen(function* () {
1248
- yield* logicalAlarms;
1249
- yield* rawAlarm;
1250
- }));
1251
- if (logicalAlarms !== void 0) return this[RunSymbol](logicalAlarms);
1252
- if (rawAlarm !== void 0) return this[RunSymbol](rawAlarm);
1253
- }
1254
- webSocketMessage(socket, message) {
1255
- if (options.webSocketMessage !== void 0) return this[RunSymbol](options.webSocketMessage(fromWebSocket(socket), message));
1182
+ //#region src/internal/Entrypoint.ts
1183
+ const provideEntrypointServices = (layer, services) => layer.pipe(Layer.provideMerge(services));
1184
+ const defineEntrypointRpcMethods = (target, prototype, rpc, reservedMethodNames, run) => {
1185
+ const methods = rpc ?? {};
1186
+ assertNoReservedMethods(target, methods, reservedMethodNames);
1187
+ for (const [key, method] of Object.entries(methods)) Object.defineProperty(prototype, key, {
1188
+ enumerable: true,
1189
+ value(...args) {
1190
+ return run(this, Effect.suspend(() => method(...args)));
1256
1191
  }
1257
- webSocketClose(socket, code, reason, wasClean) {
1258
- if (options.webSocketClose !== void 0) return this[RunSymbol](options.webSocketClose(fromWebSocket(socket), code, reason, wasClean));
1192
+ });
1193
+ };
1194
+ const assumeEntrypointClass = (entrypoint) => entrypoint;
1195
+ //#endregion
1196
+ //#region src/internal/WorkerContext.ts
1197
+ const causeError = (cause) => new Error(Cause.pretty(cause));
1198
+ const failureHandler = (cause, options) => (options?.onFailure?.(cause) ?? Effect.logError("WorkerContext.waitUntil failed", Cause.pretty(cause))).pipe(Effect.catchCause((handlerCause) => Effect.logError("WorkerContext.waitUntil failure handler failed", Cause.pretty(cause), Cause.pretty(handlerCause))));
1199
+ const fromExecutionContext = (ctx, runPromiseExit) => {
1200
+ const schedule = (effect, options, mode) => Effect.context().pipe(Effect.flatMap((context) => Effect.sync(() => {
1201
+ const runHandler = (cause) => runPromiseExit(Effect.scoped(Effect.provideContext(failureHandler(cause, options), context))).then((exit) => {
1202
+ if (Exit.isFailure(exit)) console.error("WorkerContext.waitUntil failure handler failed", Cause.pretty(exit.cause));
1203
+ });
1204
+ ctx.waitUntil(runPromiseExit(Effect.scoped(Effect.provideContext(effect, context))).then(async (exit) => {
1205
+ if (Exit.isSuccess(exit)) return;
1206
+ await runHandler(exit.cause);
1207
+ if (mode === "propagate") throw causeError(exit.cause);
1208
+ }));
1209
+ })));
1210
+ return {
1211
+ raw: ctx,
1212
+ waitUntil: (effect, options) => schedule(effect, options, options?.mode ?? "observe"),
1213
+ waitUntilPropagating: (effect, options) => schedule(effect, options, "propagate"),
1214
+ passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
1215
+ };
1216
+ };
1217
+ //#endregion
1218
+ //#region src/Worker.ts
1219
+ var Worker_exports = /* @__PURE__ */ __exportAll({
1220
+ ExecutionContext: () => ExecutionContext,
1221
+ NativeRequest: () => NativeRequest,
1222
+ Tag: () => Tag$7,
1223
+ WorkerContext: () => WorkerContext,
1224
+ implement: () => implement$4,
1225
+ isWebSocketUpgrade: () => isWebSocketUpgrade,
1226
+ make: () => make$6,
1227
+ makeFetchHandler: () => makeFetchHandler,
1228
+ method: () => method$2,
1229
+ renderHttpResponse: () => renderHttpResponse
1230
+ });
1231
+ var ExecutionContext = class extends Context.Service()("effect-cf/ExecutionContext") {};
1232
+ var WorkerContext = class extends Context.Service()("effect-cf/WorkerContext") {};
1233
+ var NativeRequest = class extends Context.Service()("effect-cf/NativeRequest") {};
1234
+ const isWebSocketUpgrade = (request) => request.headers.get("Upgrade")?.toLowerCase() === "websocket";
1235
+ const reservedMethodNames$2 = new Set([
1236
+ "constructor",
1237
+ "dup",
1238
+ "fetch",
1239
+ "connect",
1240
+ "queue",
1241
+ "scheduled",
1242
+ "tail",
1243
+ "tailStream",
1244
+ "test",
1245
+ "trace",
1246
+ "alarm",
1247
+ "webSocketMessage",
1248
+ "webSocketClose",
1249
+ "webSocketError"
1250
+ ]);
1251
+ const RunSymbol$1 = Symbol.for("effect-cf/Worker/run");
1252
+ const renderHttpResponse = (effect) => Effect.flatMap(effect, (response) => Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
1253
+ const renderFetchSuccess = (effect) => Effect.flatMap(effect, (response) => response instanceof Response ? Effect.succeed(response) : Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
1254
+ const isWorkerOptions = (options) => typeof options === "object" && options !== null && ("eventLayer" in options || "fetch" in options || "queue" in options || "rpc" in options);
1255
+ function make$6(layer, optionsOrFetch) {
1256
+ const options = isWorkerOptions(optionsOrFetch) ? optionsOrFetch : { fetch: optionsOrFetch };
1257
+ class EffectWorker extends WorkerEntrypoint {
1258
+ runtime;
1259
+ constructor(ctx, env) {
1260
+ super(ctx, env);
1261
+ let runWaitUntilEffect = () => Promise.reject(/* @__PURE__ */ new Error("WorkerContext runtime is not initialized"));
1262
+ const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(ExecutionContext, ctx), ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env))), Layer.succeed(WorkerContext, fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect))), Layer.succeed(WorkerEnvironment, env)));
1263
+ this.runtime = ManagedRuntime.make(runtimeLayer);
1264
+ runWaitUntilEffect = (effect) => this.runtime.runPromiseExit(effect);
1259
1265
  }
1260
- webSocketError(socket, error) {
1261
- if (options.webSocketError !== void 0) return this[RunSymbol](options.webSocketError(fromWebSocket(socket), error));
1266
+ [RunSymbol$1](effect, runOptions = {}) {
1267
+ const effectWithEventLayer = runOptions.eventLayer === false || options.eventLayer === void 0 ? effect : effect.pipe(Effect.provide(options.eventLayer, { local: true }));
1268
+ return this.runtime.runPromise(Effect.scoped(effectWithEventLayer));
1269
+ }
1270
+ fetch(request) {
1271
+ const fetchHandler = options.fetch;
1272
+ if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
1273
+ const requestServices = Layer.mergeAll(Layer.succeed(NativeRequest, request), Layer.succeed(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromWeb(request)));
1274
+ return this[RunSymbol$1](renderFetchSuccess(fetchHandler).pipe(Effect.provide(requestServices)));
1275
+ }
1276
+ queue(batch) {
1277
+ const queueHandler = options.queue;
1278
+ if (queueHandler === void 0) return Promise.resolve();
1279
+ const messages = batch.messages.map((message) => fromMessage(message, message.body));
1280
+ return this[RunSymbol$1](queueHandler(fromMessageBatch(batch, messages)));
1262
1281
  }
1263
1282
  }
1264
- defineEntrypointRpcMethods("Durable Object", EffectDurableObject.prototype, options.rpc, reservedMethodNames, (self, effect) => self[RunSymbol](effect));
1265
- return assumeEntrypointClass(EffectDurableObject);
1283
+ defineEntrypointRpcMethods("Worker", EffectWorker.prototype, options.rpc, reservedMethodNames$2, (self, effect) => self[RunSymbol$1](effect));
1284
+ return assumeEntrypointClass(EffectWorker);
1285
+ }
1286
+ const makeFetchHandler = (layer, options) => {
1287
+ const WorkerClass = make$6(layer, options);
1288
+ return { fetch: (request, env, ctx) => Promise.resolve(new WorkerClass(ctx, env).fetch(request)) };
1266
1289
  };
1267
- const Tag$5 = Tag$6;
1268
- const method = method$1;
1269
- const implement$2 = implement$3;
1290
+ const Tag$7 = Tag$8;
1291
+ const method$2 = method$3;
1292
+ const implement$4 = implement$5;
1270
1293
  //#endregion
1271
- //#region src/CloudflareOtlp.ts
1272
- var CloudflareOtlp_exports = /* @__PURE__ */ __exportAll({
1273
- CloudflareOtlpSettings: () => CloudflareOtlpSettings,
1274
- durableObjectLayer: () => durableObjectLayer,
1275
- instrumentDurableObjectOptions: () => instrumentDurableObjectOptions,
1276
- instrumentWorkerOptions: () => instrumentWorkerOptions,
1294
+ //#region src/DurableObjectNamespace.ts
1295
+ var DurableObjectNamespace_exports = /* @__PURE__ */ __exportAll({
1296
+ DurableObjectFetchError: () => DurableObjectFetchError,
1297
+ DurableObjectRpcError: () => DurableObjectRpcError,
1298
+ isDurableObjectNamespaceClient: () => isDurableObjectNamespaceClient,
1277
1299
  layer: () => layer$6,
1278
- layerJson: () => layerJson,
1279
- layerProtobuf: () => layerProtobuf,
1280
- settingsConfig: () => settingsConfig,
1281
- settingsLayer: () => settingsLayer,
1282
- workerLayer: () => workerLayer
1283
- });
1284
- /**
1285
- * Supported OpenTelemetry environment configuration for Cloudflare OTLP export.
1286
- *
1287
- * This config intentionally uses the conventional `OTEL_*` variable names so
1288
- * deployments can share the same settings used by other OpenTelemetry SDKs.
1289
- * It covers the OTLP HTTP settings supported by the Effect OTLP layers:
1290
- *
1291
- * - `OTEL_EXPORTER_OTLP_ENDPOINT`
1292
- * - `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`
1293
- * - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`
1294
- * - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`
1295
- * - `OTEL_EXPORTER_OTLP_HEADERS`
1296
- * - `OTEL_EXPORTER_OTLP_LOGS_HEADERS`
1297
- * - `OTEL_EXPORTER_OTLP_TRACES_HEADERS`
1298
- * - `OTEL_EXPORTER_OTLP_METRICS_HEADERS`
1299
- * - `OTEL_SERVICE_NAME`
1300
- * - `OTEL_RESOURCE_ATTRIBUTES`
1301
- *
1302
- * `OTEL_SERVICE_VERSION` is also accepted as an effect-cf convenience alias.
1303
- * The standard OpenTelemetry way to configure service version is
1304
- * `OTEL_RESOURCE_ATTRIBUTES=service.version=...`.
1305
- *
1306
- * Consumers with non-standard binding names should map those names into
1307
- * {@link CloudflareOtlpSettings} rather than changing this config globally.
1308
- */
1309
- const settingsConfig = Config.all({
1310
- endpoint: Config.string("OTEL_EXPORTER_OTLP_ENDPOINT").pipe(Config.option),
1311
- logsEndpoint: Config.string("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT").pipe(Config.option),
1312
- tracesEndpoint: Config.string("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT").pipe(Config.option),
1313
- metricsEndpoint: Config.string("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT").pipe(Config.option),
1314
- headers: Config.string("OTEL_EXPORTER_OTLP_HEADERS").pipe(Config.option),
1315
- logsHeaders: Config.string("OTEL_EXPORTER_OTLP_LOGS_HEADERS").pipe(Config.option),
1316
- tracesHeaders: Config.string("OTEL_EXPORTER_OTLP_TRACES_HEADERS").pipe(Config.option),
1317
- metricsHeaders: Config.string("OTEL_EXPORTER_OTLP_METRICS_HEADERS").pipe(Config.option),
1318
- serviceName: Config.string("OTEL_SERVICE_NAME").pipe(Config.option),
1319
- serviceVersion: Config.string("OTEL_SERVICE_VERSION").pipe(Config.option),
1320
- resourceAttributes: Config.schema(Config.Record(Schema.String, Schema.String), "OTEL_RESOURCE_ATTRIBUTES").pipe(Config.option)
1300
+ makeClient: () => makeClient$4,
1301
+ makeDirectMethods: () => makeDirectMethods
1321
1302
  });
1303
+ const expectedDurableObjectNamespace = "Durable Object namespace binding with getByName(), get(), idFromName(), idFromString(), newUniqueId(), and jurisdiction()";
1322
1304
  /**
1323
- * Service carrying already-resolved Cloudflare OTLP settings.
1324
- *
1325
- * Provide this service directly when an application needs to map custom
1326
- * Cloudflare binding names, compute settings dynamically, or override settings
1327
- * in tests. When this service is present, the OTLP layers use it instead of
1328
- * reading {@link settingsConfig}.
1329
- *
1330
- * @example
1331
- * ```ts
1332
- * const CustomOtlpSettings = Layer.effect(
1333
- * CloudflareOtlp.CloudflareOtlpSettings,
1334
- * Config.all({
1335
- * ...CloudflareOtlp.settingsConfig,
1336
- * endpoint: Config.string("MY_OTLP_ENDPOINT").pipe(Config.option),
1337
- * }),
1338
- * ).pipe(Layer.provide(WorkerConfig.layer));
1339
- * ```
1305
+ * Failure raised when invoking an RPC method on a Durable Object stub.
1340
1306
  */
1341
- var CloudflareOtlpSettings = class extends Context.Service()("effect-cf/CloudflareOtlpSettings") {};
1342
- const allSignals = [
1343
- "logs",
1344
- "traces",
1345
- "metrics"
1346
- ];
1347
- const optionToUndefined = (option) => Option.isSome(option) ? option.value : void 0;
1348
- const nonEmptyStringOption = (option) => Option.flatMap(option, (value) => {
1349
- const trimmed = value.trim();
1350
- return trimmed === "" ? Option.none() : Option.some(trimmed);
1351
- });
1352
- const nonEmptyRecordOption = (option) => Option.filter(option, (value) => Object.keys(value).length > 0);
1353
- const normalizeSettings = (settings) => ({
1354
- endpoint: nonEmptyStringOption(settings.endpoint),
1355
- logsEndpoint: nonEmptyStringOption(settings.logsEndpoint),
1356
- tracesEndpoint: nonEmptyStringOption(settings.tracesEndpoint),
1357
- metricsEndpoint: nonEmptyStringOption(settings.metricsEndpoint),
1358
- headers: nonEmptyStringOption(settings.headers),
1359
- logsHeaders: nonEmptyStringOption(settings.logsHeaders),
1360
- tracesHeaders: nonEmptyStringOption(settings.tracesHeaders),
1361
- metricsHeaders: nonEmptyStringOption(settings.metricsHeaders),
1362
- serviceName: nonEmptyStringOption(settings.serviceName),
1363
- serviceVersion: nonEmptyStringOption(settings.serviceVersion),
1364
- resourceAttributes: nonEmptyRecordOption(settings.resourceAttributes)
1365
- });
1307
+ var DurableObjectRpcError = class extends Data.TaggedError("DurableObjectRpcError") {};
1366
1308
  /**
1367
- * Layer that reads standard OpenTelemetry settings from the current Cloudflare
1368
- * `env` object.
1369
- *
1370
- * The layer depends on {@link WorkerEnvironment} and installs a
1371
- * Cloudflare-backed Effect `ConfigProvider`, so `settingsConfig` reads from
1372
- * Worker vars/secrets instead of Node process environment variables.
1309
+ * Failure raised when forwarding a request to a Durable Object stub.
1373
1310
  */
1374
- const settingsLayer = Layer.effect(CloudflareOtlpSettings, settingsConfig.pipe(Config.map(normalizeSettings))).pipe(Layer.provide(WorkerConfig.layer));
1375
- const selectedSignals = (signals) => new Set(signals ?? allSignals);
1376
- const withDefinedAttributes = (attributes) => {
1377
- const out = {};
1378
- for (const [key, value] of Object.entries(attributes)) if (value !== void 0) out[key] = value;
1379
- return out;
1380
- };
1381
- const parseHeaders = (input) => {
1382
- if (Option.isNone(input) || input.value.trim() === "") return;
1383
- const headers = {};
1384
- for (const part of input.value.split(",")) {
1385
- const index = part.indexOf("=");
1386
- if (index <= 0) continue;
1387
- const key = part.slice(0, index).trim();
1388
- const value = part.slice(index + 1).trim();
1389
- if (key !== "") headers[decodeHeaderComponent(key)] = decodeHeaderComponent(value);
1390
- }
1391
- return headers;
1392
- };
1393
- const mergeHeaders = (common, signalSpecific) => {
1394
- const commonHeaders = parseHeaders(common);
1395
- const signalHeaders = parseHeaders(signalSpecific);
1396
- if (commonHeaders === void 0 && signalHeaders === void 0) return;
1397
- return {
1398
- ...commonHeaders,
1399
- ...signalHeaders
1311
+ var DurableObjectFetchError = class extends Data.TaggedError("DurableObjectFetchError") {};
1312
+ const hasFunction$1 = (value, key) => typeof Reflect.get(value, key) === "function";
1313
+ const isDurableObjectNamespaceClient = (value) => typeof value === "object" && value !== null && hasFunction$1(value, "getByName") && hasFunction$1(value, "get") && hasFunction$1(value, "idFromName") && hasFunction$1(value, "idFromString") && hasFunction$1(value, "newUniqueId") && hasFunction$1(value, "jurisdiction");
1314
+ const makeClient$4 = (definition) => {
1315
+ return (namespace) => {
1316
+ const newUniqueId = (options) => Effect.sync(() => namespace.newUniqueId(options));
1317
+ const idFromName = (name) => Effect.sync(() => namespace.idFromName(name));
1318
+ const idFromString = (id) => Effect.sync(() => namespace.idFromString(id));
1319
+ const get = (id, options) => Effect.sync(() => namespace.get(id, options));
1320
+ const getByName = (name, options) => Effect.sync(() => namespace.getByName(name, options));
1321
+ const jurisdiction = (value) => Effect.sync(() => namespace.jurisdiction(value));
1322
+ const fetch = (stub, input, init) => Effect.tryPromise({
1323
+ try: () => stub.fetch(input, init),
1324
+ catch: (cause) => new DurableObjectFetchError({
1325
+ binding: definition.binding,
1326
+ cause
1327
+ })
1328
+ });
1329
+ const rpc = (stub, method, ...args) => Effect.gen(function* () {
1330
+ const methodName = String(method);
1331
+ return yield* invokeRpcMethod(stub, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1332
+ binding: definition.binding,
1333
+ method: methodName,
1334
+ cause
1335
+ }))), (cause) => new DurableObjectRpcError({
1336
+ binding: definition.binding,
1337
+ method: methodName,
1338
+ cause
1339
+ }));
1340
+ });
1341
+ const decodeSuccess$1 = (methodName, value) => Effect.gen(function* () {
1342
+ if (definition.definition === void 0) return value;
1343
+ return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1344
+ binding: definition.binding,
1345
+ method: methodName,
1346
+ cause
1347
+ })));
1348
+ });
1349
+ const call = (stub, method, ...args) => Effect.gen(function* () {
1350
+ const methodName = String(method);
1351
+ return yield* decodeSuccess$1(methodName, yield* resolve(yield* rpc(stub, method, ...args)).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1352
+ binding: definition.binding,
1353
+ method: methodName,
1354
+ cause
1355
+ }))));
1356
+ });
1357
+ const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1358
+ return yield* decodeSuccess$1(String(method), yield* scoped(yield* rpc(stub, method, ...args)));
1359
+ });
1360
+ const directMethods = makeDirectMethods(definition.definition, {
1361
+ call,
1362
+ fetch,
1363
+ get,
1364
+ getByName
1365
+ });
1366
+ return Object.assign(directMethods, {
1367
+ newUniqueId,
1368
+ idFromName,
1369
+ idFromString,
1370
+ get,
1371
+ getByName,
1372
+ jurisdiction,
1373
+ fetch,
1374
+ rpc,
1375
+ call,
1376
+ scopedCall,
1377
+ unsafeRaw: Effect.succeed(namespace)
1378
+ });
1400
1379
  };
1401
1380
  };
1402
- const decodeHeaderComponent = (value) => {
1403
- try {
1404
- return decodeURIComponent(value);
1405
- } catch {
1406
- return value;
1407
- }
1408
- };
1409
- const appendOtlpPath = (baseUrl, path) => `${baseUrl.replace(/\/+$/, "")}${path}`;
1410
- const makeResource = (settings, options, runtimeAttributes) => ({
1411
- serviceName: options.serviceName ?? optionToUndefined(settings.serviceName),
1412
- serviceVersion: options.serviceVersion ?? optionToUndefined(settings.serviceVersion),
1413
- attributes: {
1414
- ...optionToUndefined(settings.resourceAttributes),
1415
- ...withDefinedAttributes(runtimeAttributes),
1416
- ...options.attributes
1417
- }
1418
- });
1419
- const commonOtlpOptions = (settings, options, runtimeAttributes) => ({
1420
- resource: makeResource(settings, options, runtimeAttributes),
1421
- maxBatchSize: options.maxBatchSize,
1422
- loggerExportInterval: options.loggerExportInterval,
1423
- loggerExcludeLogSpans: options.loggerExcludeLogSpans,
1424
- loggerMergeWithExisting: options.loggerMergeWithExisting,
1425
- tracerExportInterval: options.tracerExportInterval,
1426
- tracerContext: options.tracerContext,
1427
- metricsExportInterval: options.metricsExportInterval,
1428
- metricsTemporality: options.metricsTemporality,
1429
- shutdownTimeout: options.shutdownTimeout
1430
- });
1431
- const serializationLayer = (serialization) => serialization === "json" ? OtlpSerialization.layerJson : OtlpSerialization.layerProtobuf;
1432
- const resolveSettings = Effect.gen(function* () {
1433
- const settings = yield* Effect.serviceOption(CloudflareOtlpSettings);
1434
- if (Option.isSome(settings)) return normalizeSettings(settings.value);
1435
- const env = yield* Effect.serviceOption(WorkerEnvironment);
1436
- if (Option.isSome(env)) return normalizeSettings(yield* settingsConfig.pipe(Effect.provide(ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env.value))))));
1437
- return normalizeSettings(yield* settingsConfig);
1438
- });
1439
- const mergeSignalLayers = (layers) => {
1440
- if (layers.length === 0) return Layer.empty;
1441
- let merged = layers[0];
1442
- for (let index = 1; index < layers.length; index++) merged = Layer.mergeAll(merged, layers[index]);
1443
- return merged;
1444
- };
1445
- const emptyLayer = Layer.empty;
1446
- const makeLayerFromSettings = (options = {}, runtimeAttributes = {}) => Layer.unwrap(Effect.map(resolveSettings, (settings) => {
1447
- const signals = selectedSignals(options.signals);
1448
- const endpoint = optionToUndefined(settings.endpoint);
1449
- const logsEndpoint = optionToUndefined(settings.logsEndpoint);
1450
- const tracesEndpoint = optionToUndefined(settings.tracesEndpoint);
1451
- const metricsEndpoint = optionToUndefined(settings.metricsEndpoint);
1452
- const hasSpecificEndpoint = logsEndpoint !== void 0 || tracesEndpoint !== void 0 || metricsEndpoint !== void 0;
1453
- const hasSpecificHeaders = Option.isSome(settings.logsHeaders) || Option.isSome(settings.tracesHeaders) || Option.isSome(settings.metricsHeaders);
1454
- const common = commonOtlpOptions(settings, options, runtimeAttributes);
1455
- if (endpoint !== void 0 && !hasSpecificEndpoint && !hasSpecificHeaders && signals.size === 3) return Otlp.layer({
1456
- baseUrl: endpoint,
1457
- headers: parseHeaders(settings.headers),
1458
- ...common
1459
- }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer));
1460
- const layers = [];
1461
- if (signals.has("logs")) {
1462
- const url = logsEndpoint ?? (endpoint === void 0 ? void 0 : appendOtlpPath(endpoint, "/v1/logs"));
1463
- if (url !== void 0) layers.push(OtlpLogger.layer({
1464
- url,
1465
- resource: common.resource,
1466
- headers: mergeHeaders(settings.headers, settings.logsHeaders),
1467
- exportInterval: common.loggerExportInterval,
1468
- maxBatchSize: common.maxBatchSize,
1469
- shutdownTimeout: common.shutdownTimeout,
1470
- excludeLogSpans: common.loggerExcludeLogSpans,
1471
- mergeWithExisting: common.loggerMergeWithExisting
1472
- }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer)));
1473
- }
1474
- if (signals.has("traces")) {
1475
- const url = tracesEndpoint ?? (endpoint === void 0 ? void 0 : appendOtlpPath(endpoint, "/v1/traces"));
1476
- if (url !== void 0) layers.push(OtlpTracer.layer({
1477
- url,
1478
- resource: common.resource,
1479
- headers: mergeHeaders(settings.headers, settings.tracesHeaders),
1480
- exportInterval: common.tracerExportInterval,
1481
- maxBatchSize: common.maxBatchSize,
1482
- context: common.tracerContext,
1483
- shutdownTimeout: common.shutdownTimeout
1484
- }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer)));
1485
- }
1486
- if (signals.has("metrics")) {
1487
- const url = metricsEndpoint ?? (endpoint === void 0 ? void 0 : appendOtlpPath(endpoint, "/v1/metrics"));
1488
- if (url !== void 0) layers.push(OtlpMetrics.layer({
1489
- url,
1490
- resource: common.resource,
1491
- headers: mergeHeaders(settings.headers, settings.metricsHeaders),
1492
- exportInterval: common.metricsExportInterval,
1493
- shutdownTimeout: common.shutdownTimeout,
1494
- temporality: common.metricsTemporality
1495
- }).pipe(Layer.provide(serializationLayer(options.serialization)), Layer.provide(FetchHttpClient.layer)));
1381
+ const layer$6 = (tag, definition) => layer$10(tag, definition.binding, (value) => isDurableObjectNamespaceClient(value), makeClient$4(definition), { expected: expectedDurableObjectNamespace });
1382
+ const makeDirectMethods = (rpcDefinition, helpers) => {
1383
+ const methods = {};
1384
+ if (rpcDefinition !== void 0) {
1385
+ for (const methodName of Object.keys(rpcDefinition.methods)) methods[methodName] = (stub, ...args) => helpers.call(stub, methodName, ...args);
1386
+ const makeClient = (getStub) => {
1387
+ const client = { fetch: (input, init) => Effect.gen(function* () {
1388
+ const stub = yield* getStub();
1389
+ return yield* helpers.fetch(stub, input, init);
1390
+ }) };
1391
+ for (const methodName of Object.keys(rpcDefinition.methods)) client[methodName] = (...args) => Effect.gen(function* () {
1392
+ const stub = yield* getStub();
1393
+ return yield* helpers.call(stub, methodName, ...args);
1394
+ });
1395
+ return client;
1396
+ };
1397
+ methods.byName = (name, options) => makeClient(() => helpers.getByName(name, options));
1398
+ methods.byId = (id, options) => makeClient(() => helpers.get(id, options));
1496
1399
  }
1497
- return mergeSignalLayers(layers);
1498
- }).pipe(Effect.catch((error) => Effect.logWarning("CloudflareOtlp disabled because OTLP configuration is invalid", { error: String(error) }).pipe(Effect.as(emptyLayer)))));
1499
- const makeLayer = (options = {}, runtimeAttributes = {}) => makeLayerFromSettings(options, runtimeAttributes);
1500
- /**
1501
- * Base OTLP telemetry layer for Cloudflare-compatible runtimes.
1502
- *
1503
- * The layer reads {@link CloudflareOtlpSettings} when provided. Otherwise it
1504
- * reads standard OpenTelemetry config from `WorkerEnvironment` when available,
1505
- * then falls back to the ambient Effect `ConfigProvider`.
1506
- *
1507
- * When only `OTEL_EXPORTER_OTLP_ENDPOINT` is configured, per-signal paths are
1508
- * derived by appending `/v1/logs`, `/v1/traces`, and `/v1/metrics`. Signal
1509
- * specific endpoints are used as-is, matching the OpenTelemetry OTLP exporter
1510
- * convention.
1511
- */
1512
- const layer$6 = (options = {}) => makeLayer(options);
1513
- /** Base OTLP telemetry layer forced to JSON serialization. */
1514
- const layerJson = (options = {}) => layer$6({
1515
- ...options,
1516
- serialization: "json"
1517
- });
1518
- /** Base OTLP telemetry layer forced to protobuf serialization. */
1519
- const layerProtobuf = (options = {}) => layer$6({
1520
- ...options,
1521
- serialization: "protobuf"
1400
+ return methods;
1401
+ };
1402
+ //#endregion
1403
+ //#region src/DurableObjectDefinition.ts
1404
+ var DurableObjectDefinition_exports = /* @__PURE__ */ __exportAll({
1405
+ DurableObject: () => DurableObject$1,
1406
+ Tag: () => Tag$6,
1407
+ implement: () => implement$3,
1408
+ make: () => make$5,
1409
+ method: () => method$1
1522
1410
  });
1411
+ const reservedMethodNames$1 = new Set([
1412
+ "constructor",
1413
+ "dup",
1414
+ "fetch",
1415
+ "alarm",
1416
+ "webSocketMessage",
1417
+ "webSocketClose",
1418
+ "webSocketError"
1419
+ ]);
1523
1420
  /**
1524
- * OTLP layer with Cloudflare Worker resource attributes.
1525
- *
1526
- * Provide this layer at runtime scope for long-lived metrics aggregation, or at
1527
- * handler scope when traces/logs should flush as the Cloudflare event finishes.
1421
+ * Defines a single RPC method schema in a Durable Object definition.
1528
1422
  */
1529
- const workerLayer = (options = {}) => makeLayer(options, {
1530
- "cloudflare.resource_type": "worker",
1531
- "cloudflare.worker.name": options.workerName
1532
- });
1423
+ const method$1 = method$4;
1533
1424
  /**
1534
- * OTLP layer with Cloudflare Durable Object resource attributes.
1425
+ * Creates a Durable Object RPC definition plus implementation/binding helpers.
1535
1426
  *
1536
- * The layer reads {@link DurableObjectState} so it can optionally include the
1537
- * Durable Object id. Prefer leaving `includeObjectId` disabled unless the
1538
- * backend can tolerate high-cardinality resource attributes.
1427
+ * @example
1428
+ * ```ts
1429
+ * const ChatRoom = DurableObjectDefinition.make("ChatRoom", {
1430
+ * postMessage: DurableObjectDefinition.method({
1431
+ * args: [Schema.String],
1432
+ * success: Schema.Void,
1433
+ * }),
1434
+ * });
1435
+ * ```
1539
1436
  */
1540
- const durableObjectLayer = (options = {}) => Layer.unwrap(Effect.map(DurableObjectState, (state) => makeLayer(options, {
1541
- "cloudflare.resource_type": "durable_object",
1542
- "cloudflare.durable_object.class": options.className,
1543
- "cloudflare.durable_object.id": options.includeObjectId ? state.id.toString() : void 0
1544
- })));
1545
- const provideRpcLayer = (rpc, layer) => {
1546
- if (rpc === void 0) return;
1547
- return new Proxy(rpc, { get(target, property, receiver) {
1548
- const handler = Reflect.get(target, property, receiver);
1549
- if (typeof handler !== "function") return handler;
1550
- return (...args) => Effect.suspend(() => Reflect.apply(handler, receiver, args)).pipe(Effect.provide(layer));
1551
- } });
1437
+ const makeDefinition$2 = (id, methods) => {
1438
+ assertNoReservedMethods("Durable Object", methods, reservedMethodNames$1);
1439
+ const definition = make$8(id, methods);
1440
+ return Object.assign(definition, { make: (layer, options) => make$4(layer, {
1441
+ ...options,
1442
+ rpc: wrapHandlers(definition, options.rpc)
1443
+ }) });
1552
1444
  };
1553
- /**
1554
- * Instrument Worker lifecycle handlers with event-scoped OTLP telemetry.
1555
- *
1556
- * Each defined handler is provided with {@link workerLayer}. Because Worker
1557
- * handlers run inside `Effect.scoped`, the exporter scope closes and flushes at
1558
- * the end of each Cloudflare event.
1559
- */
1560
- const instrumentWorkerOptions = (options) => (handlers) => {
1561
- const telemetryLayer = workerLayer(options);
1562
- const queue = handlers.queue;
1563
- return {
1564
- ...handlers,
1565
- fetch: handlers.fetch === void 0 ? void 0 : handlers.fetch.pipe(Effect.provide(telemetryLayer)),
1566
- queue: queue === void 0 ? void 0 : (batch) => queue(batch).pipe(Effect.provide(telemetryLayer)),
1567
- rpc: provideRpcLayer(handlers.rpc, telemetryLayer)
1568
- };
1445
+ const make$5 = (id, methods) => Tag$6()(id, methods);
1446
+ const Tag$6 = () => (id, methods) => {
1447
+ const definition = makeDefinition$2(id, methods);
1448
+ const tag = Context.Service()(id);
1449
+ const bindingDefinition = (binding) => ({
1450
+ ...binding,
1451
+ definition
1452
+ });
1453
+ const layer = (binding) => layer$6(tag, bindingDefinition(binding));
1454
+ const newUniqueId = Effect.fnUntraced(function* (options) {
1455
+ return yield* (yield* tag).newUniqueId(options);
1456
+ });
1457
+ const idFromName = Effect.fnUntraced(function* (name) {
1458
+ return yield* (yield* tag).idFromName(name);
1459
+ });
1460
+ const idFromString = Effect.fnUntraced(function* (value) {
1461
+ return yield* (yield* tag).idFromString(value);
1462
+ });
1463
+ const get = Effect.fnUntraced(function* (objectId, options) {
1464
+ return yield* (yield* tag).get(objectId, options);
1465
+ });
1466
+ const getByName = Effect.fnUntraced(function* (name, options) {
1467
+ return yield* (yield* tag).getByName(name, options);
1468
+ });
1469
+ const jurisdiction = Effect.fnUntraced(function* (value) {
1470
+ return yield* (yield* tag).jurisdiction(value);
1471
+ });
1472
+ const fetch = (stub, input, init) => Effect.gen(function* () {
1473
+ return yield* (yield* tag).fetch(stub, input, init);
1474
+ });
1475
+ const rpc = (stub, method, ...args) => Effect.gen(function* () {
1476
+ return yield* (yield* tag).rpc(stub, method, ...args);
1477
+ });
1478
+ const call = (stub, method, ...args) => Effect.gen(function* () {
1479
+ return yield* (yield* tag).call(stub, method, ...args);
1480
+ });
1481
+ const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1482
+ return yield* (yield* tag).scopedCall(stub, method, ...args);
1483
+ });
1484
+ const unsafeRaw = Effect.fnUntraced(function* () {
1485
+ return yield* (yield* tag).unsafeRaw;
1486
+ });
1487
+ const directMethods = makeDirectMethods(definition, {
1488
+ call,
1489
+ fetch,
1490
+ get,
1491
+ getByName
1492
+ });
1493
+ return Object.assign(tag, directMethods, {
1494
+ id: definition.id,
1495
+ methods: definition.methods,
1496
+ make: definition.make,
1497
+ layer,
1498
+ newUniqueId,
1499
+ idFromName,
1500
+ idFromString,
1501
+ get,
1502
+ getByName,
1503
+ jurisdiction,
1504
+ fetch,
1505
+ rpc,
1506
+ call,
1507
+ scopedCall,
1508
+ unsafeRaw
1509
+ });
1510
+ };
1511
+ const DurableObject$1 = Tag$6;
1512
+ const wrapHandlers = (definition, handlers) => {
1513
+ const wrapped = {};
1514
+ for (const key of Object.keys(definition.methods)) {
1515
+ const handler = handlers[key];
1516
+ wrapped[key] = (...args) => Effect.gen(function* () {
1517
+ return yield* encodeSuccess(definition, key, yield* handler(...yield* decodeArgs(definition, key, args)));
1518
+ });
1519
+ }
1520
+ return wrapped;
1569
1521
  };
1570
1522
  /**
1571
- * Instrument Durable Object lifecycle handlers with event-scoped OTLP telemetry.
1572
- *
1573
- * Each defined handler is provided with {@link durableObjectLayer}. Because
1574
- * Durable Object handlers run inside `Effect.scoped`, the exporter scope closes
1575
- * and flushes at the end of each Cloudflare event.
1523
+ * Helper for implementing handlers with the exact method shape of a definition.
1576
1524
  */
1577
- const instrumentDurableObjectOptions = (options) => (handlers) => {
1578
- const telemetryLayer = durableObjectLayer(options);
1579
- const alarm = handlers.alarm;
1580
- const webSocketMessage = handlers.webSocketMessage;
1581
- const webSocketClose = handlers.webSocketClose;
1582
- const webSocketError = handlers.webSocketError;
1583
- return {
1584
- ...handlers,
1585
- initialize: handlers.initialize === void 0 ? void 0 : handlers.initialize.pipe(Effect.provide(telemetryLayer)),
1586
- fetch: handlers.fetch === void 0 ? void 0 : handlers.fetch.pipe(Effect.provide(telemetryLayer)),
1587
- alarms: handlers.alarms === void 0 ? void 0 : handlers.alarms.pipe(Effect.provide(telemetryLayer)),
1588
- alarm: alarm === void 0 ? void 0 : (alarmInfo) => alarm(alarmInfo).pipe(Effect.provide(telemetryLayer)),
1589
- webSocketMessage: webSocketMessage === void 0 ? void 0 : (socket, message) => webSocketMessage(socket, message).pipe(Effect.provide(telemetryLayer)),
1590
- webSocketClose: webSocketClose === void 0 ? void 0 : (socket, code, reason, wasClean) => webSocketClose(socket, code, reason, wasClean).pipe(Effect.provide(telemetryLayer)),
1591
- webSocketError: webSocketError === void 0 ? void 0 : (socket, error) => webSocketError(socket, error).pipe(Effect.provide(telemetryLayer)),
1592
- rpc: provideRpcLayer(handlers.rpc, telemetryLayer)
1593
- };
1594
- };
1525
+ const implement$3 = (_definition, handlers) => handlers;
1595
1526
  //#endregion
1596
- //#region src/D1.ts
1597
- var D1_exports = /* @__PURE__ */ __exportAll({
1598
- Service: () => Service,
1599
- make: () => make$4
1527
+ //#region src/DurableObject.ts
1528
+ var DurableObject_exports = /* @__PURE__ */ __exportAll({
1529
+ Tag: () => Tag$5,
1530
+ implement: () => implement$2,
1531
+ make: () => make$4,
1532
+ method: () => method
1600
1533
  });
1601
- const TypeId$1 = "effect-cf/D1";
1602
- const expectedD1Database = "D1 database binding with prepare(), batch(), and exec()";
1603
- const isD1Database = (value) => {
1604
- if (typeof value !== "object" || value === null) return false;
1605
- const resource = value;
1606
- return typeof resource.prepare === "function" && typeof resource.batch === "function" && typeof resource.exec === "function";
1607
- };
1608
- /**
1609
- * Creates a typed D1 service tag plus Effect helpers.
1610
- */
1611
- const make$4 = (id, definition) => Service()(id, definition);
1534
+ const reservedMethodNames = new Set([
1535
+ "constructor",
1536
+ "dup",
1537
+ "fetch",
1538
+ "alarm",
1539
+ "webSocketMessage",
1540
+ "webSocketClose",
1541
+ "webSocketError"
1542
+ ]);
1543
+ const RunSymbol = Symbol.for("effect-cf/DurableObject/run");
1612
1544
  /**
1613
- * Builds a D1 service around a Cloudflare D1 database binding.
1614
- *
1615
- * The returned service exposes the raw `D1Database` binding and `sqlLayer(...)`
1616
- * for providing `effect/unstable/sql` via `@effect/sql-d1`.
1617
- *
1618
- * @example
1619
- * ```ts
1620
- * class TodoDatabase extends D1.Service<TodoDatabase>()("TodoDatabase", {
1621
- * binding: "TODO_DB",
1622
- * }) {}
1623
- *
1624
- * const SqlLive = TodoDatabase.sqlLayer();
1625
- * ```
1545
+ * Creates a Durable Object class backed by a single managed Effect runtime.
1626
1546
  */
1627
- const Service = () => (id, definition) => {
1628
- const tag = Service$2()(id, definition.binding, isD1Database, void 0, { expected: expectedD1Database });
1629
- const sqlLayer = (options) => Layer.unwrap(Effect.gen(function* () {
1630
- const db = yield* tag;
1631
- return D1Client.layer({
1632
- ...options,
1633
- db
1634
- });
1635
- })).pipe(Layer.provide(tag.layer));
1636
- return Object.assign(tag, {
1637
- [TypeId$1]: TypeId$1,
1638
- definition,
1639
- sqlLayer
1640
- });
1547
+ const make$4 = (layer, options = {}) => {
1548
+ class EffectDurableObject extends DurableObject {
1549
+ runtime;
1550
+ constructor(state, env) {
1551
+ super(state, env);
1552
+ const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(DurableObjectState, fromDurableObjectState(state)), Layer.succeed(WorkerEnvironment, env)));
1553
+ this.runtime = ManagedRuntime.make(runtimeLayer);
1554
+ const initialize = options.initialize;
1555
+ if (initialize !== void 0) state.waitUntil(this[RunSymbol](initialize, { eventLayer: false }));
1556
+ }
1557
+ [RunSymbol](effect, runOptions = {}) {
1558
+ const effectWithEventLayer = runOptions.eventLayer === false || options.eventLayer === void 0 ? effect : effect.pipe(Effect.provide(options.eventLayer, { local: true }));
1559
+ return this.runtime.runPromise(Effect.scoped(effectWithEventLayer));
1560
+ }
1561
+ fetch(request) {
1562
+ const fetchHandler = options.fetch;
1563
+ if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
1564
+ return this[RunSymbol](Effect.provideService(fetchHandler, NativeRequest, request));
1565
+ }
1566
+ alarm(alarmInfo) {
1567
+ const logicalAlarms = options.alarms?.pipe(Effect.asVoid);
1568
+ const rawAlarm = options.alarm?.(alarmInfo);
1569
+ if (logicalAlarms !== void 0 && rawAlarm !== void 0) return this[RunSymbol](Effect.gen(function* () {
1570
+ yield* logicalAlarms;
1571
+ yield* rawAlarm;
1572
+ }));
1573
+ if (logicalAlarms !== void 0) return this[RunSymbol](logicalAlarms);
1574
+ if (rawAlarm !== void 0) return this[RunSymbol](rawAlarm);
1575
+ }
1576
+ webSocketMessage(socket, message) {
1577
+ if (options.webSocketMessage !== void 0) return this[RunSymbol](options.webSocketMessage(fromWebSocket(socket), message));
1578
+ }
1579
+ webSocketClose(socket, code, reason, wasClean) {
1580
+ if (options.webSocketClose !== void 0) return this[RunSymbol](options.webSocketClose(fromWebSocket(socket), code, reason, wasClean));
1581
+ }
1582
+ webSocketError(socket, error) {
1583
+ if (options.webSocketError !== void 0) return this[RunSymbol](options.webSocketError(fromWebSocket(socket), error));
1584
+ }
1585
+ }
1586
+ defineEntrypointRpcMethods("Durable Object", EffectDurableObject.prototype, options.rpc, reservedMethodNames, (self, effect) => self[RunSymbol](effect));
1587
+ return assumeEntrypointClass(EffectDurableObject);
1641
1588
  };
1589
+ const Tag$5 = Tag$6;
1590
+ const method = method$1;
1591
+ const implement$2 = implement$3;
1642
1592
  //#endregion
1643
1593
  //#region src/DurableObjectAlarm.ts
1644
1594
  var DurableObjectAlarm_exports = /* @__PURE__ */ __exportAll({