effect-cf 0.5.0 → 0.7.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,19 @@
1
1
  # effect-cf
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#20](https://github.com/danieljvdm/effect-cf/pull/20) [`f57a59c`](https://github.com/danieljvdm/effect-cf/commit/f57a59c14d317438348b36ac0341dc921fe72be2) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Tighten binding APIs around Cloudflare RPC and the single-tag KV model. `rpc` now exposes the raw Cloudflare RPC result, while `call` and `scopedCall` resolve and decode definition-backed success values. Durable Object static direct helpers now keep the namespace layer requirement in their effect environment, and the old concrete `Kv.make` / `Kv.Service` constructors have been removed in favor of `Kv.Tag(...).layer({ binding })`.
8
+
9
+ - [#19](https://github.com/danieljvdm/effect-cf/pull/19) [`37b4883`](https://github.com/danieljvdm/effect-cf/commit/37b4883de9790df151ddbb16f2fd432b2d4348b5) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Replace separate binding classes with a single exported tag class API for Queues, Workflows, KV namespaces, Worker service bindings, and Durable Object namespaces. These tags now expose `layer({ binding })` directly, consumers use `const service = yield* Service`, and the old definition `.Binding(...)` / `.binding(...)` / `.Namespace(...)` / `.namespace(...)` helpers have been removed.
10
+
11
+ ## 0.6.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [#16](https://github.com/danieljvdm/effect-cf/pull/16) [`8195f35`](https://github.com/danieljvdm/effect-cf/commit/8195f356537bd8a063ddebe30f61d0028ddccba1) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Provide Effect-native clients when yielding Queue, KV, Worker service, and Durable Object namespace binding tags, while keeping existing static helpers compatible.
16
+
3
17
  ## 0.5.0
4
18
 
5
19
  ### Minor Changes
package/README.md CHANGED
@@ -32,20 +32,19 @@ Runtime creation belongs at Cloudflare entrypoints, not inside binding helpers.
32
32
  - `DurableObjectWebSocket` - WebSocket upgrade helpers for Durable Objects
33
33
  - `Kv` - typed KV namespace helper
34
34
  - `D1` - typed D1 database binding helper with an `@effect/sql-d1` backed SQL layer
35
- - `Queue` / `QueueBinding` - typed Queue producer bindings and consumer handlers
36
- - `Workflow` / `WorkflowBinding` - typed Workflow entrypoints, steps, and starter bindings
35
+ - `Queue` - typed Queue producer/consumer tags plus client and error types
36
+ - `Workflow` - typed Workflow entrypoints, steps, starter clients, and instance types
37
37
  - `Rpc` - Cloudflare RPC type helpers and scoped disposal utilities
38
38
  - `WorkerConfig` - Effect `Config` helpers backed by Cloudflare `env`
39
39
 
40
40
  ## Worker Example
41
41
 
42
42
  ```ts
43
- import { HttpServerResponse } from "effect";
43
+ import { Effect, Layer } from "effect";
44
+ import { HttpServerResponse } from "effect/unstable/http";
44
45
  import { Worker } from "effect-cf";
45
46
 
46
- export default Worker.make({
47
- fetch: () => HttpServerResponse.text("ok"),
48
- });
47
+ export default Worker.make(Layer.empty, Effect.succeed(HttpServerResponse.text("ok")));
49
48
  ```
50
49
 
51
50
  ## Durable Object Example
@@ -70,27 +69,30 @@ export const CounterDurableObject = Counter.make(Layer.empty, {
70
69
  }),
71
70
  },
72
71
  });
72
+
73
+ export const CounterLayer = Counter.layer({ binding: "COUNTER" });
74
+
75
+ export const readCounter = Effect.gen(function* () {
76
+ const counters = yield* Counter;
77
+ return yield* counters.byName("home").get();
78
+ });
73
79
  ```
74
80
 
75
- Define Wrangler bindings and migrations in the consuming application.
81
+ Define Wrangler bindings and migrations in the consuming application. Durable Object namespace bindings are provided with `YourObject.layer({ binding })`, and consumers use `const namespace = yield* YourObject`.
76
82
 
77
83
  ## Queue Example
78
84
 
79
- Queues use the same definition + binding split as Workers and Durable Objects: define the message contract once, use `.binding(...)` or `.Binding(...)` to produce from any runtime with `WorkerEnvironment`, and use `.make(...)` for the consumer Worker entrypoint.
85
+ Queues define the message contract once. The same class is the producer service tag and the consumer Worker definition: use `YourQueue.layer({ binding })` to provide a Cloudflare producer binding from `WorkerEnvironment`, and use `.make(...)` for the consumer Worker entrypoint.
80
86
 
81
87
  ```ts
