effect-cf 0.12.0 → 0.13.1

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
@@ -1,1644 +1,1614 @@
1
1
  import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
2
- import { a as WorkerConfig, i as layer$10, n as Binding_exports, o as WorkerEnvironment, r as Service$2, t as Hyperdrive_exports } from "./Hyperdrive-89hg_Fck.mjs";
2
+ import { a as WorkerConfig, i as layer$11, n as Binding_exports, o as WorkerEnvironment, r as Service$2, t as Hyperdrive_exports } from "./Hyperdrive-89hg_Fck.mjs";
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
76
  };
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
- };
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$10,
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)
755
- });
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))
765
- });
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);
766
528
  /**
767
- * Wraps native Cloudflare storage APIs as Effect-returning helpers.
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.
768
539
  */
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)
540
+ const layer$10 = (options = {}) => makeLayer(options);
541
+ /** Base OTLP telemetry layer forced to JSON serialization. */
542
+ const layerJson = (options = {}) => layer$10({
543
+ ...options,
544
+ serialization: "json"
804
545
  });
805
- //#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
546
+ /** Base OTLP telemetry layer forced to protobuf serialization. */
547
+ const layerProtobuf = (options = {}) => layer$10({
548
+ ...options,
549
+ serialization: "protobuf"
815
550
  });
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;
854
- };
855
551
  /**
856
- * Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
552
+ * OTLP layer with Cloudflare Worker resource attributes.
857
553
  *
858
- * @example
859
- * ```ts
860
- * const response = yield* DurableObjectWebSocket.acceptUpgrade({
861
- * tags: ["room:general"],
862
- * });
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.
556
+ */
557
+ const workerLayer = (options = {}) => makeLayer(options, {
558
+ "cloudflare.resource_type": "worker",
559
+ "cloudflare.worker.name": options.workerName
560
+ });
561
+ /**
562
+ * OTLP layer with Cloudflare Durable Object resource attributes.
863
563
  *
864
- * return response.response;
865
- * ```
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.
866
567
  */
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
- }))));
896
- });
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;
918
- }
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;
923
- });
924
- return {
925
- serialize,
926
- deserialize,
927
- rehydrate,
928
- schema
929
- };
930
- };
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
- });
937
- //#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))
966
- });
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;
971
- };
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
+ })));
972
573
  //#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
574
+ //#region src/D1.ts
575
+ var D1_exports = /* @__PURE__ */ __exportAll({
576
+ Service: () => Service$1,
577
+ make: () => make$10
981
578
  });
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") {};
987
- /**
988
- * Failure raised when forwarding a request to a Durable Object stub.
989
- */
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({
1004
- binding: definition.binding,
1005
- cause
1006
- })
1007
- });
1008
- const rpc = (stub, method, ...args) => Effect.gen(function* () {
1009
- 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({
1011
- binding: definition.binding,
1012
- method: methodName,
1013
- cause
1014
- }))), (cause) => new DurableObjectRpcError({
1015
- binding: definition.binding,
1016
- method: methodName,
1017
- cause
1018
- }));
1019
- });
1020
- const decodeSuccess$1 = (methodName, value) => Effect.gen(function* () {
1021
- if (definition.definition === void 0) return value;
1022
- return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1023
- binding: definition.binding,
1024
- method: methodName,
1025
- cause
1026
- })));
1027
- });
1028
- const call = (stub, method, ...args) => Effect.gen(function* () {
1029
- const methodName = String(method);
1030
- return yield* decodeSuccess$1(methodName, yield* resolve(yield* rpc(stub, method, ...args)).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1031
- binding: definition.binding,
1032
- method: methodName,
1033
- cause
1034
- }))));
1035
- });
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
1044
- });
1045
- return Object.assign(directMethods, {
1046
- newUniqueId,
1047
- idFromName,
1048
- idFromString,
1049
- get,
1050
- getByName,
1051
- jurisdiction,
1052
- fetch,
1053
- rpc,
1054
- call,
1055
- scopedCall,
1056
- unsafeRaw: Effect.succeed(namespace)
1057
- });
1058
- };
1059
- };
1060
- const layer$7 = (tag, definition) => layer$10(tag, definition.binding, (value) => isDurableObjectNamespaceClient(value), makeClient$4(definition), { expected: expectedDurableObjectNamespace });
1061
- const makeDirectMethods = (rpcDefinition, helpers) => {
1062
- 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
- }
1079
- return methods;
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";
1080
585
  };
1081
- //#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
1089
- });
1090
- const reservedMethodNames$1 = new Set([
1091
- "constructor",
1092
- "dup",
1093
- "fetch",
1094
- "alarm",
1095
- "webSocketMessage",
1096
- "webSocketClose",
1097
- "webSocketError"
1098
- ]);
1099
586
  /**
1100
- * Defines a single RPC method schema in a Durable Object definition.
587
+ * Creates a typed D1 service tag plus Effect helpers.
1101
588
  */
