effect-cf 0.32.1 → 0.34.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 +18 -0
- package/README.md +31 -1072
- package/dist/{Artifacts-DnHQA-Ax.d.mts → Artifacts-B3r3RuTB.d.mts} +1 -48
- package/dist/{Artifacts-CSIk1Oml.mjs → Artifacts-CBxWGeZB.mjs} +2 -7
- package/dist/{Binding-pfilNJmP.mjs → Binding-C82jRhdr.mjs} +1 -2
- package/dist/{Binding-xJJJPmiD.d.mts → Binding-DKcLrQCM.d.mts} +0 -45
- package/dist/ComputerArtifacts.d.mts +1 -3
- package/dist/ComputerArtifacts.mjs +1 -2
- package/dist/ComputerWorkspace.d.mts +1 -10
- package/dist/ComputerWorkspace.mjs +1 -2
- package/dist/ComputerWorkspaceHost.d.mts +1 -9
- package/dist/{ContainerNamespace-CFjiLw8b.d.mts → ContainerNamespace-DbLaeFhN.d.mts} +1 -14
- package/dist/{DurableObjectState-B0A0Y1ef.d.mts → DurableObjectState-CrEunfQ-.d.mts} +86 -254
- package/dist/{DurableObjectState-D1Ibr6k0.mjs → DurableObjectState-De4ZojhY.mjs} +2 -40
- package/dist/{ErrorMessage-BM0K-Nik.mjs → ErrorMessage-Byx2OgNd.mjs} +0 -1
- package/dist/{Hyperdrive-z-9fFz15.d.mts → Hyperdrive-HrwFlZ6x.d.mts} +1 -4
- package/dist/HyperdrivePg.d.mts +2 -11
- package/dist/HyperdrivePg.mjs +0 -8
- package/dist/Sandbox.d.mts +2 -32
- package/dist/Sandbox.mjs +2 -11
- package/dist/Vitest.d.mts +3 -31
- package/dist/Vitest.mjs +2 -17
- package/dist/{WorkflowBinding-B9_S8tX2.d.mts → WorkflowBinding-BumVQTuW.d.mts} +2 -5
- package/dist/index.d.mts +34 -480
- package/dist/index.mjs +174 -312
- package/package.json +2 -2
- package/src/AiGateway.ts +0 -6
- package/src/AnalyticsEngine.ts +0 -9
- package/src/Artifacts.ts +0 -47
- package/src/Binding.ts +0 -8
- package/src/BrowserRendering.ts +0 -4
- package/src/Cache.ts +0 -19
- package/src/CloudflareOtlp.ts +3 -39
- package/src/ComputerArtifacts.ts +0 -2
- package/src/ComputerWorkspace.ts +0 -9
- package/src/ComputerWorkspaceHost.ts +0 -8
- package/src/ContainerNamespace.ts +0 -13
- package/src/D1.ts +0 -22
- package/src/DurableObject.ts +45 -25
- package/src/DurableObjectAlarm.ts +6 -210
- package/src/DurableObjectDefinition.ts +8 -20
- package/src/DurableObjectNamespace.ts +57 -112
- package/src/DurableObjectRpcWebSocket.ts +3 -19
- package/src/DurableObjectSqlite.ts +0 -12
- package/src/DurableObjectState.ts +6 -21
- package/src/DurableObjectStorage.ts +2 -35
- package/src/DurableObjectWebSocket.ts +0 -31
- package/src/Email.ts +0 -12
- package/src/Environment.ts +0 -37
- package/src/Hyperdrive.ts +0 -3
- package/src/HyperdrivePg.ts +0 -9
- package/src/Images.ts +0 -5
- package/src/Kv.ts +0 -15
- package/src/QueueBinding.ts +0 -2
- package/src/R2.ts +0 -5
- package/src/RpcDefinition.ts +0 -2
- package/src/RpcTracing.ts +133 -0
- package/src/Sandbox.ts +0 -30
- package/src/ServiceBinding.ts +48 -125
- package/src/Vectorize.ts +0 -5
- package/src/Vitest.ts +0 -28
- package/src/WebTransport.ts +0 -15
- package/src/Worker.ts +36 -57
- package/src/WorkerDefinition.ts +5 -14
- package/src/WorkersAi.ts +0 -4
- package/src/Workflow.ts +0 -5
- package/src/WorkflowBinding.ts +0 -3
- package/src/index.ts +1 -0
- package/src/internal/Entrypoint.ts +23 -4
- package/src/internal/ErrorMessage.ts +0 -1
- package/src/internal/RpcInvocation.ts +18 -1
- package/src/internal/Runtime.ts +12 -7
- package/src/internal/WorkerContext.ts +0 -11
package/src/Worker.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import { WorkerEntrypoint as CloudflareWorkerEntrypoint } from "cloudflare:workers";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type Cause,
|
|
4
|
+
Context,
|
|
5
|
+
Effect,
|
|
6
|
+
Layer,
|
|
7
|
+
type ManagedRuntime,
|
|
8
|
+
type Scope,
|
|
9
|
+
Tracer,
|
|
10
|
+
} from "effect";
|
|
3
11
|
import { HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
4
12
|
|
|
5
13
|
import { WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
6
14
|
import { fromMessage, fromMessageBatch, type QueueHandler } from "./Queue";
|
|
7
15
|
import type * as RpcDefinition from "./RpcDefinition";
|
|
16
|
+
import type { ReceiverOptions, RpcInvocationInfo } from "./RpcTracing";
|
|
8
17
|
import * as Entrypoint from "./internal/Entrypoint";
|
|
9
18
|
import * as Runtime from "./internal/Runtime";
|
|
10
19
|
import * as Telemetry from "./internal/Telemetry";
|
|
11
20
|
import { fromExecutionContext } from "./internal/WorkerContext";
|
|
12
21
|
|
|
13
|
-
/**
|
|
14
|
-
* Access to Cloudflare's native `ExecutionContext`.
|
|
15
|
-
*/
|
|
16
22
|
export class ExecutionContext extends Context.Service<
|
|
17
23
|
ExecutionContext,
|
|
18
24
|
globalThis.ExecutionContext
|
|
19
25
|
>()("effect-cf/ExecutionContext") {}
|
|
20
26
|
|
|
21
|
-
/**
|
|
22
|
-
* Options for {@link WorkerContextService.waitUntil}.
|
|
23
|
-
*/
|
|
24
27
|
export interface WorkerContextWaitUntilOptions<E, R> {
|
|
25
28
|
/**
|
|
26
29
|
* Failure mode for the background effect: `"observe"` (default) logs or
|
|
@@ -28,13 +31,9 @@ export interface WorkerContextWaitUntilOptions<E, R> {
|
|
|
28
31
|
* native `waitUntil` promise.
|
|
29
32
|
*/
|
|
30
33
|
readonly mode?: "observe" | "propagate";
|
|
31
|
-
/** Custom failure handler for the background effect. */
|
|
32
34
|
readonly onFailure?: (cause: Cause.Cause<E>) => Effect.Effect<void, never, R>;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
/**
|
|
36
|
-
* Effect wrapper around `ExecutionContext` background APIs.
|
|
37
|
-
*/
|
|
38
37
|
export interface WorkerContextService {
|
|
39
38
|
readonly raw: globalThis.ExecutionContext;
|
|
40
39
|
waitUntil<A, E, R, R2 = never>(
|
|
@@ -46,36 +45,17 @@ export interface WorkerContextService {
|
|
|
46
45
|
options?: Omit<WorkerContextWaitUntilOptions<E, R2>, "mode">,
|
|
47
46
|
): Effect.Effect<void, never, R | R2>;
|
|
48
47
|
readonly passThroughOnException: Effect.Effect<void>;
|
|
49
|
-
/** Abort the current stateless Worker invocation (`ExecutionContext.abort`). */
|
|
50
48
|
abort(reason?: string): Effect.Effect<void>;
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
/**
|
|
54
|
-
* Service used inside handlers to schedule background work via `waitUntil`.
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* ```ts
|
|
58
|
-
* const handler = Effect.gen(function* () {
|
|
59
|
-
* const ctx = yield* Worker.WorkerContext;
|
|
60
|
-
* yield* ctx.waitUntil(Effect.log("flush analytics"));
|
|
61
|
-
* return new Response("ok");
|
|
62
|
-
* });
|
|
63
|
-
* ```
|
|
64
|
-
*/
|
|
65
51
|
export class WorkerContext extends Context.Service<WorkerContext, WorkerContextService>()(
|
|
66
52
|
"effect-cf/WorkerContext",
|
|
67
53
|
) {}
|
|
68
54
|
|
|
69
|
-
/**
|
|
70
|
-
* Access to the incoming `Request` currently handled by a worker or Durable Object fetch.
|
|
71
|
-
*/
|
|
72
55
|
export class NativeRequest extends Context.Service<NativeRequest, Request>()(
|
|
73
56
|
"effect-cf/NativeRequest",
|
|
74
57
|
) {}
|
|
75
58
|
|
|
76
|
-
/**
|
|
77
|
-
* Returns `true` when the request is a websocket upgrade request.
|
|
78
|
-
*/
|
|
79
59
|
export const isWebSocketUpgrade = (request: Request): boolean =>
|
|
80
60
|
request.headers.get("Upgrade")?.toLowerCase() === "websocket";
|
|
81
61
|
|
|
@@ -120,14 +100,16 @@ type WorkerFetchContext<ROut> =
|
|
|
120
100
|
type WorkerRpcContext<ROut> = WorkerBaseContext<ROut> | Scope.Scope;
|
|
121
101
|
|
|
122
102
|
type RuntimeContext<ROut> = WorkerBaseContext<ROut>;
|
|
123
|
-
|
|
103
|
+
/** Override to instrument the whole event, then call super[RunSymbol]. */
|
|
104
|
+
export const RunSymbol = Symbol.for("effect-cf/Worker/run");
|
|
124
105
|
const FetchSymbol = Symbol.for("effect-cf/Worker/fetch");
|
|
125
106
|
|
|
126
|
-
/**
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
107
|
+
/** Metadata available before an event effect or its event layer starts. */
|
|
108
|
+
export interface RunOptions {
|
|
109
|
+
readonly event?: "fetch" | "rpc" | "queue";
|
|
110
|
+
readonly rpc?: RpcInvocationInfo;
|
|
111
|
+
}
|
|
112
|
+
|
|
131
113
|
export type WorkerFetchSuccess = Response | HttpServerResponse.HttpServerResponse;
|
|
132
114
|
|
|
133
115
|
/**
|
|
@@ -173,9 +155,6 @@ export type RpcHandlers<ROut, Api> = {
|
|
|
173
155
|
: never;
|
|
174
156
|
};
|
|
175
157
|
|
|
176
|
-
/**
|
|
177
|
-
* Options for creating a worker class with Effect handlers.
|
|
178
|
-
*/
|
|
179
158
|
export interface WorkerOptions<
|
|
180
159
|
RRuntime,
|
|
181
160
|
REvent = never,
|
|
@@ -191,13 +170,11 @@ export interface WorkerOptions<
|
|
|
191
170
|
* flush capped at two seconds; queue handlers do not flush automatically.
|
|
192
171
|
*/
|
|
193
172
|
readonly eventLayer?: Layer.Layer<REvent, EventLayerError, WorkerBaseContext<RRuntime>>;
|
|
194
|
-
/** Main request handler. */
|
|
195
173
|
readonly fetch?: Effect.Effect<
|
|
196
174
|
WorkerFetchSuccess,
|
|
197
175
|
unknown,
|
|
198
176
|
WorkerFetchContext<RRuntime | REvent>
|
|
199
177
|
>;
|
|
200
|
-
/** Queue consumer handler invoked per message batch. */
|
|
201
178
|
readonly queue?: QueueHandler<RRuntime | REvent>;
|
|
202
179
|
/**
|
|
203
180
|
* Optional RPC methods exposed as class instance methods.
|
|
@@ -207,6 +184,8 @@ export interface WorkerOptions<
|
|
|
207
184
|
* flush silently settles within two seconds even if the exporter does not.
|
|
208
185
|
*/
|
|
209
186
|
readonly rpc?: Rpc;
|
|
187
|
+
/** Accept live native trace metadata. The client must also enable rpcTracing. */
|
|
188
|
+
readonly rpcTracing?: ReceiverOptions;
|
|
210
189
|
}
|
|
211
190
|
|
|
212
191
|
type WorkerOptionsWithEventLayer<
|
|
@@ -241,6 +220,10 @@ export type WorkerClass<Rpc extends WorkerRpc<ROut>, ROut> = new (
|
|
|
241
220
|
) => CloudflareWorkerEntrypoint<WorkerEnv> & {
|
|
242
221
|
fetch(request: Request): Promise<Response>;
|
|
243
222
|
queue(batch: globalThis.MessageBatch): Promise<void>;
|
|
223
|
+
[RunSymbol]<A, E>(
|
|
224
|
+
effect: Effect.Effect<A, E, WorkerRpcContext<ROut>>,
|
|
225
|
+
options?: RunOptions,
|
|
226
|
+
): Promise<A>;
|
|
244
227
|
[FetchSymbol](request: Request, requestContext: globalThis.ExecutionContext): Promise<Response>;
|
|
245
228
|
} & WorkerRpcContract<Rpc, ROut>;
|
|
246
229
|
|
|
@@ -313,19 +296,8 @@ const scheduleTelemetryFlush: Effect.Effect<void, never, WorkerContext> =
|
|
|
313
296
|
);
|
|
314
297
|
|
|
315
298
|
/**
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* The runtime layer is built when Cloudflare constructs the class and reused
|
|
319
|
-
* for every event the instance handles. Layer finalizers do not run when the
|
|
320
|
-
* isolate is evicted; Cloudflare provides no shutdown hook. Use `eventLayer`
|
|
321
|
-
* for resources that must be finalized per event.
|
|
322
|
-
*
|
|
323
|
-
* @example
|
|
324
|
-
* ```ts
|
|
325
|
-
* export default Worker.make(Layer.empty, {
|
|
326
|
-
* fetch: Effect.succeed(new Response("ok")),
|
|
327
|
-
* });
|
|
328
|
-
* ```
|
|
299
|
+
* The layer is built once per Worker instance and reused for its events.
|
|
300
|
+
* Eviction skips finalizers, so use `eventLayer` for per-event resources.
|
|
329
301
|
*/
|
|
330
302
|
export function make<ROut, LayerError>(
|
|
331
303
|
layer: Layer.Layer<ROut, LayerError, ExecutionContext | WorkerContext | WorkerEnvironment>,
|
|
@@ -387,8 +359,11 @@ export function make<
|
|
|
387
359
|
|
|
388
360
|
[RunSymbol]<A, E>(
|
|
389
361
|
effect: Effect.Effect<A, E, RuntimeContext<ROut> | REvent | Scope.Scope>,
|
|
362
|
+
runOptions: RunOptions = {},
|
|
390
363
|
): Promise<A> {
|
|
391
364
|
const eventLayer = options.eventLayer;
|
|
365
|
+
const parent = runOptions.rpc?.parent;
|
|
366
|
+
const parentSpan = parent === undefined ? undefined : Tracer.externalSpan(parent);
|
|
392
367
|
|
|
393
368
|
if (eventLayer === undefined) {
|
|
394
369
|
// SAFETY: the public make overloads permit an absent event layer only when REvent is never.
|
|
@@ -396,6 +371,8 @@ export function make<
|
|
|
396
371
|
this.runtime,
|
|
397
372
|
// @effect-diagnostics-next-line unsafeEffectTypeAssertion:off
|
|
398
373
|
effect as Effect.Effect<A, E, RuntimeContext<ROut> | Scope.Scope>,
|
|
374
|
+
undefined,
|
|
375
|
+
parentSpan,
|
|
399
376
|
);
|
|
400
377
|
}
|
|
401
378
|
|
|
@@ -406,7 +383,7 @@ export function make<
|
|
|
406
383
|
REvent,
|
|
407
384
|
EventLayerError,
|
|
408
385
|
LayerError
|
|
409
|
-
>(this.runtime, effect, eventLayer);
|
|
386
|
+
>(this.runtime, effect, eventLayer, parentSpan);
|
|
410
387
|
}
|
|
411
388
|
|
|
412
389
|
fetch(request: Request): Promise<Response> {
|
|
@@ -437,6 +414,7 @@ export function make<
|
|
|
437
414
|
Effect.tap(() => scheduleTelemetryFlush),
|
|
438
415
|
Effect.provide(requestServices),
|
|
439
416
|
) as Effect.Effect<Response, unknown, RuntimeContext<ROut> | REvent | Scope.Scope>,
|
|
417
|
+
{ event: "fetch" },
|
|
440
418
|
);
|
|
441
419
|
}
|
|
442
420
|
|
|
@@ -449,7 +427,7 @@ export function make<
|
|
|
449
427
|
|
|
450
428
|
const messages = batch.messages.map((message) => fromMessage(message, message.body));
|
|
451
429
|
|
|
452
|
-
return this[RunSymbol](queueHandler(fromMessageBatch(batch, messages)));
|
|
430
|
+
return this[RunSymbol](queueHandler(fromMessageBatch(batch, messages)), { event: "queue" });
|
|
453
431
|
}
|
|
454
432
|
}
|
|
455
433
|
|
|
@@ -458,8 +436,9 @@ export function make<
|
|
|
458
436
|
EffectWorker.prototype,
|
|
459
437
|
options.rpc,
|
|
460
438
|
reservedMethodNames,
|
|
461
|
-
(self, effect) => self[RunSymbol](effect),
|
|
439
|
+
(self, effect, rpc) => self[RunSymbol](effect, { event: "rpc", rpc }),
|
|
462
440
|
() => scheduleTelemetryFlush,
|
|
441
|
+
options.rpcTracing,
|
|
463
442
|
);
|
|
464
443
|
|
|
465
444
|
return Entrypoint.assumeEntrypointClass<WorkerClass<Rpc, ROut | REvent>>(EffectWorker);
|
package/src/WorkerDefinition.ts
CHANGED
|
@@ -6,6 +6,7 @@ import * as WorkerEntrypoint from "./Worker";
|
|
|
6
6
|
import type { WorkerRpcHandler } from "./Worker";
|
|
7
7
|
import type * as Rpc from "./Rpc";
|
|
8
8
|
import * as RpcDefinition from "./RpcDefinition";
|
|
9
|
+
import { recordDecodedArgs } from "./internal/RpcInvocation";
|
|
9
10
|
import * as ServiceBinding from "./ServiceBinding";
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -37,7 +38,6 @@ export namespace Method {
|
|
|
37
38
|
? [S.Schema.Type<Head>, ...ArgsFromSchemas<Tail>]
|
|
38
39
|
: Array<S.Schema.Type<Args[number]>>;
|
|
39
40
|
|
|
40
|
-
/** Method schemas cross the wire through their canonical JSON codec. */
|
|
41
41
|
type EncodedArgsFromSchemas<Args extends ReadonlyArray<ServiceFreeSchema>> = {
|
|
42
42
|
[Index in keyof Args]: S.Json;
|
|
43
43
|
};
|
|
@@ -153,6 +153,7 @@ export type Options<
|
|
|
153
153
|
|
|
154
154
|
export type LayerOptions = {
|
|
155
155
|
readonly binding: string;
|
|
156
|
+
readonly rpcTracing?: boolean;
|
|
156
157
|
};
|
|
157
158
|
|
|
158
159
|
export type TagClass<
|
|
@@ -236,19 +237,6 @@ export const method: {
|
|
|
236
237
|
}): Method<Args, Success>;
|
|
237
238
|
} = RpcDefinition.method;
|
|
238
239
|
|
|
239
|
-
/**
|
|
240
|
-
* Creates a typed worker RPC definition plus helpers for implementation and bindings.
|
|
241
|
-
*
|
|
242
|
-
* @example
|
|
243
|
-
* ```ts
|
|
244
|
-
* const CounterWorker = WorkerDefinition.make("CounterWorker", {
|
|
245
|
-
* increment: WorkerDefinition.method({
|
|
246
|
-
* args: [Schema.Number],
|
|
247
|
-
* success: Schema.Number,
|
|
248
|
-
* }),
|
|
249
|
-
* });
|
|
250
|
-
* ```
|
|
251
|
-
*/
|
|
252
240
|
const makeDefinition = <Id extends string, const MethodDefinitions extends Methods>(
|
|
253
241
|
id: Id,
|
|
254
242
|
methods: MethodDefinitions & NoReservedMethods<MethodDefinitions>,
|
|
@@ -414,6 +402,9 @@ const wrapHandlers = <ROut, const Self extends Definition.Any>(
|
|
|
414
402
|
wrapped[key] = (...args: Array<unknown>) =>
|
|
415
403
|
Effect.gen(function* () {
|
|
416
404
|
const decodedArgs = yield* RpcDefinition.decodeArgs(definition, key, args);
|
|
405
|
+
|
|
406
|
+
yield* recordDecodedArgs(decodedArgs);
|
|
407
|
+
|
|
417
408
|
const value = yield* handler(...decodedArgs);
|
|
418
409
|
|
|
419
410
|
return yield* RpcDefinition.encodeSuccess(definition, key, value);
|
package/src/WorkersAi.ts
CHANGED
|
@@ -18,7 +18,6 @@ import * as ErrorMessage from "./internal/ErrorMessage";
|
|
|
18
18
|
|
|
19
19
|
const expectedWorkersAiBinding = "Workers AI binding with run(), gateway(), and models()";
|
|
20
20
|
|
|
21
|
-
/** Error raised when a Workers AI operation fails. */
|
|
22
21
|
export class WorkersAiOperationError extends Data.TaggedError("WorkersAiOperationError")<{
|
|
23
22
|
readonly binding: string;
|
|
24
23
|
readonly operation: string;
|
|
@@ -29,9 +28,7 @@ export class WorkersAiOperationError extends Data.TaggedError("WorkersAiOperatio
|
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/** Typed Workers AI binding definition. */
|
|
33
31
|
export interface WorkersAiDefinition {
|
|
34
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
35
32
|
readonly binding: string;
|
|
36
33
|
}
|
|
37
34
|
|
|
@@ -117,7 +114,6 @@ export interface WorkersAiClient<ModelList extends AiModelListType = AiModels> {
|
|
|
117
114
|
|
|
118
115
|
declare const WorkersAiServiceTypeId: unique symbol;
|
|
119
116
|
|
|
120
|
-
/** Nominal service marker for Workers AI services created with {@link make}. */
|
|
121
117
|
export interface WorkersAiService<Id extends string> {
|
|
122
118
|
readonly [WorkersAiServiceTypeId]: {
|
|
123
119
|
readonly id: Id;
|
package/src/Workflow.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Effect wrapper for Cloudflare Workflows entrypoints and bindings; distinct
|
|
3
|
-
* from Effect's runtime-agnostic `effect/unstable/workflow` cluster module.
|
|
4
|
-
*/
|
|
5
1
|
import {
|
|
6
2
|
WorkflowEntrypoint as CloudflareWorkflowEntrypoint,
|
|
7
3
|
type WorkflowEvent as CloudflareWorkflowEvent,
|
|
@@ -46,7 +42,6 @@ export class WorkflowEvent extends Context.Service<WorkflowEvent, WorkflowEventS
|
|
|
46
42
|
|
|
47
43
|
type RunWorkflowStepEffect = <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>;
|
|
48
44
|
|
|
49
|
-
/** Failure raised when a Cloudflare Workflow step operation rejects. */
|
|
50
45
|
export class WorkflowStepError extends Data.TaggedError("WorkflowStepError")<{
|
|
51
46
|
readonly step?: string;
|
|
52
47
|
readonly operation: string;
|
package/src/WorkflowBinding.ts
CHANGED
|
@@ -67,11 +67,8 @@ export interface WorkflowBindingDefinition<
|
|
|
67
67
|
Payload extends RpcDefinition.ServiceFreeSchema,
|
|
68
68
|
Result extends RpcDefinition.ServiceFreeSchema,
|
|
69
69
|
> {
|
|
70
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
71
70
|
readonly binding: string;
|
|
72
|
-
/** Codec used to encode payloads passed to `Workflow.create`. */
|
|
73
71
|
readonly payload: Payload;
|
|
74
|
-
/** Codec used to decode completed workflow status output. */
|
|
75
72
|
readonly result: Result;
|
|
76
73
|
}
|
|
77
74
|
|
package/src/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export * as QueueDefinition from "./QueueDefinition";
|
|
|
27
27
|
export * as R2 from "./R2";
|
|
28
28
|
export * as Rpc from "./Rpc";
|
|
29
29
|
export * as RpcDefinition from "./RpcDefinition";
|
|
30
|
+
export * as RpcTracing from "./RpcTracing";
|
|
30
31
|
export * as ServiceBinding from "./ServiceBinding";
|
|
31
32
|
export * as Vectorize from "./Vectorize";
|
|
32
33
|
export * as WebTransport from "./WebTransport";
|
|
@@ -1,26 +1,44 @@
|
|
|
1
1
|
import { Effect, Layer, Schema } from "effect";
|
|
2
2
|
|
|
3
3
|
import * as RpcDefinition from "../RpcDefinition";
|
|
4
|
+
import { RpcTraceContext, type ReceiverOptions, type RpcInvocationInfo } from "../RpcTracing";
|
|
5
|
+
import { CurrentInvocation } from "./RpcInvocation";
|
|
4
6
|
|
|
5
7
|
type AnyArgs = Array<any>;
|
|
6
8
|
type EntrypointRpcMethod = (...args: AnyArgs) => Effect.Effect<any, any, any>;
|
|
7
9
|
|
|
8
10
|
export type EntrypointRpc = Record<string, EntrypointRpcMethod>;
|
|
9
11
|
|
|
12
|
+
const isRpcTraceContext = Schema.is(RpcTraceContext);
|
|
13
|
+
|
|
10
14
|
const invokeEntrypointRpcMethod = <Self>(
|
|
11
15
|
self: Self,
|
|
12
16
|
method: EntrypointRpcMethod,
|
|
13
17
|
args: AnyArgs,
|
|
14
|
-
run: (self: Self, effect: Effect.Effect<any, any, any
|
|
18
|
+
run: (self: Self, effect: Effect.Effect<any, any, any>, rpc: RpcInvocationInfo) => Promise<any>,
|
|
15
19
|
onExit: ((self: Self) => Effect.Effect<void, never, any>) | undefined,
|
|
20
|
+
service: string,
|
|
21
|
+
key: string,
|
|
22
|
+
rpcTracing: ReceiverOptions | undefined,
|
|
16
23
|
): Promise<any> => {
|
|
17
|
-
const
|
|
24
|
+
const last = args.at(-1);
|
|
25
|
+
const parent = rpcTracing !== undefined && isRpcTraceContext(last) ? last : undefined;
|
|
26
|
+
const handlerArgs = parent === undefined ? args : args.slice(0, -1);
|
|
27
|
+
const invocation: CurrentInvocation["Service"] = {
|
|
28
|
+
service: rpcTracing?.service ?? service,
|
|
29
|
+
method: key,
|
|
30
|
+
args: handlerArgs,
|
|
31
|
+
parent,
|
|
32
|
+
};
|
|
33
|
+
const handler = Effect.suspend(() => method(...handlerArgs)).pipe(
|
|
34
|
+
Effect.provideService(CurrentInvocation, invocation),
|
|
18
35
|
Effect.mapError(RpcDefinition.encodeWireError),
|
|
19
36
|
);
|
|
20
37
|
|
|
21
38
|
return run(
|
|
22
39
|
self,
|
|
23
40
|
onExit === undefined ? handler : handler.pipe(Effect.onExit(() => onExit(self))),
|
|
41
|
+
invocation,
|
|
24
42
|
);
|
|
25
43
|
};
|
|
26
44
|
|
|
@@ -36,8 +54,9 @@ export const defineEntrypointRpcMethods = <Self, Prototype extends object = obje
|
|
|
36
54
|
prototype: Prototype,
|
|
37
55
|
rpc: EntrypointRpc | undefined,
|
|
38
56
|
reservedMethodNames: ReadonlySet<string>,
|
|
39
|
-
run: (self: Self, effect: Effect.Effect<any, any, any
|
|
57
|
+
run: (self: Self, effect: Effect.Effect<any, any, any>, rpc: RpcInvocationInfo) => Promise<any>,
|
|
40
58
|
onExit?: (self: Self) => Effect.Effect<void, never, any>,
|
|
59
|
+
rpcTracing?: ReceiverOptions,
|
|
41
60
|
): void => {
|
|
42
61
|
const methods = rpc ?? {};
|
|
43
62
|
|
|
@@ -47,7 +66,7 @@ export const defineEntrypointRpcMethods = <Self, Prototype extends object = obje
|
|
|
47
66
|
Object.defineProperty(prototype, key, {
|
|
48
67
|
enumerable: true,
|
|
49
68
|
value(this: Self, ...args: AnyArgs) {
|
|
50
|
-
return invokeEntrypointRpcMethod(this, method, args, run, onExit);
|
|
69
|
+
return invokeEntrypointRpcMethod(this, method, args, run, onExit, target, key, rpcTracing);
|
|
51
70
|
},
|
|
52
71
|
});
|
|
53
72
|
}
|
|
@@ -18,7 +18,6 @@ export const causeMessage = (cause: unknown): string => {
|
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
/** Renders a violation list as a single `path: message; ...` line. */
|
|
22
21
|
export const violationsMessage = (
|
|
23
22
|
violations: ReadonlyArray<{ readonly path: string; readonly message: string }>,
|
|
24
23
|
): string => violations.map((violation) => `${violation.path}: ${violation.message}`).join("; ");
|
|
@@ -1,9 +1,26 @@
|
|
|
1
|
-
import { Effect, Predicate, Schema } from "effect";
|
|
1
|
+
import { Context, Effect, Option, Predicate, Schema } from "effect";
|
|
2
2
|
|
|
3
3
|
import type * as CloudflareRpc from "../Rpc";
|
|
4
|
+
import type { RpcInvocationInfo } from "../RpcTracing";
|
|
4
5
|
|
|
5
6
|
type AnyArgs = Array<any>;
|
|
6
7
|
|
|
8
|
+
interface Invocation extends RpcInvocationInfo {
|
|
9
|
+
decodedArgs?: ReadonlyArray<unknown>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Scoped to the incoming event effect, never the instance runtime or storage. */
|
|
13
|
+
export class CurrentInvocation extends Context.Service<CurrentInvocation, Invocation>()(
|
|
14
|
+
"effect-cf/internal/RpcInvocation",
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
export const recordDecodedArgs = (args: ReadonlyArray<unknown>): Effect.Effect<void> =>
|
|
18
|
+
Effect.map(Effect.serviceOption(CurrentInvocation), (invocation) => {
|
|
19
|
+
if (Option.isSome(invocation)) {
|
|
20
|
+
invocation.value.decodedArgs = args;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
7
24
|
export type AsyncMethodKey<Api> = {
|
|
8
25
|
[Key in keyof Api]-?: Key extends string
|
|
9
26
|
? Api[Key] extends (...args: AnyArgs) => Promise<any>
|
package/src/internal/Runtime.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConfigProvider, Effect, Layer, ManagedRuntime, type Scope } from "effect";
|
|
1
|
+
import { ConfigProvider, Effect, Layer, ManagedRuntime, type Scope, type Tracer } from "effect";
|
|
2
2
|
|
|
3
3
|
import { WorkerConfig, WorkerEnvironment, type WorkerEnv } from "../Environment";
|
|
4
4
|
import { provideEntrypointServices } from "./Entrypoint";
|
|
@@ -26,17 +26,18 @@ export const makeEntrypointRuntime = <ROut, LayerError, Services>(
|
|
|
26
26
|
return ManagedRuntime.make(provideEntrypointServices(layer, entrypointServices));
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
/** Runs an event effect whose requirements are already available in the runtime. */
|
|
30
29
|
export function runEventPromise<A, E, R, LayerError>(
|
|
31
30
|
runtime: ManagedRuntime.ManagedRuntime<R, LayerError>,
|
|
32
31
|
effect: Effect.Effect<A, E, NoInfer<R> | Scope.Scope>,
|
|
33
32
|
eventLayer?: undefined,
|
|
33
|
+
parent?: Tracer.AnySpan,
|
|
34
34
|
): Promise<A>;
|
|
35
35
|
/** Builds and provides an event layer inside the event effect's scope. */
|
|
36
36
|
export function runEventPromise<A, E, R, REvent, EventLayerError, LayerError>(
|
|
37
37
|
runtime: ManagedRuntime.ManagedRuntime<R, LayerError>,
|
|
38
38
|
effect: Effect.Effect<A, E, NoInfer<R> | REvent | Scope.Scope>,
|
|
39
39
|
eventLayer: Layer.Layer<REvent, EventLayerError, NoInfer<R>>,
|
|
40
|
+
parent?: Tracer.AnySpan,
|
|
40
41
|
): Promise<A>;
|
|
41
42
|
export function runEventPromise<A, E, R, REvent, EventLayerError, LayerError>(
|
|
42
43
|
...args:
|
|
@@ -44,20 +45,24 @@ export function runEventPromise<A, E, R, REvent, EventLayerError, LayerError>(
|
|
|
44
45
|
runtime: ManagedRuntime.ManagedRuntime<R, LayerError>,
|
|
45
46
|
effect: Effect.Effect<A, E, R | Scope.Scope>,
|
|
46
47
|
eventLayer?: undefined,
|
|
48
|
+
parent?: Tracer.AnySpan,
|
|
47
49
|
]
|
|
48
50
|
| readonly [
|
|
49
51
|
runtime: ManagedRuntime.ManagedRuntime<R, LayerError>,
|
|
50
52
|
effect: Effect.Effect<A, E, R | REvent | Scope.Scope>,
|
|
51
53
|
eventLayer: Layer.Layer<REvent, EventLayerError, R>,
|
|
54
|
+
parent?: Tracer.AnySpan,
|
|
52
55
|
]
|
|
53
56
|
): Promise<A> {
|
|
54
|
-
const [runtime, effect, eventLayer] = args;
|
|
57
|
+
const [runtime, effect, eventLayer, parent] = args;
|
|
55
58
|
|
|
56
59
|
if (eventLayer === undefined) {
|
|
57
|
-
|
|
60
|
+
const event = Effect.scoped(effect);
|
|
61
|
+
|
|
62
|
+
return runtime.runPromise(parent === undefined ? event : Effect.withParentSpan(event, parent));
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
);
|
|
65
|
+
const event = Effect.scoped(effect.pipe(Effect.provide(eventLayer, { local: true })));
|
|
66
|
+
|
|
67
|
+
return runtime.runPromise(parent === undefined ? event : Effect.withParentSpan(event, parent));
|
|
63
68
|
}
|
|
@@ -27,14 +27,6 @@ const failureHandler = <E, R>(
|
|
|
27
27
|
),
|
|
28
28
|
);
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* Builds a `waitUntil` scheduler for any Cloudflare lifecycle that accepts
|
|
32
|
-
* background promises (`ExecutionContext`, `DurableObjectState`).
|
|
33
|
-
*
|
|
34
|
-
* Background effects capture the calling fiber's context via `Effect.context`
|
|
35
|
-
* before being registered, so the default module-level `Effect.runPromiseExit`
|
|
36
|
-
* runner is sufficient; entrypoints may still pass a runtime-bound runner.
|
|
37
|
-
*/
|
|
38
30
|
export const makeWaitUntilScheduler = (
|
|
39
31
|
label: string,
|
|
40
32
|
register: (promise: Promise<unknown>) => void,
|
|
@@ -77,9 +69,6 @@ export const makeWaitUntilScheduler = (
|
|
|
77
69
|
);
|
|
78
70
|
};
|
|
79
71
|
|
|
80
|
-
/**
|
|
81
|
-
* Builds the `WorkerContext` service from a native `ExecutionContext`.
|
|
82
|
-
*/
|
|
83
72
|
export const fromExecutionContext = (
|
|
84
73
|
ctx: globalThis.ExecutionContext,
|
|
85
74
|
runPromiseExit: RunWaitUntilEffect = (effect) => Effect.runPromiseExit(effect),
|