effect-cf 0.30.0 → 0.32.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 +16 -0
- package/README.md +119 -9
- package/dist/ComputerWorkspace.d.mts +1 -1
- package/dist/ComputerWorkspace.mjs +1 -1
- package/dist/{DurableObjectState-D3k-WRnd.d.mts → DurableObjectState-B0A0Y1ef.d.mts} +3 -1
- package/dist/{DurableObjectState-CepagPkX.mjs → DurableObjectState-D1Ibr6k0.mjs} +3 -2
- package/dist/Vitest.d.mts +9 -9
- package/dist/Vitest.mjs +5 -5
- package/dist/{WorkflowBinding-CtrmxfdT.d.mts → WorkflowBinding-B9_S8tX2.d.mts} +6 -3
- package/dist/index.d.mts +109 -10
- package/dist/index.mjs +464 -32
- package/package.json +5 -5
- package/src/DurableObjectRpcWebSocket.ts +1030 -42
- package/src/Images.ts +60 -9
- package/src/Vitest.ts +9 -9
- package/src/Worker.ts +2 -0
- package/src/WorkflowBinding.ts +10 -2
- package/src/internal/WorkerContext.ts +1 -0
package/src/Images.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
HostedImagesBinding as CloudflareHostedImagesBinding,
|
|
3
|
+
ImageDirectUploadOptions as CloudflareImageDirectUploadOptions,
|
|
4
|
+
ImageDirectUploadResult as CloudflareImageDirectUploadResult,
|
|
3
5
|
ImageDrawOptions as CloudflareImageDrawOptions,
|
|
4
6
|
ImageHandle as CloudflareImageHandle,
|
|
5
7
|
ImageInfoResponse as CloudflareImageInfoResponse,
|
|
@@ -8,13 +10,16 @@ import type {
|
|
|
8
10
|
ImageListOptions as CloudflareImageListOptions,
|
|
9
11
|
ImageMetadata as CloudflareImageMetadata,
|
|
10
12
|
ImageOutputOptions as CloudflareImageOutputOptions,
|
|
13
|
+
ImageSignedUrlOptions as CloudflareImageSignedUrlOptions,
|
|
11
14
|
ImageTransform as CloudflareImageTransform,
|
|
12
15
|
ImageTransformationOutputOptions as CloudflareImageTransformationOutputOptions,
|
|
16
|
+
ImageTransformationResponseOptions as CloudflareImageTransformationResponseOptions,
|
|
13
17
|
ImageTransformationResult as CloudflareImageTransformationResult,
|
|
14
18
|
ImageTransformer as CloudflareImageTransformer,
|
|
15
19
|
ImageUpdateOptions as CloudflareImageUpdateOptions,
|
|
16
20
|
ImageUploadOptions as CloudflareImageUploadOptions,
|
|
17
21
|
Response as CloudflareResponse,
|
|
22
|
+
TextOptions as CloudflareTextOptions,
|
|
18
23
|
} from "@cloudflare/workers-types";
|
|
19
24
|
import { Context, Data, Effect, Function, Option, Predicate, type Layer } from "effect";
|
|
20
25
|
|
|
@@ -51,12 +56,17 @@ export type ImageDrawOptions = CloudflareImageDrawOptions;
|
|
|
51
56
|
export type ImageInputOptions = CloudflareImageInputOptions;
|
|
52
57
|
export type ImageOutputOptions = CloudflareImageOutputOptions;
|
|
53
58
|
export type ImageTransformationOutputOptions = CloudflareImageTransformationOutputOptions;
|
|
59
|
+
export type ImageTransformationResponseOptions = CloudflareImageTransformationResponseOptions;
|
|
54
60
|
export type ImageTransformationResult = CloudflareImageTransformationResult;
|
|
55
61
|
export type ImageUploadOptions = CloudflareImageUploadOptions;
|
|
56
62
|
export type ImageUpdateOptions = CloudflareImageUpdateOptions;
|
|
57
63
|
export type ImageListOptions = CloudflareImageListOptions;
|
|
58
64
|
export type ImageList = CloudflareImageList;
|
|
59
65
|
export type ImageMetadata = CloudflareImageMetadata;
|
|
66
|
+
export type ImageSignedUrlOptions = CloudflareImageSignedUrlOptions;
|
|
67
|
+
export type ImageDirectUploadOptions = CloudflareImageDirectUploadOptions;
|
|
68
|
+
export type ImageDirectUploadResult = CloudflareImageDirectUploadResult;
|
|
69
|
+
export type TextOptions = CloudflareTextOptions;
|
|
60
70
|
export type ImageInputValue = ReadableStream<Uint8Array> | ArrayBuffer;
|
|
61
71
|
export type ImageUploadValue = ReadableStream<Uint8Array> | ArrayBuffer;
|
|
62
72
|
|
|
@@ -79,15 +89,23 @@ export interface Steps {
|
|
|
79
89
|
readonly steps: ReadonlyArray<Step>;
|
|
80
90
|
}
|
|
81
91
|
|
|
82
|
-
export
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
export type ProcessOptions =
|
|
93
|
+
| {
|
|
94
|
+
readonly stream: ImageInputValue;
|
|
95
|
+
readonly inputOptions?: ImageInputOptions;
|
|
96
|
+
readonly outputOptions: ImageOutputOptions;
|
|
97
|
+
}
|
|
98
|
+
| {
|
|
99
|
+
readonly text: string;
|
|
100
|
+
readonly textOptions: TextOptions;
|
|
101
|
+
readonly outputOptions: ImageOutputOptions;
|
|
102
|
+
};
|
|
87
103
|
|
|
88
104
|
export interface ImagesTransformationResultClient {
|
|
89
105
|
readonly raw: CloudflareImageTransformationResult;
|
|
90
|
-
readonly response:
|
|
106
|
+
readonly response: (
|
|
107
|
+
options?: ImageTransformationResponseOptions,
|
|
108
|
+
) => Effect.Effect<CloudflareResponse, ImagesOperationError>;
|
|
91
109
|
readonly contentType: Effect.Effect<string, ImagesOperationError>;
|
|
92
110
|
readonly image: (
|
|
93
111
|
options?: ImageTransformationOutputOptions,
|
|
@@ -98,6 +116,9 @@ export interface ImageHandleClient {
|
|
|
98
116
|
readonly raw: CloudflareImageHandle;
|
|
99
117
|
readonly details: Effect.Effect<Option.Option<ImageMetadata>, ImagesOperationError>;
|
|
100
118
|
readonly bytes: Effect.Effect<Option.Option<ReadableStream<Uint8Array>>, ImagesOperationError>;
|
|
119
|
+
readonly signedUrl: (
|
|
120
|
+
options: ImageSignedUrlOptions,
|
|
121
|
+
) => Effect.Effect<string, ImagesOperationError>;
|
|
101
122
|
readonly update: (
|
|
102
123
|
options: ImageUpdateOptions,
|
|
103
124
|
) => Effect.Effect<ImageMetadata, ImagesOperationError>;
|
|
@@ -111,6 +132,9 @@ export interface HostedImagesClient {
|
|
|
111
132
|
options?: ImageUploadOptions,
|
|
112
133
|
) => Effect.Effect<ImageMetadata, ImagesOperationError>;
|
|
113
134
|
readonly list: (options?: ImageListOptions) => Effect.Effect<ImageList, ImagesOperationError>;
|
|
135
|
+
readonly createDirectUpload: (
|
|
136
|
+
options?: ImageDirectUploadOptions,
|
|
137
|
+
) => Effect.Effect<ImageDirectUploadResult, ImagesOperationError>;
|
|
114
138
|
readonly rawUnsafe: Effect.Effect<CloudflareHostedImagesBinding>;
|
|
115
139
|
}
|
|
116
140
|
|
|
@@ -123,6 +147,7 @@ export interface ImagesRuntimeBinding {
|
|
|
123
147
|
image: ImageInputValue,
|
|
124
148
|
options?: ImageInputOptions,
|
|
125
149
|
) => CloudflareImageTransformer;
|
|
150
|
+
readonly text?: (content: string, options: TextOptions) => CloudflareImageTransformer;
|
|
126
151
|
readonly hosted?: CloudflareHostedImagesBinding;
|
|
127
152
|
}
|
|
128
153
|
|
|
@@ -135,6 +160,10 @@ export interface ImagesClient {
|
|
|
135
160
|
image: ImageInputValue,
|
|
136
161
|
options?: ImageInputOptions,
|
|
137
162
|
) => Effect.Effect<CloudflareImageTransformer, ImagesOperationError>;
|
|
163
|
+
readonly text: (
|
|
164
|
+
content: string,
|
|
165
|
+
options: TextOptions,
|
|
166
|
+
) => Effect.Effect<CloudflareImageTransformer, ImagesOperationError>;
|
|
138
167
|
readonly process: (
|
|
139
168
|
steps: Steps,
|
|
140
169
|
options: ProcessOptions,
|
|
@@ -230,7 +259,10 @@ const hasFunction = <Candidate>(value: Candidate, key: string): boolean =>
|
|
|
230
259
|
const isHostedImagesBinding = <Candidate>(
|
|
231
260
|
value: Candidate,
|
|
232
261
|
): value is Candidate & CloudflareHostedImagesBinding =>
|
|
233
|
-
hasFunction(value, "image") &&
|
|
262
|
+
hasFunction(value, "image") &&
|
|
263
|
+
hasFunction(value, "upload") &&
|
|
264
|
+
hasFunction(value, "list") &&
|
|
265
|
+
hasFunction(value, "createDirectUpload");
|
|
234
266
|
|
|
235
267
|
export const isImagesBinding = <Candidate>(
|
|
236
268
|
value: Candidate,
|
|
@@ -242,7 +274,7 @@ const wrapResult = (
|
|
|
242
274
|
result: CloudflareImageTransformationResult,
|
|
243
275
|
): ImagesTransformationResultClient => ({
|
|
244
276
|
raw: result,
|
|
245
|
-
response: tryImagesSync(binding, "response", () => result.response()),
|
|
277
|
+
response: (options) => tryImagesSync(binding, "response", () => result.response(options)),
|
|
246
278
|
contentType: tryImagesSync(binding, "contentType", () => result.contentType()),
|
|
247
279
|
image: (options) => tryImagesSync(binding, "image", () => result.image(options)),
|
|
248
280
|
});
|
|
@@ -257,6 +289,9 @@ const wrapHandle = (binding: string, handle: CloudflareImageHandle): ImageHandle
|
|
|
257
289
|
Effect.map(maybe),
|
|
258
290
|
Effect.withSpan("Images.bytes"),
|
|
259
291
|
),
|
|
292
|
+
signedUrl: Effect.fn("Images.signedUrl")((options: ImageSignedUrlOptions) =>
|
|
293
|
+
tryImagesPromise(binding, "signedUrl", () => handle.signedUrl(options)),
|
|
294
|
+
),
|
|
260
295
|
update: Effect.fn("Images.update")((options: ImageUpdateOptions) =>
|
|
261
296
|
tryImagesPromise(binding, "update", () => handle.update(options)),
|
|
262
297
|
),
|
|
@@ -276,6 +311,9 @@ const wrapHosted = (
|
|
|
276
311
|
list: Effect.fn("Images.list")((options?: ImageListOptions) =>
|
|
277
312
|
tryImagesPromise(binding, "list", () => hosted.list(options)),
|
|
278
313
|
),
|
|
314
|
+
createDirectUpload: Effect.fn("Images.createDirectUpload")((options?: ImageDirectUploadOptions) =>
|
|
315
|
+
tryImagesPromise(binding, "createDirectUpload", () => hosted.createDirectUpload(options)),
|
|
316
|
+
),
|
|
279
317
|
rawUnsafe: Effect.succeed(hosted),
|
|
280
318
|
});
|
|
281
319
|
|
|
@@ -285,8 +323,20 @@ export const makeClient =
|
|
|
285
323
|
const input = (image: ImageInputValue, options?: ImageInputOptions) =>
|
|
286
324
|
tryImagesSync(definition.binding, "input", () => images.input(image, options));
|
|
287
325
|
|
|
326
|
+
const text = (content: string, options: TextOptions) =>
|
|
327
|
+
tryImagesSync(definition.binding, "text", () => {
|
|
328
|
+
if (!hasFunction(images, "text")) {
|
|
329
|
+
throw new Error("Images binding is missing text()");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return images.text!(content, options);
|
|
333
|
+
});
|
|
334
|
+
|
|
288
335
|
const process = Effect.fn("Images.process")(function* (steps: Steps, options: ProcessOptions) {
|
|
289
|
-
let transformer =
|
|
336
|
+
let transformer =
|
|
337
|
+
"text" in options
|
|
338
|
+
? yield* text(options.text, options.textOptions)
|
|
339
|
+
: yield* input(options.stream, options.inputOptions);
|
|
290
340
|
|
|
291
341
|
for (const step of steps.steps) {
|
|
292
342
|
transformer = yield* Step.$match(step, {
|
|
@@ -314,6 +364,7 @@ export const makeClient =
|
|
|
314
364
|
tryImagesPromise(definition.binding, "info", () => images.info(image, options)),
|
|
315
365
|
),
|
|
316
366
|
input,
|
|
367
|
+
text,
|
|
317
368
|
process,
|
|
318
369
|
hosted: isHostedImagesBinding(images.hosted)
|
|
319
370
|
? Option.some(wrapHosted(definition.binding, images.hosted))
|
package/src/Vitest.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Effect-native helpers for tests running in Cloudflare's Vitest
|
|
2
|
+
* Effect-native helpers for tests running in Cloudflare's Workers Vitest plugin.
|
|
3
3
|
*
|
|
4
4
|
* Import this module through the `effect-cf/vitest` subpath. It is intended to
|
|
5
5
|
* run inside the Workers test runtime, where `cloudflare:test` is available.
|
|
@@ -37,7 +37,7 @@ import type { WorkflowInstanceStatusName } from "./WorkflowBinding";
|
|
|
37
37
|
const currentEnv: WorkerEnv = env;
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Provides the Workers
|
|
40
|
+
* Provides the Workers test environment as both {@link WorkerEnvironment} and
|
|
41
41
|
* the active Effect `ConfigProvider`.
|
|
42
42
|
*/
|
|
43
43
|
export const layer: Layer.Layer<WorkerEnvironment> = Layer.mergeAll(
|
|
@@ -134,7 +134,7 @@ type PagesEventContextInitData<Context> =
|
|
|
134
134
|
: { readonly data: Data }
|
|
135
135
|
: never;
|
|
136
136
|
|
|
137
|
-
/** Initialization accepted by
|
|
137
|
+
/** Initialization accepted by the Workers Vitest plugin for a Pages Function. */
|
|
138
138
|
export type PagesEventContextInit<Function extends AnyPagesFunction> = PagesEventContextInitBase &
|
|
139
139
|
PagesEventContextInitParams<Parameters<Function>[0]> &
|
|
140
140
|
PagesEventContextInitData<Parameters<Function>[0]>;
|
|
@@ -162,14 +162,14 @@ interface QueueWorker {
|
|
|
162
162
|
queue(batch: globalThis.MessageBatch): Promise<void>;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
/** Input message accepted by
|
|
165
|
+
/** Input message accepted by the Workers Vitest plugin's `createMessageBatch` helper. */
|
|
166
166
|
export type QueueMessage<Body> = {
|
|
167
167
|
readonly id: string;
|
|
168
168
|
readonly timestamp: Date;
|
|
169
169
|
readonly attempts: number;
|
|
170
170
|
} & ({ readonly body: Body } | { readonly serializedBody: ArrayBuffer | ArrayBufferView });
|
|
171
171
|
|
|
172
|
-
/** Acknowledgement and retry result returned by
|
|
172
|
+
/** Acknowledgement and retry result returned by the Workers Vitest plugin. */
|
|
173
173
|
export type QueueResult = Awaited<ReturnType<typeof getQueueResult>>;
|
|
174
174
|
|
|
175
175
|
/** Result of invoking a queue consumer through {@link queue}. */
|
|
@@ -180,7 +180,7 @@ export interface QueueRunResult<Body> {
|
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
182
|
* Invokes an Effect-backed queue consumer, drains its `waitUntil` work, and
|
|
183
|
-
* returns
|
|
183
|
+
* returns the Workers Vitest plugin's acknowledgement and retry result.
|
|
184
184
|
*/
|
|
185
185
|
export const queue = Effect.fn("effect-cf/vitest/queue")(function* <
|
|
186
186
|
Body,
|
|
@@ -280,7 +280,7 @@ export const evictAllDurableObjects = Effect.fn("effect-cf/vitest/evictAllDurabl
|
|
|
280
280
|
},
|
|
281
281
|
);
|
|
282
282
|
|
|
283
|
-
/** A D1 migration accepted by
|
|
283
|
+
/** A D1 migration accepted by the Workers Vitest plugin. */
|
|
284
284
|
export interface D1Migration {
|
|
285
285
|
readonly name: string;
|
|
286
286
|
readonly queries: ReadonlyArray<string>;
|
|
@@ -310,7 +310,7 @@ export interface SecretsStoreSecret {
|
|
|
310
310
|
readonly metadata?: { readonly uuid: string };
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
/** Effect-native wrapper around
|
|
313
|
+
/** Effect-native wrapper around the Workers Vitest plugin's Secrets Store admin API. */
|
|
314
314
|
export interface SecretsStoreAdmin {
|
|
315
315
|
readonly raw: NativeSecretsStoreAdmin;
|
|
316
316
|
readonly create: (value: string) => Effect.Effect<string>;
|
|
@@ -445,7 +445,7 @@ const runWorkflowModifier = Effect.fnUntraced(function* <A, E, R>(
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
if (callbackExit === undefined) {
|
|
448
|
-
throw new Error("
|
|
448
|
+
throw new Error("The Workers Vitest plugin did not invoke the Workflow modifier callback");
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
return callbackExit;
|
package/src/Worker.ts
CHANGED
|
@@ -46,6 +46,8 @@ export interface WorkerContextService {
|
|
|
46
46
|
options?: Omit<WorkerContextWaitUntilOptions<E, R2>, "mode">,
|
|
47
47
|
): Effect.Effect<void, never, R | R2>;
|
|
48
48
|
readonly passThroughOnException: Effect.Effect<void>;
|
|
49
|
+
/** Abort the current stateless Worker invocation (`ExecutionContext.abort`). */
|
|
50
|
+
abort(reason?: string): Effect.Effect<void>;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
/**
|
package/src/WorkflowBinding.ts
CHANGED
|
@@ -3,7 +3,9 @@ import type {
|
|
|
3
3
|
Workflow as CloudflareWorkflow,
|
|
4
4
|
WorkflowInstance as CloudflareWorkflowInstance,
|
|
5
5
|
WorkflowInstanceCreateOptions as CloudflareWorkflowInstanceCreateOptions,
|
|
6
|
+
WorkflowInstanceLocationHint as CloudflareWorkflowInstanceLocationHint,
|
|
6
7
|
WorkflowInstanceRestartOptions as CloudflareWorkflowInstanceRestartOptions,
|
|
8
|
+
WorkflowInstanceTerminateOptions as CloudflareWorkflowInstanceTerminateOptions,
|
|
7
9
|
} from "@cloudflare/workers-types";
|
|
8
10
|
import { type Context, Data, Effect, Option, Predicate, Schema as S } from "effect";
|
|
9
11
|
|
|
@@ -23,6 +25,8 @@ export type WorkflowInstanceCreateBatchOptions<Payload, EncodedPayload = unknown
|
|
|
23
25
|
>;
|
|
24
26
|
|
|
25
27
|
export type WorkflowInstanceRestartOptions = CloudflareWorkflowInstanceRestartOptions;
|
|
28
|
+
export type WorkflowInstanceTerminateOptions = CloudflareWorkflowInstanceTerminateOptions;
|
|
29
|
+
export type WorkflowInstanceLocationHint = CloudflareWorkflowInstanceLocationHint;
|
|
26
30
|
|
|
27
31
|
export type WorkflowInstanceStatusName = CloudflareInstanceStatus["status"];
|
|
28
32
|
|
|
@@ -40,10 +44,13 @@ export interface WorkflowInstance<Result> {
|
|
|
40
44
|
readonly id: string;
|
|
41
45
|
readonly pause: Effect.Effect<void, WorkflowOperationError>;
|
|
42
46
|
readonly resume: Effect.Effect<void, WorkflowOperationError>;
|
|
43
|
-
readonly terminate:
|
|
47
|
+
readonly terminate: (
|
|
48
|
+
options?: WorkflowInstanceTerminateOptions,
|
|
49
|
+
) => Effect.Effect<void, WorkflowOperationError>;
|
|
44
50
|
readonly restart: (
|
|
45
51
|
options?: WorkflowInstanceRestartOptions,
|
|
46
52
|
) => Effect.Effect<void, WorkflowOperationError>;
|
|
53
|
+
readonly delete: Effect.Effect<void, WorkflowOperationError>;
|
|
47
54
|
readonly status: Effect.Effect<
|
|
48
55
|
WorkflowInstanceStatus<Result>,
|
|
49
56
|
WorkflowOperationError | WorkflowResultDecodeError
|
|
@@ -165,8 +172,9 @@ export const makeClient = <
|
|
|
165
172
|
id: raw.id,
|
|
166
173
|
pause: operation("pause", () => raw.pause()),
|
|
167
174
|
resume: operation("resume", () => raw.resume()),
|
|
168
|
-
terminate: operation("terminate", () => raw.terminate()),
|
|
175
|
+
terminate: (options) => operation("terminate", () => raw.terminate(options)),
|
|
169
176
|
restart: (options) => operation("restart", () => raw.restart(options)),
|
|
177
|
+
delete: operation("delete", () => raw.delete()),
|
|
170
178
|
status: operation("status", () => raw.status()).pipe(
|
|
171
179
|
Effect.flatMap((status) =>
|
|
172
180
|
Effect.gen(function* () {
|
|
@@ -101,5 +101,6 @@ export const fromExecutionContext = (
|
|
|
101
101
|
options?: Omit<WorkerContextWaitUntilOptions<E, R2>, "mode">,
|
|
102
102
|
) => schedule(effect, options, "propagate"),
|
|
103
103
|
passThroughOnException: Effect.sync(() => ctx.passThroughOnException()),
|
|
104
|
+
abort: (reason?: string) => Effect.sync(() => ctx.abort(reason)),
|
|
104
105
|
};
|
|
105
106
|
};
|