effect-cf 0.18.0 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,27 +36,26 @@
36
36
  "dev": "vp pack --watch",
37
37
  "test": "vp test",
38
38
  "check": "vp check",
39
- "prepublishOnly": "vp run build"
39
+ "typecheck": "tsc --noEmit"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@cloudflare/containers": "catalog:",
43
43
  "@cloudflare/vitest-pool-workers": "catalog:",
44
44
  "@cloudflare/workers-types": "catalog:",
45
- "@effect/platform-node": "4.0.0-beta.77",
45
+ "@effect/platform-node": "4.0.0-beta.105",
46
46
  "@effect/sql-d1": "catalog:",
47
47
  "@effect/sql-pg": "catalog:",
48
48
  "@effect/sql-sqlite-do": "catalog:",
49
49
  "@effect/vitest": "catalog:",
50
50
  "effect": "catalog:",
51
- "typescript": "^6.0.2",
52
- "vite-plus": "0.1.20",
51
+ "vite-plus": "catalog:",
53
52
  "vitest": "catalog:"
54
53
  },
55
54
  "peerDependencies": {
56
- "@effect/sql-d1": "^4.0.0-beta.77",
57
- "@effect/sql-pg": "^4.0.0-beta.77",
58
- "@effect/sql-sqlite-do": "^4.0.0-beta.77",
59
- "effect": "^4.0.0-beta.77"
55
+ "@effect/sql-d1": "^4.0.0-beta.105",
56
+ "@effect/sql-pg": "^4.0.0-beta.105",
57
+ "@effect/sql-sqlite-do": "^4.0.0-beta.105",
58
+ "effect": "^4.0.0-beta.105"
60
59
  },