1102
- const method$1 = method$4;
589
+ const make$10 = (id, definition) => Service$1()(id, definition);
1103
590
  /**
1104
- * Creates a Durable Object RPC definition plus implementation/binding helpers.
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`.
1105
595
  *
1106
596
  * @example
1107
597
  * ```ts
1108
- * const ChatRoom = DurableObjectDefinition.make("ChatRoom", {
1109
- * postMessage: DurableObjectDefinition.method({
1110
- * args: [Schema.String],
1111
- * success: Schema.Void,
1112
- * }),
1113
- * });
598
+ * class TodoDatabase extends D1.Service<TodoDatabase>()("TodoDatabase", {
599
+ * binding: "TODO_DB",
600
+ * }) {}
601
+ *
602
+ * const SqlLive = TodoDatabase.sqlLayer();
1114
603
  * ```
1115
604
  */
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, {
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
618
+ });
619
+ };
620
+ //#endregion
621
+ //#region src/QueueBinding.ts
622
+ var QueueBinding_exports = /* @__PURE__ */ __exportAll({
623
+ QueueOperationError: () => QueueOperationError,
624
+ isQueue: () => isQueue,
625
+ layer: () => layer$9,
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;
660
+ }
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)
679
+ });
680
+ };
681
+ const layer$9 = (tag, definition) => layer$11(tag, definition.binding, (value) => isQueue(value), makeClient$6(definition), { expected: expectedQueueProducer });
682
+ //#endregion
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
689
+ });
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, {
1120
696
  ...options,
1121
- rpc: wrapHandlers(definition, options.rpc)
697
+ queue: wrapHandler$1(queueDefinition, options.queue)
1122
698
  }) });
1123
699
  };
1124
- const make$6 = (id, methods) => Tag$6()(id, methods);
1125
- const Tag$6 = () => (id, methods) => {
1126
- const definition = makeDefinition$2(id, methods);
700
+ const make$9 = (id, definition) => Tag$10()(id, definition);
701
+ const Tag$10 = () => (id, definition) => {
702
+ const queueDefinition = makeDefinition$4(id, definition);
1127
703
  const tag = Context.Service()(id);
1128
- const bindingDefinition = (binding) => ({
704
+ const layer = (binding) => layer$9(tag, {
1129
705
  ...binding,
1130
- definition
1131
- });
1132
- 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);
706
+ message: definition.message
1153
707
  });
1154
- const rpc = (stub, method, ...args) => Effect.gen(function* () {
1155
- return yield* (yield* tag).rpc(stub, method, ...args);
708
+ const send = Effect.fnUntraced(function* (message, options) {
709
+ yield* (yield* tag).send(message, options);
1156
710
  });
1157
- const call = (stub, method, ...args) => Effect.gen(function* () {
1158
- return yield* (yield* tag).call(stub, method, ...args);
711
+ const sendBatch = Effect.fnUntraced(function* (messages, options) {
712
+ yield* (yield* tag).sendBatch(messages, options);
1159
713
  });
1160
- const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1161
- return yield* (yield* tag).scopedCall(stub, method, ...args);
714
+ const metrics = Effect.fnUntraced(function* () {
715
+ return yield* (yield* tag).metrics();
1162
716
  });
1163
717
  const unsafeRaw = Effect.fnUntraced(function* () {
1164
718
  return yield* (yield* tag).unsafeRaw;
1165
719
  });
1166
- const directMethods = makeDirectMethods(definition, {
1167
- call,
1168
- fetch,
1169
- get,
1170
- getByName
1171
- });
1172
- return Object.assign(tag, directMethods, {
1173
- id: definition.id,
1174
- methods: definition.methods,
1175
- make: definition.make,
720
+ return Object.assign(tag, {
721
+ id: queueDefinition.id,
722
+ message: queueDefinition.message,
723
+ make: queueDefinition.make,
1176
724
  layer,
1177
- newUniqueId,
1178
- idFromName,
1179
- idFromString,
1180
- get,
1181
- getByName,
1182
- jurisdiction,
1183
- fetch,
1184
- rpc,
1185
- call,
1186
- scopedCall,
725
+ send,
726
+ sendBatch,
727
+ metrics,
1187
728
  unsafeRaw
1188
729
  });
1189
730
  };
1190
- const DurableObject$1 = Tag$6;
1191
- const wrapHandlers = (definition, handlers) => {
1192
- const wrapped = {};
1193
- for (const key of Object.keys(definition.methods)) {
1194
- const handler = handlers[key];
1195
- wrapped[key] = (...args) => Effect.gen(function* () {
1196
- return yield* encodeSuccess(definition, key, yield* handler(...yield* decodeArgs(definition, key, args)));
1197
- });
1198
- }
1199
- return wrapped;
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
+ });
1200
737
  };
1201
- /**
1202
- * Helper for implementing handlers with the exact method shape of a definition.
1203
- */
1204
- const implement$3 = (_definition, handlers) => handlers;
738
+ const implement$7 = (_definition, handler) => handler;
1205
739
  //#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
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
1212
748
  });
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));
1256
- }
1257
- webSocketClose(socket, code, reason, wasClean) {
1258
- if (options.webSocketClose !== void 0) return this[RunSymbol](options.webSocketClose(fromWebSocket(socket), code, reason, wasClean));
1259
- }
1260
- webSocketError(socket, error) {
1261
- if (options.webSocketError !== void 0) return this[RunSymbol](options.webSocketError(fromWebSocket(socket), error));
1262
- }
1263
- }
1264
- defineEntrypointRpcMethods("Durable Object", EffectDurableObject.prototype, options.rpc, reservedMethodNames, (self, effect) => self[RunSymbol](effect));
1265
- return assumeEntrypointClass(EffectDurableObject);
1266
- };
1267
- const Tag$5 = Tag$6;
1268
- const method = method$1;
1269
- const implement$2 = implement$3;
1270
- //#endregion
1271
- //#region src/CloudflareOtlp.ts
1272
- var CloudflareOtlp_exports = /* @__PURE__ */ __exportAll({
1273
- CloudflareOtlpSettings: () => CloudflareOtlpSettings,
1274
- durableObjectLayer: () => durableObjectLayer,
1275
- instrumentDurableObjectOptions: () => instrumentDurableObjectOptions,
1276
- instrumentWorkerOptions: () => instrumentWorkerOptions,
1277
- layer: () => layer$6,
1278
- layerJson: () => layerJson,
1279
- layerProtobuf: () => layerProtobuf,
1280
- settingsConfig: () => settingsConfig,
1281
- settingsLayer: () => settingsLayer,
1282
- workerLayer: () => workerLayer
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))
1283
758
  });
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)
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))
1321
766
  });
