effect-cf 0.33.0 → 0.35.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 +22 -0
- package/README.md +31 -1079
- 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 +11 -12
- package/dist/ComputerWorkspace.mjs +31 -10
- package/dist/ComputerWorkspaceHost.d.mts +1 -9
- package/dist/{ContainerNamespace-CFjiLw8b.d.mts → ContainerNamespace-DbLaeFhN.d.mts} +1 -14
- package/dist/{DurableObjectState-CVLLse69.mjs → DurableObjectState-DcqElJ4e.mjs} +82 -89
- package/dist/{DurableObjectState-BpRjz6-q.d.mts → DurableObjectState-DpYdNZgT.d.mts} +102 -266
- 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 +8 -26
- package/dist/{WorkflowBinding-lBR4_-op.d.mts → WorkflowBinding-Cn3AuUyP.d.mts} +2 -5
- package/dist/index.d.mts +42 -480
- package/dist/index.mjs +267 -380
- package/package.json +1 -1
- package/src/AiGateway.ts +0 -6
- package/src/AnalyticsEngine.ts +8 -10
- 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 +6 -39
- package/src/ComputerArtifacts.ts +0 -2
- package/src/ComputerWorkspace.ts +53 -35
- package/src/ComputerWorkspaceHost.ts +0 -8
- package/src/ContainerNamespace.ts +0 -13
- package/src/D1.ts +0 -22
- package/src/DurableObject.ts +51 -32
- package/src/DurableObjectAlarm.ts +6 -210
- package/src/DurableObjectDefinition.ts +8 -20
- package/src/DurableObjectNamespace.ts +88 -115
- package/src/DurableObjectRpcWebSocket.ts +5 -46
- package/src/DurableObjectSqlite.ts +0 -12
- package/src/DurableObjectState.ts +18 -38
- package/src/DurableObjectStorage.ts +55 -70
- package/src/DurableObjectWebSocket.ts +23 -72
- 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 +5 -17
- package/src/RpcTracing.ts +133 -0
- package/src/Sandbox.ts +0 -30
- package/src/ServiceBinding.ts +83 -128
- package/src/Vectorize.ts +0 -5
- package/src/Vitest.ts +18 -43
- package/src/WebTransport.ts +0 -15
- package/src/Worker.ts +140 -108
- package/src/WorkerDefinition.ts +5 -14
- package/src/WorkersAi.ts +21 -18
- package/src/Workflow.ts +45 -54
- 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/NativeCallback.ts +55 -0
- package/src/internal/RpcInvocation.ts +18 -1
- package/src/internal/Runtime.ts +12 -7
- package/src/internal/WorkerContext.ts +5 -14
package/src/ServiceBinding.ts
CHANGED
|
@@ -6,13 +6,11 @@ import * as RpcDefinition from "./RpcDefinition";
|
|
|
6
6
|
import type * as WorkerDefinition from "./WorkerDefinition";
|
|
7
7
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
8
8
|
import * as RpcInvocation from "./internal/RpcInvocation";
|
|
9
|
+
import * as RpcTracing from "./RpcTracing";
|
|
9
10
|
|
|
10
11
|
const TypeId = "effect-cf/ServiceBinding" as const;
|
|
11
12
|
const expectedServiceBinding = "Worker service binding with fetch()";
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
* Minimum shape for a Cloudflare service binding.
|
|
15
|
-
*/
|
|
16
14
|
export interface ServiceFetcher {
|
|
17
15
|
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
18
16
|
}
|
|
@@ -27,9 +25,6 @@ type RpcClient<Api> = {
|
|
|
27
25
|
|
|
28
26
|
type ReservedMethodName = WorkerDefinition.ReservedMethodName | "fetch";
|
|
29
27
|
|
|
30
|
-
/**
|
|
31
|
-
* Native Cloudflare service object including optional RPC methods.
|
|
32
|
-
*/
|
|
33
28
|
export type ServiceBindingClient<Api extends object> = ServiceFetcher &
|
|
34
29
|
RpcClient<CloudflareRpc.Provider<Api, ReservedMethodName>>;
|
|
35
30
|
|
|
@@ -47,10 +42,10 @@ type ApiOrDefinition<Api extends object, Definition> = [Api] extends [never]
|
|
|
47
42
|
export interface ServiceBindingDefinition<
|
|
48
43
|
Definition extends WorkerDefinition.Definition.Any | undefined = undefined,
|
|
49
44
|
> {
|
|
50
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
51
45
|
readonly binding: string;
|
|
52
|
-
/** Optional RPC schema used for argument/result encoding. */
|
|
53
46
|
readonly definition?: Definition;
|
|
47
|
+
/** Append live trace context only when the receiver also enables rpcTracing. */
|
|
48
|
+
readonly rpcTracing?: boolean;
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
/**
|
|
@@ -112,22 +107,6 @@ export type ServiceBindingEffectClient<
|
|
|
112
107
|
Api extends object,
|
|
113
108
|
Definition extends WorkerDefinition.Definition.Any | undefined = undefined,
|
|
114
109
|
> = DirectMethods<never, Definition> & {
|
|
115
|
-
/**
|
|
116
|
-
* Forwards an HTTP request to the bound Worker service.
|
|
117
|
-
*
|
|
118
|
-
* Use this when the service binding is acting as an HTTP origin rather than a
|
|
119
|
-
* Cloudflare RPC target.
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```ts
|
|
123
|
-
* import { Effect } from "effect";
|
|
124
|
-
*
|
|
125
|
-
* const program = Effect.gen(function* () {
|
|
126
|
-
* const api = yield* ApiWorker;
|
|
127
|
-
* return yield* api.fetch(new Request("https://internal.example/users"));
|
|
128
|
-
* });
|
|
129
|
-
* ```
|
|
130
|
-
*/
|
|
131
110
|
readonly fetch: (
|
|
132
111
|
input: RequestInfo | URL,
|
|
133
112
|
init?: RequestInit,
|
|
@@ -140,20 +119,6 @@ export type ServiceBindingEffectClient<
|
|
|
140
119
|
* promise-like value and it does not decode definition-backed success schemas.
|
|
141
120
|
*
|
|
142
121
|
* Most application code should use {@link call} instead.
|
|
143
|
-
*
|
|
144
|
-
* @example
|
|
145
|
-
* ```ts
|
|
146
|
-
* import { Effect } from "effect";
|
|
147
|
-
*
|
|
148
|
-
* const program = Effect.gen(function* () {
|
|
149
|
-
* const counter = yield* CounterService;
|
|
150
|
-
*
|
|
151
|
-
* const result = yield* counter.rpc("increment", 41);
|
|
152
|
-
* const value = yield* Effect.promise(() => result);
|
|
153
|
-
*
|
|
154
|
-
* return value;
|
|
155
|
-
* });
|
|
156
|
-
* ```
|
|
157
122
|
*/
|
|
158
123
|
readonly rpc: <Method extends ServiceMethodKey<Api>>(
|
|
159
124
|
method: Method,
|
|
@@ -164,18 +129,6 @@ export type ServiceBindingEffectClient<
|
|
|
164
129
|
* the success value when the binding was created from a definition.
|
|
165
130
|
*
|
|
166
131
|
* This is the normal choice when application code wants the final typed value.
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* ```ts
|
|
170
|
-
* import { Effect } from "effect";
|
|
171
|
-
*
|
|
172
|
-
* const program = Effect.gen(function* () {
|
|
173
|
-
* const counter = yield* CounterService;
|
|
174
|
-
* const value = yield* counter.call("increment", 41);
|
|
175
|
-
*
|
|
176
|
-
* return value;
|
|
177
|
-
* });
|
|
178
|
-
* ```
|
|
179
132
|
*/
|
|
180
133
|
readonly call: <Method extends ServiceMethodKey<Api>>(
|
|
181
134
|
method: Method,
|
|
@@ -188,25 +141,15 @@ export type ServiceBindingEffectClient<
|
|
|
188
141
|
*
|
|
189
142
|
* Use this for RPC methods that return Cloudflare RPC resources or other
|
|
190
143
|
* disposable objects whose lifetime should be tied to an Effect scope.
|
|
191
|
-
*
|
|
192
|
-
* @example
|
|
193
|
-
* ```ts
|
|
194
|
-
* import { Effect } from "effect";
|
|
195
|
-
*
|
|
196
|
-
* const program = Effect.scoped(
|
|
197
|
-
* Effect.gen(function* () {
|
|
198
|
-
* const files = yield* FileService;
|
|
199
|
-
* const handle = yield* files.scopedCall("open", "report.csv");
|
|
200
|
-
*
|
|
201
|
-
* return yield* handle.read();
|
|
202
|
-
* }),
|
|
203
|
-
* );
|
|
204
|
-
* ```
|
|
205
144
|
*/
|
|
206
145
|
readonly scopedCall: <Method extends ServiceMethodKey<Api>>(
|
|
207
146
|
method: Method,
|
|
208
147
|
...args: ServiceMethodArgs<Api, Method>
|
|
209
|
-
) => Effect.Effect<
|
|
148
|
+
) => Effect.Effect<
|
|
149
|
+
Awaited<ServiceMethodSuccess<Api, Method>>,
|
|
150
|
+
ServiceBindingRpcError,
|
|
151
|
+
Scope.Scope
|
|
152
|
+
>;
|
|
210
153
|
};
|
|
211
154
|
|
|
212
155
|
export type ServiceBindingStaticClient<
|
|
@@ -229,7 +172,11 @@ export type ServiceBindingStaticClient<
|
|
|
229
172
|
readonly scopedCall: <Method extends ServiceMethodKey<Api>>(
|
|
230
173
|
method: Method,
|
|
231
174
|
...args: ServiceMethodArgs<Api, Method>
|
|
232
|
-
) => Effect.Effect<
|
|
175
|
+
) => Effect.Effect<
|
|
176
|
+
Awaited<ServiceMethodSuccess<Api, Method>>,
|
|
177
|
+
ServiceBindingRpcError,
|
|
178
|
+
Scope.Scope | R
|
|
179
|
+
>;
|
|
233
180
|
};
|
|
234
181
|
|
|
235
182
|
type ServiceBindingValue = Schema.Schema.Type<typeof Schema.Unknown>;
|
|
@@ -256,15 +203,30 @@ export const makeClient = <
|
|
|
256
203
|
init?: RequestInit,
|
|
257
204
|
) {
|
|
258
205
|
return yield* Effect.tryPromise({
|
|
259
|
-
try: () =>
|
|
206
|
+
try: (signal) => {
|
|
207
|
+
const callerSignal =
|
|
208
|
+
init?.signal !== undefined
|
|
209
|
+
? init.signal
|
|
210
|
+
: input instanceof Request
|
|
211
|
+
? input.signal
|
|
212
|
+
: undefined;
|
|
213
|
+
|
|
214
|
+
return service.fetch(input, {
|
|
215
|
+
...init,
|
|
216
|
+
signal:
|
|
217
|
+
callerSignal === null || callerSignal === undefined
|
|
218
|
+
? signal
|
|
219
|
+
: AbortSignal.any([callerSignal, signal]),
|
|
220
|
+
});
|
|
221
|
+
},
|
|
260
222
|
catch: (cause) => new ServiceBindingFetchError({ binding: definition.binding, cause }),
|
|
261
223
|
});
|
|
262
224
|
});
|
|
263
225
|
|
|
264
|
-
const rpc = Effect.
|
|
226
|
+
const rpc = Effect.fnUntraced(function* <Method extends ServiceMethodKey<Api>>(
|
|
265
227
|
method: Method,
|
|
266
228
|
...args: ServiceMethodArgs<Api, Method>
|
|
267
|
-
) {
|
|
229
|
+
): Effect.fn.Return<ServiceMethodCloudflareReturn<Api, Method>, ServiceBindingRpcError> {
|
|
268
230
|
const methodName = String(method);
|
|
269
231
|
// SAFETY: definition-backed clients derive Method and Args from this exact RPC definition.
|
|
270
232
|
const encodedArgs =
|
|
@@ -285,11 +247,15 @@ export const makeClient = <
|
|
|
285
247
|
),
|
|
286
248
|
);
|
|
287
249
|
|
|
288
|
-
|
|
250
|
+
const nativeArgs = definition.rpcTracing
|
|
251
|
+
? yield* RpcTracing.withRpcTraceContext(encodedArgs)
|
|
252
|
+
: encodedArgs;
|
|
253
|
+
|
|
254
|
+
// SAFETY: domain arguments retain their encoded order; an opted-in receiver strips only valid trace metadata.
|
|
289
255
|
return yield* RpcInvocation.invokeRpcMethod(
|
|
290
256
|
service,
|
|
291
257
|
method,
|
|
292
|
-
|
|
258
|
+
nativeArgs as ServiceMethodArgs<Api, Method>,
|
|
293
259
|
(cause) =>
|
|
294
260
|
new ServiceBindingRpcError({
|
|
295
261
|
binding: definition.binding,
|
|
@@ -302,7 +268,7 @@ export const makeClient = <
|
|
|
302
268
|
const decodeSuccess = Effect.fnUntraced(function* <Method extends ServiceMethodKey<Api>>(
|
|
303
269
|
methodName: string,
|
|
304
270
|
value: Awaited<ServiceMethodCloudflareReturn<Api, Method>>,
|
|
305
|
-
) {
|
|
271
|
+
): Effect.fn.Return<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError> {
|
|
306
272
|
if (definition.definition === undefined) {
|
|
307
273
|
// SAFETY: without a definition the resolved native RPC value is the API method's declared success.
|
|
308
274
|
return value as ServiceMethodSuccess<Api, Method>;
|
|
@@ -328,34 +294,52 @@ export const makeClient = <
|
|
|
328
294
|
return decoded as ServiceMethodSuccess<Api, Method>;
|
|
329
295
|
});
|
|
330
296
|
|
|
331
|
-
const call = Effect.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const methodName = String(method);
|
|
354
|
-
const result = yield* rpc(method, ...args);
|
|
355
|
-
const value = yield* CloudflareRpc.scoped(result);
|
|
297
|
+
const call = Effect.fnUntraced(
|
|
298
|
+
function* <Method extends ServiceMethodKey<Api>>(
|
|
299
|
+
method: Method,
|
|
300
|
+
...args: ServiceMethodArgs<Api, Method>
|
|
301
|
+
): Effect.fn.Return<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError> {
|
|
302
|
+
const methodName = String(method);
|
|
303
|
+
const value = yield* CloudflareRpc.resolve(yield* rpc(method, ...args)).pipe(
|
|
304
|
+
Effect.mapError(
|
|
305
|
+
(cause) =>
|
|
306
|
+
new ServiceBindingRpcError({
|
|
307
|
+
binding: definition.binding,
|
|
308
|
+
method: methodName,
|
|
309
|
+
cause,
|
|
310
|
+
}),
|
|
311
|
+
),
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
return yield* decodeSuccess<Method>(methodName, value);
|
|
315
|
+
},
|
|
316
|
+
(effect, ...args) =>
|
|
317
|
+
RpcTracing.withRpcClientSpan(effect, definition.binding, String(args[0])),
|
|
318
|
+
);
|
|
356
319
|
|
|
357
|
-
|
|
358
|
-
|
|
320
|
+
const scopedCall = Effect.fnUntraced(
|
|
321
|
+
function* <Method extends ServiceMethodKey<Api>>(
|
|
322
|
+
method: Method,
|
|
323
|
+
...args: ServiceMethodArgs<Api, Method>
|
|
324
|
+
): Effect.fn.Return<ServiceMethodSuccess<Api, Method>, ServiceBindingRpcError, Scope.Scope> {
|
|
325
|
+
const methodName = String(method);
|
|
326
|
+
const result = yield* rpc(method, ...args);
|
|
327
|
+
const value = yield* CloudflareRpc.scoped(result).pipe(
|
|
328
|
+
Effect.mapError(
|
|
329
|
+
(cause) =>
|
|
330
|
+
new ServiceBindingRpcError({
|
|
331
|
+
binding: definition.binding,
|
|
332
|
+
method: methodName,
|
|
333
|
+
cause,
|
|
334
|
+
}),
|
|
335
|
+
),
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
return yield* decodeSuccess<Method>(methodName, value);
|
|
339
|
+
},
|
|
340
|
+
(effect, ...args) =>
|
|
341
|
+
RpcTracing.withRpcClientSpan(effect, definition.binding, String(args[0])),
|
|
342
|
+
);
|
|
359
343
|
|
|
360
344
|
const directMethods = makeDirectMethods<never, Api, Definition>(definition.definition, call);
|
|
361
345
|
|
|
@@ -385,35 +369,6 @@ export const layer = <
|
|
|
385
369
|
{ expected: expectedServiceBinding },
|
|
386
370
|
);
|
|
387
371
|
|
|
388
|
-
/**
|
|
389
|
-
* Creates a typed Effect service for a Worker service binding.
|
|
390
|
-
*
|
|
391
|
-
* Returned value includes:
|
|
392
|
-
* - a Context tag for dependency injection
|
|
393
|
-
* - `fetch(...)` for raw HTTP forwarding
|
|
394
|
-
* - `rpc(...)` for raw Cloudflare RPC results
|
|
395
|
-
* - `call(...)` for resolved and decoded RPC results
|
|
396
|
-
* - `scopedCall(...)` for scoped and decoded disposable RPC results
|
|
397
|
-
* - direct RPC methods when `definition` is provided
|
|
398
|
-
*
|
|
399
|
-
* @example
|
|
400
|
-
* ```ts
|
|
401
|
-
* const Counter = WorkerDefinition.make("Counter", {
|
|
402
|
-
* increment: WorkerDefinition.method({
|
|
403
|
-
* args: [Schema.Number],
|
|
404
|
-
* success: Schema.Number,
|
|
405
|
-
* }),
|
|
406
|
-
* });
|
|
407
|
-
*
|
|
408
|
-
* const CounterLive = Counter.layer({ binding: "COUNTER" });
|
|
409
|
-
*
|
|
410
|
-
* const program = Effect.gen(function* () {
|
|
411
|
-
* const counter = yield* Counter;
|
|
412
|
-
* const next = yield* counter.increment(1);
|
|
413
|
-
* return next;
|
|
414
|
-
* });
|
|
415
|
-
* ```
|
|
416
|
-
*/
|
|
417
372
|
export const Service =
|
|
418
373
|
<Self, Api extends object = never>() =>
|
|
419
374
|
<
|
package/src/Vectorize.ts
CHANGED
|
@@ -22,7 +22,6 @@ import * as ErrorMessage from "./internal/ErrorMessage";
|
|
|
22
22
|
const expectedVectorizeBinding =
|
|
23
23
|
"Vectorize index binding with describe(), query(), insert(), upsert(), deleteByIds(), and getByIds()";
|
|
24
24
|
|
|
25
|
-
/** Vectorize operation represented by {@link VectorizeOperationError}. */
|
|
26
25
|
export type VectorizeOperation =
|
|
27
26
|
| "describe"
|
|
28
27
|
| "query"
|
|
@@ -32,7 +31,6 @@ export type VectorizeOperation =
|
|
|
32
31
|
| "deleteByIds"
|
|
33
32
|
| "getByIds";
|
|
34
33
|
|
|
35
|
-
/** Error raised when a Vectorize operation fails. */
|
|
36
34
|
export class VectorizeOperationError extends Data.TaggedError("VectorizeOperationError")<{
|
|
37
35
|
readonly binding: string;
|
|
38
36
|
readonly operation: VectorizeOperation;
|
|
@@ -43,9 +41,7 @@ export class VectorizeOperationError extends Data.TaggedError("VectorizeOperatio
|
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
/** Typed Vectorize binding definition. */
|
|
47
44
|
export interface VectorizeDefinition {
|
|
48
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
49
45
|
readonly binding: string;
|
|
50
46
|
}
|
|
51
47
|
|
|
@@ -114,7 +110,6 @@ export interface VectorizeClient {
|
|
|
114
110
|
|
|
115
111
|
declare const VectorizeServiceTypeId: unique symbol;
|
|
116
112
|
|
|
117
|
-
/** Nominal service marker for Vectorize services created with {@link make}. */
|
|
118
113
|
export interface VectorizeService<Id extends string> {
|
|
119
114
|
readonly [VectorizeServiceTypeId]: {
|
|
120
115
|
readonly id: Id;
|
package/src/Vitest.ts
CHANGED
|
@@ -33,27 +33,19 @@ import {
|
|
|
33
33
|
} from "./DurableObjectState";
|
|
34
34
|
import { WorkerConfig, WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
35
35
|
import type { WorkflowInstanceStatusName } from "./WorkflowBinding";
|
|
36
|
+
import { runNativeCallback } from "./internal/NativeCallback";
|
|
36
37
|
|
|
37
38
|
const currentEnv: WorkerEnv = env;
|
|
38
39
|
|
|
39
|
-
/**
|
|
40
|
-
* Provides the Workers test environment as both {@link WorkerEnvironment} and
|
|
41
|
-
* the active Effect `ConfigProvider`.
|
|
42
|
-
*/
|
|
43
40
|
export const layer: Layer.Layer<WorkerEnvironment> = Layer.mergeAll(
|
|
44
41
|
Layer.succeed(WorkerEnvironment, currentEnv),
|
|
45
42
|
ConfigProvider.layer(WorkerConfig.providerFromEnv(currentEnv)),
|
|
46
43
|
);
|
|
47
44
|
|
|
48
|
-
/** Constructor shape shared by Effect-backed Worker entrypoints. */
|
|
49
45
|
export interface WorkerConstructor<Instance> {
|
|
50
46
|
new (context: globalThis.ExecutionContext, env: WorkerEnv): Instance;
|
|
51
47
|
}
|
|
52
48
|
|
|
53
|
-
/**
|
|
54
|
-
* Creates an `ExecutionContext` and drains all `waitUntil` work before the
|
|
55
|
-
* returned effect completes, including when `use` fails or is interrupted.
|
|
56
|
-
*/
|
|
57
49
|
export const withExecutionContext = Effect.fn("effect-cf/vitest/withExecutionContext")(function* <
|
|
58
50
|
A,
|
|
59
51
|
E,
|
|
@@ -86,10 +78,8 @@ export const fetch = Effect.fn("effect-cf/vitest/fetch")(function* <Instance ext
|
|
|
86
78
|
);
|
|
87
79
|
});
|
|
88
80
|
|
|
89
|
-
/** Modules-format scheduled handler accepted by {@link scheduled}. */
|
|
90
81
|
export type ScheduledHandler = NonNullable<globalThis.ExportedHandler<WorkerEnv>["scheduled"]>;
|
|
91
82
|
|
|
92
|
-
/** Options used to construct a scheduled event controller. */
|
|
93
83
|
export interface ScheduledOptions {
|
|
94
84
|
readonly scheduledTime?: number | Date;
|
|
95
85
|
readonly cron?: string;
|
|
@@ -134,7 +124,6 @@ type PagesEventContextInitData<Context> =
|
|
|
134
124
|
: { readonly data: Data }
|
|
135
125
|
: never;
|
|
136
126
|
|
|
137
|
-
/** Initialization accepted by the Workers Vitest plugin for a Pages Function. */
|
|
138
127
|
export type PagesEventContextInit<Function extends AnyPagesFunction> = PagesEventContextInitBase &
|
|
139
128
|
PagesEventContextInitParams<Parameters<Function>[0]> &
|
|
140
129
|
PagesEventContextInitData<Parameters<Function>[0]>;
|
|
@@ -162,7 +151,6 @@ interface QueueWorker {
|
|
|
162
151
|
queue(batch: globalThis.MessageBatch): Promise<void>;
|
|
163
152
|
}
|
|
164
153
|
|
|
165
|
-
/** Input message accepted by the Workers Vitest plugin's `createMessageBatch` helper. */
|
|
166
154
|
export type QueueMessage<Body> = {
|
|
167
155
|
readonly id: string;
|
|
168
156
|
readonly timestamp: Date;
|
|
@@ -172,7 +160,6 @@ export type QueueMessage<Body> = {
|
|
|
172
160
|
/** Acknowledgement and retry result returned by the Workers Vitest plugin. */
|
|
173
161
|
export type QueueResult = Awaited<ReturnType<typeof getQueueResult>>;
|
|
174
162
|
|
|
175
|
-
/** Result of invoking a queue consumer through {@link queue}. */
|
|
176
163
|
export interface QueueRunResult<Body> {
|
|
177
164
|
readonly batch: globalThis.MessageBatch<Body>;
|
|
178
165
|
readonly result: QueueResult;
|
|
@@ -221,32 +208,34 @@ export const runInDurableObject = Effect.fn("effect-cf/vitest/runInDurableObject
|
|
|
221
208
|
stub: globalThis.DurableObjectStub<Object>,
|
|
222
209
|
use: (instance: Object, state: DurableObjectStateService) => Effect.Effect<A, E, R>,
|
|
223
210
|
): Effect.fn.Return<A, E, Exclude<R, DurableObjectState>> {
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
211
|
+
const exit = yield* runNativeCallback<A, E, Exclude<R, DurableObjectState>, Exit.Exit<A, E>>(
|
|
212
|
+
(run) =>
|
|
213
|
+
runInDurableObjectPromise(stub, (instance, nativeState) => {
|
|
214
|
+
const state = fromDurableObjectState(nativeState);
|
|
215
|
+
|
|
216
|
+
return run(
|
|
217
|
+
Effect.provideService(
|
|
218
|
+
Effect.suspend(() => use(instance, state)),
|
|
219
|
+
DurableObjectState,
|
|
220
|
+
state,
|
|
221
|
+
),
|
|
222
|
+
);
|
|
223
|
+
}),
|
|
224
|
+
).pipe(Effect.orDie);
|
|
233
225
|
|
|
234
226
|
return yield* exit;
|
|
235
227
|
});
|
|
236
228
|
|
|
237
|
-
/** Immediately runs and removes a scheduled Durable Object alarm. */
|
|
238
229
|
export const runDurableObjectAlarm = Effect.fn("effect-cf/vitest/runDurableObjectAlarm")(function* (
|
|
239
230
|
stub: globalThis.DurableObjectStub<RpcDurableObject>,
|
|
240
231
|
) {
|
|
241
232
|
return yield* Effect.promise(() => runDurableObjectAlarmPromise(stub));
|
|
242
233
|
});
|
|
243
234
|
|
|
244
|
-
/** Options controlling how Durable Object eviction handles WebSockets. */
|
|
245
235
|
export interface DurableObjectEvictionOptions {
|
|
246
236
|
readonly webSockets?: "close" | "hibernate";
|
|
247
237
|
}
|
|
248
238
|
|
|
249
|
-
/** Gracefully evicts one running Durable Object while preserving durable storage. */
|
|
250
239
|
export const evictDurableObject = Effect.fn("effect-cf/vitest/evictDurableObject")(function* (
|
|
251
240
|
stub: globalThis.DurableObjectStub<RpcDurableObject>,
|
|
252
241
|
options?: DurableObjectEvictionOptions,
|
|
@@ -254,39 +243,33 @@ export const evictDurableObject = Effect.fn("effect-cf/vitest/evictDurableObject
|
|
|
254
243
|
yield* Effect.promise(() => evictDurableObjectPromise(stub, options));
|
|
255
244
|
});
|
|
256
245
|
|
|
257
|
-
/** Lists all IDs created in a Durable Object namespace. */
|
|
258
246
|
export const listDurableObjectIds = Effect.fn("effect-cf/vitest/listDurableObjectIds")(function* <
|
|
259
247
|
Object extends RpcDurableObject | undefined,
|
|
260
248
|
>(namespace: globalThis.DurableObjectNamespace<Object>) {
|
|
261
249
|
return yield* Effect.promise(() => listDurableObjectIdsPromise(namespace));
|
|
262
250
|
});
|
|
263
251
|
|
|
264
|
-
/** Deletes data from all bindings attached to the current test Worker. */
|
|
265
252
|
export const reset = Effect.fn("effect-cf/vitest/reset")(function* () {
|
|
266
253
|
yield* Effect.promise(resetPromise);
|
|
267
254
|
});
|
|
268
255
|
|
|
269
|
-
/** Aborts all Durable Object instances without deleting their persisted data. */
|
|
270
256
|
export const abortAllDurableObjects = Effect.fn("effect-cf/vitest/abortAllDurableObjects")(
|
|
271
257
|
function* () {
|
|
272
258
|
yield* Effect.promise(abortAllDurableObjectsPromise);
|
|
273
259
|
},
|
|
274
260
|
);
|
|
275
261
|
|
|
276
|
-
/** Gracefully evicts all running Durable Objects while preserving durable storage. */
|
|
277
262
|
export const evictAllDurableObjects = Effect.fn("effect-cf/vitest/evictAllDurableObjects")(
|
|
278
263
|
function* (options?: DurableObjectEvictionOptions) {
|
|
279
264
|
yield* Effect.promise(() => evictAllDurableObjectsPromise(options));
|
|
280
265
|
},
|
|
281
266
|
);
|
|
282
267
|
|
|
283
|
-
/** A D1 migration accepted by the Workers Vitest plugin. */
|
|
284
268
|
export interface D1Migration {
|
|
285
269
|
readonly name: string;
|
|
286
270
|
readonly queries: ReadonlyArray<string>;
|
|
287
271
|
}
|
|
288
272
|
|
|
289
|
-
/** Applies all D1 migrations that have not already been recorded. */
|
|
290
273
|
export const applyD1Migrations = Effect.fn("effect-cf/vitest/applyD1Migrations")(function* (
|
|
291
274
|
database: globalThis.D1Database,
|
|
292
275
|
migrations: ReadonlyArray<D1Migration>,
|
|
@@ -347,19 +330,16 @@ type NativeWorkflowInstanceModifier = Parameters<
|
|
|
347
330
|
Parameters<NativeWorkflowInstanceIntrospector["modify"]>[0]
|
|
348
331
|
>[0];
|
|
349
332
|
|
|
350
|
-
/** Identifies one occurrence of a Workflow step or sleep. */
|
|
351
333
|
export interface WorkflowStepTarget {
|
|
352
334
|
readonly name: string;
|
|
353
335
|
readonly index?: number;
|
|
354
336
|
}
|
|
355
337
|
|
|
356
|
-
/** Event delivered to a mocked Workflow `waitForEvent` operation. */
|
|
357
338
|
export interface WorkflowMockEvent {
|
|
358
339
|
readonly type: string;
|
|
359
340
|
readonly payload: unknown;
|
|
360
341
|
}
|
|
361
342
|
|
|
362
|
-
/** Effect-native Workflow behavior modifier. */
|
|
363
343
|
export interface WorkflowInstanceModifier {
|
|
364
344
|
readonly disableSleeps: (steps?: ReadonlyArray<WorkflowStepTarget>) => Effect.Effect<void>;
|
|
365
345
|
readonly disableRetryDelays: (steps?: ReadonlyArray<WorkflowStepTarget>) => Effect.Effect<void>;
|
|
@@ -379,7 +359,6 @@ export interface WorkflowInstanceModifier {
|
|
|
379
359
|
|
|
380
360
|
type WorkflowMockResult = Schema.Schema.Type<typeof Schema.Unknown>;
|
|
381
361
|
|
|
382
|
-
/** Effect-native introspector for one Workflow instance. */
|
|
383
362
|
export interface WorkflowInstanceIntrospector {
|
|
384
363
|
readonly raw: NativeWorkflowInstanceIntrospector;
|
|
385
364
|
readonly modify: <A, E, R>(
|
|
@@ -391,7 +370,6 @@ export interface WorkflowInstanceIntrospector {
|
|
|
391
370
|
readonly getError: Effect.Effect<{ readonly name: string; readonly message: string }>;
|
|
392
371
|
}
|
|
393
372
|
|
|
394
|
-
/** Effect-native introspector for subsequently created Workflow instances. */
|
|
395
373
|
export interface WorkflowIntrospector {
|
|
396
374
|
readonly raw: NativeWorkflowIntrospector;
|
|
397
375
|
readonly modifyAll: <A, E, R>(
|
|
@@ -422,15 +400,12 @@ const runWorkflowModifier = Effect.fnUntraced(function* <A, E, R>(
|
|
|
422
400
|
register: (use: (modifier: NativeWorkflowInstanceModifier) => Promise<void>) => Promise<any>,
|
|
423
401
|
use: (modifier: WorkflowInstanceModifier) => Effect.Effect<A, E, R>,
|
|
424
402
|
): Effect.fn.Return<A, E, R> {
|
|
425
|
-
const
|
|
426
|
-
const exit = yield* Effect.promise(async () => {
|
|
403
|
+
const exit = yield* runNativeCallback<A, E, R, Exit.Exit<A, E>>(async (run) => {
|
|
427
404
|
let callbackExit: Exit.Exit<A, E> | undefined;
|
|
428
405
|
|
|
429
406
|
try {
|
|
430
407
|
await register(async (modifier) => {
|
|
431
|
-
callbackExit = await Effect.
|
|
432
|
-
use(wrapWorkflowModifier(modifier)),
|
|
433
|
-
);
|
|
408
|
+
callbackExit = await run(Effect.suspend(() => use(wrapWorkflowModifier(modifier))));
|
|
434
409
|
|
|
435
410
|
if (Exit.isFailure(callbackExit)) {
|
|
436
411
|
throw callbackExit;
|
|
@@ -449,7 +424,7 @@ const runWorkflowModifier = Effect.fnUntraced(function* <A, E, R>(
|
|
|
449
424
|
}
|
|
450
425
|
|
|
451
426
|
return callbackExit;
|
|
452
|
-
});
|
|
427
|
+
}).pipe(Effect.orDie);
|
|
453
428
|
|
|
454
429
|
return yield* exit;
|
|
455
430
|
});
|
package/src/WebTransport.ts
CHANGED
|
@@ -42,11 +42,8 @@ import { Data, Effect, Option, Predicate, Result, Schema as S } from "effect";
|
|
|
42
42
|
* `Record<string, unknown>` side of `request.cf`.
|
|
43
43
|
*/
|
|
44
44
|
export class InboundTransport extends S.Class<InboundTransport>("InboundTransport")({
|
|
45
|
-
/** The HTTP protocol the client used, e.g. `"HTTP/2"` or `"HTTP/3"`. */
|
|
46
45
|
httpProtocol: S.String,
|
|
47
|
-
/** Client round-trip time; only present for QUIC (HTTP/3) connections. */
|
|
48
46
|
clientQuicRtt: S.optional(S.Number),
|
|
49
|
-
/** Client round-trip time; only present for TCP (HTTP/1.x, HTTP/2) connections. */
|
|
50
47
|
clientTcpRtt: S.optional(S.Number),
|
|
51
48
|
}) {}
|
|
52
49
|
|
|
@@ -63,18 +60,9 @@ export const inboundTransport = (
|
|
|
63
60
|
request: Pick<CloudflareRequest, "cf">,
|
|
64
61
|
): Option.Option<InboundTransport> => Result.getSuccess(decodeInboundTransport(request.cf));
|
|
65
62
|
|
|
66
|
-
/**
|
|
67
|
-
* Returns `true` when the client reached Cloudflare's edge over QUIC
|
|
68
|
-
* (HTTP/3). Prefers the documented QUIC signal (`clientQuicRtt` is only
|
|
69
|
-
* present for QUIC connections) and falls back to the `httpProtocol` string.
|
|
70
|
-
*
|
|
71
|
-
* Note this describes the browser→edge hop only: the edge always terminates
|
|
72
|
-
* QUIC, and the Worker still handles an ordinary `fetch` Request.
|
|
73
|
-
*/
|
|
74
63
|
export const isHttp3 = (transport: InboundTransport): boolean =>
|
|
75
64
|
transport.clientQuicRtt !== undefined || transport.httpProtocol === "HTTP/3";
|
|
76
65
|
|
|
77
|
-
/** WebTransport-related capabilities of the current Workers runtime. */
|
|
78
66
|
export interface Capabilities {
|
|
79
67
|
/**
|
|
80
68
|
* Whether Worker code can accept inbound WebTransport sessions. Typed as
|
|
@@ -91,7 +79,6 @@ export interface Capabilities {
|
|
|
91
79
|
readonly outboundSessions: boolean;
|
|
92
80
|
}
|
|
93
81
|
|
|
94
|
-
/** Feature-detects the WebTransport capabilities of the current runtime. */
|
|
95
82
|
export const capabilities: Effect.Effect<Capabilities> = Effect.sync(() => {
|
|
96
83
|
const runtime = globalThis;
|
|
97
84
|
|
|
@@ -103,10 +90,8 @@ export const capabilities: Effect.Effect<Capabilities> = Effect.sync(() => {
|
|
|
103
90
|
};
|
|
104
91
|
});
|
|
105
92
|
|
|
106
|
-
/** WebTransport capability missing from the current Workers runtime. */
|
|
107
93
|
export type WebTransportCapability = "inbound-sessions" | "outbound-sessions";
|
|
108
94
|
|
|
109
|
-
/** Raised when a WebTransport capability is unavailable in this runtime. */
|
|
110
95
|
export class WebTransportUnsupportedError extends Data.TaggedError("WebTransportUnsupportedError")<{
|
|
111
96
|
readonly capability: WebTransportCapability;
|
|
112
97
|
}> {
|