61
60
  "peerDependenciesMeta": {
62
61
  "@effect/sql-pg": {
package/src/AiGateway.ts CHANGED
@@ -113,6 +113,7 @@ const tryAiGatewaySync = <A>(
113
113
  const providerUrl = (baseUrl: string, path = "") => {
114
114
  const url = new URL(baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
115
115
  const normalizedPath = path.replace(/^\/+/, "");
116
+
116
117
  return normalizedPath === "" ? url : new URL(normalizedPath, url);
117
118
  };
118
119
 
@@ -141,6 +142,7 @@ export const makeClient = (definition: AiGatewayDefinition, gateway: AiGatewayBi
141
142
  const baseUrl = yield* tryAiGatewayPromise(definition.binding, "getUrl", () =>
142
143
  gateway.getUrl(options.provider),
143
144
  );
145
+
144
146
  return yield* tryAiGatewayPromise(definition.binding, "fetch", () =>
145
147
  fetch(providerUrl(baseUrl, options.path).href, options.init),
146
148
  );
@@ -244,6 +246,7 @@ export const makeHttpClient = (
244
246
  getLog: (logId) =>
245
247
  tryAiGatewayPromise(binding, "getLog", async () => {
246
248
  const response = await request(providerUrl(gatewayUrl(definition), `logs/${logId}`).href);
249
+
247
250
  return (await response.json()) as AiGatewayLog;
248
251
  }),
249
252
  unsafeRaw: Effect.fail(
@@ -3,13 +3,13 @@ import type {
3
3
  AnalyticsEngineDataset as CloudflareAnalyticsEngineDataset,
4
4
  } from "@cloudflare/workers-types";
5
5
  import {
6
+ type Redacted,
6
7
  Config,
7
8
  Context,
8
9
  Data,
9
10
  Effect,
10
11
  Layer,
11
12
  Option,
12
- Redacted,
13
13
  Result,
14
14
  Schema as S,
15
15
  } from "effect";
@@ -558,7 +558,9 @@ const writeChunks = (
558
558
  const queryApiUrl = (definition: AnalyticsEngineQueryDefinition) => {
559
559
  const baseUrl = new URL(definition.apiBaseUrl ?? defaultQueryApiBaseUrl);
560
560
  const pathname = baseUrl.pathname.replace(/\/+$/, "");
561
+
561
562
  baseUrl.pathname = `${pathname}/accounts/${definition.accountId}/analytics_engine/sql`;
563
+
562
564
  return baseUrl.href;
563
565
  };
564
566
 
@@ -613,6 +615,7 @@ const executeQueryRequest = (
613
615
 
614
616
  if (response.status < 200 || response.status >= 300) {
615
617
  const body = yield* responseText(definition, response, "queryErrorBody");
618
+
616
619
  return yield* Effect.fail(
617
620
  analyticsEngineQueryError(
618
621
  definition,
@@ -647,6 +650,7 @@ const makeQueryClientWith = (
647
650
  ),
648
651
  ),
649
652
  );
653
+
650
654
  return yield* decodeQueryResponse(json);
651
655
  });
652
656
  const queryResult = <Row>(
@@ -783,6 +787,7 @@ export const queryLayerConfig = <Self>(
783
787
  tag,
784
788
  Effect.gen(function* () {
785
789
  const definition = yield* config;
790
+
786
791
  return yield* makeQueryClient(definition);
787
792
  }),
788
793
  );
package/src/Binding.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Context, Data, Effect, Layer } from "effect";
2
2
 
3
- import { WorkerEnvironment } from "./Environment";
4
- import type { WorkerEnv } from "./Environment";
3
+ import { WorkerEnvironment, type WorkerEnv } from "./Environment";
5
4
 
6
5
  /** Internal type id marker used by binding helper services. */
7
6
  export const TypeId = "effect-cf/Binding" as const;
@@ -121,6 +120,7 @@ const getBinding = <Resource>(
121
120
  Effect.gen(function* () {
122
121
  if (!isPropertyTarget(env)) {
123
122
  const actual = describeActual(env);
123
+
124
124
  return yield* Effect.fail(
125
125
  new BindingValidationError({
126
126
  binding,
@@ -145,6 +145,7 @@ const getBinding = <Resource>(
145
145
  if (!isResource(resource)) {
146
146
  const expected = options?.expected ?? defaultExpected;
147
147
  const actual = describeActual(resource);
148
+
148
149
  return yield* Effect.fail(
149
150
  new BindingValidationError({
150
151
  binding,
@@ -187,6 +188,7 @@ export const layer = <Self, Resource, Service = Resource>(
187
188
  Effect.gen(function* () {
188
189
  const env = yield* WorkerEnvironment;
189
190
  const resource = yield* getBinding(env, binding, isResource, options);
191
+
190
192
  return wrap === undefined ? (resource as unknown as Service) : wrap(resource);
191
193
  }),
192
194
  );
@@ -17,11 +17,19 @@ export type Signal = "logs" | "traces" | "metrics";
17
17
  /** OTLP payload serialization used by the Effect OTLP exporters. */
18
18
  export type Serialization = "json" | "protobuf";
19
19
 
20
- /** Resource metadata shared by Worker and Durable Object OTLP layers. */
20
+ /**
21
+ * Resource metadata shared by Worker and Durable Object OTLP layers.
22
+ *
23
+ * Precedence follows Effect's `OtlpResource.fromConfig`: explicit
24
+ * `serviceName`/`serviceVersion` win over matching explicit `attributes`, and
25
+ * explicit attributes win over `OTEL_SERVICE_NAME`, `OTEL_SERVICE_VERSION`, and
26
+ * `OTEL_RESOURCE_ATTRIBUTES`. Omit an option to let operators set it from the
27
+ * environment.
28
+ */
21
29
  export interface ResourceOptions {
22
- /** Explicit service name. OTEL resource environment variables take precedence. */
30
+ /** Explicit service name. Takes precedence over OTEL environment variables. */
23
31
  readonly serviceName?: string;
24
- /** Explicit service version. OTEL resource environment variables take precedence. */
32
+ /** Explicit service version. Takes precedence over OTEL environment variables. */
25
33
  readonly serviceVersion?: string;
26
34
  /** Additional resource attributes attached to exported telemetry. */
27
35
  readonly attributes?: Record<string, unknown>;
@@ -89,11 +97,13 @@ const selectedSignals = (signals: ReadonlyArray<Signal> | undefined): ReadonlySe
89
97
 
90
98
  const withDefinedAttributes = (attributes: Record<string, unknown>): Record<string, unknown> => {
91
99
  const out: Record<string, unknown> = {};
100
+
92
101
  for (const [key, value] of Object.entries(attributes)) {
93
102
  if (value !== undefined) {
94
103
  out[key] = value;
95
104
  }
96
105
  }
106
+
97
107
  return out;
98
108
  };
99
109
 
@@ -114,15 +124,14 @@ const serializationLayer = (serialization: Serialization | undefined) =>
114
124
 
115
125
  type SignalLayer = ReturnType<typeof OtlpLogger.layerFromConfig>;
116
126
 
127
+ /** Merges a non-empty signal layer list; callers handle the empty case. */
117
128
  const mergeSignalLayers = (layers: ReadonlyArray<SignalLayer>): SignalLayer => {
118
- if (layers.length === 0) {
119
- return Layer.empty;
120
- }
121
-
122
129
  let merged = layers[0]!;
130
+
123
131
  for (let index = 1; index < layers.length; index++) {
124
132
  merged = Layer.mergeAll(merged, layers[index]!);
125
133
  }
134
+
126
135
  return merged;
127
136
  };
128
137
 
@@ -164,6 +173,10 @@ const makeLayer = (
164
173
  );
165
174
  }
166
175
 
176
+ if (layers.length === 0) {
177
+ return Layer.empty;
178
+ }
179
+
167
180
  return mergeSignalLayers(layers).pipe(
168
181
  Layer.provide(cloudflareConfigProviderLayer),
169
182
  Layer.provide(serializationLayer(options.serialization)),
@@ -243,6 +243,7 @@ export const makeClient =
243
243
  options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
244
244
  ): ContainerInstanceClient => {
245
245
  const instance = getByName(name, options);
246
+
246
247
  return {
247
248
  unsafeRaw: Effect.flatMap(instance, (client) => client.unsafeRaw),
248
249
  state: Effect.flatMap(instance, (client) => client.state),
@@ -296,6 +297,7 @@ export const Tag =
296
297
  ) =>
297
298
  Effect.gen(function* () {
298
299
  const namespace = yield* tag;
300
+
299
301
  return yield* namespace.getByName(name, options);
300
302
  });
301
303
 
@@ -322,6 +324,7 @@ export const Tag =
322
324
 
323
325
  const unsafeRaw = Effect.fn(function* () {
324
326
  const namespace = yield* tag;
327
+
325
328
  return yield* namespace.unsafeRaw;
326
329
  });
327
330
 
package/src/D1.ts CHANGED
@@ -70,6 +70,7 @@ export const Service =
70
70
  Layer.unwrap(
71
71
  Effect.gen(function* () {
72
72
  const db = yield* tag;
73
+
73
74
  return D1Client.layer({ ...options, db });
74
75
  }),
75
76
  ).pipe(Layer.provide(tag.layer));
@@ -1,6 +1,13 @@
1
1
  import { DurableObject as CloudflareDurableObject } from "cloudflare:workers";
2
- import { ConfigProvider, Effect, Layer, ManagedRuntime, type Context, type Scope } from "effect";
3
- import type { Schema as S } from "effect";
2
+ import {
3
+ ConfigProvider,
4
+ Effect,
5
+ Layer,
6
+ ManagedRuntime,
7
+ type Context,
8
+ type Scope,
9
+ type Schema as S,
10
+ } from "effect";
4
11
 
5
12
  import { NativeRequest } from "./Worker";
6
13
  import { WorkerConfig, WorkerEnvironment, type WorkerEnv } from "./Environment";
@@ -173,6 +180,7 @@ export const make = <
173
180
  this.runtime = ManagedRuntime.make(runtimeLayer);
174
181
 
175
182
  const initialize = options.initialize;
183
+
176
184
  if (initialize !== undefined) {
177
185
  state.waitUntil(this[RunSymbol](initialize, { eventLayer: false }));
178
186
  }
@@ -356,6 +356,7 @@ const toRepeatEveryMillis = (input: Duration.Input | undefined) => {
356
356
  return Effect.try({
357
357
  try: () => {
358
358
  const millis = Duration.toMillis(Duration.fromInputUnsafe(input));
359
+
359
360
  if (!Number.isFinite(millis) || millis <= 0) {
360
361
  throw new Error("Alarm repeatEvery must be a positive finite duration");
361
362
  }
@@ -404,6 +405,7 @@ const toFailureRescheduleMillis = (input: Duration.Input) =>
404
405
  Effect.try({
405
406
  try: () => {
406
407
  const millis = Duration.toMillis(Duration.fromInputUnsafe(input));
408
+
407
409
  if (!Number.isFinite(millis) || millis <= 0) {
408
410
  throw new Error("Alarm failure rescheduleAfter must be a positive finite duration");
409
411
  }
@@ -430,6 +432,7 @@ export const processDue = <R = never, E = never, OnFailureR = never, OnFailureE
430
432
  ) =>
431
433
  Effect.gen(function* () {
432
434
  const durableObjectAlarm = yield* DurableObjectAlarm;
435
+
433
436
  return yield* durableObjectAlarm.processDueAlarms(handle, options);
434
437
  });
435
438
 
@@ -506,6 +509,7 @@ export const define = <const Definitions extends AlarmDefinitions>(definitions:
506
509
  (event) =>
507
510
  Effect.gen(function* () {
508
511
  const definition = definitions[event.tag];
512
+
509
513
  if (definition === undefined) {
510
514
  return;
511
515
  }
@@ -536,6 +540,7 @@ export const define = <const Definitions extends AlarmDefinitions>(definitions:
536
540
  const action = getAlarmDefinitionFailureAction(definitions[failure.tag]);
537
541
  const optionAction =
538
542
  options?.onFailure === undefined ? undefined : yield* options.onFailure(failure);
543
+
539
544
  return action ?? optionAction;
540
545
  }),
541
546
  },
@@ -602,6 +607,7 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
602
607
 
603
608
  if (next === undefined) {
604
609
  yield* state.storage.deleteAlarm();
610
+
605
611
  return;
606
612
  }
607
613
 
@@ -625,7 +631,9 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
625
631
  row.run_at,
626
632
  row.payload,
627
633
  );
634
+
628
635
  yield* cursor.rowsWritten;
636
+
629
637
  return;
630
638
  }
631
639
 
@@ -642,6 +650,7 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
642
650
  row.repeat_every_ms,
643
651
  row.payload,
644
652
  );
653
+
645
654
  yield* cursor.rowsWritten;
646
655
  },
647
656
  );
@@ -660,7 +669,9 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
660
669
  row.run_at,
661
670
  row.payload,
662
671
  );
672
+
663
673
  yield* cursor.rowsWritten;
674
+
664
675
  return;
665
676
  }
666
677
 
@@ -678,11 +689,13 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
678
689
  row.repeat_every_ms,
679
690
  row.payload,
680
691
  );
692
+
681
693
  yield* cursor.rowsWritten;
682
694
  });
683
695
 
684
696
  const cancelAlarm = Effect.fn("DurableObjectAlarm.cancelAlarm")(function* (input: AlarmRef) {
685
697
  const ref = yield* decodeAlarmRef(input);
698
+
686
699
  yield* state.storage.transaction(() =>
687
700
  Effect.gen(function* () {
688
701
  yield* ensureTable(state);
@@ -780,15 +793,18 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
780
793
  : yield* toFailureRescheduleMillis(actionRetryDelay);
781
794
 
782
795
  yield* rescheduleFailedAlarm(row, retryDelay);
796
+
783
797
  return "continue" as const;
784
798
  }
785
799
 
786
800
  if (actionMode === "skip-and-advance-repeat") {
787
801
  yield* acknowledgeAlarm(row);
802
+
788
803
  return "continue" as const;
789
804
  }
790
805
 
791
806
  yield* reconcileAlarm();
807
+
792
808
  return "stop" as const;
793
809
  };
794
810
 
@@ -797,6 +813,7 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
797
813
 
798
814
  if (Exit.isFailure(eventExit)) {
799
815
  const action = yield* handleFailure(row, undefined, eventExit.cause);
816
+
800
817
  if (action === "stop") {
801
818
  return yield* Effect.failCause(eventExit.cause);
802
819
  }
@@ -808,6 +825,7 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
808
825
 
809
826
  if (Exit.isFailure(handleExit)) {
810
827
  const action = yield* handleFailure(row, event, handleExit.cause);
828
+
811
829
  if (action === "stop") {
812
830
  return yield* Effect.failCause(handleExit.cause);
813
831
  }
@@ -819,6 +837,7 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
819
837
  }
820
838
 
821
839
  yield* reconcileAlarm();
840
+
822
841
  return { failed, handled };
823
842
  });
824
843
 
@@ -1,7 +1,6 @@
1
- import { Context, Effect, type Layer } from "effect";
2
- import type { Schema as S } from "effect";
1
+ import { Context, Effect, type Layer, type Schema as S } from "effect";
3
2
 
4
- import * as Binding from "./Binding";
3
+ import type * as Binding from "./Binding";
5
4
  import * as DurableObjectEntrypoint from "./DurableObject";
6
5
  import type { DurableObjectHandler } from "./DurableObject";
7
6
  import * as DurableObjectNamespace from "./DurableObjectNamespace";
@@ -10,6 +9,13 @@ import type * as Rpc from "./Rpc";
10
9
  import * as RpcDefinition from "./RpcDefinition";
11
10
  import type { WorkerEnvironment } from "./Environment";
12
11
 
12
+ /**
13
+ * The client tuple types are re-established by the final `TagClass` cast, so
14
+ * these internal invocations erase the binding client's generic argument
15
+ * tuples instead of instantiating them at `never`.
16
+ */
17
+ type UnsafeInvoke<E> = (...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, E>;
18
+
13
19
  export type ServiceFreeSchema = S.Codec<any, any, never, never>;
14
20
 
15
21
  export interface Method<
@@ -232,6 +238,7 @@ export const Tag =
232
238
  methods: MethodsShape & NoReservedMethods<MethodsShape>,
233
239
  ) => {
234
240
  const definition = makeDefinition<Id, MethodsShape>(id, methods);
241
+
235
242
  type SelfDefinition = Definition<Id, MethodsShape>;
236
243
  type ClientApi = Api<SelfDefinition>;
237
244
  const tag = Context.Service<
@@ -254,16 +261,19 @@ export const Tag =
254
261
  options?: globalThis.DurableObjectNamespaceNewUniqueIdOptions,
255
262
  ) {
256
263
  const namespace = yield* tag;
264
+
257
265
  return yield* namespace.newUniqueId(options);
258
266
  });
259
267
 
260
268
  const idFromName = Effect.fnUntraced(function* (name: string) {
261
269
  const namespace = yield* tag;
270
+
262
271
  return yield* namespace.idFromName(name);
263
272
  });
264
273
 
265
274
  const idFromString = Effect.fnUntraced(function* (value: string) {
266
275
  const namespace = yield* tag;
276
+
267
277
  return yield* namespace.idFromString(value);
268
278
  });
269
279
 
@@ -272,6 +282,7 @@ export const Tag =
272
282
  options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
273
283
  ) {
274
284
  const namespace = yield* tag;
285
+
275
286
  return yield* namespace.get(objectId, options);
276
287
  });
277
288
 
@@ -280,11 +291,13 @@ export const Tag =
280
291
  options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
281
292
  ) {
282
293
  const namespace = yield* tag;
294
+
283
295
  return yield* namespace.getByName(name, options);
284
296
  });
285
297
 
286
298
  const jurisdiction = Effect.fnUntraced(function* (value: globalThis.DurableObjectJurisdiction) {
287
299
  const namespace = yield* tag;
300
+
288
301
  return yield* namespace.jurisdiction(value);
289
302
  });
290
303
 
@@ -295,6 +308,7 @@ export const Tag =
295
308
  ) =>
296
309
  Effect.gen(function* () {
297
310
  const namespace = yield* tag;
311
+
298
312
  return yield* namespace.fetch(stub, input, init);
299
313
  });
300
314
 
@@ -305,7 +319,12 @@ export const Tag =
305
319
  ) =>
306
320
  Effect.gen(function* () {
307
321
  const namespace = yield* tag;
308
- return yield* namespace.rpc(stub, method as never, ...(args as never));
322
+
323
+ return yield* (namespace.rpc as UnsafeInvoke<DurableObjectNamespace.DurableObjectRpcError>)(
324
+ stub,
325
+ method,
326
+ ...args,
327
+ );
309
328
  });
310
329
 
311
330
  const call = <Method extends keyof ClientApi>(
@@ -315,7 +334,10 @@ export const Tag =
315
334
  ) =>
316
335
  Effect.gen(function* () {
317
336
  const namespace = yield* tag;
318
- return yield* namespace.call(stub, method as never, ...(args as never));
337
+
338
+ return yield* (
339
+ namespace.call as UnsafeInvoke<DurableObjectNamespace.DurableObjectRpcError>
340
+ )(stub, method, ...args);
319
341
  });
320
342
 
321
343
  const scopedCall = <Method extends keyof ClientApi>(
@@ -325,11 +347,15 @@ export const Tag =
325
347
  ) =>
326
348
  Effect.gen(function* () {
327
349
  const namespace = yield* tag;
328
- return yield* namespace.scopedCall(stub, method as never, ...(args as never));
350
+
351
+ return yield* (
352
+ namespace.scopedCall as UnsafeInvoke<DurableObjectNamespace.DurableObjectRpcError>
353
+ )(stub, method, ...args);
329
354
  });
330
355
 
331
356
  const unsafeRaw = Effect.fnUntraced(function* () {
332
357
  const namespace = yield* tag;
358
+
333
359
  return yield* namespace.unsafeRaw;
334
360
  });
335
361
 
@@ -374,10 +400,12 @@ const wrapHandlers = <ROut, const Self extends Definition.Any>(
374
400
  RpcDefinition.Definition.MethodNames<Self>
375
401
  >) {
376
402
  const handler = handlers[key];
403
+
377
404
  wrapped[key] = (...args: Array<unknown>) =>
378
405
  Effect.gen(function* () {
379
406
  const decodedArgs = yield* RpcDefinition.decodeArgs(definition, key, args);
380
407
  const value = yield* handler(...decodedArgs);
408
+
381
409
  return yield* RpcDefinition.encodeSuccess(definition, key, value);
382
410
  });
383
411
  }
@@ -1,4 +1,4 @@
1
- import { Context, Data, Effect, type Scope } from "effect";
1
+ import { Data, Effect, type Context, type Scope } from "effect";
2
2
 
3
3
  import * as Binding from "./Binding";
4
4
  import * as CloudflareRpc from "./Rpc";
@@ -511,6 +511,7 @@ export const makeClient = <
511
511
  const methodName = String(method);
512
512
  const result = yield* rpc(stub, method, ...args);
513
513
  const value = yield* CloudflareRpc.scoped(result);
514
+
514
515
  return yield* decodeSuccess<Method>(methodName, value);
515
516
  });
516
517
 
@@ -598,6 +599,7 @@ export const makeDirectMethods = <
598
599
  fetch: (input: RequestInfo | URL, init?: RequestInit) =>
599
600
  Effect.gen(function* () {
600
601
  const stub = yield* getStub();
602
+
601
603
  return yield* helpers.fetch(stub, input, init);
602
604
  }),
603
605
  } as Record<string, unknown>;
@@ -606,6 +608,7 @@ export const makeDirectMethods = <
606
608
  client[methodName] = (...args: Array<unknown>) =>
607
609
  Effect.gen(function* () {
608
610
  const stub = yield* getStub();
611
+
609
612
  return yield* (
610
613
  helpers.call as (
611
614
  stub: DurableObjectStubClient<Api>,
@@ -70,18 +70,23 @@ export const layer = (options: LayerOptions = {}) =>
70
70
 
71
71
  const reserveClientId = (socket: DurableWebSocket) => {
72
72
  const attachment = readAttachment(socket.raw, attachmentKey);
73
+
73
74
  if (attachment !== undefined) {
74
75
  nextClientId = Math.max(nextClientId, attachment + 1);
76
+
75
77
  return attachment;
76
78
  }
77
79
 
78
80
  const id = nextClientId++;
81
+
79
82
  writeAttachment(socket.raw, attachmentKey, id);
83
+
80
84
  return id;
81
85
  };
82
86
 
83
87
  const register = (socket: DurableWebSocket) => {
84
88
  const existing = connectionsBySocket.get(socket.raw);
89
+
85
90
  if (existing !== undefined) {
86
91
  return existing;
87
92
  }
@@ -95,12 +100,14 @@ export const layer = (options: LayerOptions = {}) =>
95
100
  connectionsBySocket.set(socket.raw, connection);
96
101
  connectionsById.set(connection.id, connection);
97
102
  clientIds.add(connection.id);
103
+
98
104
  return connection;
99
105
  };
100
106
 
101
107
  const unregister = (socket: DurableWebSocket) =>
102
108
  Effect.sync(() => {
103
109
  const connection = connectionsBySocket.get(socket.raw);
110
+
104
111
  if (connection === undefined) {
105
112
  return;
106
113
  }
@@ -119,11 +126,13 @@ export const layer = (options: LayerOptions = {}) =>
119
126
  Effect.sync(() => {
120
127
  try {
121
128
  const encoded = connection.parser.encode(response);
129
+
122
130
  if (encoded !== undefined) {
123
131
  connection.socket.raw.send(encoded);
124
132
  }
125
133
  } catch (cause) {
126
134
  const encoded = connection.parser.encode(RpcMessage.ResponseDefectEncoded(cause));
135
+
127
136
  if (encoded !== undefined) {
128
137
  connection.socket.raw.send(encoded);
129
138
  }
@@ -137,11 +146,13 @@ export const layer = (options: LayerOptions = {}) =>
137
146
  disconnects,
138
147
  send: (clientId, response) => {
139
148
  const connection = connectionsById.get(clientId);
149
+
140
150
  return connection === undefined ? Effect.void : send(connection, response);
141
151
  },
142
152
  end: (clientId) =>
143
153
  Effect.sync(() => {
144
154
  const connection = connectionsById.get(clientId);
155
+
145
156
  connection?.socket.raw.close();
146
157
  }),
147
158
  clientIds: Effect.sync(() => clientIds),
@@ -167,8 +178,10 @@ export const layer = (options: LayerOptions = {}) =>
167
178
  });
168
179
 
169
180
  const run = writeRequest;
181
+
170
182
  if (run === undefined) {
171
183
  yield* send(connection, RpcMessage.ResponseDefectEncoded("RPC server is not ready"));
184
+
172
185
  return;
173
186
  }
174
187
 
@@ -178,6 +191,7 @@ export const layer = (options: LayerOptions = {}) =>
178
191
  }).pipe(
179
192
  Effect.catch((error) => {
180
193
  const connection = register(socket);
194
+
181
195
  return send(connection, error);
182
196
  }),
183
197
  ),
@@ -21,6 +21,7 @@ export const layer = (options?: SqliteLayerOptions) =>
21
21
  Layer.unwrap(
22
22
  Effect.gen(function* () {
23
23
  const state = yield* DurableObjectState;
24
+
24
25
  return SqliteClient.layer({ ...options, db: state.raw.storage.sql });
25
26
  }),
26
27
  );
@@ -219,11 +219,13 @@ const schemaBackedSyncKvStorage = <Key, Value, EncodedValue>(
219
219
  Effect.gen(function* () {
220
220
  const encodedKey = yield* encodeKey(key);
221
221
  const encodedValue = yield* encodeValue(value);
222
+
222
223
  yield* tryStorageSync("kv.put", () => kv.put(encodedKey, encodedValue));
223
224
  }),
224
225
  delete: (key) =>
225
226
  Effect.gen(function* () {
226
227
  const encodedKey = yield* encodeKey(key);
228
+
227
229
  return yield* tryStorageSync("kv.delete", () => kv.delete(encodedKey));
228
230
  }),
229
231
  list: (options) =>