1322
- /**
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
- * ```
1340
- */
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);
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);
1351
780
  });
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)
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
1365
802
  });
1366
- /**
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.
1373
- */
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);
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;
1390
831
  }
1391
- return headers;
1392
832
  };
1393
- const mergeHeaders = (common, signalSpecific) => {
1394
- const commonHeaders = parseHeaders(common);
1395
- const signalHeaders = parseHeaders(signalSpecific);
1396
- if (commonHeaders === void 0 && signalHeaders === void 0) return;
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) {
1397
837
  return {
1398
- ...commonHeaders,
1399
- ...signalHeaders
838
+ args: definition.args ?? [],
839
+ success: definition.success
1400
840
  };
1401
- };
1402
- const decodeHeaderComponent = (value) => {
1403
- try {
1404
- return decodeURIComponent(value);
1405
- } catch {
1406
- return value;
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
+ }))));
1407
863
  }
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
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
+ }))));
1417
883
  }
884
+ return encoded;
1418
885
  });
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
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$8,
961
+ makeClient: () => makeClient$5,
962
+ makeDirectMethods: () => makeDirectMethods$1
963
+ });
964
+ const TypeId$1 = "effect-cf/ServiceBinding";
965
+ const expectedServiceBinding = "Worker service binding with fetch()";
966
+ /**
967
+ * Failure raised when calling `fetch` on a service binding.
968
+ */
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({
980
+ binding: definition.binding,
981
+ cause
982
+ })
983
+ });
984
+ const rpc = (method, ...args) => Effect.gen(function* () {
985
+ const methodName = String(method);
986
+ return yield* invokeRpcMethod(service, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
987
+ binding: definition.binding,
988
+ method: methodName,
989
+ cause
990
+ }))), (cause) => new ServiceBindingRpcError({
991
+ binding: definition.binding,
992
+ method: methodName,
993
+ cause
994
+ }));
995
+ });
996
+ const decodeSuccess$2 = (methodName, value) => Effect.gen(function* () {
997
+ if (definition.definition === void 0) return value;
998
+ return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
999
+ binding: definition.binding,
1000
+ method: methodName,
1001
+ cause
1002
+ })));
1003
+ });
1004
+ const call = (method, ...args) => Effect.gen(function* () {
1005
+ const methodName = String(method);
1006
+ return yield* decodeSuccess$2(methodName, yield* resolve(yield* rpc(method, ...args)).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
1007
+ binding: definition.binding,
1008
+ method: methodName,
1009
+ cause
1010
+ }))));
1011
+ });
1012
+ const scopedCall = (method, ...args) => Effect.gen(function* () {
1013
+ return yield* decodeSuccess$2(String(method), yield* scoped(yield* rpc(method, ...args)));
1014
+ });
1015
+ const directMethods = makeDirectMethods$1(definition.definition, call);
1016
+ return Object.assign(directMethods, {
1017
+ fetch,
1018
+ rpc,
1019
+ call,
1020
+ scopedCall
1021
+ });
1022
+ };
1023
+ };
1024
+ const layer$8 = (tag, definition) => layer$11(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) => {
1079
+ const methods = {};
1080
+ if (rpcDefinition !== void 0) for (const methodName of Object.keys(rpcDefinition.methods)) methods[methodName] = (...args) => call(methodName, ...args);
1081
+ return methods;
1082
+ };
1083
+ //#endregion
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
1091
+ });
1092
+ const reservedMethodNames$3 = new Set([
1093
+ "constructor",
1094
+ "dup",
1095
+ "fetch",
1096
+ "connect",
1097
+ "queue",
1098
+ "scheduled",
1099
+ "tail",
1100
+ "tailStream",
1101
+ "test",
1102
+ "trace",
1103
+ "alarm",
1104
+ "webSocketMessage",
1105
+ "webSocketClose",
1106
+ "webSocketError"
1107
+ ]);
1108
+ /**
1109
+ * Defines a single RPC method schema in a worker definition.
1110
+ */
1111
+ const method$3 = method$4;
1112
+ /**
1113
+ * Creates a typed worker RPC definition plus helpers for implementation and bindings.
1114
+ *
1115
+ * @example
1116
+ * ```ts
1117
+ * const CounterWorker = WorkerDefinition.make("CounterWorker", {
1118
+ * increment: WorkerDefinition.method({
1119
+ * args: [Schema.Number],
1120
+ * success: Schema.Number,
1121
+ * }),
1122
+ * });
1123
+ * ```
1124
+ */
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, {
1129
+ ...options,
1130
+ rpc: wrapHandlers$1(definition, options.rpc)
1131
+ }) });
1132
+ };
1133
+ const make$7 = (id, methods) => Tag$8()(id, methods);
1134
+ const Tag$8 = () => (id, methods) => {
1135
+ const definition = makeDefinition$3(id, methods);
1136
+ const tag = Context.Service()(id);
1137
+ const bindingDefinition = (binding) => ({
1138
+ ...binding,
1139
+ definition
1140
+ });
1141
+ const layer = (binding) => layer$8(tag, bindingDefinition(binding));
1142
+ const fetch = (input, init) => Effect.gen(function* () {
1143
+ return yield* (yield* tag).fetch(input, init);
1144
+ });
1145
+ const rpc = (method, ...args) => Effect.gen(function* () {
1146
+ return yield* (yield* tag).rpc(method, ...args);
1147
+ });
1148
+ const call = (method, ...args) => Effect.gen(function* () {
1149
+ return yield* (yield* tag).call(method, ...args);
1150
+ });
1151
+ const scopedCall = (method, ...args) => Effect.gen(function* () {
1152
+ return yield* (yield* tag).scopedCall(method, ...args);
1153
+ });
1154
+ const directMethods = makeDirectMethods$1(definition, call);
1155
+ return Object.assign(tag, directMethods, {
1156
+ id: definition.id,
1157
+ methods: definition.methods,
1158
+ make: definition.make,
1159
+ layer,
1160
+ fetch,
1161
+ rpc,
1162
+ call,
1163
+ scopedCall
1164
+ });
1165
+ };
1166
+ const Worker = Tag$8;
1167
+ const wrapHandlers$1 = (definition, handlers) => {
1168
+ const wrapped = {};
1169
+ for (const key of Object.keys(definition.methods)) {
1170
+ const handler = handlers[key];
1171
+ wrapped[key] = (...args) => Effect.gen(function* () {
1172
+ return yield* encodeSuccess(definition, key, yield* handler(...yield* decodeArgs(definition, key, args)));
1173
+ });
1174
+ }
1175
+ return wrapped;
1176
+ };
1177
+ /**
1178
+ * Helper for implementing handlers with the exact method shape of a definition.
1179
+ */
1180
+ const implement$5 = (_definition, handlers) => handlers;
1181
+ //#endregion
1182
+ //#region src/internal/Clock.ts
1183
+ const maxTimerMillis = 2 ** 31 - 1;
1184
+ const nanosPerMilli = BigInt(1e6);
1185
+ const clock = {
1186
+ currentTimeMillisUnsafe: () => Date.now(),
1187
+ currentTimeMillis: Effect.sync(() => clock.currentTimeMillisUnsafe()),
1188
+ currentTimeNanosUnsafe: () => BigInt(Date.now()) * nanosPerMilli,
1189
+ currentTimeNanos: Effect.sync(() => clock.currentTimeNanosUnsafe()),
1190
+ sleep: (duration) => {
1191
+ const millis = Duration.toMillis(duration);
1192
+ if (millis <= 0) return Effect.yieldNow;
1193
+ return Effect.callback((resume) => {
1194
+ if (millis > maxTimerMillis) return;
1195
+ const handle = setTimeout(() => resume(Effect.void), millis);
1196
+ return Effect.sync(() => clearTimeout(handle));
1197
+ });
1198
+ }
1199
+ };
1200
+ const layer$7 = Layer.effect(Clock.Clock, Effect.succeed(clock));
1201
+ //#endregion
1202
+ //#region src/internal/Entrypoint.ts
1203
+ const provideEntrypointServices = (layer, services) => layer.pipe(Layer.provideMerge(services));
1204
+ const defineEntrypointRpcMethods = (target, prototype, rpc, reservedMethodNames, run) => {
1205
+ const methods = rpc ?? {};
1206
+ assertNoReservedMethods(target, methods, reservedMethodNames);
1207
+ for (const [key, method] of Object.entries(methods)) Object.defineProperty(prototype, key, {
1208
+ enumerable: true,
1209
+ value(...args) {
1210
+ return run(this, Effect.suspend(() => method(...args)));
1211
+ }
1212
+ });
1213
+ };
1214
+ const assumeEntrypointClass = (entrypoint) => entrypoint;
1215
+ //#endregion
1216
+ //#region src/internal/WorkerContext.ts
1217
+ const causeError = (cause) => new Error(Cause.pretty(cause));
1218
+ 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))));
1219
+ const fromExecutionContext = (ctx, runPromiseExit) => {
1220
+ const schedule = (effect, options, mode) => Effect.context().pipe(Effect.flatMap((context) => Effect.sync(() => {
1221
+ const runHandler = (cause) => runPromiseExit(Effect.scoped(Effect.provideContext(failureHandler(cause, options), context))).then((exit) => {
1222
+ if (Exit.isFailure(exit)) console.error("WorkerContext.waitUntil failure handler failed", Cause.pretty(exit.cause));
1223
+ });
1224
+ ctx.waitUntil(runPromiseExit(Effect.scoped(Effect.provideContext(effect, context))).then(async (exit) => {
1225
+ if (Exit.isSuccess(exit)) return;
1226
+ await runHandler(exit.cause);
1227
+ if (mode === "propagate") throw causeError(exit.cause);
1228
+ }));
1229
+ })));
1230
+ return {
1231
+ raw: ctx,
1232
+ waitUntil: (effect, options) => schedule(effect, options, options?.mode ?? "observe"),
1233
+ waitUntilPropagating: (effect, options) => schedule(effect, options, "propagate"),
1234
+ passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
1235
+ };
1236
+ };
1237
+ //#endregion
1238
+ //#region src/Worker.ts
1239
+ var Worker_exports = /* @__PURE__ */ __exportAll({
1240
+ ExecutionContext: () => ExecutionContext,
1241
+ NativeRequest: () => NativeRequest,
1242
+ Tag: () => Tag$7,
1243
+ WorkerContext: () => WorkerContext,
1244
+ implement: () => implement$4,
1245
+ isWebSocketUpgrade: () => isWebSocketUpgrade,
1246
+ make: () => make$6,
1247
+ makeFetchHandler: () => makeFetchHandler,
1248
+ method: () => method$2,
1249
+ renderHttpResponse: () => renderHttpResponse
1430
1250
  });
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);
1251
+ var ExecutionContext = class extends Context.Service()("effect-cf/ExecutionContext") {};
1252
+ var WorkerContext = class extends Context.Service()("effect-cf/WorkerContext") {};
1253
+ var NativeRequest = class extends Context.Service()("effect-cf/NativeRequest") {};
1254
+ const isWebSocketUpgrade = (request) => request.headers.get("Upgrade")?.toLowerCase() === "websocket";
1255
+ const reservedMethodNames$2 = new Set([
1256
+ "constructor",
1257
+ "dup",
1258
+ "fetch",
1259
+ "connect",
1260
+ "queue",
1261
+ "scheduled",
1262
+ "tail",
1263
+ "tailStream",
1264
+ "test",
1265
+ "trace",
1266
+ "alarm",
1267
+ "webSocketMessage",
1268
+ "webSocketClose",
1269
+ "webSocketError"
1270
+ ]);
1271
+ const RunSymbol$1 = Symbol.for("effect-cf/Worker/run");
1272
+ const renderHttpResponse = (effect) => Effect.flatMap(effect, (response) => Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
1273
+ const renderFetchSuccess = (effect) => Effect.flatMap(effect, (response) => response instanceof Response ? Effect.succeed(response) : Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
1274
+ const isWorkerOptions = (options) => typeof options === "object" && options !== null && ("eventLayer" in options || "fetch" in options || "queue" in options || "rpc" in options);
1275
+ function make$6(layer, optionsOrFetch) {
1276
+ const options = isWorkerOptions(optionsOrFetch) ? optionsOrFetch : { fetch: optionsOrFetch };
1277
+ class EffectWorker extends WorkerEntrypoint {
1278
+ runtime;
1279
+ constructor(ctx, env) {
1280
+ super(ctx, env);
1281
+ let runWaitUntilEffect = () => Promise.reject(/* @__PURE__ */ new Error("WorkerContext runtime is not initialized"));
1282
+ const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(layer$7, Layer.succeed(ExecutionContext, ctx), ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env))), Layer.succeed(WorkerContext, fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect))), Layer.succeed(WorkerEnvironment, env)));
1283
+ this.runtime = ManagedRuntime.make(runtimeLayer);
1284
+ runWaitUntilEffect = (effect) => this.runtime.runPromiseExit(effect);
1285
+ }
1286
+ [RunSymbol$1](effect, runOptions = {}) {
1287
+ const effectWithEventLayer = runOptions.eventLayer === false || options.eventLayer === void 0 ? effect : effect.pipe(Effect.provide(options.eventLayer, { local: true }));
1288
+ return this.runtime.runPromise(Effect.scoped(effectWithEventLayer));
1289
+ }
1290
+ fetch(request) {
1291
+ const fetchHandler = options.fetch;
1292
+ if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
1293
+ const requestServices = Layer.mergeAll(Layer.succeed(NativeRequest, request), Layer.succeed(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromWeb(request)));
1294
+ return this[RunSymbol$1](renderFetchSuccess(fetchHandler).pipe(Effect.provide(requestServices)));
1295
+ }
1296
+ queue(batch) {
1297
+ const queueHandler = options.queue;
1298
+ if (queueHandler === void 0) return Promise.resolve();
1299
+ const messages = batch.messages.map((message) => fromMessage(message, message.body));
1300
+ return this[RunSymbol$1](queueHandler(fromMessageBatch(batch, messages)));
1301
+ }
1302
+ }
1303
+ defineEntrypointRpcMethods("Worker", EffectWorker.prototype, options.rpc, reservedMethodNames$2, (self, effect) => self[RunSymbol$1](effect));
1304
+ return assumeEntrypointClass(EffectWorker);
1305
+ }
1306
+ const makeFetchHandler = (layer, options) => {
1307
+ const WorkerClass = make$6(layer, options);
1308
+ return { fetch: (request, env, ctx) => Promise.resolve(new WorkerClass(ctx, env).fetch(request)) };
1309
+ };
1310
+ const Tag$7 = Tag$8;
1311
+ const method$2 = method$3;
1312
+ const implement$4 = implement$5;
1313
+ //#endregion
1314
+ //#region src/DurableObjectNamespace.ts
1315
+ var DurableObjectNamespace_exports = /* @__PURE__ */ __exportAll({
1316
+ DurableObjectFetchError: () => DurableObjectFetchError,
1317
+ DurableObjectRpcError: () => DurableObjectRpcError,
1318
+ isDurableObjectNamespaceClient: () => isDurableObjectNamespaceClient,
1319
+ layer: () => layer$6,
1320
+ makeClient: () => makeClient$4,
1321
+ makeDirectMethods: () => makeDirectMethods
1438
1322
  });
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;
1323
+ const expectedDurableObjectNamespace = "Durable Object namespace binding with getByName(), get(), idFromName(), idFromString(), newUniqueId(), and jurisdiction()";
1324
+ /**
1325
+ * Failure raised when invoking an RPC method on a Durable Object stub.
1326
+ */
1327
+ var DurableObjectRpcError = class extends Data.TaggedError("DurableObjectRpcError") {};
1328
+ /**
1329
+ * Failure raised when forwarding a request to a Durable Object stub.
1330
+ */
1331
+ var DurableObjectFetchError = class extends Data.TaggedError("DurableObjectFetchError") {};
1332
+ const hasFunction$1 = (value, key) => typeof Reflect.get(value, key) === "function";
1333
+ 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");
1334
+ const makeClient$4 = (definition) => {
1335
+ return (namespace) => {
1336
+ const newUniqueId = (options) => Effect.sync(() => namespace.newUniqueId(options));
1337
+ const idFromName = (name) => Effect.sync(() => namespace.idFromName(name));
1338
+ const idFromString = (id) => Effect.sync(() => namespace.idFromString(id));
1339
+ const get = (id, options) => Effect.sync(() => namespace.get(id, options));
1340
+ const getByName = (name, options) => Effect.sync(() => namespace.getByName(name, options));
1341
+ const jurisdiction = (value) => Effect.sync(() => namespace.jurisdiction(value));
1342
+ const fetch = (stub, input, init) => Effect.tryPromise({
1343
+ try: () => stub.fetch(input, init),
1344
+ catch: (cause) => new DurableObjectFetchError({
1345
+ binding: definition.binding,
1346
+ cause
1347
+ })
1348
+ });
1349
+ const rpc = (stub, method, ...args) => Effect.gen(function* () {
1350
+ const methodName = String(method);
1351
+ return yield* invokeRpcMethod(stub, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1352
+ binding: definition.binding,
1353
+ method: methodName,
1354
+ cause
1355
+ }))), (cause) => new DurableObjectRpcError({
1356
+ binding: definition.binding,
1357
+ method: methodName,
1358
+ cause
1359
+ }));
1360
+ });
1361
+ const decodeSuccess$1 = (methodName, value) => Effect.gen(function* () {
1362
+ if (definition.definition === void 0) return value;
1363
+ return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1364
+ binding: definition.binding,
1365
+ method: methodName,
1366
+ cause
1367
+ })));
1368
+ });
1369
+ const call = (stub, method, ...args) => Effect.gen(function* () {
1370
+ const methodName = String(method);
1371
+ return yield* decodeSuccess$1(methodName, yield* resolve(yield* rpc(stub, method, ...args)).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
1372
+ binding: definition.binding,
1373
+ method: methodName,
1374
+ cause
1375
+ }))));
1376
+ });
1377
+ const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1378
+ return yield* decodeSuccess$1(String(method), yield* scoped(yield* rpc(stub, method, ...args)));
1379
+ });
1380
+ const directMethods = makeDirectMethods(definition.definition, {
1381
+ call,
1382
+ fetch,
1383
+ get,
1384
+ getByName
1385
+ });
1386
+ return Object.assign(directMethods, {
1387
+ newUniqueId,
1388
+ idFromName,
1389
+ idFromString,
1390
+ get,
1391
+ getByName,
1392
+ jurisdiction,
1393
+ fetch,
1394
+ rpc,
1395
+ call,
1396
+ scopedCall,
1397
+ unsafeRaw: Effect.succeed(namespace)
1398
+ });
1399
+ };
1444
1400
  };
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)));
1401
+ const layer$6 = (tag, definition) => layer$11(tag, definition.binding, (value) => isDurableObjectNamespaceClient(value), makeClient$4(definition), { expected: expectedDurableObjectNamespace });
1402
+ const makeDirectMethods = (rpcDefinition, helpers) => {
1403
+ const methods = {};
1404
+ if (rpcDefinition !== void 0) {
1405
+ for (const methodName of Object.keys(rpcDefinition.methods)) methods[methodName] = (stub, ...args) => helpers.call(stub, methodName, ...args);
1406
+ const makeClient = (getStub) => {
1407
+ const client = { fetch: (input, init) => Effect.gen(function* () {
1408
+ const stub = yield* getStub();
1409
+ return yield* helpers.fetch(stub, input, init);
1410
+ }) };
1411
+ for (const methodName of Object.keys(rpcDefinition.methods)) client[methodName] = (...args) => Effect.gen(function* () {
1412
+ const stub = yield* getStub();
1413
+ return yield* helpers.call(stub, methodName, ...args);
1414
+ });
1415
+ return client;
1416
+ };
1417
+ methods.byName = (name, options) => makeClient(() => helpers.getByName(name, options));
1418
+ methods.byId = (id, options) => makeClient(() => helpers.get(id, options));
1496
1419
  }
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"
1420
+ return methods;
1421
+ };
1422
+ //#endregion
1423
+ //#region src/DurableObjectDefinition.ts
1424
+ var DurableObjectDefinition_exports = /* @__PURE__ */ __exportAll({
1425
+ DurableObject: () => DurableObject$1,
1426
+ Tag: () => Tag$6,
1427
+ implement: () => implement$3,
1428
+ make: () => make$5,
1429
+ method: () => method$1
1522
1430
  });
