effect-cf 0.2.0 → 0.3.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.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#10](https://github.com/danieljvdm/effect-cf/pull/10) [`a0e3f43`](https://github.com/danieljvdm/effect-cf/commit/a0e3f436df695b8ea3908fbb7813efea099ccd13) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Type Durable Object websocket lifecycle handlers with `DurableWebSocket` instead of raw `WebSocket`, so handlers can use the Effect-native durable socket API without manually wrapping Cloudflare sockets.
8
+
3
9
  ## 0.2.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -144,7 +144,7 @@ Durable Object application sockets should use the hibernation-compatible state A
144
144
 
145
145
  ```ts
146
146
  import { Effect, Schema as S } from "effect";
147
- import { DurableObjectState, DurableObjectWebSocket, Worker } from "effect-cf";
147
+ import { DurableObject, DurableObjectState, DurableObjectWebSocket, Worker } from "effect-cf";
148
148
 
149
149
  const ConnectionAttachment = S.Struct({
150
150
  id: S.String,
@@ -173,6 +173,17 @@ export const fetch = Effect.gen(function* () {
173
173
 
174
174
  `DurableWebSocket` keeps the native socket available as `socket.raw`, while `send`, `close`, `serializeAttachment`, and `deserializeAttachment` return typed `Effect` failures. Use `state.getWebSockets(tag)` to retrieve wrapped sockets for broadcast and rehydration.
175
175
 
176
+ `DurableObject.make` lifecycle handlers receive wrapped sockets automatically:
177
+
178
+ ```ts
179
+ export const RoomLive = DurableObject.make(layer, {
180
+ webSocketMessage: (socket, message) =>
181
+ Effect.gen(function* () {
182
+ yield* socket.send(message);
183
+ }),
184
+ });
185
+ ```
186
+
176
187
  Schema-backed attachments can rehydrate hibernated sockets:
177
188
 
178
189
  ```ts
package/dist/index.d.mts CHANGED
@@ -468,11 +468,11 @@ interface DurableWebSocketHandlers<R = never, E = unknown> {
468
468
  readonly close?: (socket: DurableWebSocket, code: number, reason: string, wasClean: boolean) => Effect.Effect<void, E, R>;
469
469
  readonly error?: (socket: DurableWebSocket, error: unknown) => Effect.Effect<void, E, R>;
470
470
  }
471
- /** Adapts wrapped websocket lifecycle handlers to `DurableObject.make` raw callbacks. */
471
+ /** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
472
472
  declare const handlers: <R = never, E = unknown>(options: DurableWebSocketHandlers<R, E>) => {
473
- webSocketMessage: ((socket: WebSocket, message: string | ArrayBuffer) => Effect.Effect<void, E, R>) | undefined;
474
- webSocketClose: ((socket: WebSocket, code: number, reason: string, wasClean: boolean) => Effect.Effect<void, E, R>) | undefined;
475
- webSocketError: ((socket: WebSocket, error: unknown) => Effect.Effect<void, E, R>) | undefined;
473
+ webSocketMessage: ((socket: DurableWebSocket, message: string | ArrayBuffer) => Effect.Effect<void, E, R>) | undefined;
474
+ webSocketClose: ((socket: DurableWebSocket, code: number, reason: string, wasClean: boolean) => Effect.Effect<void, E, R>) | undefined;
475
+ webSocketError: ((socket: DurableWebSocket, error: unknown) => Effect.Effect<void, E, R>) | undefined;
476
476
  };
477
477
  declare namespace DurableObjectState_d_exports {
478
478
  export { DurableObjectState, DurableObjectStateService, fromDurableObjectState };
@@ -1457,9 +1457,9 @@ interface DurableObjectOptions<ROut, Rpc extends DurableObjectRpc<ROut>> {
1457
1457
  */
1458
1458
  readonly alarms?: Effect.Effect<unknown, unknown, HandlerContext<ROut>>;
1459
1459
  readonly alarm?: (alarmInfo?: globalThis.AlarmInvocationInfo) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
1460
- readonly webSocketMessage?: (socket: WebSocket, message: string | ArrayBuffer) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
1461
- readonly webSocketClose?: (socket: WebSocket, code: number, reason: string, wasClean: boolean) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
1462
- readonly webSocketError?: (socket: WebSocket, error: unknown) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
1460
+ readonly webSocketMessage?: (socket: DurableWebSocket, message: string | ArrayBuffer) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
1461
+ readonly webSocketClose?: (socket: DurableWebSocket, code: number, reason: string, wasClean: boolean) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
1462
+ readonly webSocketError?: (socket: DurableWebSocket, error: unknown) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
1463
1463
  }
