{"version":3,"sources":["../src/mod.ts","../src/websocket.ts"],"sourcesContent":["import * as wasmBindings from \"@rivetkit/rivetkit-wasm\";\nimport wasmModule from \"@rivetkit/rivetkit-wasm/rivetkit_wasm_bg.wasm\";\nimport {\n\tRegistry,\n\ttype RegistryActors,\n\ttype RegistryConfigInput,\n\tsetup as rivetkitSetup,\n} from \"rivetkit\";\n// Installs the fetch-based `globalThis.WebSocket` shim required for the wasm\n// runtime's outbound tunnel to the Rivet engine. Imported for its side effect.\nimport \"./websocket\";\n\nconst DEFAULT_MANAGER_PATH = \"/api/rivet\";\n\n/** Config passed to `setup` / `createHandler`. The wasm runtime is wired automatically. */\nexport type CloudflareSetupConfig<A extends RegistryActors> = Omit<\n\tRegistryConfigInput<A>,\n\t\"runtime\" | \"wasm\"\n>;\n\n/**\n * Wraps rivetkit's `setup` with the Cloudflare Workers WebAssembly runtime wired\n * in. Returns a typed `Registry`, so you can derive a typed client with\n * `createClient<typeof registry>(...)` and pass the same registry to\n * `createHandler`.\n */\nexport function setup<A extends RegistryActors>(\n\tconfig: CloudflareSetupConfig<A>,\n): Registry<A> {\n\treturn rivetkitSetup<A>({\n\t\truntime: \"wasm\",\n\t\twasm: { bindings: wasmBindings, initInput: wasmModule },\n\t\tnoWelcome: true,\n\t\t...config,\n\t} as RegistryConfigInput<A>);\n}\n\nexport interface CreateHandlerOptions {\n\t/**\n\t * Path the Rivet manager API is mounted at. Defaults to `/api/rivet`.\n\t *\n\t * `rivet dev` and the engine poll `<managerPath>/metadata`, so changing this\n\t * also requires configuring the engine-side serverless runner URL to match.\n\t */\n\tmanagerPath?: string;\n\t/**\n\t * Handler for requests that fall outside the Rivet manager API path. Accepts\n\t * a plain `(request, env, ctx)` handler or a framework `fetch` such as\n\t * Hono's `app.fetch`.\n\t */\n\t// biome-ignore lint/suspicious/noExplicitAny: accept any fetch handler shape (e.g. Hono's app.fetch).\n\tfetch?: (request: Request, ...args: any[]) => Response | Promise<Response>;\n}\n\nexport interface CloudflareHandler {\n\tfetch(request: Request, env: unknown, ctx: unknown): Promise<Response>;\n}\n\ntype EnvRecord = Record<string, string | undefined>;\n\n// Fill connection config from the per-request `env` on first request. On\n// Cloudflare the env is not available at module scope, so values that were not\n// set explicitly in the config are sourced from `RIVET_*` Worker variables here.\nfunction applyEnv(\n\tregistry: Registry<RegistryActors>,\n\tenv: EnvRecord,\n\tmanagerPath: string,\n): void {\n\tconst config = registry.config as RegistryConfigInput<RegistryActors>;\n\tif (!config.endpoint && env.RIVET_ENDPOINT) {\n\t\tconfig.endpoint = env.RIVET_ENDPOINT;\n\t}\n\tif (!config.namespace && env.RIVET_NAMESPACE) {\n\t\tconfig.namespace = env.RIVET_NAMESPACE;\n\t}\n\tif (!config.token && env.RIVET_TOKEN) {\n\t\tconfig.token = env.RIVET_TOKEN;\n\t}\n\tif (env.RIVET_POOL && !config.envoy?.poolName) {\n\t\tconfig.envoy = { ...config.envoy, poolName: env.RIVET_POOL };\n\t}\n\tif (!config.serverless?.basePath) {\n\t\tconfig.serverless = { ...config.serverless, basePath: managerPath };\n\t}\n}\n\n/**\n * Creates a Cloudflare Workers handler that hosts Rivet Actors on the wasm\n * runtime. Accepts either a registry from this package's `setup` or a setup\n * config (which is wired through `setup` for you).\n *\n * The Rivet manager API is mounted at `managerPath` (default `/api/rivet`).\n * Requests outside that path are routed to `options.fetch` if provided, letting\n * you mount your own routes alongside Rivet. The engine endpoint is read from\n * `RIVET_ENDPOINT` (with `RIVET_NAMESPACE`, `RIVET_TOKEN`, `RIVET_POOL` optional)\n * unless set in the config.\n */\nexport function createHandler<A extends RegistryActors>(\n\tregistry: Registry<A>,\n\toptions?: CreateHandlerOptions,\n): CloudflareHandler;\nexport function createHandler<A extends RegistryActors>(\n\tconfig: CloudflareSetupConfig<A>,\n\toptions?: CreateHandlerOptions,\n): CloudflareHandler;\nexport function createHandler<A extends RegistryActors>(\n\tregistryOrConfig: Registry<A> | CloudflareSetupConfig<A>,\n\toptions: CreateHandlerOptions = {},\n): CloudflareHandler {\n\tconst managerPath = options.managerPath ?? DEFAULT_MANAGER_PATH;\n\tconst registry =\n\t\tregistryOrConfig instanceof Registry\n\t\t\t? registryOrConfig\n\t\t\t: setup(registryOrConfig);\n\tlet envApplied = false;\n\n\treturn {\n\t\tasync fetch(request, env, ctx) {\n\t\t\tif (!envApplied) {\n\t\t\t\tapplyEnv(\n\t\t\t\t\tregistry as Registry<RegistryActors>,\n\t\t\t\t\t(env ?? {}) as EnvRecord,\n\t\t\t\t\tmanagerPath,\n\t\t\t\t);\n\t\t\t\tenvApplied = true;\n\t\t\t}\n\n\t\t\tconst url = new URL(request.url);\n\t\t\tif (\n\t\t\t\turl.pathname === managerPath ||\n\t\t\t\turl.pathname.startsWith(`${managerPath}/`)\n\t\t\t) {\n\t\t\t\treturn registry.handler(request);\n\t\t\t}\n\n\t\t\tif (options.fetch) {\n\t\t\t\treturn options.fetch(request, env, ctx);\n\t\t\t}\n\n\t\t\treturn new Response(\n\t\t\t\t\"This is a RivetKit server.\\n\\nLearn more at https://rivet.dev\\n\",\n\t\t\t);\n\t\t},\n\t};\n}\n","// Cloudflare Workers do not implement an outbound `new WebSocket(url)` client\n// constructor, but the wasm actor runtime opens its tunnel to the Rivet engine\n// through `globalThis.WebSocket`. This shim translates that constructor into\n// Cloudflare's fetch-based upgrade (`fetch(url, { Upgrade })` + `response.webSocket`)\n// and installs itself on `globalThis` so both the wasm tunnel and the TypeScript\n// client path resolve a working implementation.\n\ntype WebSocketProtocolInput = string | string[] | undefined;\n\ntype CloudflareSocket = WebSocket & { accept(): void };\n\nclass FetchWebSocket {\n\tstatic readonly CONNECTING = 0;\n\tstatic readonly OPEN = 1;\n\tstatic readonly CLOSING = 2;\n\tstatic readonly CLOSED = 3;\n\n\tbinaryType: BinaryType = \"arraybuffer\";\n\tonopen: ((event: Event) => void) | null = null;\n\tonmessage: ((event: MessageEvent) => void) | null = null;\n\tonclose: ((event: CloseEvent) => void) | null = null;\n\tonerror: ((event: Event) => void) | null = null;\n\treadyState = FetchWebSocket.CONNECTING;\n\t#socket: CloudflareSocket | undefined;\n\t#pending: Array<string | ArrayBuffer | ArrayBufferView> = [];\n\n\tconstructor(url: string, protocols?: WebSocketProtocolInput) {\n\t\tvoid this.#connect(url, protocols);\n\t}\n\n\tasync #connect(url: string, protocols?: WebSocketProtocolInput) {\n\t\ttry {\n\t\t\tconst protocolList = Array.isArray(protocols)\n\t\t\t\t? protocols\n\t\t\t\t: protocols\n\t\t\t\t\t? [protocols]\n\t\t\t\t\t: [];\n\t\t\tconst headers = new Headers({ Upgrade: \"websocket\" });\n\t\t\tif (protocolList.length > 0) {\n\t\t\t\theaders.set(\"Sec-WebSocket-Protocol\", protocolList.join(\", \"));\n\t\t\t}\n\t\t\tconst response = await fetch(\n\t\t\t\turl.replace(/^ws:/, \"http:\").replace(/^wss:/, \"https:\"),\n\t\t\t\t{ headers },\n\t\t\t);\n\t\t\tconst socket = (\n\t\t\t\tresponse as unknown as { webSocket: CloudflareSocket | null }\n\t\t\t).webSocket;\n\t\t\tif (!socket) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`websocket upgrade failed with status ${response.status}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tsocket.accept();\n\t\t\tsocket.binaryType = this.binaryType;\n\t\t\tthis.#socket = socket;\n\t\t\tthis.readyState = FetchWebSocket.OPEN;\n\t\t\tsocket.addEventListener(\"message\", (event) => {\n\t\t\t\tthis.onmessage?.(event);\n\t\t\t});\n\t\t\tsocket.addEventListener(\"close\", (event) => {\n\t\t\t\tthis.readyState = FetchWebSocket.CLOSED;\n\t\t\t\tthis.onclose?.(event);\n\t\t\t});\n\t\t\tsocket.addEventListener(\"error\", (event) => {\n\t\t\t\tthis.onerror?.(event);\n\t\t\t});\n\t\t\tthis.onopen?.(new Event(\"open\"));\n\t\t\tfor (const data of this.#pending.splice(0)) {\n\t\t\t\tsocket.send(data);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(\"rivetkit cloudflare websocket shim failed\", error);\n\t\t\tthis.readyState = FetchWebSocket.CLOSED;\n\t\t\tthis.onerror?.(error instanceof Event ? error : new Event(\"error\"));\n\t\t\tthis.onclose?.(new CloseEvent(\"close\", { code: 1006 }));\n\t\t}\n\t}\n\n\tsend(data: string | ArrayBuffer | ArrayBufferView) {\n\t\tif (this.readyState === FetchWebSocket.CONNECTING) {\n\t\t\tthis.#pending.push(data);\n\t\t\treturn;\n\t\t}\n\t\tthis.#socket?.send(data);\n\t}\n\n\tclose(code?: number, reason?: string) {\n\t\tthis.readyState = FetchWebSocket.CLOSING;\n\t\tthis.#socket?.close(code, reason);\n\t}\n}\n\nconst globalScope = globalThis as unknown as {\n\tWebSocket: typeof WebSocket;\n\t__RIVETKIT_CF_WEBSOCKET_INSTALLED__?: boolean;\n};\n\n// Install once per isolate.\nif (!globalScope.__RIVETKIT_CF_WEBSOCKET_INSTALLED__) {\n\tglobalScope.WebSocket = FetchWebSocket as unknown as typeof WebSocket;\n\tglobalScope.__RIVETKIT_CF_WEBSOCKET_INSTALLED__ = true;\n}\n\nexport { FetchWebSocket };\n"],"mappings":"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","names":["_a"]}