1431
+ const reservedMethodNames$1 = new Set([
1432
+ "constructor",
1433
+ "dup",
1434
+ "fetch",
1435
+ "alarm",
1436
+ "webSocketMessage",
1437
+ "webSocketClose",
1438
+ "webSocketError"
1439
+ ]);
1523
1440
  /**
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.
1441
+ * Defines a single RPC method schema in a Durable Object definition.
1528
1442
  */
1529
- const workerLayer = (options = {}) => makeLayer(options, {
1530
- "cloudflare.resource_type": "worker",
1531
- "cloudflare.worker.name": options.workerName
1532
- });
1443
+ const method$1 = method$4;
1533
1444
  /**
1534
- * OTLP layer with Cloudflare Durable Object resource attributes.
1445
+ * Creates a Durable Object RPC definition plus implementation/binding helpers.
1535
1446
  *
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.
1447
+ * @example
1448
+ * ```ts
1449
+ * const ChatRoom = DurableObjectDefinition.make("ChatRoom", {
1450
+ * postMessage: DurableObjectDefinition.method({
1451
+ * args: [Schema.String],
1452
+ * success: Schema.Void,
1453
+ * }),
1454
+ * });
1455
+ * ```
1539
1456
  */
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
- } });
1457
+ const makeDefinition$2 = (id, methods) => {
1458
+ assertNoReservedMethods("Durable Object", methods, reservedMethodNames$1);
1459
+ const definition = make$8(id, methods);
1460
+ return Object.assign(definition, { make: (layer, options) => make$4(layer, {
1461
+ ...options,
1462
+ rpc: wrapHandlers(definition, options.rpc)
1463
+ }) });
1552
1464
  };
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
- };
1465
+ const make$5 = (id, methods) => Tag$6()(id, methods);
1466
+ const Tag$6 = () => (id, methods) => {
1467
+ const definition = makeDefinition$2(id, methods);
1468
+ const tag = Context.Service()(id);
1469
+ const bindingDefinition = (binding) => ({
1470
+ ...binding,
1471
+ definition
1472
+ });
1473
+ const layer = (binding) => layer$6(tag, bindingDefinition(binding));
1474
+ const newUniqueId = Effect.fnUntraced(function* (options) {
1475
+ return yield* (yield* tag).newUniqueId(options);
1476
+ });
1477
+ const idFromName = Effect.fnUntraced(function* (name) {
1478
+ return yield* (yield* tag).idFromName(name);
1479
+ });
1480
+ const idFromString = Effect.fnUntraced(function* (value) {
1481
+ return yield* (yield* tag).idFromString(value);
1482
+ });
1483
+ const get = Effect.fnUntraced(function* (objectId, options) {
1484
+ return yield* (yield* tag).get(objectId, options);
1485
+ });
1486
+ const getByName = Effect.fnUntraced(function* (name, options) {
1487
+ return yield* (yield* tag).getByName(name, options);
1488
+ });
1489
+ const jurisdiction = Effect.fnUntraced(function* (value) {
1490
+ return yield* (yield* tag).jurisdiction(value);
1491
+ });
1492
+ const fetch = (stub, input, init) => Effect.gen(function* () {
1493
+ return yield* (yield* tag).fetch(stub, input, init);
1494
+ });
1495
+ const rpc = (stub, method, ...args) => Effect.gen(function* () {
1496
+ return yield* (yield* tag).rpc(stub, method, ...args);
1497
+ });
1498
+ const call = (stub, method, ...args) => Effect.gen(function* () {
1499
+ return yield* (yield* tag).call(stub, method, ...args);
1500
+ });
1501
+ const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1502
+ return yield* (yield* tag).scopedCall(stub, method, ...args);
1503
+ });
1504
+ const unsafeRaw = Effect.fnUntraced(function* () {
1505
+ return yield* (yield* tag).unsafeRaw;
1506
+ });
1507
+ const directMethods = makeDirectMethods(definition, {
1508
+ call,
1509
+ fetch,
1510
+ get,
1511
+ getByName
1512
+ });
1513
+ return Object.assign(tag, directMethods, {
1514
+ id: definition.id,
1515
+ methods: definition.methods,
1516
+ make: definition.make,
1517
+ layer,
1518
+ newUniqueId,
1519
+ idFromName,
1520
+ idFromString,
1521
+ get,
1522
+ getByName,
1523
+ jurisdiction,
1524
+ fetch,
1525
+ rpc,
1526
+ call,
1527
+ scopedCall,
1528
+ unsafeRaw
1529
+ });
1530
+ };
1531
+ const DurableObject$1 = Tag$6;
1532
+ const wrapHandlers = (definition, handlers) => {
1533
+ const wrapped = {};
1534
+ for (const key of Object.keys(definition.methods)) {
1535
+ const handler = handlers[key];
1536
+ wrapped[key] = (...args) => Effect.gen(function* () {
1537
+ return yield* encodeSuccess(definition, key, yield* handler(...yield* decodeArgs(definition, key, args)));
1538
+ });
1539
+ }
1540
+ return wrapped;
1569
1541
  };
