effect-cf 0.30.0 → 0.31.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # effect-cf
2
2
 
3
+ ## 0.31.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#116](https://github.com/danieljvdm/effect-cf/pull/116) [`98d343b`](https://github.com/danieljvdm/effect-cf/commit/98d343ba7d5a427789ec8e7fc030668987eab1ea) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Move the optional `effect-cf/vitest` peer from `@cloudflare/vitest-pool-workers` to `@cloudflare/vitest-plugin` `^1.0.0`. The package API is unchanged: keep using `cloudflareTest()` and `cloudflare:test`.
8
+
9
+ - [#118](https://github.com/danieljvdm/effect-cf/pull/118) [`80730a8`](https://github.com/danieljvdm/effect-cf/commit/80730a82b26728e824ba6e4ed8bdbe290428baa6) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Pin the Cloudflare Workers runtime stack to workerd `1.20260820.1` (`@cloudflare/workers-types@^5.20260820.1`, wrangler `4.125.0`, recommended `compatibility_date` `2026-08-20`).
10
+
11
+ Images gains text rasterization (`text` / `process` text input), hosted `createDirectUpload` and `signedUrl`, and `response(options?)` for extra headers. Workflow instances gain `delete`, optional `terminate({ rollback })`, and `create`/`createBatch` `locationHint` via the updated types. `Worker.WorkerContext` now wraps the non-experimental `ExecutionContext.abort`.
12
+
3
13
  ## 0.30.0
4
14
 
5
15
  ### Minor Changes
package/README.md CHANGED
@@ -4,7 +4,8 @@ Effect-native Cloudflare primitives for Workers, Durable Objects, Containers, bi
4
4
 
5
5
  ## Install
6
6
 
7
- `effect-cf` targets Effect `^4.0.0-beta.105`.
7
+ `effect-cf` targets Effect `^4.0.0-beta.105` and Cloudflare workerd `1.20260820.1`
8
+ (`@cloudflare/workers-types@5.20260820.1`, recommended `compatibility_date` `2026-08-20`).
8
9
 
9
10
  ```bash
10
11
  bun add effect-cf "effect@^4.0.0-beta.105"
@@ -72,12 +73,12 @@ Runtime creation belongs at Cloudflare entrypoints, not inside binding helpers.
72
73
  - `Rpc` - Cloudflare RPC type helpers and scoped disposal utilities
73
74
  - `WebTransport` - truthful WebTransport/HTTP-3 boundary: typed runtime capabilities and decoded inbound protocol metadata
74
75
  - `WorkerConfig` - Effect `Config` helpers backed by Cloudflare `env`
75
- - `effect-cf/vitest` - Effect-native runners and scoped test helpers for Cloudflare's Vitest Workers pool
76
+ - `effect-cf/vitest` - Effect-native runners and scoped test helpers for Cloudflare's Workers Vitest plugin
76
77
 
77
- ## Vitest Workers Pool
78
+ ## Vitest Workers Plugin
78
79
 
79
- Install and configure a `^0.21.3` release of
80
- [`@cloudflare/vitest-pool-workers`](https://github.com/cloudflare/workers-sdk/tree/main/packages/vitest-pool-workers#readme),
80
+ Install and configure a `^1.0.0` release of
81
+ [`@cloudflare/vitest-plugin`](https://github.com/cloudflare/workers-sdk/tree/main/packages/vitest-plugin#readme),
81
82
  then import the test-only helpers from `effect-cf/vitest`. The `fetch` runner
82
83
  constructs the Worker with the current test environment and waits for all
83
84
  `waitUntil` work before completing the Effect.
@@ -109,7 +110,7 @@ it.effect("reads Wrangler vars", () =>
109
110
  ```
110
111
 
111
112
  Queue consumers can be invoked with typed message bodies while retaining the
112
- pool's acknowledgement and retry result:
113
+ plugin's acknowledgement and retry result:
113
114
 
114
115
  ```ts
115
116
  it.effect("acknowledges a job", () =>
@@ -130,7 +131,7 @@ it.effect("acknowledges a job", () =>
130
131
 
131
132
  Scheduled handlers and Pages Functions use the same lifecycle behavior: their
132
133
  Effects complete only after the event's `waitUntil` work has settled. Pages
133
- tests must configure the `ASSETS` binding required by Pool Workers.
134
+ tests must configure the `ASSETS` binding required by the Workers Vitest plugin.
134
135
 
135
136
  ```ts
136
137
  it.effect("runs the cron handler", () =>
@@ -719,10 +720,26 @@ export const resizeAvatar = (image: Images.ImageInputValue) =>
719
720
  },
720
721
  );
721
722
 
722
- return yield* result.response;
723
+ return yield* result.response();
723
724
  });