1464
1464
  /**
1465
1465
  * Cloudflare `DurableObject` constructor produced by {@link make}.
package/dist/index.mjs CHANGED
@@ -923,11 +923,11 @@ const attachment = (schema) => {
923
923
  schema
924
924
  };
925
925
  };
926
- /** Adapts wrapped websocket lifecycle handlers to `DurableObject.make` raw callbacks. */
926
+ /** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
927
927
  const handlers = (options) => ({
928
- webSocketMessage: options.message === void 0 ? void 0 : (socket, message) => options.message?.(fromWebSocket(socket), message) ?? Effect.void,
929
- webSocketClose: options.close === void 0 ? void 0 : (socket, code, reason, wasClean) => options.close?.(fromWebSocket(socket), code, reason, wasClean) ?? Effect.void,
930
- webSocketError: options.error === void 0 ? void 0 : (socket, error) => options.error?.(fromWebSocket(socket), error) ?? Effect.void
928
+ webSocketMessage: options.message,
929
+ webSocketClose: options.close,
930
+ webSocketError: options.error
931
931
  });
932
932
  //#endregion
933
933
  //#region src/DurableObjectState.ts
@@ -1230,13 +1230,13 @@ const make$4 = (layer, options = {}) => {
1230
1230
  if (rawAlarm !== void 0) return this[RunSymbol](rawAlarm);
1231
1231
  }
1232
1232
  webSocketMessage(socket, message) {
1233
- if (options.webSocketMessage !== void 0) return this[RunSymbol](options.webSocketMessage(socket, message));
1233
+ if (options.webSocketMessage !== void 0) return this[RunSymbol](options.webSocketMessage(fromWebSocket(socket), message));
1234
1234
  }
1235
1235
  webSocketClose(socket, code, reason, wasClean) {
1236
- if (options.webSocketClose !== void 0) return this[RunSymbol](options.webSocketClose(socket, code, reason, wasClean));
1236
+ if (options.webSocketClose !== void 0) return this[RunSymbol](options.webSocketClose(fromWebSocket(socket), code, reason, wasClean));
1237
1237
  }
1238
1238
  webSocketError(socket, error) {
1239
- if (options.webSocketError !== void 0) return this[RunSymbol](options.webSocketError(socket, error));
1239
+ if (options.webSocketError !== void 0) return this[RunSymbol](options.webSocketError(fromWebSocket(socket), error));
1240
1240
  }
1241
1241
  }
1242
1242
  defineEntrypointRpcMethods("Durable Object", EffectDurableObject.prototype, options.rpc, reservedMethodNames, (self, effect) => self[RunSymbol](effect));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -4,6 +4,7 @@ import { Effect, Layer, ManagedRuntime, type Scope } from "effect";
4
4
  import { NativeRequest } from "./Worker";
5
5
  import { WorkerEnvironment, type WorkerEnv } from "./Environment";
6
6
  import { DurableObjectState, fromDurableObjectState } from "./DurableObjectState";
7
+ import { fromWebSocket, type DurableWebSocket } from "./DurableObjectWebSocket";
7
8
  import * as DurableObjectDefinition from "./DurableObjectDefinition";
8
9
  import * as Entrypoint from "./internal/Entrypoint";
9
10
 
@@ -84,17 +85,17 @@ export interface DurableObjectOptions<ROut, Rpc extends DurableObjectRpc<ROut>>
84
85
  alarmInfo?: globalThis.AlarmInvocationInfo,
85
86
  ) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
86
87
  readonly webSocketMessage?: (
87
- socket: WebSocket,
88
+ socket: DurableWebSocket,
88
89
  message: string | ArrayBuffer,
89
90
  ) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
90
91
  readonly webSocketClose?: (
91
- socket: WebSocket,
92
+ socket: DurableWebSocket,
92
93
  code: number,
93
94
  reason: string,
94
95
  wasClean: boolean,
95
96
  ) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
96
97
  readonly webSocketError?: (
97
- socket: WebSocket,
98
+ socket: DurableWebSocket,
98
99
  error: unknown,
99
100
  ) => Effect.Effect<void, unknown, HandlerContext<ROut>>;
100
101
  }
@@ -172,7 +173,7 @@ export const make = <
172
173
 
173
174
  webSocketMessage(socket: WebSocket, message: string | ArrayBuffer): Promise<void> | void {
174
175
  if (options.webSocketMessage !== undefined) {
175
- return this[RunSymbol](options.webSocketMessage(socket, message));
176
+ return this[RunSymbol](options.webSocketMessage(fromWebSocket(socket), message));
176
177
  }
177
178
  }
178
179
 
@@ -183,13 +184,15 @@ export const make = <
183
184
  wasClean: boolean,
184
185
  ): Promise<void> | void {
185
186
  if (options.webSocketClose !== undefined) {
186
- return this[RunSymbol](options.webSocketClose(socket, code, reason, wasClean));
187
+ return this[RunSymbol](
188
+ options.webSocketClose(fromWebSocket(socket), code, reason, wasClean),
189
+ );
187
190
  }
188
191
  }
189
192
 
190
193
  webSocketError(socket: WebSocket, error: unknown): Promise<void> | void {
191
194
  if (options.webSocketError !== undefined) {
192
- return this[RunSymbol](options.webSocketError(socket, error));
195
+ return this[RunSymbol](options.webSocketError(fromWebSocket(socket), error));
193
196
  }
194
197
  }
195
198
  }
@@ -251,21 +251,9 @@ export interface DurableWebSocketHandlers<R = never, E = unknown> {
251
251
  readonly error?: (socket: DurableWebSocket, error: unknown) => Effect.Effect<void, E, R>;
252
252
  }
253
253
 
254
- /** Adapts wrapped websocket lifecycle handlers to `DurableObject.make` raw callbacks. */
254
+ /** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
255
255
  export const handlers = <R = never, E = unknown>(options: DurableWebSocketHandlers<R, E>) => ({
256
- webSocketMessage:
257
- options.message === undefined
258
- ? undefined
259
- : (socket: WebSocket, message: string | ArrayBuffer) =>
260
- options.message?.(fromWebSocket(socket), message) ?? Effect.void,
261
- webSocketClose:
262
- options.close === undefined
263
- ? undefined
264
- : (socket: WebSocket, code: number, reason: string, wasClean: boolean) =>
265
- options.close?.(fromWebSocket(socket), code, reason, wasClean) ?? Effect.void,
266
- webSocketError:
267
- options.error === undefined
268
- ? undefined
269
- : (socket: WebSocket, error: unknown) =>
270
- options.error?.(fromWebSocket(socket), error) ?? Effect.void,
256
+ webSocketMessage: options.message,
257
+ webSocketClose: options.close,
258
+ webSocketError: options.error,
271
259
  });