/// import type { Pipeline } from "cloudflare:pipelines"; import type * as Effect from "effect/Effect"; import type { Redacted } from "effect/Redacted"; import type * as Stream from "effect/Stream"; import type { Output } from "../../Output.ts"; // Aliased so the ambient Cloudflare `Rpc` namespace (from // @cloudflare/workers-types, referenced above) stays reachable for // `Rpc.DurableObjectBranded`. import type { Rpc as AlchemyRpc } from "../../Rpc.ts"; import type { WorkflowLike } from "../Workflows/Workflow.ts"; // NOTE: import the service modules directly rather than `import * as Cloudflare // from "../index.ts"`. Importing the whole Cloudflare barrel here creates a // circular re-export when the barrel does `export * from "./Workers/index.ts"` // (the barrel must enumerate this module, which imports the barrel back), which // collapses inference of the large `providers()` collection to `unknown`. import type * as AI from "../AI/index.ts"; import type * as AnalyticsEngine from "../AnalyticsEngine/index.ts"; import type * as ArtifactsNs from "../Artifacts/index.ts"; import type { Container } from "../Containers/Container.ts"; import type * as D1 from "../D1/index.ts"; import type * as Email from "../Email/index.ts"; import type * as FlagshipNs from "../Flagship/index.ts"; import type * as HyperdriveNs from "../Hyperdrive/index.ts"; import type * as ImagesNs from "../Images/index.ts"; import type * as KV from "../KV/index.ts"; import type * as PipelinesNs from "../Pipelines/index.ts"; import type * as Queues from "../Queues/index.ts"; import type * as R2 from "../R2/index.ts"; import type * as StreamNs from "../Stream/index.ts"; import type { VpcService } from "../VpcService/VpcService.ts"; import type { VpcServiceLookup } from "../VpcService/VpcServiceLookup.ts"; import type { DispatchNamespace as DispatchNamespaceResource } from "../WorkersForPlatforms/DispatchNamespace.ts"; import type { AIBinding } from "./AIBinding.ts"; import type { Assets } from "./Assets.ts"; import type * as WorkerOnlyBinding from "./Binding.ts"; import type { BrowserBinding } from "./BrowserBinding.ts"; import type { DurableObjectLike } from "./DurableObject.ts"; import type { RateLimitBinding } from "./RateLimitBinding.ts"; import type { RpcErrorEnvelope, RpcStreamEnvelope } from "./Rpc.ts"; import type { SecretKeyBinding } from "./SecretKeyBinding.ts"; import type { VersionMetadataBinding } from "./VersionMetadataBinding.ts"; import type { Worker } from "./Worker.ts"; import type { WorkerEntrypointBinding } from "./WorkerEntrypoint.ts"; import type { WorkerLoader as WorkerLoaderResource } from "./WorkerLoader.ts"; export type InferEnv = W extends Effect.Effect ? InferEnv : W extends Worker ? InferEnv> : { [k in keyof W]: GetBindingType; }; export type GetBindingType = // A named-entrypoint service binding (`Cloudflare.WorkerEntrypoint`). // Tested first: the marker *contains* a Worker, so the later Worker // branches must never see it. T extends WorkerEntrypointBinding ? Fetcher : // A Container bound in `env` is a container-backed Durable Object class — // the runtime binding is the class's namespace. Must be tested BEFORE the // generic Effect unwrap: a Container declaration is itself an Effect. T extends Container.Decl ? DurableObjectNamespace : // A Worker-only binding lifted by `.pipe(Alchemy.remote())` — the brand // carries the underlying binding value type; recurse on it. Must also // be tested BEFORE the generic Effect unwrap (its Effect `A` is the // runtime client, not the binding value). T extends WorkerOnlyBinding.BindingEffect ? GetBindingType : // `Worker.URL` (an Effect resolving to a deferred string accessor) needs // no case of its own: the generic Effect unwrap below reduces it to // `string` via the fallthrough. T extends | Output | Effect.Effect ? GetBindingType : T extends FlagshipNs.App ? Flagship : T extends Assets ? Service : T extends AlchemyRpc ? RpcWireShape & Service : T extends D1.Database ? D1Database : T extends R2.Bucket ? R2Bucket : T extends KV.Namespace ? KVNamespace : T extends DispatchNamespaceResource ? DispatchNamespace : T extends Queues.Queue ? Queue : T extends AI.Gateway ? Ai : T extends AIBinding ? Ai : T extends AI.Search ? AiSearchInstance : T extends AI.SearchNamespace ? AiSearchNamespace : T extends Email.SendEmail ? SendEmail : T extends AnalyticsEngine.Dataset ? AnalyticsEngineDataset : T extends ArtifactsNs.Namespace ? Artifacts : T extends RateLimitBinding ? RateLimit : T extends SecretKeyBinding ? CryptoKey : T extends ImagesNs.ImagesBinding ? ImagesBinding : T extends BrowserBinding ? BrowserRun : // The ambient global `StreamBinding` from // @cloudflare/workers-types (the alchemy binding value // type of the same name is only reachable as // `StreamNs.StreamBinding`). T extends StreamNs.StreamBinding ? StreamBinding : T extends HyperdriveNs.Connection ? Hyperdrive : T extends VersionMetadataBinding ? WorkerVersionMetadata : T extends WorkerLoaderResource ? WorkerLoader : T extends WorkflowLike< infer Params > ? Workflow : T extends DurableObjectLike ? DurableObjectNamespace< Exclude< T["Shape"], undefined > > : T extends | VpcService | VpcServiceLookup ? Fetcher : T extends | PipelinesNs.Stream | PipelinesNs.LegacyPipeline ? Pipeline : T extends Redacted ? // redacteds are always stored as secret_text, so are always string // we JSON.stringify when not a Redacted string : T; /** * Cloudflare service-binding wire shape for an Effect-native Worker. * * Effect/Stream return values are encoded as envelopes on the wire (see * `RpcErrorEnvelope`, `RpcStreamEnvelope`), so the mapped types reflect what * the raw binding actually resolves to. `fetch` is dropped from the user * shape and re-introduced via `Service` so callers get the standard * `(input, init?) => Promise` signature. * * Use {@link toRpcAsync} to wrap a binding into a Promise-flavored view * where envelopes are decoded for you. */ export type RpcWireShape = { [K in keyof Shape as K extends "fetch" ? never : K]: Shape[K] extends ( ...args: infer A ) => Effect.Effect ? (...args: A) => Promise : Shape[K] extends (...args: infer A) => Stream.Stream ? (...args: A) => Promise : Shape[K] extends Effect.Effect ? Promise : Shape[K] extends Stream.Stream ? Promise : Shape[K] extends (...args: infer A) => infer R ? (...args: A) => Promise> : Promise; };