effect-cf 0.8.0 → 0.9.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,11 @@
1
1
  # effect-cf
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#25](https://github.com/danieljvdm/effect-cf/pull/25) [`c7daaff`](https://github.com/danieljvdm/effect-cf/commit/c7daaff779934c83519ad9689e1f98dc100b5251) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add a Durable Object `initialize` hook for running Effect setup each time Cloudflare loads a Durable Object instance into memory.
8
+
3
9
  ## 0.8.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -240,6 +240,25 @@ In definition-backed workflows, the `payload` argument is the typed decoded payl
240
240
 
241
241
  ## Durable Object WebSockets
242
242
 
243
+ Use `initialize` for work that should run each time Cloudflare loads a Durable
244
+ Object instance into memory. Yield `state.blockConcurrencyWhile(...)` when
245
+ later events should wait for initialize to finish. If work should happen only once
246
+ for a Durable Object id, store a sentinel in Durable Object storage.
247
+
248
+ ```ts
249
+ export const RoomLive = DurableObject.make(layer, {
250
+ initialize: Effect.gen(function* () {
251
+ const state = yield* DurableObjectState.DurableObjectState;
252
+ yield* state.blockConcurrencyWhile(
253
+ Effect.gen(function* () {
254
+ yield* state.storage.put("loadedAt", Date.now());
255
+ }),
256
+ );
257
+ }),
258
+ fetch,
259
+ });
260
+ ```
261
+
243
262
  Durable Object application sockets should use the hibernation-compatible state API. Accept sockets with `DurableObjectWebSocket.acceptUpgrade(...)`; do not call `server.accept()` or attach native `message` listeners in application code.
244
263
 
245
264
  ```ts
package/dist/index.d.mts CHANGED
@@ -376,7 +376,7 @@ declare const method$3: {
376
376
  <Success extends ServiceFreeSchema$3>(definition: {
377
377
  readonly success: Success;
378
378
  }): Method$4<readonly [], Success>;
379
- <const Args extends ReadonlyArray<ServiceFreeSchema$3>, Success extends ServiceFreeSchema$3>(definition: {
379
+ <const Args extends readonly ServiceFreeSchema$3[], Success extends ServiceFreeSchema$3>(definition: {
380
380
  readonly args: Args;
381
381
  readonly success: Success;
382
382
  }): Method$4<Args, Success>;
@@ -1288,6 +1288,15 @@ type RpcHandlers<ROut, Api> = { readonly [Key in keyof Api as Key extends keyof
1288
1288
  * Options for creating a Durable Object class backed by Effect handlers.
1289
1289
  */
1290
1290
  interface DurableObjectOptions<ROut, Rpc extends DurableObjectRpc<ROut>> {
1291
+ /**
1292
+ * Effect run when Cloudflare loads this Durable Object instance into memory.
1293
+ *
1294
+ * Use `DurableObjectState.blockConcurrencyWhile` inside this hook when
1295
+ * incoming events should wait for setup to finish. Cloudflare may construct
1296
+ * the same Durable Object id again after eviction or restart; use Durable
1297
+ * Object storage if work must happen only once per id.
1298
+ */
1299
+ readonly initialize?: Effect.Effect<void, unknown, HandlerContext<ROut>>;
1291
1300
  /** Optional RPC methods exposed as Durable Object instance methods. */
1292
1301
  readonly rpc?: Rpc;
1293
1302
  /** Optional fetch handler for HTTP/WebSocket requests. */
package/dist/index.mjs CHANGED
@@ -1253,6 +1253,8 @@ const make$4 = (layer, options = {}) => {
1253
1253
  super(state, env);
1254
1254
  const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(DurableObjectState, fromDurableObjectState(state)), Layer.succeed(WorkerEnvironment, env)));
1255
1255
  this.runtime = ManagedRuntime.make(runtimeLayer);
1256
+ const initialize = options.initialize;
1257
+ if (initialize !== void 0) state.waitUntil(this[RunSymbol](initialize));
1256
1258
  }
1257
1259
  [RunSymbol](effect) {
1258
1260
  return this.runtime.runPromise(Effect.scoped(effect));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -73,6 +73,15 @@ export type RpcHandlers<ROut, Api> = {
73
73
  * Options for creating a Durable Object class backed by Effect handlers.
74
74
  */
75
75
  export interface DurableObjectOptions<ROut, Rpc extends DurableObjectRpc<ROut>> {
76
+ /**
77
+ * Effect run when Cloudflare loads this Durable Object instance into memory.
78
+ *
79
+ * Use `DurableObjectState.blockConcurrencyWhile` inside this hook when
80
+ * incoming events should wait for setup to finish. Cloudflare may construct
81
+ * the same Durable Object id again after eviction or restart; use Durable
82
+ * Object storage if work must happen only once per id.
83
+ */
84
+ readonly initialize?: Effect.Effect<void, unknown, HandlerContext<ROut>>;
76
85
  /** Optional RPC methods exposed as Durable Object instance methods. */
77
86
  readonly rpc?: Rpc;
78
87
  /** Optional fetch handler for HTTP/WebSocket requests. */
@@ -137,6 +146,11 @@ export const make = <
137
146
  const runtimeLayer = Entrypoint.provideEntrypointServices(layer, services);
138
147
 
139
148
  this.runtime = ManagedRuntime.make(runtimeLayer);
149
+
150
+ const initialize = options.initialize;
151
+ if (initialize !== undefined) {
152
+ state.waitUntil(this[RunSymbol](initialize));
153
+ }
140
154
  }
141
155
 
142
156
  [RunSymbol]<A, E>(effect: Effect.Effect<A, E, HandlerContext<ROut>>): Promise<A> {