effect-cf 0.41.0 → 0.41.1

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.
@@ -6,6 +6,7 @@ import * as S from "effect/Schema";
6
6
  import type { Layer } from "effect";
7
7
 
8
8
  import * as Binding from "./Binding";
9
+ import * as RpcTargets from "./RpcTargets";
9
10
  import type { WorkerEnvironment } from "./Environment";
10
11
  import * as ErrorMessage from "./internal/ErrorMessage";
11
12
 
@@ -231,6 +232,7 @@ const tryContainerPromise = <A>(
231
232
  instance: string,
232
233
  operation: string,
233
234
  evaluate: () => Promise<A>,
235
+ target: ContainerStub,
234
236
  ): Effect.Effect<A, ContainerOperationError> =>
235
237
  Effect.tryPromise({
236
238
  try: evaluate,
@@ -241,13 +243,15 @@ const tryContainerPromise = <A>(
241
243
  operation,
242
244
  cause,
243
245
  }),
244
- });
246
+ }).pipe(Effect.tapCause(() => RpcTargets.invalidate(target)));
245
247
 
246
248
  const makeInstanceClient = <Stub extends ContainerStub>(
247
249
  definition: ContainerNamespaceDefinition,
248
250
  instance: string,
249
251
  stub: Stub,
250
252
  ): ContainerInstanceClient<Stub> => {
253
+ const attempt = <A>(operation: string, evaluate: () => Promise<A>) =>
254
+ tryContainerPromise(definition, instance, operation, evaluate, stub);
251
255
  const spanOptions = (operation: string) => ({
252
256
  attributes: { binding: definition.binding, instance, operation },
253
257
  });
@@ -256,9 +260,7 @@ const makeInstanceClient = <Stub extends ContainerStub>(
256
260
  `ContainerNamespace.${operation}`,
257
261
  spanOptions(operation),
258
262
  )(function* (hosts: ReadonlyArray<string>) {
259
- return yield* tryContainerPromise(definition, instance, operation, () =>
260
- stub[operation]([...hosts]),
261
- );
263
+ return yield* attempt(operation, () => stub[operation]([...hosts]));
262
264
  });
263
265
  const hostnameOperation = (
264
266
  operation: "allowHost" | "denyHost" | "removeAllowedHost" | "removeDeniedHost",
@@ -267,14 +269,12 @@ const makeInstanceClient = <Stub extends ContainerStub>(
267
269
  `ContainerNamespace.${operation}`,
268
270
  spanOptions(operation),
269
271
  )(function* (hostname: string) {
270
- return yield* tryContainerPromise(definition, instance, operation, () =>
271
- stub[operation](hostname),
272
- );
272
+ return yield* attempt(operation, () => stub[operation](hostname));
273
273
  });
274
274
 
275
275
  return {
276
276
  rawUnsafe: Effect.succeed(stub),
277
- state: tryContainerPromise(definition, instance, "state", () => stub.getState()).pipe(
277
+ state: attempt("state", () => stub.getState()).pipe(
278
278
  Effect.flatMap(S.decodeUnknownEffect(ContainerState)),
279
279
  Effect.mapError((cause) =>
280
280
  cause instanceof ContainerOperationError
@@ -292,41 +292,33 @@ const makeInstanceClient = <Stub extends ContainerStub>(
292
292
  "ContainerNamespace.fetch",
293
293
  spanOptions("fetch"),
294
294
  )(function* (input: RequestInfo | URL, init?: RequestInit) {
295
- return yield* tryContainerPromise(definition, instance, "fetch", () =>
296
- stub.fetch(input, init),
297
- );
295
+ return yield* attempt("fetch", () => stub.fetch(input, init));
298
296
  }),
299
297
  start: Effect.fn(
300
298
  "ContainerNamespace.start",
301
299
  spanOptions("start"),
302
300
  )(function* (options?: ContainerStartOptions, waitOptions?: ContainerWaitOptions) {
303
- return yield* tryContainerPromise(definition, instance, "start", () =>
304
- stub.start(options, waitOptions),
305
- );
301
+ return yield* attempt("start", () => stub.start(options, waitOptions));
306
302
  }),
307
303
  startAndWaitForPorts: Effect.fn(
308
304
  "ContainerNamespace.startAndWaitForPorts",
309
305
  spanOptions("startAndWaitForPorts"),
310
306
  )(function* (options?: ContainerStartAndWaitForPortsOptions) {
311
- return yield* tryContainerPromise(definition, instance, "startAndWaitForPorts", () =>
312
- stub.startAndWaitForPorts(options),
313
- );
307
+ return yield* attempt("startAndWaitForPorts", () => stub.startAndWaitForPorts(options));
314
308
  }),
315
309
  waitForPort: Effect.fn(
316
310
  "ContainerNamespace.waitForPort",
317
311
  spanOptions("waitForPort"),
318
312
  )(function* (options: ContainerWaitOptions) {
319
- return yield* tryContainerPromise(definition, instance, "waitForPort", () =>
320
- stub.waitForPort(options),
321
- );
313
+ return yield* attempt("waitForPort", () => stub.waitForPort(options));
322
314
  }),
323
315
  stop: Effect.fn(
324
316
  "ContainerNamespace.stop",
325
317
  spanOptions("stop"),
326
318
  )(function* (signal?: ContainerStopSignal) {
327
- return yield* tryContainerPromise(definition, instance, "stop", () => stub.stop(signal));
319
+ return yield* attempt("stop", () => stub.stop(signal));
328
320
  }),
329
- destroy: tryContainerPromise(definition, instance, "destroy", () => stub.destroy()).pipe(
321
+ destroy: attempt("destroy", () => stub.destroy()).pipe(
330
322
  Effect.withSpan("ContainerNamespace.destroy", spanOptions("destroy")),
331
323
  ),
332
324
  setAllowedHosts: hostListOperation("setAllowedHosts"),
@@ -352,23 +344,24 @@ export const makeClient =
352
344
  name: string,
353
345
  options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
354
346
  ) =>
355
- Effect.try({
356
- try: () =>
357
- makeInstanceClient(
358
- definition,
359
- name,
360
- // SAFETY: getByName has a single call signature, so its return type is
361
- // exactly the namespace's stub type.
362
- namespace.getByName(name, options) as ContainerStubOf<Namespace>,
363
- ),
364
- catch: (cause) =>
365
- new ContainerOperationError({
366
- binding: definition.binding,
367
- instance: name,
368
- operation: "getByName",
369
- cause,
370
- }),
371
- });
347
+ RpcTargets.get(
348
+ namespace,
349
+ JSON.stringify(["container", name, options]),
350
+ () =>
351
+ // SAFETY: getByName returns the namespace's declared native stub type.
352
+ namespace.getByName(name, options) as ContainerStubOf<Namespace>,
353
+ ).pipe(
354
+ Effect.map((stub) => makeInstanceClient(definition, name, stub)),
355
+ Effect.mapError(
356
+ (error) =>
357
+ new ContainerOperationError({
358
+ binding: definition.binding,
359
+ instance: name,
360
+ operation: "getByName",
361
+ cause: error.cause,
362
+ }),
363
+ ),
364
+ );
372
365
 
373
366
  const byName = (
374
367
  name: string,
package/src/RpcTargets.ts CHANGED
@@ -1,21 +1,15 @@
1
- import * as Context from "effect/Context";
2
1
  import * as Effect from "effect/Effect";
3
2
  import * as Data from "effect/Data";
4
3
  import type * as Scope from "effect/Scope";
5
4
  import * as Option from "effect/Option";
6
5
 
6
+ import { CurrentTargets, type Targets } from "./internal/RpcTargets";
7
+
7
8
  /** A native RPC target could not be constructed. */
8
9
  export class RpcTargetError extends Data.TaggedError("RpcTargetError")<{
9
10
  readonly cause: unknown;
10
11
  }> {}
11
12
 
12
- interface Targets {
13
- get<A extends object, Owner extends object>(owner: Owner, address: string, create: () => A): A;
14
- invalidate<Target extends object>(target: Target): void;
15
- }
16
-
17
- class CurrentTargets extends Context.Service<CurrentTargets, Targets>()("effect-cf/RpcTargets") {}
18
-
19
13
  /**
20
14
  * Reuse a native RPC target within the current invocation. Native Durable Object
21
15
  * stubs capture the calling request's channel when created. Recreating a stub