effect-cf 0.17.1 → 0.20.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 +24 -0
- package/README.md +50 -3
- package/dist/{Hyperdrive-C0vfrPeG.d.mts → Hyperdrive-RTjgirMV.d.mts} +7 -12
- package/dist/HyperdrivePg.d.mts +2 -6
- package/dist/HyperdrivePg.mjs +0 -1
- package/dist/index.d.mts +223 -118
- package/dist/index.mjs +587 -164
- package/package.json +8 -9
- package/src/AiGateway.ts +3 -0
- package/src/AnalyticsEngine.ts +6 -1
- package/src/Binding.ts +4 -2
- package/src/Cache.ts +104 -0
- package/src/CloudflareOtlp.ts +20 -7
- package/src/ContainerNamespace.ts +3 -0
- package/src/D1.ts +1 -0
- package/src/DurableObject.ts +10 -2
- package/src/DurableObjectAlarm.ts +19 -0
- package/src/DurableObjectDefinition.ts +34 -6
- package/src/DurableObjectNamespace.ts +4 -1
- package/src/DurableObjectRpcWebSocket.ts +14 -0
- package/src/DurableObjectSqlite.ts +1 -0
- package/src/DurableObjectStorage.ts +2 -0
- package/src/DurableObjectWebSocket.ts +4 -1
- package/src/Email.ts +354 -10
- package/src/HyperdrivePg.ts +1 -1
- package/src/Kv.ts +3 -1
- package/src/QueueBinding.ts +2 -1
- package/src/QueueDefinition.ts +6 -1
- package/src/R2.ts +1 -0
- package/src/RpcDefinition.ts +2 -0
- package/src/ServiceBinding.ts +6 -1
- package/src/Worker.ts +10 -2
- package/src/WorkerDefinition.ts +28 -6
- package/src/WorkflowBinding.ts +5 -2
- package/src/WorkflowDefinition.ts +6 -1
- package/src/index.ts +1 -0
- package/src/internal/Clock.ts +9 -0
- package/src/internal/RpcInvocation.ts +1 -0
- package/dist/Hyperdrive-89hg_Fck.mjs +0 -156
- /package/dist/{chunk-CfYAbeIz.mjs → rolldown-runtime-D7D4PA-g.mjs} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# effect-cf
|
|
2
2
|
|
|
3
|
+
## 0.20.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#64](https://github.com/danieljvdm/effect-cf/pull/64) [`d333039`](https://github.com/danieljvdm/effect-cf/commit/d33303949ac38d2a2e942954d0edbfeeebc16b81) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Upgrade Effect to `4.0.0-beta.105`. The `effect`, `@effect/sql-d1`, `@effect/sql-pg`, and `@effect/sql-sqlite-do` peer ranges now require `^4.0.0-beta.105`, so upgrade Effect alongside this release.
|
|
8
|
+
|
|
9
|
+
`CloudflareOtlp` resource precedence has flipped to match Effect's `OtlpResource.fromConfig`. Explicit `resource.serviceName` and `resource.serviceVersion` now take precedence over `OTEL_SERVICE_NAME`, `OTEL_SERVICE_VERSION`, and `OTEL_RESOURCE_ATTRIBUTES`; previously the environment won. Omit an option to keep letting operators set it from the environment.
|
|
10
|
+
|
|
11
|
+
## 0.19.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [#61](https://github.com/danieljvdm/effect-cf/pull/61) [`7aa75de`](https://github.com/danieljvdm/effect-cf/commit/7aa75de93408b1eb345ab530f852db9038923f3d) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add Cloudflare Email Service sending support to `Email`.
|
|
16
|
+
|
|
17
|
+
Structured messages sent through a `send_email` binding are now validated against documented Email Sending limits — combined `to`/`cc`/`bcc` recipients, attachment count, custom header sizes, and required fields — and fail with `EmailValidationError` before the binding is called. Opt out with `layer({ binding, send: { validate: false } })`. Raw RFC 5322 `EmailMessage` values are still passed through untouched, so the legacy `cloudflare:email` API keeps working.
|
|
18
|
+
|
|
19
|
+
Cloudflare's `E_*` error codes are now reported on `EmailOperationError.code`, with the documented set exported as `Email.emailErrorCodes` and `Email.EmailErrorCode`. Documented limits are exported as `Email.sendLimits`.
|
|
20
|
+
|
|
21
|
+
## 0.18.0
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- [#58](https://github.com/danieljvdm/effect-cf/pull/58) [`c5bac36`](https://github.com/danieljvdm/effect-cf/commit/c5bac367587c314a17b32e984faee546a488f1ff) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add Effect-native support for Cloudflare's default and named Cache API instances, including typed operation errors and `Option`-based cache misses.
|
|
26
|
+
|
|
3
27
|
## 0.17.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# effect-cf
|
|
2
2
|
|
|
3
|
-
Effect-native Cloudflare primitives for Workers, Durable Objects, Containers, bindings, KV, D1, Queues, Email, Analytics Engine, Workflows, and Durable Object storage.
|
|
3
|
+
Effect-native Cloudflare primitives for Workers, Durable Objects, Containers, bindings, Cache, KV, D1, Queues, Email, Analytics Engine, Workflows, and Durable Object storage.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -31,12 +31,13 @@ Runtime creation belongs at Cloudflare entrypoints, not inside binding helpers.
|
|
|
31
31
|
- `DurableObjectState` / `DurableObjectStorage` - Effect wrappers for state, alarms, SQL, and embedded KV
|
|
32
32
|
- `DurableObjectWebSocket` - WebSocket upgrade helpers for Durable Objects
|
|
33
33
|
- `ContainerNamespace` - named Cloudflare Container instances with Effect-wrapped request and lifecycle operations
|
|
34
|
+
- `Cache` - Effect wrapper for Cloudflare's default and named Cache API instances
|
|
34
35
|
- `Kv` - typed KV namespace helper
|
|
35
36
|
- `D1` - typed D1 database binding helper with an `@effect/sql-d1` backed SQL layer
|
|
36
37
|
- `R2` - typed R2 bucket binding helper with Effect-wrapped object and multipart operations
|
|
37
38
|
- `Hyperdrive` - typed Hyperdrive binding helper for connection strings and optional Postgres SQL integration
|
|
38
39
|
- `Images` - typed Cloudflare Images binding helper with transformation APIs and optional hosted image operations
|
|
39
|
-
- `Email` - typed Cloudflare
|
|
40
|
+
- `Email` - typed Cloudflare Email Service binding helper for `send_email` bindings, with limit validation and typed error codes
|
|
40
41
|
- `AnalyticsEngine` - typed Cloudflare Analytics Engine write bindings and SQL API query helpers
|
|
41
42
|
- `Queue` - typed Queue producer/consumer tags plus client and error types
|
|
42
43
|
- `Workflow` - typed Workflow entrypoints, steps, starter clients, and instance types
|
|
@@ -161,6 +162,38 @@ Producers should usually use `const queue = yield* AvatarQueue` and then call `q
|
|
|
161
162
|
|
|
162
163
|
Queue handlers run inline failures through Cloudflare's normal retry path. If background work scheduled with `WorkerContext.waitUntil(...)` should also make the batch retry, use `WorkerContext.waitUntilPropagating(...)` or `waitUntil(..., { mode: "propagate" })`; the default `waitUntil` mode observes and logs failures without rejecting the native `waitUntil` promise.
|
|
163
164
|
|
|
165
|
+
## Cache Example
|
|
166
|
+
|
|
167
|
+
`Cache.layer` exposes Cloudflare's global Cache API as an Effect service. Cache misses are represented by `Option.none()`, and named caches are available through `open(...)`.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { Effect, Option } from "effect";
|
|
171
|
+
import { Cache, Worker } from "effect-cf";
|
|
172
|
+
|
|
173
|
+
export default Worker.make(Cache.layer, {
|
|
174
|
+
fetch: Effect.gen(function* () {
|
|
175
|
+
const request = yield* Worker.NativeRequest;
|
|
176
|
+
const storage = yield* Cache.CacheStorage;
|
|
177
|
+
const cached = yield* storage.default.match(request);
|
|
178
|
+
|
|
179
|
+
if (Option.isSome(cached)) {
|
|
180
|
+
return cached.value;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const response = new Response("fresh", {
|
|
184
|
+
headers: { "Cache-Control": "public, max-age=300" },
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const context = yield* Worker.WorkerContext;
|
|
188
|
+
yield* context.waitUntil(storage.default.put(request, response.clone()));
|
|
189
|
+
|
|
190
|
+
return response;
|
|
191
|
+
}),
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Use `const cache = yield* storage.open("api-cache")` for a named cache. `match`, `put`, `delete`, and `open` failures are reported as `CacheOperationError` values.
|
|
196
|
+
|
|
164
197
|
## R2 Example
|
|
165
198
|
|
|
166
199
|
R2 bucket tags expose Cloudflare object operations as Effects and map nullable reads to `Option`.
|
|
@@ -251,7 +284,7 @@ export const resizeAvatar = (image: Images.ImageInputValue) =>
|
|
|
251
284
|
|
|
252
285
|
## Email Example
|
|
253
286
|
|
|
254
|
-
Email tags expose Cloudflare
|
|
287
|
+
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`.
|
|
255
288
|
|
|
256
289
|
```ts
|
|
257
290
|
import { Effect } from "effect";
|
|
@@ -275,6 +308,20 @@ export const sendWelcomeEmail = (to: string) =>
|
|
|
275
308
|
});
|
|
276
309
|
```
|
|
277
310
|
|
|
311
|
+
Onboard the sending domain under **Compute > Email Service > Email Sending**, then declare the binding in the consuming Worker's `wrangler.jsonc`:
|
|
312
|
+
|
|
313
|
+
```jsonc
|
|
314
|
+
{
|
|
315
|
+
"send_email": [{ "name": "EMAIL" }],
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Messages that violate a documented limit fail with `EmailValidationError` carrying every violation, without calling the binding. Use `layer({ binding, send: { validate: false } })` to skip validation and let Cloudflare reject the message instead. Raw RFC 5322 `EmailMessage` values are always passed through untouched, so the legacy `cloudflare:email` API keeps working.
|
|
320
|
+
|
|
321
|
+
Cloudflare's total message size limit is exposed as `Email.sendLimits.maxMessageBytes` but is not enforced, because the encoded MIME size is only known once Cloudflare composes the message. Oversized messages fail at the binding with `E_CONTENT_TOO_LARGE`.
|
|
322
|
+
|
|
323
|
+
See [`examples/email/README.md`](../../examples/email/README.md) for domain onboarding, binding restrictions, and typed recovery from `EmailValidationError` and `EmailOperationError`.
|
|
324
|
+
|
|
278
325
|
## Analytics Engine Example
|
|
279
326
|
|
|
280
327
|
Analytics Engine tags expose Cloudflare dataset bindings as Effect-wrapped `writeDataPoint(...)` operations. Writes use Cloudflare's native non-blocking runtime API and are validated against Workers Analytics Engine limits before reaching the binding.
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { Config, ConfigProvider, Context, Effect, Layer } from "effect";
|
|
2
|
-
import * as _$effect_Types0 from "effect/Types";
|
|
3
|
-
import * as _$effect_Cause0 from "effect/Cause";
|
|
4
|
-
import * as _$effect_Redacted0 from "effect/Redacted";
|
|
5
|
-
import * as _$effect_Layer0 from "effect/Layer";
|
|
6
|
-
|
|
7
2
|
//#region src/Environment.d.ts
|
|
8
3
|
/** Cloudflare worker environment object (`env`). */
|
|
9
4
|
type WorkerEnv = Cloudflare.Env;
|
|
@@ -13,7 +8,7 @@ declare const WorkerEnvironment_base: Context.ServiceClass<WorkerEnvironment, "e
|
|
|
13
8
|
*/
|
|
14
9
|
declare class WorkerEnvironment extends WorkerEnvironment_base {}
|
|
15
10
|
type ScalarConfigValue = string | number | boolean;
|
|
16
|
-
type ScalarConfigKey = Extract<{ readonly [Key in keyof Cloudflare.Env]-?: NonNullable<Cloudflare.Env[Key]> extends ScalarConfigValue ? Key : never }[keyof Cloudflare.Env], string>;
|
|
11
|
+
type ScalarConfigKey = Extract<{ readonly [Key in keyof Cloudflare.Env]-?: NonNullable<Cloudflare.Env[Key]> extends ScalarConfigValue ? Key : never; }[keyof Cloudflare.Env], string>;
|
|
17
12
|
/**
|
|
18
13
|
* Effect `Config` helpers for scalar Cloudflare vars and secrets declared on
|
|
19
14
|
* `Cloudflare.Env`.
|
|
@@ -49,7 +44,7 @@ declare namespace WorkerConfig {
|
|
|
49
44
|
/** Read a scalar Cloudflare var or secret as a string. */
|
|
50
45
|
const string: <const Name extends Key>(name: Name) => Config.Config<string>;
|
|
51
46
|
/** Read a scalar Cloudflare secret as a redacted string. */
|
|
52
|
-
const redacted: <const Name extends Key>(name: Name) => Config.Config<
|
|
47
|
+
const redacted: <const Name extends Key>(name: Name) => Config.Config<import("effect/Redacted").Redacted<string>>;
|
|
53
48
|
/** Read a scalar Cloudflare var or secret as a number. */
|
|
54
49
|
const number: <const Name extends Key>(name: Name) => Config.Config<number>;
|
|
55
50
|
/** Read a scalar Cloudflare var or secret as an integer. */
|
|
@@ -69,18 +64,18 @@ declare namespace WorkerConfig {
|
|
|
69
64
|
* Replace the active Effect `ConfigProvider` with one backed by the current
|
|
70
65
|
* Cloudflare worker `env` object.
|
|
71
66
|
*/
|
|
72
|
-
const providerLayer:
|
|
67
|
+
const providerLayer: import("effect/Layer").Layer<never, never, WorkerEnvironment>;
|
|
73
68
|
/** Alias for `providerLayer` for concise use in worker layers. */
|
|
74
|
-
const layer:
|
|
69
|
+
const layer: import("effect/Layer").Layer<never, never, WorkerEnvironment>;
|
|
75
70
|
/** Build a `ConfigProvider` layer with a custom `env` conversion function. */
|
|
76
|
-
const layerWith: (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) =>
|
|
71
|
+
const layerWith: (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) => import("effect/Layer").Layer<never, never, WorkerEnvironment>;
|
|
77
72
|
}
|
|
78
73
|
declare namespace Binding_d_exports {
|
|
79
74
|
export { BindingNotFoundError, BindingService, BindingValidationError, Service, TypeId, ValidationOptions, layer$1 as layer };
|
|
80
75
|
}
|
|
81
76
|
/** Internal type id marker used by binding helper services. */
|
|
82
77
|
declare const TypeId: "effect-cf/Binding";
|
|
83
|
-
declare const BindingNotFoundError_base: new <A extends Record<string, any> = {}>(args:
|
|
78
|
+
declare const BindingNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
84
79
|
readonly _tag: "BindingNotFoundError";
|
|
85
80
|
} & Readonly<A>;
|
|
86
81
|
/** Error raised when a configured binding does not exist on `env`. */
|
|
@@ -88,7 +83,7 @@ declare class BindingNotFoundError extends BindingNotFoundError_base<{
|
|
|
88
83
|
readonly binding: string;
|
|
89
84
|
readonly message: string;
|
|
90
85
|
}> {}
|
|
91
|
-
declare const BindingValidationError_base: new <A extends Record<string, any> = {}>(args:
|
|
86
|
+
declare const BindingValidationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
92
87
|
readonly _tag: "BindingValidationError";
|
|
93
88
|
} & Readonly<A>;
|
|
94
89
|
/** Error raised when a binding exists but does not match the expected shape. */
|
package/dist/HyperdrivePg.d.mts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { i as BindingNotFoundError, n as LayerOptions, o as BindingValidationError, r as TagClass, u as WorkerEnvironment } from "./Hyperdrive-
|
|
1
|
+
import { i as BindingNotFoundError, n as LayerOptions, o as BindingValidationError, r as TagClass, u as WorkerEnvironment } from "./Hyperdrive-RTjgirMV.mjs";
|
|
2
2
|
import { Layer } from "effect";
|
|
3
3
|
import { PgClient } from "@effect/sql-pg";
|
|
4
|
-
import * as _$effect_unstable_sql_SqlClient0 from "effect/unstable/sql/SqlClient";
|
|
5
|
-
import * as _$effect_unstable_sql_SqlError0 from "effect/unstable/sql/SqlError";
|
|
6
|
-
import * as _$effect_Scope0 from "effect/Scope";
|
|
7
|
-
|
|
8
4
|
//#region src/HyperdrivePg.d.ts
|
|
9
5
|
type PgLayerOptions = Omit<PgClient.PgClientConfig & {
|
|
10
6
|
readonly acquireForStream?: boolean;
|
|
11
7
|
}, "url" | "host" | "port" | "path" | "ssl" | "database" | "username" | "password" | "stream">;
|
|
12
|
-
declare const layer: <Self, Id extends string>(tag: TagClass<Self, Id>, binding: LayerOptions, options?: PgLayerOptions) => Layer.Layer<PgClient.PgClient |
|
|
8
|
+
declare const layer: <Self, Id extends string>(tag: TagClass<Self, Id>, binding: LayerOptions, options?: PgLayerOptions) => Layer.Layer<PgClient.PgClient | import("effect/unstable/sql/SqlClient").SqlClient, BindingNotFoundError | BindingValidationError | import("effect/unstable/sql/SqlError").SqlError, WorkerEnvironment | Exclude<Exclude<Self, import("effect/Scope").Scope>, Self>>;
|
|
13
9
|
//#endregion
|
|
14
10
|
export { PgLayerOptions, layer };
|
package/dist/HyperdrivePg.mjs
CHANGED