1570
1542
  /**
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.
1543
+ * Helper for implementing handlers with the exact method shape of a definition.
1576
1544
  */
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
- };
1545
+ const implement$3 = (_definition, handlers) => handlers;
1595
1546
  //#endregion
1596
- //#region src/D1.ts
1597
- var D1_exports = /* @__PURE__ */ __exportAll({
1598
- Service: () => Service,
1599
- make: () => make$4
1547
+ //#region src/DurableObject.ts
1548
+ var DurableObject_exports = /* @__PURE__ */ __exportAll({
1549
+ Tag: () => Tag$5,
1550
+ implement: () => implement$2,
1551
+ make: () => make$4,
1552
+ method: () => method
1600
1553
  });
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);
1554
+ const reservedMethodNames = new Set([
1555
+ "constructor",
1556
+ "dup",
1557
+ "fetch",
1558
+ "alarm",
1559
+ "webSocketMessage",
1560
+ "webSocketClose",
1561
+ "webSocketError"
1562
+ ]);
1563
+ const RunSymbol = Symbol.for("effect-cf/DurableObject/run");
1612
1564
  /**
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
- * ```
1565
+ * Creates a Durable Object class backed by a single managed Effect runtime.
1626
1566
  */
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
- });
1567
+ const make$4 = (layer, options = {}) => {
1568
+ class EffectDurableObject extends DurableObject {
1569
+ runtime;
1570
+ constructor(state, env) {
1571
+ super(state, env);
1572
+ const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(layer$7, Layer.succeed(DurableObjectState, fromDurableObjectState(state)), Layer.succeed(WorkerEnvironment, env)));
1573
+ this.runtime = ManagedRuntime.make(runtimeLayer);
1574
+ const initialize = options.initialize;
1575
+ if (initialize !== void 0) state.waitUntil(this[RunSymbol](initialize, { eventLayer: false }));
1576
+ }
1577
+ [RunSymbol](effect, runOptions = {}) {
1578
+ const effectWithEventLayer = runOptions.eventLayer === false || options.eventLayer === void 0 ? effect : effect.pipe(Effect.provide(options.eventLayer, { local: true }));
1579
+ return this.runtime.runPromise(Effect.scoped(effectWithEventLayer));
1580
+ }
1581
+ fetch(request) {
1582
+ const fetchHandler = options.fetch;
1583
+ if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
1584
+ return this[RunSymbol](Effect.provideService(fetchHandler, NativeRequest, request));
1585
+ }
1586
+ alarm(alarmInfo) {
1587
+ const logicalAlarms = options.alarms?.pipe(Effect.asVoid);
1588
+ const rawAlarm = options.alarm?.(alarmInfo);
1589
+ if (logicalAlarms !== void 0 && rawAlarm !== void 0) return this[RunSymbol](Effect.gen(function* () {
1590
+ yield* logicalAlarms;
1591
+ yield* rawAlarm;
1592
+ }));
1593
+ if (logicalAlarms !== void 0) return this[RunSymbol](logicalAlarms);
1594
+ if (rawAlarm !== void 0) return this[RunSymbol](rawAlarm);
1595
+ }
1596
+ webSocketMessage(socket, message) {
1597
+ if (options.webSocketMessage !== void 0) return this[RunSymbol](options.webSocketMessage(fromWebSocket(socket), message));
1598
+ }
1599
+ webSocketClose(socket, code, reason, wasClean) {
1600
+ if (options.webSocketClose !== void 0) return this[RunSymbol](options.webSocketClose(fromWebSocket(socket), code, reason, wasClean));
1601
+ }
1602
+ webSocketError(socket, error) {
1603
+ if (options.webSocketError !== void 0) return this[RunSymbol](options.webSocketError(fromWebSocket(socket), error));
1604
+ }
1605
+ }
1606
+ defineEntrypointRpcMethods("Durable Object", EffectDurableObject.prototype, options.rpc, reservedMethodNames, (self, effect) => self[RunSymbol](effect));
1607
+ return assumeEntrypointClass(EffectDurableObject);
1641
1608
  };
