import * as Effect from "effect/Effect"; import type { Env } from "./config.ts"; import { registryFailure, type RegistryFailure, } from "./installation-errors.ts"; import { registryName } from "./installation-metadata.ts"; import type { InstallationRegistry } from "./installation-registry.ts"; import type { RegistryResult } from "./registry-result.ts"; type RegistryMethods = Pick< InstallationRegistry, | "reserve" | "get" | "getDomain" | "domainReplay" | "startDomain" | "updateDomain" | "list" | "start" | "replay" | "operation" | "active" | "intent" | "update" >; // Derive application types from the server contract, before Wrangler's RPC // transformation adds pipelining and disposal to the transport return values. export type InstallationRegistryClient = { [K in keyof RegistryMethods]: RegistryMethods[K] extends ( ...args: infer Args ) => Promise> ? (...args: Args) => Effect.Effect : never; }; export const installationRegistryStub = ( env: Env, subject: string, ): DurableObjectStub => env.INSTALLATIONS.get(env.INSTALLATIONS.idFromName(registryName(subject))); // Calling a client method only describes the RPC. The response becomes a typed // failure when executed; transport exceptions remain defects. No RPC is retried. function rpc( call: (...args: Args) => Promise>, ) { return (...args: Args) => Effect.promise(() => call(...args)).pipe( Effect.flatMap((result) => result.ok ? Effect.succeed(result.value) : Effect.fail(registryFailure(result.error)), ), ); } export function registryClient( stub: DurableObjectStub, ): InstallationRegistryClient { return { reserve: rpc((...args: Parameters) => stub.reserve(...args), ), get: rpc((...args: Parameters) => stub.get(...args), ), getDomain: rpc((...args: Parameters) => stub.getDomain(...args), ), domainReplay: rpc((...args: Parameters) => stub.domainReplay(...args), ), startDomain: rpc((...args: Parameters) => stub.startDomain(...args), ), updateDomain: rpc((...args: Parameters) => stub.updateDomain(...args), ), list: rpc((...args: Parameters) => stub.list(...args), ), start: rpc((...args: Parameters) => stub.start(...args), ), replay: rpc((...args: Parameters) => stub.replay(...args), ), operation: rpc((...args: Parameters) => stub.operation(...args), ), active: rpc((...args: Parameters) => stub.active(...args), ), intent: rpc((...args: Parameters) => stub.intent(...args), ), update: rpc((...args: Parameters) => stub.update(...args), ), }; } export const installationRegistry = ( env: Env, subject: string, ): InstallationRegistryClient => registryClient(installationRegistryStub(env, subject));