effect-cf 0.20.1 → 0.22.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 +44 -0
- package/README.md +2 -2
- package/dist/{Hyperdrive-RTjgirMV.d.mts → Hyperdrive-COyg7R26.d.mts} +40 -13
- package/dist/HyperdrivePg.d.mts +13 -5
- package/dist/HyperdrivePg.mjs +12 -7
- package/dist/index.d.mts +708 -549
- package/dist/index.mjs +924 -587
- package/package.json +10 -5
- package/src/AiGateway.ts +82 -47
- package/src/AnalyticsEngine.ts +74 -58
- package/src/Binding.ts +66 -13
- package/src/BrowserRendering.ts +30 -7
- package/src/Cache.ts +32 -8
- package/src/CloudflareOtlp.ts +32 -9
- package/src/ContainerNamespace.ts +87 -55
- package/src/D1.ts +13 -3
- package/src/DurableObject.ts +27 -164
- package/src/DurableObjectAlarm.ts +30 -9
- package/src/DurableObjectDefinition.ts +58 -54
- package/src/DurableObjectNamespace.ts +99 -96
- package/src/DurableObjectRpcWebSocket.ts +14 -6
- package/src/DurableObjectSqlite.ts +6 -3
- package/src/DurableObjectState.ts +6 -9
- package/src/DurableObjectStorage.ts +7 -1
- package/src/DurableObjectWebSocket.ts +51 -41
- package/src/Email.ts +40 -13
- package/src/Environment.ts +26 -6
- package/src/Hyperdrive.ts +2 -2
- package/src/HyperdrivePg.ts +25 -13
- package/src/Images.ts +77 -82
- package/src/Kv.ts +37 -27
- package/src/Queue.ts +6 -1
- package/src/QueueBinding.ts +18 -21
- package/src/QueueDefinition.ts +15 -14
- package/src/R2.ts +107 -29
- package/src/Rpc.ts +3 -1
- package/src/RpcDefinition.ts +177 -133
- package/src/ServiceBinding.ts +112 -108
- package/src/Vectorize.ts +59 -14
- package/src/Worker.ts +172 -192
- package/src/WorkerDefinition.ts +5 -10
- package/src/WorkersAi.ts +27 -17
- package/src/Workflow.ts +54 -49
- package/src/WorkflowBinding.ts +19 -11
- package/src/WorkflowDefinition.ts +24 -27
- package/src/index.ts +4 -3
- package/src/internal/Entrypoint.ts +3 -1
- package/src/internal/ErrorMessage.ts +24 -0
- package/src/internal/RpcInvocation.ts +11 -8
- package/src/internal/Runtime.ts +52 -0
- package/src/internal/WorkerContext.ts +14 -2
- package/src/Entry.ts +0 -259
- package/src/internal/Clock.ts +0 -37
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# effect-cf
|
|
2
2
|
|
|
3
|
+
## 0.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#73](https://github.com/danieljvdm/effect-cf/pull/73) [`9096e1e`](https://github.com/danieljvdm/effect-cf/commit/9096e1e6801bb9ac29ce8de0fa30902d9e210983) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Encode RPC method schemas through their canonical JSON codec at the Workers RPC boundary. Declaration schemas such as `Schema.Result` keep their container instance in their encoded form, so Durable Object, Worker entrypoint, and service binding RPC methods declared with them crashed in production with `DataCloneError` even though local same-isolate calls worked. Wire values are now plain JSON in both directions: clients encode arguments and decode results back into real instances, servers decode arguments and encode results, and codec failures still surface as tagged errors naming the definition and method. The `Method.EncodedArgs` and `Method.EncodedSuccess` utility types now report the JSON wire form.
|
|
8
|
+
|
|
9
|
+
## 0.21.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#69](https://github.com/danieljvdm/effect-cf/pull/69) [`16d6190`](https://github.com/danieljvdm/effect-cf/commit/16d6190bc022f040b6e9ddb1f583a973357598c3) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Align effect-cf with effect 4.0.0-beta.105 canonical APIs. This release contains breaking renames alongside behavior fixes surfaced by a full audit of the beta.65 → beta.105 upgrade.
|
|
14
|
+
|
|
15
|
+
Breaking changes:
|
|
16
|
+
|
|
17
|
+
- `unsafeRaw` is now `rawUnsafe` on every binding client and definition tag, following the effect v4 `Unsafe`-suffix convention. Definition tag statics are now Effect properties (matching the client shape) rather than zero-arg functions.
|
|
18
|
+
- `Kv` clients: `remove` is now `delete`.
|
|
19
|
+
- Layer variants renamed: `AnalyticsEngine.queryFetchLayer`/`queryFetchLayerConfig` → `layerFetch`/`layerFetchConfig` (tag fields `fetchLayer`/`fetchLayerConfig` likewise); `CloudflareOtlp.workerLayer`/`durableObjectLayer` → `layerWorker`/`layerDurableObject`.
|
|
20
|
+
- Definition tags (Durable Objects, Queues, Workflows, Containers, Bindings) are keyed as `effect-cf/<Module>/<id>` instead of the bare user id, so a definition named `"X"` no longer silently collides with an unrelated service keyed `"X"`. `definition.id` is unchanged.
|
|
21
|
+
- Queue producers must provide `sendBatch`; the silent sequential-send fallback (which lost batch atomicity) was removed and now fails with `QueueOperationError`.
|
|
22
|
+
- `Worker.renderHttpResponse` removed — return `HttpServerResponse` values directly from fetch handlers to get canonical response handling, including streaming-scope transfer.
|
|
23
|
+
- `RpcDefinition`: the plain-Error `ReservedMethodNameError` and `assertNoReservedMethodNames` were removed (use `assertNoReservedMethods`, which now throws the tagged `RpcReservedMethodNameError`); the `index` field was removed from argument encode/decode errors (positional info lives in the schema issue path).
|
|
24
|
+
- `Worker.TagFactory` / `DurableObject.TagFactory` types removed; the definition type surface is now re-exported from `WorkerDefinition`/`DurableObjectDefinition`.
|
|
25
|
+
- The unexported legacy `Entry` module and the internal Cloudflare clock were deleted; the effect default clock is used (its epoch time is monotonic-anchored, so it may skew from `Date.now()` by microseconds).
|
|
26
|
+
- effect peer dependencies are pinned exactly to `4.0.0-beta.105` while the package depends on `effect/unstable/*` modules.
|
|
27
|
+
|
|
28
|
+
Fixes:
|
|
29
|
+
|
|
30
|
+
- `DurableObjectSqlite.layer` now passes Durable Object storage to the SQL client, so `sql.withTransaction` works — previously every transaction failed at runtime.
|
|
31
|
+
- `CloudflareOtlp` layers now expose `OtlpExporter.Flusher`, and Worker fetch handlers automatically flush buffered telemetry via `ctx.waitUntil` after each response — telemetry is no longer lost when the isolate freezes after responding.
|
|
32
|
+
- Worker fetch handlers built with `makeFetchHandler` cache the runtime per environment instead of rebuilding every layer on each request.
|
|
33
|
+
- RPC method errors keep their tags across the Workers RPC wire: `RpcArgumentCountError`, `RpcArgumentDecodeError`, and `RpcSuccessEncodeError` are schema-serialized at the entrypoint and rehydrated as tagged instances on the caller side.
|
|
34
|
+
- The Durable Object RPC WebSocket transport closes the socket with code 1009 when a frame exceeds the serialization buffer limit instead of leaving the connection in a poisoned state.
|
|
35
|
+
- `DurableObjectWebSocket.acceptUpgrade` fails with a typed `DurableWebSocketAttachmentError` for non-serializable attachments instead of an untyped defect.
|
|
36
|
+
- Cloudflare Workflow steps fail with a typed `WorkflowStepError` carrying the step name, operation, and cause instead of leaking raw `unknown` rejections.
|
|
37
|
+
- `AiGateway` HTTP requests abort in-flight fetches when the running fiber is interrupted, and merge a caller-supplied `AbortSignal`.
|
|
38
|
+
|
|
39
|
+
Additions:
|
|
40
|
+
|
|
41
|
+
- Named tracing spans across the public client surface (`Kv.put`, `R2.get`, `DurableObject.call`, `QueueBinding.send`, `Email.send`, ...) with binding/operation attributes, so operations show up in the OTLP traces the package exports.
|
|
42
|
+
- Error classes render actionable messages by default: `Cause.pretty` and logs now show the binding, operation, error code when present, and the underlying cause instead of an empty message with a stack trace.
|
|
43
|
+
- `WorkerConfig.providerFromEnv` accepts `{ preserveEmptyStrings: true }` for environments where an empty-string var must decode as `""` rather than as absent.
|
|
44
|
+
- `Email` error `code` extraction is documented as best-effort (dev-time remote-proxy bindings can strip the property).
|
|
45
|
+
- `package.json` declares `sideEffects: []` for better tree-shaking of Workers bundles, and `@cloudflare/workers-types` is an optional peer for consumers type-checking against the public declarations.
|
|
46
|
+
|
|
3
47
|
## 0.20.1
|
|
4
48
|
|
|
5
49
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -119,7 +119,7 @@ export default Worker.make(RenderersLive, {
|
|
|
119
119
|
|
|
120
120
|
The instance client exposes `state`, `fetch`, `start`,
|
|
121
121
|
`startAndWaitForPorts`, `stop`, `destroy`, and the Effect-valued native
|
|
122
|
-
`
|
|
122
|
+
`rawUnsafe` stub.
|
|
123
123
|
Responses are returned unchanged, including non-2xx and WebSocket upgrade
|
|
124
124
|
responses. If the Container uses outbound interception, also export
|
|
125
125
|
`ContainerProxy` from `@cloudflare/containers`.
|
|
@@ -366,7 +366,7 @@ export const recordPageView = (request: Request) =>
|
|
|
366
366
|
|
|
367
367
|
Define the dataset binding in the consuming Worker's `wrangler.jsonc` with `analytics_engine_datasets`, then provide `RequestAnalytics.layer({ binding: "REQUEST_ANALYTICS" })` from the Worker layer. Invalid writes fail with `AnalyticsEngineWriteValidationError` by default. Use `write: { onInvalid: "drop" }` on the layer or `{ onInvalid: "drop" }` per call when dropping invalid points is preferable.
|
|
368
368
|
|
|
369
|
-
Analytics Engine query tags wrap Cloudflare's HTTP SQL API. Configuration can stay in Effect `Config`, including a redacted API token, the outbound transport is an Effect `HttpClient` dependency, and rows can be decoded with Effect schemas at the query boundary. Use `
|
|
369
|
+
Analytics Engine query tags wrap Cloudflare's HTTP SQL API. Configuration can stay in Effect `Config`, including a redacted API token, the outbound transport is an Effect `HttpClient` dependency, and rows can be decoded with Effect schemas at the query boundary. Use `layerFetchConfig(...)` as shorthand when the platform fetch-backed client is enough.
|
|
370
370
|
|
|
371
371
|
```ts
|
|
372
372
|
import { Effect, Layer, Schema as S } from "effect";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Config, ConfigProvider, Context, Effect, Layer } from "effect";
|
|
2
|
-
|
|
2
|
+
declare namespace Environment_d_exports {
|
|
3
|
+
export { WorkerConfig, WorkerEnv, WorkerEnvironment };
|
|
4
|
+
}
|
|
3
5
|
/** Cloudflare worker environment object (`env`). */
|
|
4
6
|
type WorkerEnv = Cloudflare.Env;
|
|
5
7
|
declare const WorkerEnvironment_base: Context.ServiceClass<WorkerEnvironment, "effect-cf/WorkerEnvironment", Cloudflare.Env>;
|
|
@@ -51,8 +53,23 @@ declare namespace WorkerConfig {
|
|
|
51
53
|
const integer: <const Name extends Key>(name: Name) => Config.Config<number>;
|
|
52
54
|
/** Read a scalar Cloudflare var or secret as a boolean. */
|
|
53
55
|
const boolean: <const Name extends Key>(name: Name) => Config.Config<boolean>;
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
+
/** Options for building a `ConfigProvider` from a Cloudflare worker `env` object. */
|
|
57
|
+
interface ProviderOptions {
|
|
58
|
+
/**
|
|
59
|
+
* Keep empty-string env values as explicit `""` config values.
|
|
60
|
+
*
|
|
61
|
+
* By default (absent or `false`), empty strings are treated as missing
|
|
62
|
+
* config, matching `ConfigProvider.fromUnknown`.
|
|
63
|
+
*/
|
|
64
|
+
readonly preserveEmptyStrings?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Build a `ConfigProvider` from a Cloudflare worker `env` object.
|
|
68
|
+
*
|
|
69
|
+
* Empty-string values are treated as missing config by default; pass
|
|
70
|
+
* `{ preserveEmptyStrings: true }` to keep them as explicit values.
|
|
71
|
+
*/
|
|
72
|
+
const providerFromEnv: (env: WorkerEnv, options?: ProviderOptions) => ConfigProvider.ConfigProvider;
|
|
56
73
|
/**
|
|
57
74
|
* Build a `ConfigProvider` from the current `WorkerEnvironment` with a custom
|
|
58
75
|
* conversion function.
|
|
@@ -64,17 +81,19 @@ declare namespace WorkerConfig {
|
|
|
64
81
|
* Replace the active Effect `ConfigProvider` with one backed by the current
|
|
65
82
|
* Cloudflare worker `env` object.
|
|
66
83
|
*/
|
|
67
|
-
const providerLayer:
|
|
84
|
+
const providerLayer: Layer.Layer<never, never, WorkerEnvironment>;
|
|
68
85
|
/** Alias for `providerLayer` for concise use in worker layers. */
|
|
69
|
-
const layer:
|
|
86
|
+
const layer: Layer.Layer<never, never, WorkerEnvironment>;
|
|
70
87
|
/** Build a `ConfigProvider` layer with a custom `env` conversion function. */
|
|
71
|
-
const layerWith: (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) =>
|
|
88
|
+
const layerWith: (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) => Layer.Layer<never, never, WorkerEnvironment>;
|
|
72
89
|
}
|
|
73
90
|
declare namespace Binding_d_exports {
|
|
74
91
|
export { BindingNotFoundError, BindingService, BindingValidationError, Service, TypeId, ValidationOptions, layer$1 as layer };
|
|
75
92
|
}
|
|
76
93
|
/** Internal type id marker used by binding helper services. */
|
|
77
|
-
declare const TypeId: "effect-cf/Binding";
|
|
94
|
+
declare const TypeId: "~effect-cf/Binding";
|
|
95
|
+
/** Internal type id marker used by binding helper services. */
|
|
96
|
+
type TypeId = typeof TypeId;
|
|
78
97
|
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 & {
|
|
79
98
|
readonly _tag: "BindingNotFoundError";
|
|
80
99
|
} & Readonly<A>;
|
|
@@ -98,14 +117,22 @@ interface ValidationOptions {
|
|
|
98
117
|
}
|
|
99
118
|
/**
|
|
100
119
|
* Creates a Context tag + layer for reading and validating a Cloudflare binding.
|
|
120
|
+
*
|
|
121
|
+
* The Context key is namespaced as `effect-cf/Binding/<id>`; `id` stays the
|
|
122
|
+
* bare user-supplied identifier.
|
|
101
123
|
*/
|
|
102
|
-
interface BindingService<Self, Id extends string, Service> extends Context.ServiceClass<Self, Id
|
|
103
|
-
readonly [TypeId]:
|
|
124
|
+
interface BindingService<Self, Id extends string, Service> extends Context.ServiceClass<Self, `effect-cf/Binding/${Id}`, Service> {
|
|
125
|
+
readonly [TypeId]: TypeId;
|
|
126
|
+
readonly id: Id;
|
|
104
127
|
readonly binding: string;
|
|
105
128
|
readonly layer: Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
106
129
|
}
|
|
107
|
-
declare
|
|
108
|
-
declare
|
|
130
|
+
declare function layer$1<Self, Resource>(tag: Context.Service<Self, Resource>, binding: string, isResource: (value: unknown) => value is Resource, wrap?: undefined, options?: ValidationOptions): Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
131
|
+
declare function layer$1<Self, Resource, Service>(tag: Context.Service<Self, Service>, binding: string, isResource: (value: unknown) => value is Resource, wrap: (resource: Resource) => Service, options?: ValidationOptions): Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
132
|
+
declare const Service: <Self>() => {
|
|
133
|
+
<Id extends string, Resource>(id: Id, binding: string, isResource: (value: unknown) => value is Resource, wrap?: undefined, options?: ValidationOptions): BindingService<Self, Id, Resource>;
|
|
134
|
+
<Id extends string, Resource, Service>(id: Id, binding: string, isResource: (value: unknown) => value is Resource, wrap: (resource: Resource) => Service, options?: ValidationOptions): BindingService<Self, Id, Service>;
|
|
135
|
+
};
|
|
109
136
|
declare namespace Hyperdrive_d_exports {
|
|
110
137
|
export { HyperdriveClient, HyperdriveDefinition, HyperdriveService, LayerOptions, Tag, TagClass, isHyperdrive, layer, make, makeClient };
|
|
111
138
|
}
|
|
@@ -116,7 +143,7 @@ interface HyperdriveDefinition {
|
|
|
116
143
|
}
|
|
117
144
|
interface HyperdriveClient {
|
|
118
145
|
readonly connectionString: string;
|
|
119
|
-
readonly
|
|
146
|
+
readonly rawUnsafe: Effect.Effect<Hyperdrive>;
|
|
120
147
|
readonly definition: HyperdriveDefinition;
|
|
121
148
|
}
|
|
122
149
|
declare const HyperdriveServiceTypeId: unique symbol;
|
|
@@ -139,4 +166,4 @@ declare const layer: <Self>(tag: Context.Service<Self, HyperdriveClient>, defini
|
|
|
139
166
|
declare const make: <Id extends string>(id: Id) => TagClass<HyperdriveService<Id>, Id>;
|
|
140
167
|
declare const Tag: <Self>() => <Id extends string>(id: Id) => TagClass<Self, Id>;
|
|
141
168
|
//#endregion
|
|
142
|
-
export { BindingService as a,
|
|
169
|
+
export { BindingService as a, Environment_d_exports as c, WorkerEnvironment as d, BindingNotFoundError as i, WorkerConfig as l, LayerOptions as n, BindingValidationError as o, TagClass as r, Binding_d_exports as s, Hyperdrive_d_exports as t, WorkerEnv as u };
|
package/dist/HyperdrivePg.d.mts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import { i as BindingNotFoundError, n as LayerOptions, o as BindingValidationError, r as TagClass
|
|
1
|
+
import { d as WorkerEnvironment, i as BindingNotFoundError, n as LayerOptions, o as BindingValidationError, r as TagClass } from "./Hyperdrive-COyg7R26.mjs";
|
|
2
2
|
import { Layer } from "effect";
|
|
3
3
|
import { PgClient } from "@effect/sql-pg";
|
|
4
|
+
import { SqlClient, SqlError } from "effect/unstable/sql";
|
|
4
5
|
//#region src/HyperdrivePg.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/** Hyperdrive owns database pooling, so app-side pool and connection options are not exposed. */
|
|
7
|
+
type PgLayerOptions = Omit<Parameters<typeof PgClient.makeClient>[0], "url" | "host" | "port" | "path" | "ssl" | "database" | "username" | "password" | "stream">;
|
|
8
|
+
/**
|
|
9
|
+
* Provides `PgClient` and `SqlClient` backed by a Hyperdrive binding.
|
|
10
|
+
*
|
|
11
|
+
* Note: since Effect `4.0.0-beta.99`, `PgClient.makeClient` connects eagerly,
|
|
12
|
+
* so the TCP connection to Hyperdrive is opened when this layer is built.
|
|
13
|
+
* In per-request Workers runtimes, build the layer within the request
|
|
14
|
+
* lifecycle rather than sharing it across requests.
|
|
15
|
+
*/
|
|
16
|
+
declare const layer: <Self, Id extends string>(tag: TagClass<Self, Id>, binding: LayerOptions, options?: PgLayerOptions) => Layer.Layer<PgClient.PgClient | SqlClient.SqlClient, BindingNotFoundError | BindingValidationError | SqlError.SqlError, WorkerEnvironment>;
|
|
9
17
|
//#endregion
|
|
10
18
|
export { PgLayerOptions, layer };
|
package/dist/HyperdrivePg.mjs
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { Effect, Layer, Redacted } from "effect";
|
|
2
2
|
import { PgClient } from "@effect/sql-pg";
|
|
3
3
|
//#region src/HyperdrivePg.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Provides `PgClient` and `SqlClient` backed by a Hyperdrive binding.
|
|
6
|
+
*
|
|
7
|
+
* Note: since Effect `4.0.0-beta.99`, `PgClient.makeClient` connects eagerly,
|
|
8
|
+
* so the TCP connection to Hyperdrive is opened when this layer is built.
|
|
9
|
+
* In per-request Workers runtimes, build the layer within the request
|
|
10
|
+
* lifecycle rather than sharing it across requests.
|
|
11
|
+
*/
|
|
12
|
+
const layer = (tag, binding, options) => PgClient.layerFrom(Effect.flatMap(tag, (hyperdrive) => PgClient.makeClient({
|
|
13
|
+
...options,
|
|
14
|
+
url: Redacted.make(hyperdrive.connectionString)
|
|
15
|
+
}))).pipe(Layer.provide(tag.layer(binding)));
|
|
11
16
|
//#endregion
|
|
12
17
|
export { layer };
|