1609
+ const Tag$5 = Tag$6;
1610
+ const method = method$1;
1611
+ const implement$2 = implement$3;
1642
1612
  //#endregion
1643
1613
  //#region src/DurableObjectAlarm.ts
1644
1614
  var DurableObjectAlarm_exports = /* @__PURE__ */ __exportAll({
@@ -2205,7 +2175,7 @@ const makeClient$3 = (definition) => (images) => {
2205
2175
  unsafeRaw: Effect.succeed(images)
2206
2176
  };
2207
2177
  };
2208
- const layer$3 = (tag, definition) => layer$10(tag, definition.binding, isImagesBinding, makeClient$3(definition), { expected: expectedImagesBinding });
2178
+ const layer$3 = (tag, definition) => layer$11(tag, definition.binding, isImagesBinding, makeClient$3(definition), { expected: expectedImagesBinding });
2209
2179
  const make$3 = (id) => Tag$4()(id);
2210
2180
  const Tag$4 = () => (id) => {
2211
2181
  const tag = Context.Service()(id);
@@ -2300,7 +2270,7 @@ const makeClient$2 = (definition) => {
2300
2270
  unsafeRaw: Effect.succeed(kv)
2301
2271
  });
2302
2272
  };
2303
- const layer$2 = (tag, definition) => layer$10(tag, definition.binding, isKvNamespace, makeClient$2(definition), { expected: expectedKvNamespace });
2273
+ const layer$2 = (tag, definition) => layer$11(tag, definition.binding, isKvNamespace, makeClient$2(definition), { expected: expectedKvNamespace });
2304
2274
  const makeDefinition$1 = (id, definition) => {
2305
2275
  const kvDefinition = {
2306
2276
  id,
@@ -2417,7 +2387,7 @@ const makeClient$1 = (definition) => {
2417
2387
  };
2418
2388
  };
2419
2389
  };
