effect-cf 0.35.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +2 -0
- package/dist/ComputerWorkspace.d.mts +1 -1
- package/dist/ComputerWorkspace.mjs +1 -1
- package/dist/DurableObjectState-CpgAmFqo.d.mts +244 -0
- package/dist/{DurableObjectState-DcqElJ4e.mjs → DurableObjectState-DLL0YgBd.mjs} +3 -60
- package/dist/Mcp.d.mts +122 -0
- package/dist/Mcp.mjs +270 -0
- package/dist/Vitest.d.mts +2 -2
- package/dist/Vitest.mjs +2 -1
- package/dist/{DurableObjectState-DpYdNZgT.d.mts → Worker-Dl6_Pijl.d.mts} +2 -242
- package/dist/Worker-XsGJsCJX.mjs +885 -0
- package/dist/WorkerContext-Yobnfw-K.mjs +60 -0
- package/dist/{WorkflowBinding-Cn3AuUyP.d.mts → WorkflowBinding-CvJT9hB5.d.mts} +1 -1
- package/dist/index.d.mts +22 -3
- package/dist/index.mjs +114 -979
- package/package.json +12 -1
- package/src/DurableObjectAlarm.ts +80 -30
- package/src/Mcp.ts +531 -0
|
@@ -0,0 +1,885 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { a as WorkerEnvironment, i as WorkerConfig, t as causeMessage } from "./ErrorMessage-Byx2OgNd.mjs";
|
|
3
|
+
import { n as Service$1, r as layer$2 } from "./Binding-C82jRhdr.mjs";
|
|
4
|
+
import { t as fromExecutionContext } from "./WorkerContext-Yobnfw-K.mjs";
|
|
5
|
+
import { Cause, Clock, ConfigProvider, Context, Data, Effect, Exit, Layer, ManagedRuntime, Option, Predicate, References, Schema, Tracer } from "effect";
|
|
6
|
+
import { HttpEffect, HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
7
|
+
import { OtlpExporter } from "effect/unstable/observability";
|
|
8
|
+
import { RpcStub, RpcTarget, WorkerEntrypoint } from "cloudflare:workers";
|
|
9
|
+
//#region src/QueueBinding.ts
|
|
10
|
+
var QueueBinding_exports = /* @__PURE__ */ __exportAll({
|
|
11
|
+
QueueOperationError: () => QueueOperationError,
|
|
12
|
+
isQueue: () => isQueue,
|
|
13
|
+
layer: () => layer$1,
|
|
14
|
+
makeClient: () => makeClient$1
|
|
15
|
+
});
|
|
16
|
+
const expectedQueueProducer = "Queue producer binding with send(); optional sendBatch()/metrics()";
|
|
17
|
+
var QueueOperationError = class extends Data.TaggedError("QueueOperationError") {};
|
|
18
|
+
const tryQueuePromise = (binding, operation, evaluate) => Effect.tryPromise({
|
|
19
|
+
try: evaluate,
|
|
20
|
+
catch: (cause) => new QueueOperationError({
|
|
21
|
+
binding,
|
|
22
|
+
operation,
|
|
23
|
+
cause,
|
|
24
|
+
message: `Cloudflare queue binding "${binding}" operation "${operation}" failed`
|
|
25
|
+
})
|
|
26
|
+
});
|
|
27
|
+
const isQueue = (value) => Predicate.hasProperty(value, "send") && Predicate.isFunction(value.send);
|
|
28
|
+
const makeClient$1 = (definition) => {
|
|
29
|
+
const encodeMessage = Schema.encodeEffect(definition.message);
|
|
30
|
+
return (queue) => ({
|
|
31
|
+
send: Effect.fn("QueueBinding.send", { attributes: {
|
|
32
|
+
binding: definition.binding,
|
|
33
|
+
operation: "send"
|
|
34
|
+
} })(function* (message, options) {
|
|
35
|
+
const encoded = yield* encodeMessage(message);
|
|
36
|
+
yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
|
|
37
|
+
}),
|
|
38
|
+
sendBatch: Effect.fn("QueueBinding.sendBatch", { attributes: {
|
|
39
|
+
binding: definition.binding,
|
|
40
|
+
operation: "sendBatch"
|
|
41
|
+
} })(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) return yield* new QueueOperationError({
|
|
49
|
+
binding: definition.binding,
|
|
50
|
+
operation: "sendBatch",
|
|
51
|
+
cause: /* @__PURE__ */ new Error(`Queue binding "${definition.binding}" does not provide sendBatch()`),
|
|
52
|
+
message: `Cloudflare queue binding "${definition.binding}" does not provide sendBatch()`
|
|
53
|
+
});
|
|
54
|
+
yield* tryQueuePromise(definition.binding, "sendBatch", () => sendBatch.call(queue, encodedMessages, options));
|
|
55
|
+
}),
|
|
56
|
+
metrics: () => {
|
|
57
|
+
const metrics = queue.metrics;
|
|
58
|
+
if (metrics === void 0) return Effect.fail(new QueueOperationError({
|
|
59
|
+
binding: definition.binding,
|
|
60
|
+
operation: "metrics",
|
|
61
|
+
cause: /* @__PURE__ */ new Error(`Queue binding "${definition.binding}" does not provide metrics()`),
|
|
62
|
+
message: `Cloudflare queue binding "${definition.binding}" does not provide metrics()`
|
|
63
|
+
}));
|
|
64
|
+
return tryQueuePromise(definition.binding, "metrics", () => metrics.call(queue));
|
|
65
|
+
},
|
|
66
|
+
rawUnsafe: Effect.succeed(queue)
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const layer$1 = (tag, definition) => layer$2(tag, definition.binding, (value) => isQueue(value), makeClient$1(definition), { expected: expectedQueueProducer });
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/QueueDefinition.ts
|
|
72
|
+
var QueueDefinition_exports = /* @__PURE__ */ __exportAll({
|
|
73
|
+
Queue: () => Queue$1,
|
|
74
|
+
Tag: () => Tag$2,
|
|
75
|
+
implement: () => implement$2,
|
|
76
|
+
make: () => make$3
|
|
77
|
+
});
|
|
78
|
+
const makeDefinition$1 = (id, definition) => {
|
|
79
|
+
const queueDefinition = {
|
|
80
|
+
id,
|
|
81
|
+
message: definition.message
|
|
82
|
+
};
|
|
83
|
+
return Object.assign(queueDefinition, { make: (layer, options) => make(layer, {
|
|
84
|
+
...options,
|
|
85
|
+
queue: wrapHandler(queueDefinition, options.queue)
|
|
86
|
+
}) });
|
|
87
|
+
};
|
|
88
|
+
const make$3 = (id, definition) => Tag$2()(id, definition);
|
|
89
|
+
const Tag$2 = () => (id, definition) => {
|
|
90
|
+
const queueDefinition = makeDefinition$1(id, definition);
|
|
91
|
+
const tag = Context.Service()(`effect-cf/Queue/${id}`);
|
|
92
|
+
const layer = (binding) => layer$1(tag, {
|
|
93
|
+
...binding,
|
|
94
|
+
message: definition.message
|
|
95
|
+
});
|
|
96
|
+
const send = Effect.fnUntraced(function* (message, options) {
|
|
97
|
+
yield* (yield* tag).send(message, options);
|
|
98
|
+
});
|
|
99
|
+
const sendBatch = Effect.fnUntraced(function* (messages, options) {
|
|
100
|
+
yield* (yield* tag).sendBatch(messages, options);
|
|
101
|
+
});
|
|
102
|
+
const metrics = Effect.fnUntraced(function* () {
|
|
103
|
+
return yield* (yield* tag).metrics();
|
|
104
|
+
});
|
|
105
|
+
const rawUnsafe = Effect.flatMap(tag, (queue) => queue.rawUnsafe);
|
|
106
|
+
return Object.assign(tag, {
|
|
107
|
+
id: queueDefinition.id,
|
|
108
|
+
message: queueDefinition.message,
|
|
109
|
+
make: queueDefinition.make,
|
|
110
|
+
layer,
|
|
111
|
+
send,
|
|
112
|
+
sendBatch,
|
|
113
|
+
metrics,
|
|
114
|
+
rawUnsafe
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
const Queue$1 = Tag$2;
|
|
118
|
+
const wrapHandler = (definition, handler) => {
|
|
119
|
+
const decodeBody = Schema.decodeUnknownEffect(definition.message);
|
|
120
|
+
return Effect.fnUntraced(function* (batch) {
|
|
121
|
+
yield* handler(yield* decodeBatch(batch.raw, decodeBody));
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
const implement$2 = (_definition, handler) => handler;
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/Queue.ts
|
|
127
|
+
var Queue_exports = /* @__PURE__ */ __exportAll({
|
|
128
|
+
QueueMessageDecodeError: () => QueueMessageDecodeError,
|
|
129
|
+
Tag: () => Tag$1,
|
|
130
|
+
decodeBatch: () => decodeBatch,
|
|
131
|
+
fromMessage: () => fromMessage,
|
|
132
|
+
fromMessageBatch: () => fromMessageBatch,
|
|
133
|
+
implement: () => implement$1
|
|
134
|
+
});
|
|
135
|
+
var QueueMessageDecodeError = class extends Data.TaggedError("QueueMessageDecodeError") {
|
|
136
|
+
get message() {
|
|
137
|
+
return `Queue "${this.queue}" failed to decode message "${this.messageId}" at index ${this.index}: ${causeMessage(this.cause)}`;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const fromMessage = (message, body) => ({
|
|
141
|
+
raw: message,
|
|
142
|
+
id: message.id,
|
|
143
|
+
timestamp: message.timestamp,
|
|
144
|
+
body,
|
|
145
|
+
attempts: message.attempts,
|
|
146
|
+
ack: Effect.sync(() => message.ack()),
|
|
147
|
+
retry: (options) => Effect.sync(() => message.retry(options))
|
|
148
|
+
});
|
|
149
|
+
const fromMessageBatch = (batch, messages) => ({
|
|
150
|
+
raw: batch,
|
|
151
|
+
messages,
|
|
152
|
+
queue: batch.queue,
|
|
153
|
+
metadata: batch.metadata,
|
|
154
|
+
ackAll: Effect.sync(() => batch.ackAll()),
|
|
155
|
+
retryAll: (options) => Effect.sync(() => batch.retryAll(options))
|
|
156
|
+
});
|
|
157
|
+
const decodeBatch = (batch, decodeBody) => Effect.gen(function* () {
|
|
158
|
+
const messages = [];
|
|
159
|
+
for (let index = 0; index < batch.messages.length; index++) {
|
|
160
|
+
const message = batch.messages[index];
|
|
161
|
+
const body = yield* decodeBody(message.body).pipe(Effect.mapError((cause) => new QueueMessageDecodeError({
|
|
162
|
+
queue: batch.queue,
|
|
163
|
+
messageId: message.id,
|
|
164
|
+
index,
|
|
165
|
+
cause
|
|
166
|
+
})));
|
|
167
|
+
messages.push(fromMessage(message, body));
|
|
168
|
+
}
|
|
169
|
+
return fromMessageBatch(batch, messages);
|
|
170
|
+
});
|
|
171
|
+
const Tag$1 = Tag$2;
|
|
172
|
+
const implement$1 = implement$2;
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/RpcDefinition.ts
|
|
175
|
+
var RpcDefinition_exports = /* @__PURE__ */ __exportAll({
|
|
176
|
+
RpcArgumentCountError: () => RpcArgumentCountError,
|
|
177
|
+
RpcArgumentDecodeError: () => RpcArgumentDecodeError,
|
|
178
|
+
RpcArgumentEncodeError: () => RpcArgumentEncodeError,
|
|
179
|
+
RpcReservedMethodNameError: () => RpcReservedMethodNameError,
|
|
180
|
+
RpcSuccessDecodeError: () => RpcSuccessDecodeError,
|
|
181
|
+
RpcSuccessEncodeError: () => RpcSuccessEncodeError,
|
|
182
|
+
assertNoReservedMethods: () => assertNoReservedMethods,
|
|
183
|
+
decodeArgs: () => decodeArgs,
|
|
184
|
+
decodeSuccess: () => decodeSuccess,
|
|
185
|
+
decodeWireError: () => decodeWireError,
|
|
186
|
+
encodeArgs: () => encodeArgs,
|
|
187
|
+
encodeSuccess: () => encodeSuccess,
|
|
188
|
+
encodeWireError: () => encodeWireError,
|
|
189
|
+
isWireError: () => isWireError,
|
|
190
|
+
make: () => make$2,
|
|
191
|
+
method: () => method$1,
|
|
192
|
+
reservedMethodNames: () => reservedMethodNames$2
|
|
193
|
+
});
|
|
194
|
+
var RpcReservedMethodNameError = class extends Data.TaggedError("RpcReservedMethodNameError") {
|
|
195
|
+
get message() {
|
|
196
|
+
return `${this.definition} RPC method "${this.method}" is reserved by Cloudflare Workers RPC`;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
var RpcArgumentCountError = class extends Schema.TaggedError()("RpcArgumentCountError", {
|
|
200
|
+
definition: Schema.String,
|
|
201
|
+
method: Schema.String,
|
|
202
|
+
expected: Schema.Number,
|
|
203
|
+
actual: Schema.Number
|
|
204
|
+
}) {
|
|
205
|
+
get message() {
|
|
206
|
+
return `${this.definition} RPC method "${this.method}" expected ${this.expected} arguments but received ${this.actual}`;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
var RpcArgumentDecodeError = class extends Schema.TaggedError()("RpcArgumentDecodeError", {
|
|
210
|
+
definition: Schema.String,
|
|
211
|
+
method: Schema.String,
|
|
212
|
+
cause: Schema.Defect()
|
|
213
|
+
}) {
|
|
214
|
+
get message() {
|
|
215
|
+
return `${this.definition} RPC method "${this.method}" argument decode failed: ${causeMessage(this.cause)}`;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
var RpcArgumentEncodeError = class extends Data.TaggedError("RpcArgumentEncodeError") {
|
|
219
|
+
get message() {
|
|
220
|
+
return `${this.definition} RPC method "${this.method}" argument encode failed: ${causeMessage(this.cause)}`;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
var RpcSuccessDecodeError = class extends Data.TaggedError("RpcSuccessDecodeError") {
|
|
224
|
+
get message() {
|
|
225
|
+
return `${this.definition} RPC method "${this.method}" success decode failed: ${causeMessage(this.cause)}`;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
var RpcSuccessEncodeError = class extends Schema.TaggedError()("RpcSuccessEncodeError", {
|
|
229
|
+
definition: Schema.String,
|
|
230
|
+
method: Schema.String,
|
|
231
|
+
cause: Schema.Defect()
|
|
232
|
+
}) {
|
|
233
|
+
get message() {
|
|
234
|
+
return `${this.definition} RPC method "${this.method}" success encode failed: ${causeMessage(this.cause)}`;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
const WireErrorSchema = Schema.Union([
|
|
238
|
+
RpcArgumentCountError,
|
|
239
|
+
RpcArgumentDecodeError,
|
|
240
|
+
RpcSuccessEncodeError
|
|
241
|
+
]);
|
|
242
|
+
const wireErrorKey = "effect-cf/RpcDefinition/wireError";
|
|
243
|
+
const isWireError = (error) => error instanceof RpcArgumentCountError || error instanceof RpcArgumentDecodeError || error instanceof RpcSuccessEncodeError;
|
|
244
|
+
/**
|
|
245
|
+
* Encodes package RPC errors into a plain `Error` envelope so their tags
|
|
246
|
+
* survive Cloudflare RPC serialization, which drops custom error properties.
|
|
247
|
+
*/
|
|
248
|
+
const encodeWireError = (error) => {
|
|
249
|
+
if (!isWireError(error)) return error;
|
|
250
|
+
try {
|
|
251
|
+
return new Error(JSON.stringify({ [wireErrorKey]: Schema.encodeSync(WireErrorSchema)(error) }));
|
|
252
|
+
} catch {
|
|
253
|
+
return error;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
const decodeWireError = (cause) => {
|
|
257
|
+
if (!(cause instanceof Error)) return cause;
|
|
258
|
+
try {
|
|
259
|
+
const parsed = Schema.decodeUnknownSync(Schema.Unknown)(JSON.parse(cause.message));
|
|
260
|
+
if (!Predicate.hasProperty(parsed, wireErrorKey)) return cause;
|
|
261
|
+
return Schema.decodeUnknownSync(WireErrorSchema)(parsed[wireErrorKey]);
|
|
262
|
+
} catch {
|
|
263
|
+
return cause;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
const reservedMethodNames$2 = /* @__PURE__ */ new Set([
|
|
267
|
+
"constructor",
|
|
268
|
+
"fetch",
|
|
269
|
+
"connect",
|
|
270
|
+
"alarm",
|
|
271
|
+
"webSocketMessage",
|
|
272
|
+
"webSocketClose",
|
|
273
|
+
"webSocketError",
|
|
274
|
+
"then",
|
|
275
|
+
"dup",
|
|
276
|
+
"dispose",
|
|
277
|
+
"serialize",
|
|
278
|
+
"deserialize"
|
|
279
|
+
]);
|
|
280
|
+
/**
|
|
281
|
+
* Workers RPC structured-clones every value that crosses an isolate boundary
|
|
282
|
+
* and rejects class instances. Declaration schemas such as `Schema.Result`
|
|
283
|
+
* keep their container instance in their `Encoded` form, so the declared
|
|
284
|
+
* schemas are lowered to their canonical JSON codec before touching the wire.
|
|
285
|
+
*/
|
|
286
|
+
const wireCodec = (schema) => Schema.toCodecJson(schema);
|
|
287
|
+
const assertNoReservedMethods = (target, methods, reserved) => {
|
|
288
|
+
for (const method of Object.keys(methods)) if (reserved.has(method)) throw new RpcReservedMethodNameError({
|
|
289
|
+
definition: target,
|
|
290
|
+
method
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
function method$1(definition) {
|
|
294
|
+
return {
|
|
295
|
+
args: definition.args ?? [],
|
|
296
|
+
success: definition.success
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
const decodeArgs = Effect.fnUntraced(function* (definition, methodName, args) {
|
|
300
|
+
const methodDefinition = definition.methods[methodName];
|
|
301
|
+
if (args.length !== methodDefinition.args.length) return yield* new RpcArgumentCountError({
|
|
302
|
+
definition: definition.id,
|
|
303
|
+
method: methodName,
|
|
304
|
+
expected: methodDefinition.args.length,
|
|
305
|
+
actual: args.length
|
|
306
|
+
});
|
|
307
|
+
return yield* Schema.decodeUnknownEffect(wireCodec(Schema.Tuple(methodDefinition.args)))(args).pipe(Effect.mapError((cause) => new RpcArgumentDecodeError({
|
|
308
|
+
definition: definition.id,
|
|
309
|
+
method: methodName,
|
|
310
|
+
cause
|
|
311
|
+
})));
|
|
312
|
+
});
|
|
313
|
+
const encodeArgs = Effect.fnUntraced(function* (definition, methodName, args) {
|
|
314
|
+
const methodDefinition = definition.methods[methodName];
|
|
315
|
+
if (args.length !== methodDefinition.args.length) return yield* new RpcArgumentCountError({
|
|
316
|
+
definition: definition.id,
|
|
317
|
+
method: methodName,
|
|
318
|
+
expected: methodDefinition.args.length,
|
|
319
|
+
actual: args.length
|
|
320
|
+
});
|
|
321
|
+
return yield* Schema.encodeUnknownEffect(wireCodec(Schema.Tuple(methodDefinition.args)))(args).pipe(Effect.mapError((cause) => new RpcArgumentEncodeError({
|
|
322
|
+
definition: definition.id,
|
|
323
|
+
method: methodName,
|
|
324
|
+
cause
|
|
325
|
+
})));
|
|
326
|
+
});
|
|
327
|
+
const encodeSuccess = (definition, methodName, value) => {
|
|
328
|
+
const methodDefinition = definition.methods[methodName];
|
|
329
|
+
return Schema.encodeUnknownEffect(wireCodec(methodDefinition.success))(value).pipe(Effect.mapError((cause) => new RpcSuccessEncodeError({
|
|
330
|
+
definition: definition.id,
|
|
331
|
+
method: methodName,
|
|
332
|
+
cause
|
|
333
|
+
})));
|
|
334
|
+
};
|
|
335
|
+
const decodeSuccess = (definition, methodName, value) => {
|
|
336
|
+
const methodDefinition = definition.methods[methodName];
|
|
337
|
+
return Schema.decodeUnknownEffect(wireCodec(methodDefinition.success))(value).pipe(Effect.mapError((cause) => new RpcSuccessDecodeError({
|
|
338
|
+
definition: definition.id,
|
|
339
|
+
method: methodName,
|
|
340
|
+
cause
|
|
341
|
+
})));
|
|
342
|
+
};
|
|
343
|
+
const make$2 = (id, methods) => {
|
|
344
|
+
assertNoReservedMethods(id, methods, reservedMethodNames$2);
|
|
345
|
+
return {
|
|
346
|
+
id,
|
|
347
|
+
methods
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region src/RpcTracing.ts
|
|
352
|
+
var RpcTracing_exports = /* @__PURE__ */ __exportAll({
|
|
353
|
+
RpcTraceContext: () => RpcTraceContext,
|
|
354
|
+
withRpcClientSpan: () => withRpcClientSpan,
|
|
355
|
+
withRpcServerSpan: () => withRpcServerSpan,
|
|
356
|
+
withRpcTraceContext: () => withRpcTraceContext
|
|
357
|
+
});
|
|
358
|
+
/**
|
|
359
|
+
* Live native RPC metadata. Opted-in receivers reserve a valid trailing value
|
|
360
|
+
* with this tag for transport context; do not use it as a final domain argument.
|
|
361
|
+
* Never store this in durable messages or envelopes.
|
|
362
|
+
*/
|
|
363
|
+
const RpcTraceContext = Schema.Struct({
|
|
364
|
+
_tag: Schema.Literal("effect-cf/RpcTraceContext/v1"),
|
|
365
|
+
traceId: Schema.String.check(Schema.isPattern(/^(?!0{32}$)[0-9a-f]{32}$/)),
|
|
366
|
+
spanId: Schema.String.check(Schema.isPattern(/^(?!0{16}$)[0-9a-f]{16}$/)),
|
|
367
|
+
sampled: Schema.Boolean
|
|
368
|
+
});
|
|
369
|
+
const isRpcTraceContext$1 = Schema.is(RpcTraceContext);
|
|
370
|
+
/**
|
|
371
|
+
* Appends the current live parent only for a receiver that has opted in.
|
|
372
|
+
* Call this inside the CLIENT span, immediately before the native invocation.
|
|
373
|
+
* With no valid propagating parent, the original argument array is returned.
|
|
374
|
+
*/
|
|
375
|
+
const withRpcTraceContext = Effect.fnUntraced(function* (args) {
|
|
376
|
+
if (yield* Tracer.DisablePropagation) return args;
|
|
377
|
+
const parent = yield* Effect.serviceOption(Tracer.ParentSpan);
|
|
378
|
+
if (Option.isNone(parent) || Context.get(parent.value.annotations, Tracer.DisablePropagation)) return args;
|
|
379
|
+
const context = {
|
|
380
|
+
_tag: "effect-cf/RpcTraceContext/v1",
|
|
381
|
+
traceId: parent.value.traceId,
|
|
382
|
+
spanId: parent.value.spanId,
|
|
383
|
+
sampled: parent.value.sampled
|
|
384
|
+
};
|
|
385
|
+
return isRpcTraceContext$1(context) ? [...args, context] : args;
|
|
386
|
+
});
|
|
387
|
+
const attributes = (service, method) => ({
|
|
388
|
+
"sentry.op": "rpc",
|
|
389
|
+
"rpc.system.name": "cloudflare",
|
|
390
|
+
"rpc.method": `${service}/${method}`,
|
|
391
|
+
"server.address": service
|
|
392
|
+
});
|
|
393
|
+
const withRpcSpan = (effect, service, method, options) => Effect.useSpan(`${service}/${method}`, {
|
|
394
|
+
...options,
|
|
395
|
+
attributes: attributes(service, method)
|
|
396
|
+
}, (span) => effect.pipe(Effect.withParentSpan(span), Effect.onExit((exit) => {
|
|
397
|
+
if (Exit.isSuccess(exit) || Cause.hasInterruptsOnly(exit.cause) || span.status._tag === "Ended") return Effect.void;
|
|
398
|
+
return Effect.gen(function* () {
|
|
399
|
+
const endTime = (yield* References.TracerTimingEnabled) ? yield* Clock.currentTimeNanos : 0n;
|
|
400
|
+
span.attribute("error.type", "_OTHER");
|
|
401
|
+
span.end(endTime, Exit.fail("RPC failed"));
|
|
402
|
+
});
|
|
403
|
+
})));
|
|
404
|
+
/** Wrap the whole call, including native result resolution and success decoding. */
|
|
405
|
+
const withRpcClientSpan = (effect, binding, method) => withRpcSpan(effect, binding, method, { kind: "client" });
|
|
406
|
+
/**
|
|
407
|
+
* Optional application instrumentation for the entire receiver effect.
|
|
408
|
+
* Use in a RunSymbol override to include argument decode, handler and encode.
|
|
409
|
+
* Records stable service/method attributes and failure status, not argument or
|
|
410
|
+
* error payloads. The original typed failure still propagates to the caller.
|
|
411
|
+
*/
|
|
412
|
+
const withRpcServerSpan = (effect, invocation) => withRpcSpan(effect, invocation.service, invocation.method, {
|
|
413
|
+
kind: "server",
|
|
414
|
+
parent: invocation.parent === void 0 ? void 0 : Tracer.externalSpan(invocation.parent)
|
|
415
|
+
});
|
|
416
|
+
//#endregion
|
|
417
|
+
//#region src/internal/RpcInvocation.ts
|
|
418
|
+
/** Scoped to the incoming event effect, never the instance runtime or storage. */
|
|
419
|
+
var CurrentInvocation = class extends Context.Service()("effect-cf/internal/RpcInvocation") {};
|
|
420
|
+
const recordDecodedArgs = (args) => Effect.map(Effect.serviceOption(CurrentInvocation), (invocation) => {
|
|
421
|
+
if (Option.isSome(invocation)) invocation.value.decodedArgs = args;
|
|
422
|
+
});
|
|
423
|
+
const invokeWithReceiver = (value, receiver, args) => {
|
|
424
|
+
return Function.prototype.apply.call(value, receiver, args);
|
|
425
|
+
};
|
|
426
|
+
const lookupRpcMethod = (target, method, makeError) => Effect.try({
|
|
427
|
+
try: () => {
|
|
428
|
+
if (!Predicate.isObjectKeyword(target)) throw new TypeError(`RPC target is not object-like`);
|
|
429
|
+
const receiver = target;
|
|
430
|
+
const value = receiver[method];
|
|
431
|
+
if (!Predicate.isFunction(value)) throw new TypeError(`RPC method "${String(method)}" is not callable`);
|
|
432
|
+
const callable = value;
|
|
433
|
+
return (...args) => invokeWithReceiver(callable, receiver, args);
|
|
434
|
+
},
|
|
435
|
+
catch: makeError
|
|
436
|
+
});
|
|
437
|
+
const invokeRpcMethod = Effect.fnUntraced(function* (target, method, args, makeError) {
|
|
438
|
+
const fn = yield* lookupRpcMethod(target, method, makeError);
|
|
439
|
+
return yield* Effect.try({
|
|
440
|
+
try: () => fn(...args),
|
|
441
|
+
catch: makeError
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region src/internal/Entrypoint.ts
|
|
446
|
+
const isRpcTraceContext = Schema.is(RpcTraceContext);
|
|
447
|
+
const invokeEntrypointRpcMethod = (self, method, args, run, onExit, service, key, rpcTracing) => {
|
|
448
|
+
const last = args.at(-1);
|
|
449
|
+
const parent = rpcTracing !== void 0 && isRpcTraceContext(last) ? last : void 0;
|
|
450
|
+
const handlerArgs = parent === void 0 ? args : args.slice(0, -1);
|
|
451
|
+
const invocation = {
|
|
452
|
+
service: rpcTracing?.service ?? service,
|
|
453
|
+
method: key,
|
|
454
|
+
args: handlerArgs,
|
|
455
|
+
parent
|
|
456
|
+
};
|
|
457
|
+
const handler = Effect.suspend(() => method(...handlerArgs)).pipe(Effect.provideService(CurrentInvocation, invocation), Effect.mapError(encodeWireError));
|
|
458
|
+
return run(self, onExit === void 0 ? handler : handler.pipe(Effect.onExit(() => onExit(self))), invocation);
|
|
459
|
+
};
|
|
460
|
+
const provideEntrypointServices = (layer, services) => layer.pipe(Layer.provideMerge(services));
|
|
461
|
+
const defineEntrypointRpcMethods = (target, prototype, rpc, reservedMethodNames, run, onExit, rpcTracing) => {
|
|
462
|
+
const methods = rpc ?? {};
|
|
463
|
+
assertNoReservedMethods(target, methods, reservedMethodNames);
|
|
464
|
+
for (const [key, method] of Object.entries(methods)) Object.defineProperty(prototype, key, {
|
|
465
|
+
enumerable: true,
|
|
466
|
+
value(...args) {
|
|
467
|
+
return invokeEntrypointRpcMethod(this, method, args, run, onExit, target, key, rpcTracing);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
};
|
|
471
|
+
const assumeEntrypointClass = (entrypoint) => {
|
|
472
|
+
return entrypoint;
|
|
473
|
+
};
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region src/internal/Runtime.ts
|
|
476
|
+
/**
|
|
477
|
+
* Assembles the shared `ManagedRuntime` used by the Cloudflare entrypoint
|
|
478
|
+
* classes (Worker, Durable Object, Workflow).
|
|
479
|
+
*
|
|
480
|
+
* The entrypoint-specific services are merged with the env-backed
|
|
481
|
+
* `ConfigProvider` and `WorkerEnvironment`, then provided to the user-supplied
|
|
482
|
+
* layer so the resulting runtime satisfies both the user services and the
|
|
483
|
+
* platform services.
|
|
484
|
+
*/
|
|
485
|
+
const makeEntrypointRuntime = (layer, env, services) => {
|
|
486
|
+
const entrypointServices = Layer.mergeAll(services, ConfigProvider.layer(WorkerConfig.providerFromEnv(env)), Layer.succeed(WorkerEnvironment, env));
|
|
487
|
+
return ManagedRuntime.make(provideEntrypointServices(layer, entrypointServices));
|
|
488
|
+
};
|
|
489
|
+
function runEventPromise(...args) {
|
|
490
|
+
const [runtime, effect, eventLayer, parent] = args;
|
|
491
|
+
if (eventLayer === void 0) {
|
|
492
|
+
const event = Effect.scoped(effect);
|
|
493
|
+
return runtime.runPromise(parent === void 0 ? event : Effect.withParentSpan(event, parent));
|
|
494
|
+
}
|
|
495
|
+
const event = Effect.scoped(effect.pipe(Effect.provide(eventLayer, { local: true })));
|
|
496
|
+
return runtime.runPromise(parent === void 0 ? event : Effect.withParentSpan(event, parent));
|
|
497
|
+
}
|
|
498
|
+
//#endregion
|
|
499
|
+
//#region src/internal/Telemetry.ts
|
|
500
|
+
/** Maximum event lifetime spent on an internally scheduled telemetry flush. */
|
|
501
|
+
const scheduledFlushTimeout = "2 seconds";
|
|
502
|
+
/**
|
|
503
|
+
* Schedules a configured OTLP flusher through the current Cloudflare event.
|
|
504
|
+
*
|
|
505
|
+
* The handed-off effect is best-effort: it settles within two seconds and
|
|
506
|
+
* silently absorbs every failure cause so telemetry cannot extend or fail the
|
|
507
|
+
* user event, or recursively log through an unhealthy exporter.
|
|
508
|
+
*/
|
|
509
|
+
const scheduleTelemetryFlush$1 = (waitUntil) => Effect.gen(function* () {
|
|
510
|
+
const flusher = yield* Effect.serviceOption(OtlpExporter.Flusher);
|
|
511
|
+
if (Option.isNone(flusher)) return;
|
|
512
|
+
yield* waitUntil(flusher.value.flush.pipe(Effect.timeoutOption(scheduledFlushTimeout), Effect.ignoreCause, Effect.asVoid));
|
|
513
|
+
}).pipe(Effect.ignoreCause);
|
|
514
|
+
//#endregion
|
|
515
|
+
//#region src/Rpc.ts
|
|
516
|
+
var Rpc_exports = /* @__PURE__ */ __exportAll({
|
|
517
|
+
RpcStub: () => RpcStub,
|
|
518
|
+
RpcTarget: () => RpcTarget,
|
|
519
|
+
dispose: () => dispose,
|
|
520
|
+
isDisposable: () => isDisposable,
|
|
521
|
+
resolve: () => resolve,
|
|
522
|
+
scoped: () => scoped
|
|
523
|
+
});
|
|
524
|
+
const isDisposable = (value) => Predicate.hasProperty(value, Symbol.dispose) && Predicate.isFunction(value[Symbol.dispose]);
|
|
525
|
+
const dispose = (value) => Effect.sync(() => {
|
|
526
|
+
if (isDisposable(value)) value[Symbol.dispose]();
|
|
527
|
+
});
|
|
528
|
+
const resolve = (value) => Predicate.isPromiseLike(value) ? Effect.tryPromise({
|
|
529
|
+
try: () => Promise.resolve(value),
|
|
530
|
+
catch: (cause) => decodeWireError(cause)
|
|
531
|
+
}) : Effect.sync(() => {
|
|
532
|
+
return value;
|
|
533
|
+
});
|
|
534
|
+
const scoped = (value) => Effect.acquireRelease(resolve(value), (resolved) => dispose(resolved));
|
|
535
|
+
//#endregion
|
|
536
|
+
//#region src/ServiceBinding.ts
|
|
537
|
+
var ServiceBinding_exports = /* @__PURE__ */ __exportAll({
|
|
538
|
+
Service: () => Service,
|
|
539
|
+
ServiceBindingFetchError: () => ServiceBindingFetchError,
|
|
540
|
+
ServiceBindingRpcError: () => ServiceBindingRpcError,
|
|
541
|
+
isServiceBindingClient: () => isServiceBindingClient,
|
|
542
|
+
layer: () => layer,
|
|
543
|
+
makeClient: () => makeClient,
|
|
544
|
+
makeDirectMethods: () => makeDirectMethods
|
|
545
|
+
});
|
|
546
|
+
const TypeId = "effect-cf/ServiceBinding";
|
|
547
|
+
const expectedServiceBinding = "Worker service binding with fetch()";
|
|
548
|
+
/**
|
|
549
|
+
* Failure raised when calling `fetch` on a service binding.
|
|
550
|
+
*/
|
|
551
|
+
var ServiceBindingFetchError = class extends Data.TaggedError("ServiceBindingFetchError") {
|
|
552
|
+
get message() {
|
|
553
|
+
return `Service binding "${this.binding}" fetch failed: ${causeMessage(this.cause)}`;
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
/**
|
|
557
|
+
* Failure raised when invoking an RPC method on a service binding.
|
|
558
|
+
*/
|
|
559
|
+
var ServiceBindingRpcError = class extends Data.TaggedError("ServiceBindingRpcError") {
|
|
560
|
+
get message() {
|
|
561
|
+
return `Service binding "${this.binding}" RPC method "${this.method}" failed: ${causeMessage(this.cause)}`;
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const ServiceBindingSchema = Schema.declare((value) => Predicate.hasProperty(value, "fetch") && Predicate.isFunction(value.fetch));
|
|
565
|
+
const decodeServiceBinding = Schema.decodeUnknownOption(ServiceBindingSchema);
|
|
566
|
+
const isServiceBindingClient = (value) => Option.isSome(decodeServiceBinding(value));
|
|
567
|
+
const makeClient = (definition) => {
|
|
568
|
+
return (service) => {
|
|
569
|
+
const fetch = Effect.fn("ServiceBinding.fetch")(function* (input, init) {
|
|
570
|
+
return yield* Effect.tryPromise({
|
|
571
|
+
try: (signal) => {
|
|
572
|
+
const callerSignal = init?.signal !== void 0 ? init.signal : input instanceof Request ? input.signal : void 0;
|
|
573
|
+
return service.fetch(input, {
|
|
574
|
+
...init,
|
|
575
|
+
signal: callerSignal === null || callerSignal === void 0 ? signal : AbortSignal.any([callerSignal, signal])
|
|
576
|
+
});
|
|
577
|
+
},
|
|
578
|
+
catch: (cause) => new ServiceBindingFetchError({
|
|
579
|
+
binding: definition.binding,
|
|
580
|
+
cause
|
|
581
|
+
})
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
const rpc = Effect.fnUntraced(function* (method, ...args) {
|
|
585
|
+
const methodName = String(method);
|
|
586
|
+
const encodedArgs = definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
587
|
+
binding: definition.binding,
|
|
588
|
+
method: methodName,
|
|
589
|
+
cause
|
|
590
|
+
})));
|
|
591
|
+
const nativeArgs = definition.rpcTracing ? yield* withRpcTraceContext(encodedArgs) : encodedArgs;
|
|
592
|
+
return yield* invokeRpcMethod(service, method, nativeArgs, (cause) => new ServiceBindingRpcError({
|
|
593
|
+
binding: definition.binding,
|
|
594
|
+
method: methodName,
|
|
595
|
+
cause
|
|
596
|
+
}));
|
|
597
|
+
});
|
|
598
|
+
const decodeSuccess$1 = Effect.fnUntraced(function* (methodName, value) {
|
|
599
|
+
if (definition.definition === void 0) return value;
|
|
600
|
+
return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
601
|
+
binding: definition.binding,
|
|
602
|
+
method: methodName,
|
|
603
|
+
cause
|
|
604
|
+
})));
|
|
605
|
+
});
|
|
606
|
+
const call = Effect.fnUntraced(function* (method, ...args) {
|
|
607
|
+
const methodName = String(method);
|
|
608
|
+
const value = yield* resolve(yield* rpc(method, ...args)).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
609
|
+
binding: definition.binding,
|
|
610
|
+
method: methodName,
|
|
611
|
+
cause
|
|
612
|
+
})));
|
|
613
|
+
return yield* decodeSuccess$1(methodName, value);
|
|
614
|
+
}, (effect, ...args) => withRpcClientSpan(effect, definition.binding, String(args[0])));
|
|
615
|
+
const scopedCall = Effect.fnUntraced(function* (method, ...args) {
|
|
616
|
+
const methodName = String(method);
|
|
617
|
+
const result = yield* rpc(method, ...args);
|
|
618
|
+
const value = yield* scoped(result).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
619
|
+
binding: definition.binding,
|
|
620
|
+
method: methodName,
|
|
621
|
+
cause
|
|
622
|
+
})));
|
|
623
|
+
return yield* decodeSuccess$1(methodName, value);
|
|
624
|
+
}, (effect, ...args) => withRpcClientSpan(effect, definition.binding, String(args[0])));
|
|
625
|
+
const directMethods = makeDirectMethods(definition.definition, call);
|
|
626
|
+
return Object.assign(directMethods, {
|
|
627
|
+
fetch,
|
|
628
|
+
rpc,
|
|
629
|
+
call,
|
|
630
|
+
scopedCall
|
|
631
|
+
});
|
|
632
|
+
};
|
|
633
|
+
};
|
|
634
|
+
const layer = (tag, definition) => layer$2(tag, definition.binding, (value) => isServiceBindingClient(value), makeClient(definition), { expected: expectedServiceBinding });
|
|
635
|
+
const Service = () => (id, definition) => {
|
|
636
|
+
const tag = Service$1()(id, definition.binding, (value) => isServiceBindingClient(value), makeClient(definition));
|
|
637
|
+
const fetch = Effect.fnUntraced(function* (input, init) {
|
|
638
|
+
return yield* (yield* tag).fetch(input, init);
|
|
639
|
+
});
|
|
640
|
+
const rpc = Effect.fnUntraced(function* (method, ...args) {
|
|
641
|
+
return yield* (yield* tag).rpc(method, ...args);
|
|
642
|
+
});
|
|
643
|
+
const call = Effect.fnUntraced(function* (method, ...args) {
|
|
644
|
+
return yield* (yield* tag).call(method, ...args);
|
|
645
|
+
});
|
|
646
|
+
const scopedCall = Effect.fnUntraced(function* (method, ...args) {
|
|
647
|
+
return yield* (yield* tag).scopedCall(method, ...args);
|
|
648
|
+
});
|
|
649
|
+
const directMethods = makeDirectMethods(definition.definition, call);
|
|
650
|
+
return Object.assign(tag, directMethods, {
|
|
651
|
+
[TypeId]: TypeId,
|
|
652
|
+
definition,
|
|
653
|
+
fetch,
|
|
654
|
+
rpc,
|
|
655
|
+
call,
|
|
656
|
+
scopedCall
|
|
657
|
+
});
|
|
658
|
+
};
|
|
659
|
+
const makeDirectMethods = (rpcDefinition, call) => {
|
|
660
|
+
const methods = {};
|
|
661
|
+
if (rpcDefinition !== void 0) {
|
|
662
|
+
const invoke = call;
|
|
663
|
+
for (const methodName of Object.keys(rpcDefinition.methods)) methods[methodName] = (...args) => invoke(methodName, ...args);
|
|
664
|
+
}
|
|
665
|
+
return methods;
|
|
666
|
+
};
|
|
667
|
+
//#endregion
|
|
668
|
+
//#region src/WorkerDefinition.ts
|
|
669
|
+
var WorkerDefinition_exports = /* @__PURE__ */ __exportAll({
|
|
670
|
+
Tag: () => Tag,
|
|
671
|
+
Worker: () => Worker,
|
|
672
|
+
implement: () => implement,
|
|
673
|
+
make: () => make$1,
|
|
674
|
+
method: () => method
|
|
675
|
+
});
|
|
676
|
+
const reservedMethodNames$1 = /* @__PURE__ */ new Set([
|
|
677
|
+
"constructor",
|
|
678
|
+
"dup",
|
|
679
|
+
"fetch",
|
|
680
|
+
"connect",
|
|
681
|
+
"queue",
|
|
682
|
+
"scheduled",
|
|
683
|
+
"tail",
|
|
684
|
+
"tailStream",
|
|
685
|
+
"test",
|
|
686
|
+
"trace",
|
|
687
|
+
"alarm",
|
|
688
|
+
"webSocketMessage",
|
|
689
|
+
"webSocketClose",
|
|
690
|
+
"webSocketError"
|
|
691
|
+
]);
|
|
692
|
+
const assumeTagClass = (value) => {
|
|
693
|
+
return value;
|
|
694
|
+
};
|
|
695
|
+
/**
|
|
696
|
+
* Defines a single RPC method schema in a worker definition.
|
|
697
|
+
*/
|
|
698
|
+
const method = method$1;
|
|
699
|
+
const makeDefinition = (id, methods) => {
|
|
700
|
+
assertNoReservedMethods("Worker", methods, reservedMethodNames$1);
|
|
701
|
+
const definition = make$2(id, methods);
|
|
702
|
+
return Object.assign(definition, { make: (layer, options) => {
|
|
703
|
+
const workerOptions = {
|
|
704
|
+
...options,
|
|
705
|
+
rpc: wrapHandlers(definition, options.rpc)
|
|
706
|
+
};
|
|
707
|
+
if (workerOptions.eventLayer === void 0) return make(layer, workerOptions);
|
|
708
|
+
return make(layer, workerOptions);
|
|
709
|
+
} });
|
|
710
|
+
};
|
|
711
|
+
const make$1 = (id, methods) => Tag()(id, methods);
|
|
712
|
+
const Tag = () => (id, methods) => {
|
|
713
|
+
const definition = makeDefinition(id, methods);
|
|
714
|
+
const tag = Context.Service()(id);
|
|
715
|
+
const bindingDefinition = (binding) => ({
|
|
716
|
+
...binding,
|
|
717
|
+
definition
|
|
718
|
+
});
|
|
719
|
+
const layer$3 = (binding) => layer(tag, bindingDefinition(binding));
|
|
720
|
+
const fetch = (input, init) => Effect.gen(function* () {
|
|
721
|
+
return yield* (yield* tag).fetch(input, init);
|
|
722
|
+
});
|
|
723
|
+
const rpc = (method, ...args) => Effect.gen(function* () {
|
|
724
|
+
return yield* (yield* tag).rpc(method, ...args);
|
|
725
|
+
});
|
|
726
|
+
const call = (method, ...args) => Effect.gen(function* () {
|
|
727
|
+
return yield* (yield* tag).call(method, ...args);
|
|
728
|
+
});
|
|
729
|
+
const scopedCall = (method, ...args) => Effect.gen(function* () {
|
|
730
|
+
return yield* (yield* tag).scopedCall(method, ...args);
|
|
731
|
+
});
|
|
732
|
+
const directMethods = makeDirectMethods(definition, call);
|
|
733
|
+
return assumeTagClass(Object.assign(tag, directMethods, {
|
|
734
|
+
id: definition.id,
|
|
735
|
+
methods: definition.methods,
|
|
736
|
+
make: definition.make,
|
|
737
|
+
layer: layer$3,
|
|
738
|
+
fetch,
|
|
739
|
+
rpc,
|
|
740
|
+
call,
|
|
741
|
+
scopedCall
|
|
742
|
+
}));
|
|
743
|
+
};
|
|
744
|
+
const Worker = Tag;
|
|
745
|
+
const wrapHandlers = (definition, handlers) => {
|
|
746
|
+
const wrapped = Object.create(null);
|
|
747
|
+
for (const key of Object.keys(definition.methods)) {
|
|
748
|
+
const handler = handlers[key];
|
|
749
|
+
wrapped[key] = (...args) => Effect.gen(function* () {
|
|
750
|
+
const decodedArgs = yield* decodeArgs(definition, key, args);
|
|
751
|
+
yield* recordDecodedArgs(decodedArgs);
|
|
752
|
+
const value = yield* handler(...decodedArgs);
|
|
753
|
+
return yield* encodeSuccess(definition, key, value);
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
return wrapped;
|
|
757
|
+
};
|
|
758
|
+
/**
|
|
759
|
+
* Helper for implementing handlers with the exact method shape of a definition.
|
|
760
|
+
*/
|
|
761
|
+
const implement = (_definition, handlers) => handlers;
|
|
762
|
+
//#endregion
|
|
763
|
+
//#region src/Worker.ts
|
|
764
|
+
var Worker_exports = /* @__PURE__ */ __exportAll({
|
|
765
|
+
ExecutionContext: () => ExecutionContext,
|
|
766
|
+
NativeRequest: () => NativeRequest,
|
|
767
|
+
RunSymbol: () => RunSymbol,
|
|
768
|
+
Tag: () => Tag,
|
|
769
|
+
WorkerContext: () => WorkerContext,
|
|
770
|
+
implement: () => implement,
|
|
771
|
+
isWebSocketUpgrade: () => isWebSocketUpgrade,
|
|
772
|
+
make: () => make,
|
|
773
|
+
makeFetchHandler: () => makeFetchHandler,
|
|
774
|
+
method: () => method
|
|
775
|
+
});
|
|
776
|
+
var ExecutionContext = class extends Context.Service()("effect-cf/ExecutionContext") {};
|
|
777
|
+
var WorkerContext = class extends Context.Service()("effect-cf/WorkerContext") {};
|
|
778
|
+
var NativeRequest = class extends Context.Service()("effect-cf/NativeRequest") {};
|
|
779
|
+
const isWebSocketUpgrade = (request) => request.headers.get("Upgrade")?.toLowerCase() === "websocket";
|
|
780
|
+
const reservedMethodNames = /* @__PURE__ */ new Set([
|
|
781
|
+
...reservedMethodNames$2,
|
|
782
|
+
"queue",
|
|
783
|
+
"scheduled",
|
|
784
|
+
"tail",
|
|
785
|
+
"tailStream",
|
|
786
|
+
"test",
|
|
787
|
+
"trace"
|
|
788
|
+
]);
|
|
789
|
+
/** Override to instrument the whole event, then call super[RunSymbol]. */
|
|
790
|
+
const RunSymbol = Symbol.for("effect-cf/Worker/run");
|
|
791
|
+
const FetchSymbol = Symbol.for("effect-cf/Worker/fetch");
|
|
792
|
+
const renderFetchSuccess = (effect, eventLayer) => Effect.suspend(() => {
|
|
793
|
+
let nativeResponse;
|
|
794
|
+
let webResponse;
|
|
795
|
+
const httpApp = Effect.flatMap(effect, (response) => {
|
|
796
|
+
if (response instanceof Response) {
|
|
797
|
+
nativeResponse = response;
|
|
798
|
+
return Effect.succeed(HttpServerResponse.empty());
|
|
799
|
+
}
|
|
800
|
+
return Effect.succeed(response);
|
|
801
|
+
});
|
|
802
|
+
const handleResponse = (request, response) => nativeResponse !== void 0 ? Effect.void : Effect.map(Effect.context(), (context) => {
|
|
803
|
+
webResponse = HttpServerResponse.toWeb(HttpEffect.scopeTransferToStream(response), {
|
|
804
|
+
withoutBody: request.method === "HEAD",
|
|
805
|
+
context
|
|
806
|
+
});
|
|
807
|
+
});
|
|
808
|
+
const telemetryMiddleware = HttpMiddleware.make((self) => Effect.gen(function* () {
|
|
809
|
+
yield* Effect.addFinalizer(() => scheduleTelemetryFlush);
|
|
810
|
+
return yield* self;
|
|
811
|
+
}));
|
|
812
|
+
const handled = eventLayer === void 0 ? HttpEffect.toHandled(httpApp, handleResponse, telemetryMiddleware) : Effect.flatMap(References.TracerEnabled, (tracerEnabled) => HttpEffect.toHandled(httpApp, handleResponse, HttpMiddleware.make((self) => Effect.provideService(Effect.gen(function* () {
|
|
813
|
+
const context = yield* Layer.build(Layer.fresh(eventLayer));
|
|
814
|
+
yield* Effect.addFinalizer(() => Effect.provideContext(scheduleTelemetryFlush, context));
|
|
815
|
+
return yield* HttpMiddleware.tracer(self).pipe(Effect.onExit(() => Effect.yieldNow), Effect.provideContext(context));
|
|
816
|
+
}), References.TracerEnabled, tracerEnabled))).pipe(Effect.withTracerEnabled(false)));
|
|
817
|
+
const captured = () => nativeResponse ?? webResponse ?? new Response(null, { status: 500 });
|
|
818
|
+
return Effect.matchCause(handled, {
|
|
819
|
+
onFailure: captured,
|
|
820
|
+
onSuccess: captured
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
const isWorkerOptions = (options) => !Effect.isEffect(options);
|
|
824
|
+
/**
|
|
825
|
+
* Drains buffered OTLP telemetry when the fetch Effect scope closes. Effect
|
|
826
|
+
* response streams transfer that scope to the body and schedule the flush when
|
|
827
|
+
* the body finishes or is canceled.
|
|
828
|
+
*
|
|
829
|
+
* The flush is handed to `ctx.waitUntil` instead of being awaited by the
|
|
830
|
+
* handler. It is a no-op when the context does not contain an
|
|
831
|
+
* `OtlpExporter.Flusher`, and silently settles within two seconds.
|
|
832
|
+
*/
|
|
833
|
+
const scheduleTelemetryFlush = scheduleTelemetryFlush$1((flush) => Effect.flatMap(WorkerContext, (workerContext) => workerContext.waitUntil(flush)));
|
|
834
|
+
function make(layer, optionsOrFetch) {
|
|
835
|
+
const options = isWorkerOptions(optionsOrFetch) ? optionsOrFetch : { fetch: optionsOrFetch };
|
|
836
|
+
class EffectWorker extends WorkerEntrypoint {
|
|
837
|
+
runtime;
|
|
838
|
+
constructor(ctx, env) {
|
|
839
|
+
super(ctx, env);
|
|
840
|
+
this.runtime = makeEntrypointRuntime(layer, env, Layer.mergeAll(Layer.succeed(ExecutionContext, ctx), Layer.succeed(WorkerContext, fromExecutionContext(ctx))));
|
|
841
|
+
}
|
|
842
|
+
[RunSymbol](effect, runOptions = {}) {
|
|
843
|
+
const eventLayer = runOptions.event === "fetch" ? void 0 : options.eventLayer;
|
|
844
|
+
const parent = runOptions.rpc?.parent;
|
|
845
|
+
const parentSpan = parent === void 0 ? void 0 : Tracer.externalSpan(parent);
|
|
846
|
+
if (eventLayer === void 0) return runEventPromise(this.runtime, effect, void 0, parentSpan);
|
|
847
|
+
return runEventPromise(this.runtime, effect, eventLayer, parentSpan);
|
|
848
|
+
}
|
|
849
|
+
fetch(request) {
|
|
850
|
+
return this[FetchSymbol](request);
|
|
851
|
+
}
|
|
852
|
+
[FetchSymbol](request, requestContext) {
|
|
853
|
+
const fetchHandler = options.fetch;
|
|
854
|
+
if (fetchHandler === void 0) return Promise.resolve(new Response("Not Found", { status: 404 }));
|
|
855
|
+
const ctx = requestContext ?? this.ctx;
|
|
856
|
+
const requestServices = Layer.mergeAll(Layer.succeed(NativeRequest, request), Layer.succeed(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromWeb(request)), Layer.succeed(ExecutionContext, ctx), Layer.succeed(WorkerContext, fromExecutionContext(ctx)));
|
|
857
|
+
return this[RunSymbol](renderFetchSuccess(fetchHandler, options.eventLayer).pipe(Effect.provide(requestServices)), { event: "fetch" });
|
|
858
|
+
}
|
|
859
|
+
queue(batch) {
|
|
860
|
+
const queueHandler = options.queue;
|
|
861
|
+
if (queueHandler === void 0) return Promise.resolve();
|
|
862
|
+
const messages = batch.messages.map((message) => fromMessage(message, message.body));
|
|
863
|
+
return this[RunSymbol](queueHandler(fromMessageBatch(batch, messages)).pipe(Effect.onExit(() => scheduleTelemetryFlush)), { event: "queue" });
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
defineEntrypointRpcMethods("Worker", EffectWorker.prototype, options.rpc, reservedMethodNames, (self, effect, rpc) => self[RunSymbol](effect, {
|
|
867
|
+
event: "rpc",
|
|
868
|
+
rpc
|
|
869
|
+
}), () => scheduleTelemetryFlush, options.rpcTracing);
|
|
870
|
+
return assumeEntrypointClass(EffectWorker);
|
|
871
|
+
}
|
|
872
|
+
function makeFetchHandler(layer, options) {
|
|
873
|
+
const WorkerClass = options.eventLayer === void 0 ? make(layer, options) : make(layer, options);
|
|
874
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
875
|
+
return { fetch: (request, env, ctx) => {
|
|
876
|
+
let instance = instances.get(env);
|
|
877
|
+
if (instance === void 0) {
|
|
878
|
+
instance = new WorkerClass(ctx, env);
|
|
879
|
+
instances.set(env, instance);
|
|
880
|
+
}
|
|
881
|
+
return instance[FetchSymbol](request, ctx);
|
|
882
|
+
} };
|
|
883
|
+
}
|
|
884
|
+
//#endregion
|
|
885
|
+
export { QueueDefinition_exports as A, decodeSuccess as C, method$1 as D, make$2 as E, reservedMethodNames$2 as O, decodeArgs as S, encodeSuccess as T, RpcTracing_exports as _, WorkerDefinition_exports as a, RpcDefinition_exports as b, resolve as c, makeEntrypointRuntime as d, runEventPromise as f, recordDecodedArgs as g, invokeRpcMethod as h, Worker_exports as i, QueueBinding_exports as j, Queue_exports as k, scoped as l, defineEntrypointRpcMethods as m, NativeRequest as n, ServiceBinding_exports as o, assumeEntrypointClass as p, WorkerContext as r, Rpc_exports as s, ExecutionContext as t, scheduleTelemetryFlush$1 as u, withRpcClientSpan as v, encodeArgs as w, assertNoReservedMethods as x, withRpcTraceContext as y };
|