{"version":3,"file":"index.cjs","names":["wsAcceptorCarrier","ClientCryptoKeyLink","serveChannel","httpAcceptorCarrier","combineChannels","serveHost","forwardTo"],"sources":["../../../src/platform/cloudflare/index.ts"],"sourcesContent":["import {\n  ClientCryptoKeyLink,\n  createDurableObjectStorageAdapter,\n  createKVStorageAdapter,\n  type StorageAdapter,\n  type TCreateDurableObjectStorageOptions,\n  type TCreateKVStorageOptions,\n} from \"@nice-code/util\";\nimport type { RuntimeCoordinate } from \"@nice-code/wire\";\nimport {\n  clientCoordinateFromAttachment,\n  createInMemoryTofuVerifyKeyResolver,\n  type ESecurityLevel,\n  type IClientVerifyKeyResolver,\n} from \"@nice-code/wire\";\nimport {\n  cloudflareReliableLog,\n  createSqlReliableLogStore,\n  type ISqlStorage,\n  type ISqlStorageCursor,\n} from \"@nice-code/wire/platform/cloudflare\";\nimport type { ActionDomain } from \"../../ActionDefinition/Domain/ActionDomain\";\nimport type { ActionRuntime } from \"../../ActionRuntime/ActionRuntime\";\nimport type { TActionRuntimeHandler } from \"../../ActionRuntime/ActionRuntime.types\";\nimport {\n  combineChannels,\n  type IActionChannel,\n  type TCombinedAcceptorDomains,\n} from \"../../ActionRuntime/Channel/ActionChannel\";\nimport {\n  type IChannelServer,\n  type IServeConnectionStateOptions,\n  serveChannel,\n} from \"../../ActionRuntime/Channel/serveChannel\";\nimport {\n  type IChannelHostAdapter,\n  serveHost,\n  type TServeHostOptions,\n} from \"../../ActionRuntime/Channel/serveHost\";\nimport {\n  forwardTo,\n  type IFetchHandler,\n  type IForwardContext,\n  type IForwardToOptions,\n} from \"../../ActionRuntime/Gateway/forwardTo\";\nimport type { IAcceptorFrameProtocol } from \"../../ActionRuntime/Handler/PeerLink/Acceptor/ChannelAcceptor\";\nimport type { ConnectionStateStore } from \"../../ActionRuntime/Handler/PeerLink/Acceptor/Hibernation/ConnectionStateStore\";\nimport type {\n  IDuplexAcceptorCarrier,\n  IInboundFrameLimits,\n  TAcceptorCarrier,\n} from \"../../ActionRuntime/Transport/Carrier/AcceptorCarrier.types\";\nimport { wsAcceptorCarrier } from \"../../ActionRuntime/Transport/Carrier/duplex/ws/wsAcceptorCarrier\";\nimport { httpAcceptorCarrier } from \"../../ActionRuntime/Transport/Carrier/exchange/http/httpAcceptorCarrier\";\n\nexport {\n  cloudflareReliableLog,\n  createSqlReliableLogStore,\n  type ISqlStorage,\n  type ISqlStorageCursor,\n};\n\n/**\n * Cloudflare-specific helpers for `@nice-code/action`, imported from `@nice-code/action/platform/cloudflare`.\n * They collapse the Durable Object boilerplate (the `WebSocketPair` upgrade, hibernation attachment wiring,\n * and DO-storage adapter) into one-liners you hand to `serveChannel`. The core library stays\n * platform-agnostic — nothing here is reachable from the main entry.\n *\n * The Workers runtime surface this module needs is declared *structurally* (and the two globals it\n * constructs are declared module-locally below) rather than pulled from `@cloudflare/workers-types`, so the\n * library's own DOM-lib build never clashes with that package's global `Response`/`WebSocket` redefinitions.\n * A real `DurableObjectState` and its hibernatable `WebSocket`s satisfy these shapes.\n */\n\ntype TDurableObjectStorage = TCreateDurableObjectStorageOptions[\"durableObjectStorage\"];\n\n/** The slice of a Durable Object's hibernatable WebSocket these helpers touch. */\nexport interface IDurableObjectWebSocket {\n  send(data: string | ArrayBuffer | Uint8Array): void;\n  serializeAttachment(value: unknown): void;\n  // Mirrors the Workers runtime's `any` return so a typed connection binding round-trips without a cast.\n  deserializeAttachment(): any;\n}\n\n/**\n * The authenticated client coordinate persisted on a hibernatable socket's attachment (review\n * A.5): the supported way to answer \"who is this socket?\" — live and at DO wake — instead of\n * reaching into the attachment's raw shape (`attachment?.binding?.client?.…`), which is the\n * library's private persistence format. `undefined` for a socket with no readable binding (e.g.\n * still mid-handshake, or persisted before the versioned binding schema).\n */\nexport function clientCoordinateFromConnection(\n  ws: IDurableObjectWebSocket,\n): RuntimeCoordinate | undefined {\n  return clientCoordinateFromAttachment(ws.deserializeAttachment());\n}\n\n/** The slice of a Durable Object's `state` (its `ctx`) these helpers touch. */\nexport interface IDurableObjectContext {\n  /** DO storage; `sql` is present on a SQLite-backed class and backs the persisted reliability tier. */\n  storage: TDurableObjectStorage & { sql?: ISqlStorage };\n  getWebSockets(): IDurableObjectWebSocket[];\n  acceptWebSocket(ws: IDurableObjectWebSocket): void;\n  /** Register a runtime-answered keepalive so pings never wake the DO. */\n  setWebSocketAutoResponse(pair: IWebSocketRequestResponsePair): void;\n}\n\n/** An `IChannelServer` whose connections are a Durable Object's hibernatable WebSockets — the type to\n * store the result of `serveChannel(...)` in when serving over {@link durableObjectWsCarrier}. `TApp` is the\n * per-connection app-state type when `connectionState` is used (defaults to `unknown` otherwise). */\nexport type TDurableObjectChannelServer<TApp = unknown> = IChannelServer<\n  IDurableObjectWebSocket,\n  TApp\n>;\n\n// Workers runtime globals, declared module-locally (the runtime provides them at deploy time). Declaring\n// them here keeps them out of the package's global scope, so the DOM lib's `Response`/`WebSocket` stand\n// elsewhere. The `Response` constructor type still returns the DOM `Response` — only its init gains the\n// Workers-only `webSocket` field.\ndeclare const WebSocketPair: {\n  new (): { 0: IDurableObjectWebSocket; 1: IDurableObjectWebSocket };\n};\ndeclare const Response: {\n  new (\n    body: BodyInit | null,\n    init?: {\n      status?: number;\n      statusText?: string;\n      headers?: HeadersInit;\n      webSocket?: IDurableObjectWebSocket;\n    },\n  ): Response;\n};\n/** The keepalive pair shape — just the fields the Workers runtime's `WebSocketRequestResponsePair` exposes. */\ninterface IWebSocketRequestResponsePair {\n  readonly request: string;\n  readonly response: string;\n}\ndeclare const WebSocketRequestResponsePair: {\n  new (request: string, response: string): IWebSocketRequestResponsePair;\n};\n\nexport interface IDurableObjectWsCarrierOptions {\n  /**\n   * Whether each socket runs the secure handshake (default `true`). Pass `false` for a plain WS endpoint —\n   * then `serveChannel` needs no `storage` for this carrier.\n   */\n  secure?: boolean;\n  /**\n   * Sockets this carrier must ignore when it enumerates the DO's connections at wake. A Durable Object\n   * may hold sockets that are not client links — a devtools dev socket, say — and a channel server\n   * must never try to rehydrate a binding for one.\n   */\n  excludeConnection?: (connection: IDurableObjectWebSocket) => boolean;\n  /** Carrier-level frame/rate enforcement before secure handshake and action decoding. */\n  inboundLimits?: IInboundFrameLimits<IDurableObjectWebSocket>;\n}\n\n/**\n * The devtools handle a DO can hand to {@link serveDurableObject} — structurally the wire devtools\n * host (`createNiceDurableObjectDevtools(ctx, …)` from `@nice-code/devtools/server`). Typed\n * structurally so this package gains no runtime dependency on the devtools packages: a production\n * Worker that never imports devtools ships none of it. Devtools rides the wire mux as its own\n * (token-gated, plain-admitted) **protocol** — no separate dev route, no socket bookkeeping:\n * passing the handle registers the protocol beside the app's `protocols` and defaults the server's\n * `wireTap` to the handle's traffic core.\n */\nexport interface IDurableObjectDevtoolsHandle {\n  /**\n   * Whether this handle is live.\n   *\n   * A *disabled* handle — production, or no dev token — is inert but not absent:\n   * `createNiceDurableObjectDevtools` hands one back rather than making every DO write the same\n   * `token ? devtools(…) : undefined` conditional. Its `wireTap` is a no-op (wiring it anyway\n   * would make the wire size every frame to feed a sink) and it carries no protocol. Absent reads\n   * as enabled.\n   */\n  readonly enabled?: boolean;\n  readonly wireTap: import(\"@nice-code/wire\").TWireTapFn;\n  /** The devtools wire acceptor protocol — registered alongside the app's `protocols`. */\n  readonly protocol?: IAcceptorFrameProtocol<IDurableObjectWebSocket>;\n}\n\n/**\n * Build a hibernatable-WebSocket acceptor carrier for a Durable Object in one call — the `send`, the\n * `WebSocketPair` upgrade, and the hibernation attachment hooks all derived from the DO's `ctx`. Hand it\n * straight to `serveChannel`'s `carriers`, and forward the DO's socket events to the returned handle:\n * ```ts\n * const ws = durableObjectWsCarrier(this.ctx);\n * const server = serveChannel(runtime, channel, {\n *   clientEnv,\n *   storage: durableObjectStorage(this.ctx, { keyPrefix: \"ws:\" }),\n *   handlers: [localHandler],\n *   carriers: [ws, httpAcceptorCarrier()],\n * });\n * // webSocketMessage(c, m)  => ws.receive(c, m);\n * // webSocketClose/Error(c) => ws.drop(c);\n * ```\n *\n * The carrier exposes the DO's socket attachment to `serveChannel`, which persists the routing binding\n * there and replays it on wake — and, when `connectionState` is requested, co-stores per-connection app\n * state in the *same* attachment, so both survive eviction without the DO wiring any of it by hand.\n */\nexport function durableObjectWsCarrier(\n  ctx: IDurableObjectContext,\n  options: IDurableObjectWsCarrierOptions = {},\n): IDuplexAcceptorCarrier<IDurableObjectWebSocket> {\n  return wsAcceptorCarrier<IDurableObjectWebSocket>({\n    secure: options.secure,\n    inboundLimits: options.inboundLimits,\n    send: (ws, frame) => ws.send(frame),\n    upgrade: () => {\n      const pair = new WebSocketPair();\n      const client = pair[0];\n      const server = pair[1];\n      // Hibernatable WebSocket — the DO can sleep between messages.\n      ctx.acceptWebSocket(server);\n      return new Response(null, { status: 101, webSocket: client });\n    },\n    // Raw access to each socket's attachment; `serveChannel` owns the composite (binding + app) layout.\n    attachmentStore: {\n      getConnections: () => {\n        const connections = ctx.getWebSockets();\n        const exclude = options.excludeConnection;\n        return exclude == null ? connections : connections.filter((ws) => !exclude(ws));\n      },\n      read: (ws) => ws.deserializeAttachment(),\n      write: (ws, value) => ws.serializeAttachment(value),\n    },\n  });\n}\n\nexport interface IDurableObjectStorageOptions {\n  /** Namespace prefix for every key (e.g. `\"demo-ws:\"`), so several adapters can share one DO storage. */\n  keyPrefix?: string;\n}\n\n/**\n * Wrap a Durable Object's storage as a {@link StorageAdapter} for `serveChannel`'s `storage` — sugar over\n * `createDurableObjectStorageAdapter({ durableObjectStorage: ctx.storage, … })` so a DO needs one import.\n */\nexport function durableObjectStorage(\n  ctx: IDurableObjectContext,\n  options: IDurableObjectStorageOptions = {},\n): StorageAdapter {\n  return createDurableObjectStorageAdapter({\n    durableObjectStorage: ctx.storage,\n    keyPrefix: options.keyPrefix,\n  });\n}\n\n/**\n * Wrap a Cloudflare KV namespace as a {@link StorageAdapter} for an action endpoint's `storage` — sugar\n * over `@nice-code/util`'s `createKVStorageAdapter`, re-exported here so a Worker integrating\n * `@nice-code/action` needs only one import. Back a stateless {@link serveWorker} endpoint's crypto\n * identity + TOFU pins with it.\n */\nexport function kvStorageAdapter(options: TCreateKVStorageOptions): StorageAdapter {\n  return createKVStorageAdapter(options);\n}\n\n/** {@link serveWorker}'s options — the stateless-Worker counterpart of {@link serveDurableObject}. */\nexport interface IServeWorkerOptions<TO_ACCEPTOR extends readonly ActionDomain<any>[]> {\n  /**\n   * Factory for this endpoint's runtime — a factory, not an instance, because the Workers runtime forbids\n   * generating random ids / doing I/O at module scope. `serveWorker` builds it lazily on the first request\n   * and memoizes it for the isolate's life.\n   */\n  runtime: () => ActionRuntime;\n  /** Coordinate of the connecting clients (the offline-return scoring fallback; see `serveChannel`). */\n  clientEnv?: RuntimeCoordinate;\n  /**\n   * Backing store for the crypto identity + TOFU pins — a generic {@link StorageAdapter} the developer\n   * supplies (e.g. {@link kvStorageAdapter} over a KV namespace). Required unless `secure: false`.\n   */\n  storage?: StorageAdapter;\n  /**\n   * Factory for your execution handlers (e.g. the local handler holding the action cases) — a factory, not\n   * an array, for the same reason as {@link runtime}: constructing a handler generates a random id, which\n   * the Workers runtime forbids at module scope. `serveWorker` calls it lazily on the first request.\n   */\n  handlers?: () => TActionRuntimeHandler[];\n  /** Accepted level(s); defaults to negotiating any of none/authenticated/encrypted. */\n  securityLevel?: ESecurityLevel | readonly ESecurityLevel[];\n  /**\n   * Trust policy for a client's verify key. Defaults to **in-memory TOFU** — the right default for a public\n   * endpoint hit by fresh per-page client identities (persisting their pins would only accumulate, and each\n   * key is signature-verified). Pass a storage-backed resolver for cross-isolate pinning.\n   */\n  verifyKeyResolver?: IClientVerifyKeyResolver;\n  /** Whether the exchange runs the secure handshake (default `true`). `false` = a plain endpoint, no storage. */\n  secure?: boolean;\n  /** CORS for the endpoint (default permissive `*`; `false` attaches none). */\n  cors?: Record<string, string> | false;\n  /**\n   * Crypto-identity provisioning. `\"required\"` (default) builds an `identityMode: \"required\"` link and\n   * provisions it once on the first request — fork-safe on an *eventually-consistent* store (Cloudflare KV),\n   * where a transient read miss could otherwise fork a second identity that pinned clients then reject.\n   * `\"lazy\"` defers to the store's own consistency (fine for a strongly-consistent store). Ignored when\n   * `link` is passed (then you own provisioning out-of-band).\n   */\n  identityMode?: \"required\" | \"lazy\";\n  /** Pre-built crypto identity; overrides the storage-derived link (you then `provisionIdentity()` it yourself). */\n  link?: ClientCryptoKeyLink;\n  /** Default per-action timeout for server-initiated actions awaiting a client response. */\n  defaultTimeout?: number;\n  /**\n   * The individual channels this endpoint serves, for **subset selection** — set by {@link serveWorkers} so a\n   * client connecting any subset (advertised as `hello.channels` tags) gets the matching composed dictionary\n   * version. Omit for a single channel (then `channel` is used as-is). When two or more are given, a\n   * connection with no advertised tags falls back to the combined `channel`.\n   */\n  channels?: readonly IActionChannel<any, any>[];\n  /** Internal: the carrier channel this endpoint serves (always one HTTP exchange carrier). */\n  _channelDomains?: TO_ACCEPTOR;\n}\n\n/** The handle {@link serveWorker} returns — forward the Worker's `fetch` to it. */\nexport interface IWorkerChannelServer {\n  /** Forward the Worker's incoming request here. Awaits one-time identity provisioning on the first call. */\n  fetch(request: Request): Promise<Response>;\n  /**\n   * Provision the crypto identity out-of-band (idempotent). Call from a one-time deploy step for a\n   * multi-region deploy; otherwise the first `fetch` provisions lazily for you.\n   */\n  provision(): Promise<void>;\n}\n\n/**\n * Serve a secure channel from a **stateless Worker** in one call — the stateless counterpart of\n * {@link serveDurableObject}. It folds in everything a hand-rolled stateless endpoint repeats: the crypto\n * identity link (with one-time provisioning on an eventually-consistent store), the in-memory TOFU default,\n * the single HTTP-exchange carrier, and the lazy memoization the Workers global scope forces. The whole\n * thing builds on the first request and is reused across the isolate's life:\n * ```ts\n * const serveCreate = serveWorker(bridgeCreateChannel, {\n *   runtime: () => new ActionRuntime(bridgeCreatorCoord),\n *   clientEnv: frontendCoord,\n *   storage: kvStorageAdapter({ kvNamespace: env.KV, keyPrefix: \"bridge-create-identity:\" }),\n *   handlers: () => [bridgeCreateHandler()],\n * });\n * // route it: honoApi.on([\"POST\", \"OPTIONS\"], \"/create/secure\", (c) => serveCreate.fetch(c.req.raw));\n * // or drop into a router: actionRouter().route(\"/create/*\", serveCreate)\n * ```\n *\n * A stateless Worker realistically serves the **HTTP-exchange** path only (no durable sockets) — WebSocket\n * / stateful channels live in a Durable Object (`serveDurableObject`), reached through {@link forwardToDurableObject}.\n *\n * To serve **several channels** on one stateless endpoint, use {@link serveWorkers} (the multi-channel form\n * — the stateless dual of `serveChannels`): it composes the matching dictionary version per connection from\n * the client's advertised subset, so a client connecting just one channel via `connectChannel` is accepted.\n */\nexport function serveWorker<\n  TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\n  TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\n>(\n  channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>,\n  options: IServeWorkerOptions<TO_ACCEPTOR>,\n): IWorkerChannelServer {\n  const identityMode = options.identityMode ?? \"required\";\n  const secure = options.secure ?? true;\n\n  let built: { server: IChannelServer<unknown>; provisioned: Promise<void> } | undefined;\n  const get = (): { server: IChannelServer<unknown>; provisioned: Promise<void> } => {\n    if (built != null) return built;\n\n    const link =\n      secure && options.link == null && options.storage != null\n        ? new ClientCryptoKeyLink({ storageAdapter: options.storage, identityMode })\n        : options.link;\n\n    const server = serveChannel<TO_ACCEPTOR, TO_CONNECTOR, unknown, unknown>(\n      options.runtime(),\n      channel,\n      {\n        clientEnv: options.clientEnv,\n        storage: options.storage,\n        link,\n        verifyKeyResolver:\n          options.verifyKeyResolver ?? (secure ? createInMemoryTofuVerifyKeyResolver() : undefined),\n        securityLevel: options.securityLevel,\n        defaultTimeout: options.defaultTimeout,\n        carriers: [httpAcceptorCarrier({ secure, cors: options.cors })],\n        channels: options.channels,\n        handlers: options.handlers?.(),\n      },\n    );\n\n    // Provision once when we own a `required`-mode link; otherwise nothing to await (lazy init, a caller-\n    // owned link, or a plain endpoint).\n    const provisioned =\n      link != null && options.link == null && identityMode === \"required\"\n        ? link.provisionIdentity()\n        : Promise.resolve();\n\n    built = { server, provisioned };\n    return built;\n  };\n\n  return {\n    async fetch(request: Request): Promise<Response> {\n      const { server, provisioned } = get();\n      await provisioned;\n      return server.fetch(request);\n    },\n    async provision(): Promise<void> {\n      await get().provisioned;\n    },\n  };\n}\n\n/**\n * Serve a **set** of channels from one stateless Worker endpoint — the stateless dual of `serveChannels`\n * and the multi-channel form of {@link serveWorker}. The channels are combined into one (their domains\n * unioned in list order, see {@link combineChannels}) and served over a single HTTP-exchange carrier + one\n * crypto identity; the runtime routes each inbound action to its handler by domain, exactly as for a single\n * channel. Crucially the individual channels are passed through as the **subset registry**, so a client\n * connecting just one of them via `connectChannel` advertises its tag and gets the matching composed\n * dictionary version — without this, a combined endpoint would reject every single-channel client with a\n * dictionary-version mismatch (the trap that forces a per-channel endpoint otherwise).\n * ```ts\n * const serveStatelessApi = serveWorkers([bridgeCreateChannel, walletRegisterChannel], {\n *   runtime: () => new ActionRuntime(backendCoord),\n *   storage: kvStorageAdapter({ kvNamespace: env.KV, keyPrefix: \"stateless-api-identity:\" }),\n *   securityLevel: ESecurityLevel.encrypted,\n *   handlers: () => [bridgeCreateHandler(), walletRegisterHandler()],\n * });\n * // route it: actionRouter().route(\"/api/action/*\", serveStatelessApi)\n * ```\n * Both ends must list the **same channels in the same order** (the `combineChannels` contract) — though each\n * client only connects the subset it uses (one channel via `connectChannel`, several via `connectChannels`).\n * A multi-role endpoint serving clients of several envs should omit `clientEnv` (see `serveChannel`).\n */\nexport function serveWorkers<const CHANNELS extends readonly IActionChannel<any, any>[]>(\n  channels: CHANNELS,\n  options: IServeWorkerOptions<TCombinedAcceptorDomains<CHANNELS>>,\n): IWorkerChannelServer {\n  return serveWorker(\n    combineChannels(channels) as IActionChannel<TCombinedAcceptorDomains<CHANNELS>, any>,\n    { ...options, channels },\n  );\n}\n\nexport interface ICloudflareDurableObjectHostOptions {\n  /** Namespace prefix for the DO-storage crypto identity keys (e.g. `\"lobby-ws:\"`). */\n  keyPrefix?: string;\n  /**\n   * The HTTP fallback that sits beside the WebSocket: `\"plain\"` (default — POSTs the raw action wire, the\n   * usual fallback for a public client), `\"secure\"` (the full handshake-protected exchange, sharing the WS\n   * identity), or `false` (WebSocket only).\n   */\n  httpFallback?: \"plain\" | \"secure\" | false;\n  /** Whether the WebSocket runs the secure handshake (default `true`). `false` = a plain WS endpoint. */\n  secure?: boolean;\n  /**\n   * Prebuilt identity/TOFU storage. Defaults to a tracked adapter over `ctx.storage`; pass an\n   * untracked/prefixed adapter when whole-object deletion owns reclamation or when sharing identity.\n   */\n  storage?: StorageAdapter;\n  /** Carrier-level frame/rate enforcement before secure handshake and action decoding. */\n  inboundLimits?: IInboundFrameLimits<IDurableObjectWebSocket>;\n}\n\n/**\n * Build the {@link IChannelHostAdapter} for a Durable Object in one call — the entire repeated transport\n * stack a DO would otherwise assemble by hand: a hibernatable secure WebSocket carrier, an HTTP fallback,\n * the DO-storage-backed crypto identity, and a runtime-answered `ping`/`pong` keepalive (so pings never\n * wake the DO). Hand it to {@link serveHost}, or use {@link serveDurableObject} which composes both.\n */\nexport function cloudflareDurableObjectHost(\n  ctx: IDurableObjectContext,\n  options: ICloudflareDurableObjectHostOptions = {},\n): IChannelHostAdapter<IDurableObjectWebSocket> {\n  const httpFallback = options.httpFallback ?? \"plain\";\n  const carriers: TAcceptorCarrier<IDurableObjectWebSocket>[] = [\n    // (A devtools dial needs no exclusion here: it is a plain wire connection with no channel\n    // binding, so the hibernation replay skips it naturally.)\n    durableObjectWsCarrier(ctx, {\n      secure: options.secure,\n      inboundLimits: options.inboundLimits,\n    }),\n  ];\n  if (httpFallback !== false) {\n    carriers.push(httpAcceptorCarrier({ secure: httpFallback === \"secure\" }));\n  }\n\n  return {\n    carriers,\n    storage: options.storage ?? durableObjectStorage(ctx, { keyPrefix: options.keyPrefix }),\n    onServed: () => {\n      // Keepalive answered by the runtime itself — pings never wake the DO.\n      ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair(\"ping\", \"pong\"));\n    },\n  };\n}\n\n/** {@link serveDurableObject}'s options: the `serveHost` surface + the DO runtime + the host knobs. */\nexport type TServeDurableObjectOptions<\n  TO_ACCEPTOR extends readonly ActionDomain<any>[],\n  TApp = unknown,\n> = TServeHostOptions<TO_ACCEPTOR, IDurableObjectWebSocket, TApp> &\n  ICloudflareDurableObjectHostOptions & {\n    /** This DO's runtime (e.g. `new ActionRuntime(coord.withPersistentId(ctx.id.toString()))`). */\n    runtime: ActionRuntime;\n    /**\n     * A devtools handle from `createNiceDurableObjectDevtools(ctx, …)`. Passing it wires the whole\n     * observation path: the server's `wireTap` feeds the devtools traffic core (unless the app\n     * brought its own tap), and the handle's devtools **protocol** — token-gated, plain-admitted —\n     * is registered beside the app's `protocols`, so a devtools window dials this DO's ordinary\n     * WebSocket endpoint. Omit it (or pass a disabled handle) and a DO ships no devtools protocol\n     * and no cost — the default.\n     */\n    devtools?: IDurableObjectDevtoolsHandle;\n  };\n\n/**\n * Serve a channel from a Durable Object **with devtools attached**:\n * ```ts\n * const devtools = createNiceDurableObjectDevtools(this.ctx, {\n *   runtime, stage: \"development\", token: env.DEVTOOLS_TOKEN,\n *   realms: { match: () => this.engine },\n * });\n * this.server = serveDurableObject(this.ctx, channel, { runtime, devtools });\n * ```\n * The DO's forwards (`fetch` / `receive` / `drop`) stay exactly as they are — devtools rides the\n * wire mux as its own token-gated protocol on the same sockets. See `createWireDevtoolsHost` for\n * the safety model and the hibernation caveat.\n */\n\n/**\n * Serve a secure channel from a Durable Object in one call — the whole transport stack\n * ({@link cloudflareDurableObjectHost}: hibernatable secure WebSocket + HTTP fallback + DO-storage crypto\n * identity + keepalive) folded in, leaving the DO to forward its four socket lifecycle methods to the\n * returned server's `fetch` / `receive` / `drop`:\n * ```ts\n * const server = serveDurableObject(this.ctx, lobbyChannel, {\n *   runtime, clientEnv,\n *   connectionState: { schema: vs_player }, // optional, survives hibernation\n *   channelCases: { join: (action, conn) => { conn.setState(action.input); conn.broadcast(…); } },\n * });\n * // fetch(req)              => server.fetch(req)\n * // webSocketMessage(ws, m) => server.receive(ws, m)\n * // webSocketClose/Error(ws)=> server.drop(ws)\n * ```\n * Passing `connectionState` narrows the return so `server.connections` is non-optional.\n *\n * To serve **several channels** on one DO endpoint, pass a channel *array* — the DO becomes a multi-channel\n * acceptor and a client connecting any subset (via `connectChannels` / `connectChannel`) gets the matching\n * codec composed per connection:\n * ```ts\n * const server = serveDurableObject(this.ctx, [coreChannel, lobbyChannel], { runtime, clientEnv, handlers });\n * ```\n */\nexport function serveDurableObject<\n  TO_ACCEPTOR extends readonly ActionDomain<any>[],\n  TO_CONNECTOR extends readonly ActionDomain<any>[],\n  TApp,\n>(\n  ctx: IDurableObjectContext,\n  channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>,\n  options: TServeDurableObjectOptions<TO_ACCEPTOR, TApp> & {\n    connectionState: IServeConnectionStateOptions<TApp>;\n  },\n): TDurableObjectChannelServer<TApp> & {\n  connections: ConnectionStateStore<IDurableObjectWebSocket, TApp>;\n};\nexport function serveDurableObject<\n  TO_ACCEPTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\n  TO_CONNECTOR extends readonly ActionDomain<any>[] = readonly ActionDomain<any>[],\n  TApp = unknown,\n>(\n  ctx: IDurableObjectContext,\n  channel: IActionChannel<TO_ACCEPTOR, TO_CONNECTOR>,\n  options: TServeDurableObjectOptions<TO_ACCEPTOR, TApp>,\n): TDurableObjectChannelServer<TApp>;\nexport function serveDurableObject<\n  const CHANNELS extends readonly IActionChannel<any, any>[],\n  TApp,\n>(\n  ctx: IDurableObjectContext,\n  channels: CHANNELS,\n  options: TServeDurableObjectOptions<TCombinedAcceptorDomains<CHANNELS>, TApp> & {\n    connectionState: IServeConnectionStateOptions<TApp>;\n  },\n): TDurableObjectChannelServer<TApp> & {\n  connections: ConnectionStateStore<IDurableObjectWebSocket, TApp>;\n};\nexport function serveDurableObject<\n  const CHANNELS extends readonly IActionChannel<any, any>[],\n  TApp = unknown,\n>(\n  ctx: IDurableObjectContext,\n  channels: CHANNELS,\n  options: TServeDurableObjectOptions<TCombinedAcceptorDomains<CHANNELS>, TApp>,\n): TDurableObjectChannelServer<TApp>;\nexport function serveDurableObject(\n  ctx: IDurableObjectContext,\n  channelOrChannels:\n    | IActionChannel<readonly ActionDomain<any>[], readonly ActionDomain<any>[]>\n    | readonly IActionChannel<any, any>[],\n  options: TServeDurableObjectOptions<readonly ActionDomain<any>[], any>,\n): TDurableObjectChannelServer<any> {\n  const {\n    runtime,\n    keyPrefix,\n    httpFallback,\n    secure,\n    storage,\n    inboundLimits,\n    devtools,\n    ...serveOptions\n  } = options;\n  const host = cloudflareDurableObjectHost(ctx, {\n    keyPrefix,\n    httpFallback,\n    secure,\n    storage,\n    inboundLimits,\n  });\n\n  // A live devtools handle contributes two things and changes nothing else: its traffic core IS\n  // the wire tap (unless the app brought its own — a *disabled* handle is skipped: its tap is a\n  // no-op, and handing it over would still make the wire size every frame), and its devtools\n  // protocol rides the mux beside the app's `protocols` — the devtools window dials this DO's\n  // ordinary WebSocket endpoint, admission is the protocol's own token gate.\n  const devtoolsLive = devtools != null && devtools.enabled !== false;\n  const serveOptionsWithDevtools = devtoolsLive\n    ? {\n        ...serveOptions,\n        ...(serveOptions.wireTap == null ? { wireTap: devtools.wireTap } : {}),\n        ...(devtools.protocol != null\n          ? { protocols: [...(serveOptions.protocols ?? []), devtools.protocol] }\n          : {}),\n      }\n    : serveOptions;\n\n  // A channel array → a multi-channel acceptor: serve the combined channel, but pass the individual\n  // channels as the registry so a client connecting any subset composes the matching codec per connection.\n  return Array.isArray(channelOrChannels)\n    ? serveHost(runtime, combineChannels(channelOrChannels), host, {\n        ...serveOptionsWithDevtools,\n        channels: channelOrChannels,\n      })\n    : serveHost(\n        runtime,\n        channelOrChannels as IActionChannel<\n          readonly ActionDomain<any>[],\n          readonly ActionDomain<any>[]\n        >,\n        host,\n        serveOptionsWithDevtools,\n      );\n}\n\n/** The slice of a Durable Object stub {@link forwardToDurableObject} calls — `env.NS.get(id)`. */\nexport interface IDurableObjectStub {\n  fetch(request: Request): Promise<Response>;\n}\n\n/**\n * Build an opaque forwarder that fans a Worker's incoming action request out to a *per-id* (or singleton)\n * Durable Object which serves the exchange itself — the CF-specific sugar over the generic {@link forwardTo}.\n *\n * A secure exchange body is opaque to the Worker (handshake / encrypted frames), so the DO it belongs to is\n * chosen from the **URL**, not the body; security stays end-to-end between the origin client and the DO.\n * The CORS `OPTIONS` preflight is answered *at the edge* (default) so a per-id DO is never woken (or billed)\n * just to reply to a preflight. Returns an {@link IFetchHandler}, so it drops into {@link actionRouter} or\n * any framework:\n * ```ts\n * // wrangler: a Durable Object namespace `BRIDGE`, each instance one bridge serving `bridgeChannel`.\n * const router = actionRouter()\n *   .route(\"/bridge/:id/*\", forwardToDurableObject(({ params }) =>\n *      env.BRIDGE.get(env.BRIDGE.idFromString(params.id))))   // per-id, E2E client ↔ DO\n *   .route(\"/app/*\", forwardToDurableObject(() =>\n *      env.APP.get(env.APP.idFromName(\"main\"))));              // singleton\n * export default { fetch: (request: Request) => router.fetch(request) };\n *\n * // …and in the Durable Object, serve the secure exchange (+ a WS upgrade) as usual:\n * //   fetch(request) { return this.server.fetch(request); }\n * //   where this.server = serveDurableObject(this.ctx, bridgeChannel, { runtime, httpFallback: \"secure\" });\n * ```\n * `pickStub` may be async (e.g. to look an id up first); it receives `{ request, url, params }` (matched\n * path params when forwarded through {@link actionRouter}).\n */\nexport function forwardToDurableObject(\n  pickStub: (ctx: IForwardContext) => IDurableObjectStub | Promise<IDurableObjectStub>,\n  options?: IForwardToOptions,\n): IFetchHandler {\n  return forwardTo(pickStub, options);\n}\n"],"mappings":"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"}