2420
- const layer$1 = (tag, definition) => layer$10(tag, definition.binding, isR2Bucket, makeClient$1(definition), { expected: expectedR2Bucket });
2390
+ const layer$1 = (tag, definition) => layer$11(tag, definition.binding, isR2Bucket, makeClient$1(definition), { expected: expectedR2Bucket });
2421
2391
  const make$2 = (id) => Tag$2()(id);
2422
2392
  const Tag$2 = () => (id) => {
2423
2393
  const tag = Context.Service()(id);
@@ -2503,7 +2473,7 @@ const makeClient = (definition) => {
2503
2473
  unsafeRaw: Effect.succeed(workflow)
2504
2474
  });
2505
2475
  };
2506
- const layer = (tag, definition) => layer$10(tag, definition.binding, (value) => isWorkflow(value), makeClient(definition), { expected: expectedWorkflow });
2476
+ const layer = (tag, definition) => layer$11(tag, definition.binding, (value) => isWorkflow(value), makeClient(definition), { expected: expectedWorkflow });
2507
2477
  //#endregion
2508
2478
  //#region src/WorkflowDefinition.ts
2509
2479
  var WorkflowDefinition_exports = /* @__PURE__ */ __exportAll({
@@ -2524,7 +2494,7 @@ const make$1 = (id, definition) => Tag$1()(id, definition);
2524
2494
  const Tag$1 = () => (id, definition) => {
2525
2495
  const workflowDefinition = makeDefinition(id, definition);
2526
2496
  const tag = Context.Service()(id);
2527
- const layer$11 = (binding) => layer(tag, {
2497
+ const layer$12 = (binding) => layer(tag, {
2528
2498
  ...binding,
2529
2499
  payload: definition.payload,
2530
2500
  result: definition.result
@@ -2546,7 +2516,7 @@ const Tag$1 = () => (id, definition) => {
2546
2516
  payload: workflowDefinition.payload,
2547
2517
  result: workflowDefinition.result,
2548
2518
  make: workflowDefinition.make,
2549
- layer: layer$11,
2519
+ layer: layer$12,
2550
2520
  create,
2551
2521
  createBatch,
2552
2522
  get,