724
725
  ```
725
726
 
727
+ ## Cloudflare runtime pin
728
+
729
+ `effect-cf` develops and tests against a fixed Cloudflare Workers runtime stack. Keep consumer
730
+ `compatibility_date` and optional `@cloudflare/workers-types` peers at or above this pin:
731
+
732
+ | Pin | Version |
733
+ | ------------------------------------------- | -------------- |
734
+ | workerd | `1.20260820.1` |
735
+ | `@cloudflare/workers-types` (optional peer) | `5.20260820.1` |
736
+ | wrangler (repo catalog / examples) | `4.125.0` |
737
+ | Recommended `compatibility_date` | `2026-08-20` |
738
+
739
+ The date in the `workerd` / `@cloudflare/workers-types` version is the API surface this package wraps.
740
+ Repo catalog pins live in the root `package.json` `catalog` field (`@cloudflare/workers-types`, `wrangler`).
741
+ `wrangler@4.125.0` pulls `workerd@1.20260820.1` and peers `@cloudflare/workers-types@^5.20260820.1`.
742
+
726
743
  ## Email Example
727
744
 
728
745
  Email tags expose Cloudflare Email Service `send_email` bindings as Effect-wrapped `send(...)` operations. Structured messages are validated against documented Email Sending limits before reaching the binding, and Cloudflare's `E_*` error codes are surfaced on `EmailOperationError.code`.
@@ -1,5 +1,5 @@
1
1
  import { ComputerArtifactsClient } from "./ComputerArtifacts.mjs";
2
- import { t as DurableObjectState } from "./DurableObjectState-D3k-WRnd.mjs";
2
+ import { t as DurableObjectState } from "./DurableObjectState-DVIgf0sA.mjs";
3
3
  import { Context, Effect, Layer, Schema, Scope, Stream } from "effect";
4
4
  import { CommitView, GitClient, GitCloneOptions, GitCommitOptions, GitDiffOptions, GitFetchOptions, GitLogOptions, GitUpdateRefOptions } from "@cloudflare/computer/git";
5
5
  import { ExecSyncResult, RuntimeExecOptions, RuntimeGetOptions, RuntimeKillOptions, ShellValue, SkippedEntry, ThinkWorkspaceCompatibility, WorkspaceClient, WorkspaceRuntimeResult, WorkspaceRuntimeValue as WorkspaceRuntimeValue$1 } from "@cloudflare/computer";
@@ -1,4 +1,4 @@
1
- import { t as DurableObjectState } from "./DurableObjectState-CepagPkX.mjs";
1
+ import { t as DurableObjectState } from "./DurableObjectState-CxS5Y2hf.mjs";
2
2
  import { fromClient } from "./ComputerArtifacts.mjs";
3
3
  import { t as lookup } from "./ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs";
4
4
  import { Context, Effect, Layer, Predicate, Schema, Stream } from "effect";
@@ -308,7 +308,8 @@ const fromExecutionContext = (ctx, runPromiseExit = (effect) => Effect.runPromis
308
308
  raw: ctx,
309
309
  waitUntil: (effect, options) => schedule(effect, options, options?.mode ?? "observe"),
310
310
  waitUntilPropagating: (effect, options) => schedule(effect, options, "propagate"),
311
- passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
311
+ passThroughOnException: Effect.sync(() => ctx.passThroughOnException()),
312
+ abort: (reason) => Effect.sync(() => ctx.abort(reason))
312
313
  };
313
314
  };
314
315
  //#endregion
@@ -834,6 +834,8 @@ interface WorkerContextService {
834
834
  waitUntil<A, E, R, R2 = never>(effect: Effect.Effect<A, E, R>, options?: WorkerContextWaitUntilOptions<E, R2>): Effect.Effect<void, never, R | R2>;
835
835
  waitUntilPropagating<A, E, R, R2 = never>(effect: Effect.Effect<A, E, R>, options?: Omit<WorkerContextWaitUntilOptions<E, R2>, "mode">): Effect.Effect<void, never, R | R2>;
836
836
  readonly passThroughOnException: Effect.Effect<void>;
837
+ /** Abort the current stateless Worker invocation (`ExecutionContext.abort`). */
838
+ abort(reason?: string): Effect.Effect<void>;
837
839
  }
838
840
  declare const WorkerContext_base: Context.ServiceClass<WorkerContext, "effect-cf/WorkerContext", WorkerContextService>;
839
841
  /**
package/dist/Vitest.d.mts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { c as WorkerEnvironment, s as WorkerEnv } from "./Binding-xJJJPmiD.mjs";
2
- import { n as DurableObjectStateService, t as DurableObjectState } from "./DurableObjectState-D3k-WRnd.mjs";
3
- import { o as WorkflowInstanceStatusName } from "./WorkflowBinding-CtrmxfdT.mjs";
2
+ import { n as DurableObjectStateService, t as DurableObjectState } from "./DurableObjectState-DVIgf0sA.mjs";
3
+ import { o as WorkflowInstanceStatusName } from "./WorkflowBinding-C9KRmfDU.mjs";
4
4
  import { Effect, Layer, Schema } from "effect";
5
5
  import { DurableObject } from "cloudflare:workers";
6
6
  import { adminSecretsStore as adminSecretsStore$1, getQueueResult, introspectWorkflow as introspectWorkflow$1, introspectWorkflowInstance as introspectWorkflowInstance$1 } from "cloudflare:test";
7
7
  //#region src/Vitest.d.ts
8
8
  /**
9
- * Provides the Workers pool environment as both {@link WorkerEnvironment} and
9
+ * Provides the Workers test environment as both {@link WorkerEnvironment} and
10
10
  * the active Effect `ConfigProvider`.
11
11
  */
12
12
  declare const layer: Layer.Layer<WorkerEnvironment>;
@@ -54,7 +54,7 @@ type PagesEventContextInitData<Context> = Context extends globalThis.EventContex
54
54
  } : {
55
55
  readonly data: Data;
56
56
  } : never;
57
- /** Initialization accepted by Pool Workers for a Pages Function. */
57
+ /** Initialization accepted by the Workers Vitest plugin for a Pages Function. */
58
58
  type PagesEventContextInit<Function extends AnyPagesFunction> = PagesEventContextInitBase & PagesEventContextInitParams<Parameters<Function>[0]> & PagesEventContextInitData<Parameters<Function>[0]>;
59
59
  /**
60
60
  * Invokes a Pages Function with a typed event context and drains its
@@ -64,7 +64,7 @@ declare const pages: <Function extends AnyPagesFunction>(handler: Function, init
64
64
  interface QueueWorker {
65
65
  queue(batch: globalThis.MessageBatch): Promise<void>;
66
66
  }
67
- /** Input message accepted by Pool Workers' `createMessageBatch` helper. */
67
+ /** Input message accepted by the Workers Vitest plugin's `createMessageBatch` helper. */
68
68
  type QueueMessage<Body> = {
69
69
  readonly id: string;
70
70
  readonly timestamp: Date;
@@ -74,7 +74,7 @@ type QueueMessage<Body> = {
74
74
  } | {
75
75
  readonly serializedBody: ArrayBuffer | ArrayBufferView;
76
76
  });
77
- /** Acknowledgement and retry result returned by Pool Workers. */
77
+ /** Acknowledgement and retry result returned by the Workers Vitest plugin. */
78
78
  type QueueResult = Awaited<ReturnType<typeof getQueueResult>>;
79
79
  /** Result of invoking a queue consumer through {@link queue}. */
80
80
  interface QueueRunResult<Body> {
@@ -83,7 +83,7 @@ interface QueueRunResult<Body> {
83
83
  }
84
84
  /**
85
85
  * Invokes an Effect-backed queue consumer, drains its `waitUntil` work, and
86
- * returns Pool Workers' acknowledgement and retry result.
86
+ * returns the Workers Vitest plugin's acknowledgement and retry result.
87
87
  */
88
88
  declare const queue: <Body, Instance extends QueueWorker>(Worker: WorkerConstructor<Instance>, queueName: string, messages: readonly QueueMessage<Body>[], workerEnv?: Cloudflare.Env | undefined) => Effect.Effect<QueueRunResult<Body>, never, never>;
89
89
  /**
@@ -110,7 +110,7 @@ declare const reset: () => Effect.Effect<void, never, never>;
110
110
  declare const abortAllDurableObjects: () => Effect.Effect<void, never, never>;
111
111
  /** Gracefully evicts all running Durable Objects while preserving durable storage. */
112
112
  declare const evictAllDurableObjects: (options?: DurableObjectEvictionOptions | undefined) => Effect.Effect<void, never, never>;
113
- /** A D1 migration accepted by Pool Workers. */
113
+ /** A D1 migration accepted by the Workers Vitest plugin. */
114
114
  interface D1Migration {
115
115
  readonly name: string;
116
116
  readonly queries: ReadonlyArray<string>;
@@ -125,7 +125,7 @@ interface SecretsStoreSecret {
125
125
  readonly uuid: string;
126
126
  };
127
127
  }
128
- /** Effect-native wrapper around Pool Workers' Secrets Store admin API. */
128
+ /** Effect-native wrapper around the Workers Vitest plugin's Secrets Store admin API. */
129
129
  interface SecretsStoreAdmin {
130
130
  readonly raw: NativeSecretsStoreAdmin;
131
131
  readonly create: (value: string) => Effect.Effect<string>;
package/dist/Vitest.mjs CHANGED
@@ -1,18 +1,18 @@
1
1
  import { a as WorkerEnvironment, i as WorkerConfig } from "./ErrorMessage-BM0K-Nik.mjs";
2
- import { r as fromDurableObjectState, t as DurableObjectState } from "./DurableObjectState-CepagPkX.mjs";
2
+ import { r as fromDurableObjectState, t as DurableObjectState } from "./DurableObjectState-CxS5Y2hf.mjs";
3
3
  import { ConfigProvider, Effect, Exit, Layer } from "effect";
4
4
  import { env } from "cloudflare:workers";
5
5
  import { abortAllDurableObjects as abortAllDurableObjects$1, adminSecretsStore as adminSecretsStore$1, applyD1Migrations as applyD1Migrations$1, createExecutionContext, createMessageBatch, createPagesEventContext, createScheduledController, evictAllDurableObjects as evictAllDurableObjects$1, evictDurableObject as evictDurableObject$1, getQueueResult, introspectWorkflow as introspectWorkflow$1, introspectWorkflowInstance as introspectWorkflowInstance$1, listDurableObjectIds as listDurableObjectIds$1, reset as reset$1, runDurableObjectAlarm as runDurableObjectAlarm$1, runInDurableObject as runInDurableObject$1, waitOnExecutionContext } from "cloudflare:test";
6
6
  //#region src/Vitest.ts
7
7
  /**
8
- * Effect-native helpers for tests running in Cloudflare's Vitest Workers pool.
8
+ * Effect-native helpers for tests running in Cloudflare's Workers Vitest plugin.
9
9
  *
10
10
  * Import this module through the `effect-cf/vitest` subpath. It is intended to
11
11
  * run inside the Workers test runtime, where `cloudflare:test` is available.
12
12
  */
13
13
  const currentEnv = env;
14
14
  /**
15
- * Provides the Workers pool environment as both {@link WorkerEnvironment} and
15
+ * Provides the Workers test environment as both {@link WorkerEnvironment} and
16
16
  * the active Effect `ConfigProvider`.
17
17
  */
18
18
  const layer = Layer.mergeAll(Layer.succeed(WorkerEnvironment, currentEnv), ConfigProvider.layer(WorkerConfig.providerFromEnv(currentEnv)));
@@ -50,7 +50,7 @@ const pages = Effect.fn("effect-cf/vitest/pages")(function* (handler, init) {
50
50
  });
51
51
  /**
52
52
  * Invokes an Effect-backed queue consumer, drains its `waitUntil` work, and
53
- * returns Pool Workers' acknowledgement and retry result.
53
+ * returns the Workers Vitest plugin's acknowledgement and retry result.
54
54
  */
55
55
  const queue = Effect.fn("effect-cf/vitest/queue")(function* (Worker, queueName, messages, workerEnv = currentEnv) {
56
56
  return yield* withExecutionContext(Effect.fnUntraced(function* (context) {
@@ -146,7 +146,7 @@ const runWorkflowModifier = Effect.fnUntraced(function* (register, use) {
146
146
  if (callbackExit !== void 0 && Exit.isFailure(callbackExit)) return callbackExit;
147
147
  throw cause;
148
148
  }
149
- if (callbackExit === void 0) throw new Error("Pool Workers did not invoke the Workflow modifier callback");
149
+ if (callbackExit === void 0) throw new Error("The Workers Vitest plugin did not invoke the Workflow modifier callback");
150
150
  return callbackExit;
151
151
  });
152
152
  });
@@ -1,14 +1,16 @@
1
1
  import { c as WorkerEnvironment, r as BindingValidationError, t as BindingNotFoundError } from "./Binding-xJJJPmiD.mjs";
2
- import { x as ServiceFreeSchema } from "./DurableObjectState-D3k-WRnd.mjs";
2
+ import { x as ServiceFreeSchema } from "./DurableObjectState-DVIgf0sA.mjs";
3
3
  import { Context, Effect, Option, Schema } from "effect";
4
4
  declare namespace WorkflowBinding_d_exports {
5
- export { WorkflowBindingClient, WorkflowBindingDefinition, WorkflowInstance, WorkflowInstanceCreateBatchOptions, WorkflowInstanceCreateOptions, WorkflowInstanceEvent, WorkflowInstanceRestartOptions, WorkflowInstanceStatus, WorkflowInstanceStatusName, WorkflowOperationError, WorkflowResultDecodeError, isWorkflow, layer, makeClient };
5
+ export { WorkflowBindingClient, WorkflowBindingDefinition, WorkflowInstance, WorkflowInstanceCreateBatchOptions, WorkflowInstanceCreateOptions, WorkflowInstanceEvent, WorkflowInstanceLocationHint, WorkflowInstanceRestartOptions, WorkflowInstanceStatus, WorkflowInstanceStatusName, WorkflowInstanceTerminateOptions, WorkflowOperationError, WorkflowResultDecodeError, isWorkflow, layer, makeClient };
6
6
  }
7
7
  type WorkflowInstanceCreateOptions<Payload> = Omit<CloudflareWorkflowInstanceCreateOptions<Payload>, "params">;
8
8
  type WorkflowInstanceCreateBatchOptions<Payload, EncodedPayload = unknown> = ReadonlyArray<{
9
9
  readonly payload: Payload;
10
10
  } & WorkflowInstanceCreateOptions<EncodedPayload>>;
11
11
  type WorkflowInstanceRestartOptions = CloudflareWorkflowInstanceRestartOptions;
12
+ type WorkflowInstanceTerminateOptions = CloudflareWorkflowInstanceTerminateOptions;
13
+ type WorkflowInstanceLocationHint = CloudflareWorkflowInstanceLocationHint;
12
14
  type WorkflowInstanceStatusName = CloudflareInstanceStatus["status"];
13
15
  interface WorkflowInstanceStatus<Result> {
14
16
  readonly status: WorkflowInstanceStatusName;
@@ -23,8 +25,9 @@ interface WorkflowInstance<Result> {
23
25
  readonly id: string;
24
26
  readonly pause: Effect.Effect<void, WorkflowOperationError>;
25
27
  readonly resume: Effect.Effect<void, WorkflowOperationError>;
26
- readonly terminate: Effect.Effect<void, WorkflowOperationError>;
28
+ readonly terminate: (options?: WorkflowInstanceTerminateOptions) => Effect.Effect<void, WorkflowOperationError>;
27
29
  readonly restart: (options?: WorkflowInstanceRestartOptions) => Effect.Effect<void, WorkflowOperationError>;
30
+ readonly delete: Effect.Effect<void, WorkflowOperationError>;
28
31
  readonly status: Effect.Effect<WorkflowInstanceStatus<Result>, WorkflowOperationError | WorkflowResultDecodeError>;
29
32
  readonly sendEvent: (event: WorkflowInstanceEvent) => Effect.Effect<void, WorkflowOperationError>;
30
33
  }
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { a as Environment_d_exports, c as WorkerEnvironment, i as Binding_d_exports, n as BindingService, o as WorkerConfig, r as BindingValidationError, s as WorkerEnv, t as BindingNotFoundError } from "./Binding-xJJJPmiD.mjs";
2
2
  import { l as Artifacts_d_exports } from "./Artifacts-DnHQA-Ax.mjs";
3
- import { C as Rpc_d_exports, D as StorageOperationError, E as DurableObjectStorage_d_exports, S as Provider, T as DurableWebSocket, _ as Definition$4, a as NativeRequest, b as RpcDefinition_d_exports, c as WorkerDefinition_d_exports, d as AsyncMethodCloudflareReturn, f as AsyncMethodKey, g as QueueBinding_d_exports, h as QueueDefinition_d_exports, i as ExecutionContext, l as ServiceBinding_d_exports, m as Queue_d_exports, o as WorkerContext, p as AsyncMethodSuccess, r as DurableObjectState_d_exports, s as Worker_d_exports, t as DurableObjectState, u as AsyncMethodArgs, v as Method$2, w as DurableObjectWebSocket_d_exports, x as ServiceFreeSchema$1, y as ReservedMethodName$2 } from "./DurableObjectState-D3k-WRnd.mjs";
3
+ import { C as Rpc_d_exports, D as StorageOperationError, E as DurableObjectStorage_d_exports, S as Provider, T as DurableWebSocket, _ as Definition$4, a as NativeRequest, b as RpcDefinition_d_exports, c as WorkerDefinition_d_exports, d as AsyncMethodCloudflareReturn, f as AsyncMethodKey, g as QueueBinding_d_exports, h as QueueDefinition_d_exports, i as ExecutionContext, l as ServiceBinding_d_exports, m as Queue_d_exports, o as WorkerContext, p as AsyncMethodSuccess, r as DurableObjectState_d_exports, s as Worker_d_exports, t as DurableObjectState, u as AsyncMethodArgs, v as Method$2, w as DurableObjectWebSocket_d_exports, x as ServiceFreeSchema$1, y as ReservedMethodName$2 } from "./DurableObjectState-DVIgf0sA.mjs";
4
4
  import { t as Hyperdrive_d_exports } from "./Hyperdrive-z-9fFz15.mjs";
5
5
  import { t as ContainerNamespace_d_exports } from "./ContainerNamespace-CFjiLw8b.mjs";
6
- import { a as WorkflowInstanceCreateOptions, i as WorkflowInstanceCreateBatchOptions, n as WorkflowBinding_d_exports, r as WorkflowInstance, s as WorkflowOperationError, t as WorkflowBindingClient } from "./WorkflowBinding-CtrmxfdT.mjs";
6
+ import { a as WorkflowInstanceCreateOptions, i as WorkflowInstanceCreateBatchOptions, n as WorkflowBinding_d_exports, r as WorkflowInstance, s as WorkflowOperationError, t as WorkflowBindingClient } from "./WorkflowBinding-C9KRmfDU.mjs";
7
7
  import { Cause, Config, Context, Data, DateTime, Duration, Effect, Layer, Option, Predicate, Redacted, Schema, Scope } from "effect";
8
8
  import { Headers as Headers$1, HttpClient, HttpClientResponse } from "effect/unstable/http";
9
9
  import { OtlpExporter, OtlpResource } from "effect/unstable/observability";
@@ -1491,7 +1491,7 @@ declare const layer$4: <Self>(tag: Context.Service<Self, EmailClient>, definitio
1491
1491
  declare const make$5: <Id extends string>(id: Id) => TagClass$6<EmailService<Id>, Id>;
1492
1492
  declare const Tag$7: <Self>() => <Id extends string>(id: Id) => TagClass$6<Self, Id>;
1493
1493
  declare namespace Images_d_exports {
1494
- export { DrawStepOptions, HostedImagesClient, ImageDrawOptions, ImageHandleClient, ImageInfoResponse, ImageInputOptions, ImageInputValue, ImageList, ImageListOptions, ImageMetadata, ImageOutputOptions, ImageTransform, ImageTransformationOutputOptions, ImageTransformationResult, ImageUpdateOptions, ImageUploadOptions, ImageUploadValue, ImagesClient, ImagesDefinition, ImagesOperationError, ImagesRuntimeBinding, ImagesService, ImagesTransformationResultClient, LayerOptions$5 as LayerOptions, ProcessOptions, Step, Steps, Tag$6 as Tag, TagClass$5 as TagClass, TypeId, draw, empty, isImagesBinding, layer$3 as layer, make$4 as make, makeClient$3 as makeClient, transform };
1494
+ export { DrawStepOptions, HostedImagesClient, ImageDirectUploadOptions, ImageDirectUploadResult, ImageDrawOptions, ImageHandleClient, ImageInfoResponse, ImageInputOptions, ImageInputValue, ImageList, ImageListOptions, ImageMetadata, ImageOutputOptions, ImageSignedUrlOptions, ImageTransform, ImageTransformationOutputOptions, ImageTransformationResponseOptions, ImageTransformationResult, ImageUpdateOptions, ImageUploadOptions, ImageUploadValue, ImagesClient, ImagesDefinition, ImagesOperationError, ImagesRuntimeBinding, ImagesService, ImagesTransformationResultClient, LayerOptions$5 as LayerOptions, ProcessOptions, Step, Steps, Tag$6 as Tag, TagClass$5 as TagClass, TextOptions, TypeId, draw, empty, isImagesBinding, layer$3 as layer, make$4 as make, makeClient$3 as makeClient, transform };
1495
1495
  }
1496
1496
  declare const TypeId: "~effect-cf/Images/Steps";
1497
1497
  type TypeId = typeof TypeId;
@@ -1517,12 +1517,17 @@ type ImageDrawOptions = CloudflareImageDrawOptions;
1517
1517
  type ImageInputOptions = CloudflareImageInputOptions;
1518
1518
  type ImageOutputOptions = CloudflareImageOutputOptions;
1519
1519
  type ImageTransformationOutputOptions = CloudflareImageTransformationOutputOptions;
1520
+ type ImageTransformationResponseOptions = CloudflareImageTransformationResponseOptions;
1520
1521
  type ImageTransformationResult = CloudflareImageTransformationResult;
1521
1522
  type ImageUploadOptions = CloudflareImageUploadOptions;
1522
1523
  type ImageUpdateOptions = CloudflareImageUpdateOptions;
1523
1524
  type ImageListOptions = CloudflareImageListOptions;
1524
1525
  type ImageList = CloudflareImageList;
1525
1526
  type ImageMetadata = CloudflareImageMetadata;
1527
+ type ImageSignedUrlOptions = CloudflareImageSignedUrlOptions;
1528
+ type ImageDirectUploadOptions = CloudflareImageDirectUploadOptions;
1529
+ type ImageDirectUploadResult = CloudflareImageDirectUploadResult;
1530
+ type TextOptions = CloudflareTextOptions;
1526
1531
  type ImageInputValue = ReadableStream<Uint8Array> | ArrayBuffer;
1527
1532
  type ImageUploadValue = ReadableStream<Uint8Array> | ArrayBuffer;
1528
1533
  interface DrawStepOptions {
@@ -1598,14 +1603,18 @@ interface Steps {
1598
1603
  readonly [TypeId]: typeof TypeId;
1599
1604
  readonly steps: ReadonlyArray<Step>;
1600
1605
  }
1601
- interface ProcessOptions {
1606
+ type ProcessOptions = {
1602
1607
  readonly stream: ImageInputValue;
1603
1608
  readonly inputOptions?: ImageInputOptions;
1604
1609
  readonly outputOptions: ImageOutputOptions;
1605
- }
1610
+ } | {
1611
+ readonly text: string;
1612
+ readonly textOptions: TextOptions;
1613
+ readonly outputOptions: ImageOutputOptions;
1614
+ };
1606
1615
  interface ImagesTransformationResultClient {
1607
1616
  readonly raw: CloudflareImageTransformationResult;
1608
- readonly response: Effect.Effect<CloudflareResponse, ImagesOperationError>;
1617
+ readonly response: (options?: ImageTransformationResponseOptions) => Effect.Effect<CloudflareResponse, ImagesOperationError>;
1609
1618
  readonly contentType: Effect.Effect<string, ImagesOperationError>;
1610
1619
  readonly image: (options?: ImageTransformationOutputOptions) => Effect.Effect<ReadableStream<Uint8Array>, ImagesOperationError>;
1611
1620
  }
@@ -1613,6 +1622,7 @@ interface ImageHandleClient {
1613
1622
  readonly raw: CloudflareImageHandle;
1614
1623
  readonly details: Effect.Effect<Option.Option<ImageMetadata>, ImagesOperationError>;
1615
1624
  readonly bytes: Effect.Effect<Option.Option<ReadableStream<Uint8Array>>, ImagesOperationError>;
1625
+ readonly signedUrl: (options: ImageSignedUrlOptions) => Effect.Effect<string, ImagesOperationError>;
1616
1626
  readonly update: (options: ImageUpdateOptions) => Effect.Effect<ImageMetadata, ImagesOperationError>;
1617
1627
  readonly delete: Effect.Effect<boolean, ImagesOperationError>;
1618
1628
  }
@@ -1620,16 +1630,19 @@ interface HostedImagesClient {
1620
1630
  readonly image: (imageId: string) => ImageHandleClient;
1621
1631
  readonly upload: (image: ImageUploadValue, options?: ImageUploadOptions) => Effect.Effect<ImageMetadata, ImagesOperationError>;
1622
1632
  readonly list: (options?: ImageListOptions) => Effect.Effect<ImageList, ImagesOperationError>;
1633
+ readonly createDirectUpload: (options?: ImageDirectUploadOptions) => Effect.Effect<ImageDirectUploadResult, ImagesOperationError>;
1623
1634
  readonly rawUnsafe: Effect.Effect<CloudflareHostedImagesBinding>;
1624
1635
  }
1625
1636
  interface ImagesRuntimeBinding {
1626
1637
  readonly info: (image: ImageInputValue, options?: ImageInputOptions) => Promise<ImageInfoResponse>;
1627
1638
  readonly input: (image: ImageInputValue, options?: ImageInputOptions) => CloudflareImageTransformer;
1639
+ readonly text?: (content: string, options: TextOptions) => CloudflareImageTransformer;
1628
1640
  readonly hosted?: CloudflareHostedImagesBinding;
1629
1641
  }
1630
1642
  interface ImagesClient {
1631
1643
  readonly info: (image: ImageInputValue, options?: ImageInputOptions) => Effect.Effect<ImageInfoResponse, ImagesOperationError>;
1632
1644
  readonly input: (image: ImageInputValue, options?: ImageInputOptions) => Effect.Effect<CloudflareImageTransformer, ImagesOperationError>;
1645
+ readonly text: (content: string, options: TextOptions) => Effect.Effect<CloudflareImageTransformer, ImagesOperationError>;
1633
1646
  readonly process: (steps: Steps, options: ProcessOptions) => Effect.Effect<ImagesTransformationResultClient, ImagesOperationError>;
1634
1647
  readonly hosted: Option.Option<HostedImagesClient>;
1635
1648
  readonly rawUnsafe: Effect.Effect<ImagesRuntimeBinding>;
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { a as WorkerEnvironment, i as WorkerConfig, n as violationsMessage, r as Environment_exports, t as causeMessage } from "./ErrorMessage-BM0K-Nik.mjs";
3
3
  import { n as Service$2, r as layer$19, t as Binding_exports } from "./Binding-pfilNJmP.mjs";
4
4
  import { n as Artifacts_exports } from "./Artifacts-CSIk1Oml.mjs";
5
- import { a as DurableObjectWebSocket_exports, i as fromExecutionContext, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState } from "./DurableObjectState-CepagPkX.mjs";
5
+ import { a as DurableObjectWebSocket_exports, i as fromExecutionContext, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState } from "./DurableObjectState-CxS5Y2hf.mjs";
6
6
  import { Cause, Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Function as Function$1, Layer, ManagedRuntime, Option, Predicate, Queue, Result, Schema } from "effect";
7
7
  import { FetchHttpClient, HttpClient, HttpClientRequest, HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
8
8
  import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
@@ -2918,11 +2918,11 @@ const tryImagesSync = (binding, operation, evaluate) => Effect.try({
2918
2918
  });
2919
2919
  const maybe = (value) => value === null ? Option.none() : Option.some(value);
2920
2920
  const hasFunction = (value, key) => Predicate.hasProperty(value, key) && Predicate.isFunction(value[key]);
2921
- const isHostedImagesBinding = (value) => hasFunction(value, "image") && hasFunction(value, "upload") && hasFunction(value, "list");
2921
+ const isHostedImagesBinding = (value) => hasFunction(value, "image") && hasFunction(value, "upload") && hasFunction(value, "list") && hasFunction(value, "createDirectUpload");
2922
2922
  const isImagesBinding = (value) => hasFunction(value, "info") && hasFunction(value, "input");
2923
2923
  const wrapResult = (binding, result) => ({
2924
2924
  raw: result,
2925
- response: tryImagesSync(binding, "response", () => result.response()),
2925
+ response: (options) => tryImagesSync(binding, "response", () => result.response(options)),
2926
2926
  contentType: tryImagesSync(binding, "contentType", () => result.contentType()),
2927
2927
  image: (options) => tryImagesSync(binding, "image", () => result.image(options))
2928
2928
  });
@@ -2930,6 +2930,7 @@ const wrapHandle = (binding, handle) => ({
2930
2930
  raw: handle,
2931
2931
  details: tryImagesPromise(binding, "details", () => handle.details()).pipe(Effect.map(maybe), Effect.withSpan("Images.details")),
2932
2932
  bytes: tryImagesPromise(binding, "bytes", () => handle.bytes()).pipe(Effect.map(maybe), Effect.withSpan("Images.bytes")),
2933
+ signedUrl: Effect.fn("Images.signedUrl")((options) => tryImagesPromise(binding, "signedUrl", () => handle.signedUrl(options))),
2933
2934
  update: Effect.fn("Images.update")((options) => tryImagesPromise(binding, "update", () => handle.update(options))),
2934
2935
  delete: tryImagesPromise(binding, "delete", () => handle.delete()).pipe(Effect.withSpan("Images.delete"))
2935
2936
  });
@@ -2937,12 +2938,17 @@ const wrapHosted = (binding, hosted) => ({
2937
2938
  image: (imageId) => wrapHandle(binding, hosted.image(imageId)),
2938
2939
  upload: Effect.fn("Images.upload")((image, options) => tryImagesPromise(binding, "upload", () => hosted.upload(image, options))),
2939
2940
  list: Effect.fn("Images.list")((options) => tryImagesPromise(binding, "list", () => hosted.list(options))),
2941
+ createDirectUpload: Effect.fn("Images.createDirectUpload")((options) => tryImagesPromise(binding, "createDirectUpload", () => hosted.createDirectUpload(options))),
2940
2942
  rawUnsafe: Effect.succeed(hosted)
2941
2943
  });
2942
2944
  const makeClient$4 = (definition) => (images) => {
2943
2945
  const input = (image, options) => tryImagesSync(definition.binding, "input", () => images.input(image, options));
2946
+ const text = (content, options) => tryImagesSync(definition.binding, "text", () => {
2947
+ if (!hasFunction(images, "text")) throw new Error("Images binding is missing text()");
2948
+ return images.text(content, options);
2949
+ });
2944
2950
  const process = Effect.fn("Images.process")(function* (steps, options) {
2945
- let transformer = yield* input(options.stream, options.inputOptions);
2951
+ let transformer = "text" in options ? yield* text(options.text, options.textOptions) : yield* input(options.stream, options.inputOptions);
2946
2952
  for (const step of steps.steps) transformer = yield* Step.$match(step, {
2947
2953
  Draw: (drawStep) => tryImagesSync(definition.binding, "draw", () => transformer.draw(drawStep.image, drawStep.options)),
2948
2954
  Transform: (transformStep) => tryImagesSync(definition.binding, "transform", () => transformer.transform(transformStep.transform))
@@ -2954,6 +2960,7 @@ const makeClient$4 = (definition) => (images) => {
2954
2960
  definition,
2955
2961
  info: Effect.fn("Images.info")((image, options) => tryImagesPromise(definition.binding, "info", () => images.info(image, options))),
2956
2962
  input,
2963
+ text,
2957
2964
  process,
2958
2965
  hosted: isHostedImagesBinding(images.hosted) ? Option.some(wrapHosted(definition.binding, images.hosted)) : Option.none(),
2959
2966
  rawUnsafe: Effect.succeed(images)
@@ -3377,8 +3384,9 @@ const makeClient = (definition) => {
3377
3384
  id: raw.id,
3378
3385
  pause: operation("pause", () => raw.pause()),
3379
3386
  resume: operation("resume", () => raw.resume()),
3380
- terminate: operation("terminate", () => raw.terminate()),
3387
+ terminate: (options) => operation("terminate", () => raw.terminate(options)),
3381
3388
  restart: (options) => operation("restart", () => raw.restart(options)),
3389
+ delete: operation("delete", () => raw.delete()),
3382
3390
  status: operation("status", () => raw.status()).pipe(Effect.flatMap((status) => Effect.gen(function* () {
3383
3391
  const output = status.output === void 0 || status.output === null && status.status !== "complete" ? Option.none() : Option.some(yield* decodeResult(status.output).pipe(Effect.mapError((cause) => new WorkflowResultDecodeError({
3384
3392
  binding: definition.binding,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -68,7 +68,7 @@
68
68
  "@cloudflare/computer": "0.2.0",
69
69
  "@cloudflare/containers": "catalog:",
70
70
  "@cloudflare/sandbox": "0.13.0-next.738.2",
71
- "@cloudflare/vitest-pool-workers": "catalog:",
71
+ "@cloudflare/vitest-plugin": "catalog:",
72
72
  "@cloudflare/workers-types": "catalog:",
73
73
  "@effect/platform-node": "^4.0.0-rc.110",
74
74
  "@effect/sql-d1": "catalog:",
@@ -84,8 +84,8 @@
84
84
  "peerDependencies": {
85
85
  "@cloudflare/computer": "^0.2.0",
86
86
  "@cloudflare/sandbox": "^0.13.0-next.738.2",
87
- "@cloudflare/vitest-pool-workers": "^0.21.3",
88
- "@cloudflare/workers-types": "^4.20260611.1",
87
+ "@cloudflare/vitest-plugin": "^1.0.0",
88
+ "@cloudflare/workers-types": "^5.20260820.1",
89
89
  "@effect/sql-d1": "^4.0.0-rc.110",
90
90
  "@effect/sql-pg": "^4.0.0-rc.110",
91
91
  "@effect/sql-sqlite-do": "^4.0.0-rc.110",
@@ -98,7 +98,7 @@
98
98
  "@cloudflare/sandbox": {
99
99
  "optional": true
100
100
  },
101
- "@cloudflare/vitest-pool-workers": {
101
+ "@cloudflare/vitest-plugin": {
102
102
  "optional": true
103
103
  },
104
104
  "@cloudflare/workers-types": {
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 interface ProcessOptions {
83
- readonly stream: ImageInputValue;
84
- readonly inputOptions?: ImageInputOptions;
85
- readonly outputOptions: ImageOutputOptions;
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: Effect.Effect<CloudflareResponse, ImagesOperationError>;
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") && hasFunction(value, "upload") && hasFunction(value, "list");
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 = yield* input(options.stream, options.inputOptions);
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 Workers pool.
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 pool environment as both {@link WorkerEnvironment} and
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 Pool Workers for a Pages Function. */
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 Pool Workers' `createMessageBatch` helper. */
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 Pool Workers. */
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 Pool Workers' acknowledgement and retry result.
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 Pool Workers. */
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 Pool Workers' Secrets Store admin API. */
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("Pool Workers did not invoke the Workflow modifier callback");
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
  /**
@@ -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: Effect.Effect<void, WorkflowOperationError>;
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
  };