82
88
  import { Effect, Layer, Schema as S } from "effect";
83
89
  import { Queue } from "effect-cf";
84
90
 
85
- class AvatarJobs extends Queue.Tag<AvatarJobs>()("AvatarJobs", {
91
+ class AvatarQueue extends Queue.Tag<AvatarQueue>()("AvatarQueue", {
86
92
  message: S.Struct({ userId: S.String, imageKey: S.String }),
87
93
  }) {}
88
94
 
89
- export const AvatarQueue = AvatarJobs.binding("AvatarQueue", {
90
- binding: "AVATAR_QUEUE",
91
- });
92
-
93
- export const AvatarQueueConsumer = AvatarJobs.make(Layer.empty, {
95
+ export const AvatarQueueConsumer = AvatarQueue.make(Layer.empty, {
94
96
  queue: (batch) =>
95
97
  Effect.gen(function* () {
96
98
  for (const message of batch.messages) {
@@ -99,9 +101,17 @@ export const AvatarQueueConsumer = AvatarJobs.make(Layer.empty, {
99
101
  }
100
102
  }),
101
103
  });
104
+
105
+ export const AvatarQueueLayer = AvatarQueue.layer({ binding: "AVATAR_QUEUE" });
106
+
107
+ export const enqueueAvatar = (userId: string, imageKey: string) =>
108
+ Effect.gen(function* () {
109
+ const queue = yield* AvatarQueue;
110
+ yield* queue.send({ userId, imageKey });
111
+ });
102
112
  ```
103
113
 
104
- Producers can use `AvatarQueue.send(...)`, `AvatarQueue.sendBatch(...)`, and `AvatarQueue.metrics` from any Worker, Durable Object, or Workflow layer that provides `WorkerEnvironment`.
114
+ Producers should usually use `const queue = yield* AvatarQueue` and then call `queue.send(...)`, `queue.sendBatch(...)`, or `queue.metrics()`. The static `AvatarQueue.send(...)` helpers remain available for concise one-off calls.
105
115
 
106
116
  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.
107
117
 
@@ -130,12 +140,10 @@ export const ExportWorkflowEntrypoint = ExportWorkflow.make(Layer.empty, {
130
140
  }),
131
141
  });
132
142
 
133
- export const ExportWorkflowBinding = ExportWorkflow.binding("ExportWorkflow", {
134
- binding: "EXPORT_WORKFLOW",
135
- });
143
+ export const ExportWorkflowLayer = ExportWorkflow.layer({ binding: "EXPORT_WORKFLOW" });
136
144
  ```
137
145
 
138
- Use `ExportWorkflowBinding.create(...)`, `createBatch(...)`, and `get(...)` to start and inspect instances.
146
+ Provide `ExportWorkflow.layer({ binding: "EXPORT_WORKFLOW" })`, then use `const workflow = yield* ExportWorkflow` or the static `ExportWorkflow.create(...)`, `createBatch(...)`, and `get(...)` helpers to start and inspect instances.
139
147
 
140
148
  In definition-backed workflows, the `payload` argument is the typed decoded payload and is the source of truth. `Workflow.WorkflowEvent.payload` is also re-provided decoded for convenience; `Workflow.WorkflowEvent.raw.payload` remains the native Cloudflare event payload.
141
149
 
@@ -187,24 +195,23 @@ export const RoomLive = DurableObject.make(layer, {
187
195
 
188
196
  Schema-backed attachments can rehydrate hibernated sockets:
189
197
 
190
- ```ts
191
- const restored =
192
- yield *
193
- Attachments.rehydrate({
194
- tag: "room:general",
195
- onInvalid: "ignore-and-close",
196
- });
198
+ ```text
199
+ const restored = yield* Attachments.rehydrate({
200
+ tag: "room:general",
201
+ onInvalid: "ignore-and-close",
202
+ });
197
203
 
198
204
  for (const { socket, attachment } of restored) {
199
- yield * socket.send(`restored:${attachment.id}`).pipe(Effect.ignore);
205
+ yield* socket.send(`restored:${attachment.id}`).pipe(Effect.ignore);
200
206
  }
201
207
  ```
202
208
 
203
209
  Worker-to-Durable-Object forwarding should stay native so WebSocket upgrade responses are preserved:
204
210
 
205
- ```ts
211
+ ```text
206
212
  if (Worker.isWebSocketUpgrade(request)) {
207
- return yield * ChatRooms.byName(roomId).fetch(request);
213
+ const rooms = yield* ChatRoom;
214
+ return yield* rooms.byName(roomId).fetch(request);
208
215
  }
209
216
  ```
210
217