{
  "version": 3,
  "sources": ["../../../../src/workers/browser-rendering/binding.worker.ts"],
  "sourcesContent": ["import assert from \"node:assert\";\nimport {\n\tDELETE,\n\tGET,\n\tHttpError,\n\tMiniflareDurableObject,\n\tPOST,\n\tPUT,\n\tRouter,\n\tSharedBindings,\n} from \"miniflare:shared\";\nimport type { Fetcher } from \"@cloudflare/workers-types/experimental\";\nimport type {\n\tMiniflareDurableObjectCf,\n\tMiniflareDurableObjectEnv,\n\tRouteHandler,\n\tTimerHandle,\n} from \"miniflare:shared\";\n\ninterface BrowserSessionEnv extends MiniflareDurableObjectEnv {\n\t[SharedBindings.MAYBE_SERVICE_LOOPBACK]: Fetcher;\n}\n\ninterface Env {\n\t[SharedBindings.MAYBE_SERVICE_LOOPBACK]: Fetcher;\n\tBrowserSession: DurableObjectNamespace;\n}\n\nexport type SessionInfo = {\n\twsEndpoint: string;\n\tsessionId: string;\n\tstartTime: number;\n\tconnectionId?: string;\n\tconnectionStartTime?: number;\n};\n\nfunction isClosed(ws: WebSocket | undefined): boolean {\n\treturn !ws || ws.readyState === WebSocket.CLOSED;\n}\n\nfunction chromeBaseUrl(wsEndpoint: string): string {\n\tconst u = new URL(wsEndpoint.replace(\"ws://\", \"http://\"));\n\treturn `http://${u.host}`;\n}\n\n// Reserved codes 1005 (No Status Received) and 1006 (Abnormal Closure) are\n// valid in CloseEvent but throw InvalidAccessError when passed to .close().\nfunction forwardClose(target?: WebSocket, e?: CloseEvent) {\n\tif (!target) {\n\t\treturn;\n\t}\n\tif (!e?.code || e?.code === 1005 || e?.code === 1006) {\n\t\ttarget.close();\n\t} else {\n\t\ttarget.close(e.code, e.reason);\n\t}\n}\n\nexport class BrowserSession extends MiniflareDurableObject<BrowserSessionEnv> {\n\tsessionInfo?: SessionInfo;\n\tchromeWs?: WebSocket;\n\tlegacyServerWs?: WebSocket;\n\twss: Array<{ chrome: WebSocket; server: WebSocket }> = [];\n\t#statusTimeout: TimerHandle | undefined;\n\n\t// --- Internal routes (called by module handler, not user-facing) ---\n\n\t@POST(\"/session-info\")\n\tsetSessionInfoRoute: RouteHandler = async (req) => {\n\t\tthis.sessionInfo = await req.json();\n\t\t// Establish a persistent WebSocket to Chrome's DevTools endpoint.\n\t\t// This serves as the health indicator for the session and is reused\n\t\t// by the legacy chunked-framing client (/v1/connectDevtools).\n\t\tconst wsUrl = this.sessionInfo.wsEndpoint.replace(\"ws://\", \"http://\");\n\t\tconst resp = await fetch(wsUrl, { headers: { Upgrade: \"websocket\" } });\n\t\tassert(resp.webSocket !== null, \"Expected a WebSocket response\");\n\t\tthis.chromeWs = resp.webSocket;\n\t\tthis.chromeWs.accept();\n\t\t// Forward Chrome messages to whatever legacyServerWs is currently connected.\n\t\t// Set up once here so reconnects don't accumulate duplicate listeners.\n\t\tthis.chromeWs.addEventListener(\"message\", (m) => {\n\t\t\tif (!this.legacyServerWs) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst string = new TextEncoder().encode(m.data as string);\n\t\t\tconst data = new Uint8Array(string.length + 4);\n\t\t\tconst view = new DataView(data.buffer);\n\t\t\tview.setUint32(0, string.length, true);\n\t\t\tdata.set(string, 4);\n\t\t\tthis.legacyServerWs.send(data);\n\t\t});\n\t\tthis.chromeWs.addEventListener(\"close\", (e) => {\n\t\t\tthis.closeSession(e);\n\t\t});\n\t\tthis.#scheduleStatusCheck();\n\t\treturn new Response(null, { status: 204 });\n\t};\n\n\t@GET(\"/session-info\")\n\tgetSessionInfoRoute: RouteHandler = async () => {\n\t\tif (isClosed(this.chromeWs)) {\n\t\t\tthis.closeSession();\n\t\t}\n\t\tif (!this.sessionInfo) {\n\t\t\treturn new Response(null, { status: 204 });\n\t\t}\n\t\treturn Response.json(this.sessionInfo);\n\t};\n\n\t@GET(\"/v1/connectDevtools\")\n\tconnectDevtools: RouteHandler = async () => {\n\t\tassert(\n\t\t\tthis.sessionInfo !== undefined,\n\t\t\t\"sessionInfo must be set before connecting\"\n\t\t);\n\t\tassert(\n\t\t\tthis.chromeWs !== undefined,\n\t\t\t\"chromeWs must be established before connecting\"\n\t\t);\n\t\tif (this.legacyServerWs !== undefined) {\n\t\t\tthrow new HttpError(409, \"WebSocket already initialized\");\n\t\t}\n\n\t\tconst webSocketPair = new WebSocketPair();\n\t\tconst [client, server] = Object.values(webSocketPair);\n\n\t\tserver.accept();\n\n\t\tserver.addEventListener(\"message\", (m) => {\n\t\t\tif (m.data === \"ping\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.chromeWs?.send(\n\t\t\t\tnew TextDecoder().decode((m.data as ArrayBuffer).slice(4))\n\t\t\t);\n\t\t});\n\t\tserver.addEventListener(\"close\", (e) => {\n\t\t\tthis.closeWebSockets(e);\n\t\t});\n\t\tthis.legacyServerWs = server;\n\t\tthis.sessionInfo.connectionId = crypto.randomUUID();\n\t\tthis.sessionInfo.connectionStartTime = Date.now();\n\n\t\treturn new Response(null, {\n\t\t\tstatus: 101,\n\t\t\twebSocket: client,\n\t\t\theaders: { \"cf-browser-session-id\": this.name },\n\t\t});\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/version\")\n\tjsonVersion: RouteHandler = async () => {\n\t\treturn this.#proxyJsonRequest(\"/json/version\");\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/list\")\n\tjsonList: RouteHandler = async () => {\n\t\treturn this.#proxyJsonRequest(\"/json/list\");\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json\")\n\tjsonAlias: RouteHandler = async () => {\n\t\treturn this.#proxyJsonRequest(\"/json/list\");\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/protocol\")\n\tjsonProtocol: RouteHandler = async () => {\n\t\treturn this.#proxyJsonRequest(\"/json/protocol\");\n\t};\n\n\t@PUT(\"/v1/devtools/browser/:sessionId/json/new\")\n\tjsonNew: RouteHandler = async (_req, _params, url) => {\n\t\treturn this.#proxyJsonRequest(\n\t\t\t`/json/new?${new URLSearchParams({ url: url.searchParams.get(\"url\") ?? \"\" })}`,\n\t\t\t\"PUT\"\n\t\t);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/activate/:targetId\")\n\tjsonActivate: RouteHandler<{ targetId: string }> = async (_req, params) => {\n\t\treturn this.#proxyJsonRequest(`/json/activate/${params?.targetId}`);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/close/:targetId\")\n\tjsonClose: RouteHandler<{ targetId: string }> = async (_req, params) => {\n\t\treturn this.#proxyJsonRequest(`/json/close/${params?.targetId}`);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/page/:pageId\")\n\tpageWebSocket: RouteHandler<{ pageId: string }> = async (_req, params) => {\n\t\tif (!this.sessionInfo) {\n\t\t\treturn Response.json({ error: \"Browser not found\" }, { status: 404 });\n\t\t}\n\t\treturn this.#proxyRawWebSocket(\n\t\t\t`${chromeBaseUrl(this.sessionInfo.wsEndpoint).replace(\"http://\", \"ws://\")}/devtools/page/${params?.pageId}`\n\t\t);\n\t};\n\n\t@DELETE(\"/v1/devtools/browser/:sessionId\")\n\tcloseBrowser: RouteHandler = async () => {\n\t\t// Browser.close CDP doesn't reliably kill Chrome, so we kill via loopback\n\t\t// instead. The DO returns immediately so it stays idle while the\n\t\t// module-level binding worker waits for Chrome to fully exit.\n\t\tif (this.sessionInfo) {\n\t\t\tconst closeUrl = new URL(\"http://localhost/browser/close\");\n\t\t\tcloseUrl.searchParams.set(\"sessionId\", this.sessionInfo.sessionId);\n\t\t\tvoid this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch(closeUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t});\n\t\t}\n\t\treturn Response.json({ status: \"closed\" });\n\t};\n\n\t@GET(\"/v1/devtools/session/:sessionId\")\n\tsessionDetail: RouteHandler = async () => {\n\t\tif (!this.sessionInfo) {\n\t\t\treturn Response.json({ error: \"Session not found\" }, { status: 404 });\n\t\t}\n\t\treturn Response.json({\n\t\t\tsessionId: this.sessionInfo.sessionId,\n\t\t\tstartTime: this.sessionInfo.startTime,\n\t\t\tconnectionId: this.sessionInfo.connectionId,\n\t\t\tconnectionStartTime: this.sessionInfo.connectionStartTime,\n\t\t});\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId\")\n\tconnect: RouteHandler = async (_req) => {\n\t\tassert(\n\t\t\tthis.sessionInfo !== undefined,\n\t\t\t\"sessionInfo must be set before connecting\"\n\t\t);\n\n\t\tconst wsUrl = this.sessionInfo.wsEndpoint.replace(\"ws://\", \"http://\");\n\t\tconst resp = await this.#proxyRawWebSocket(wsUrl);\n\n\t\tthis.sessionInfo.connectionId = crypto.randomUUID();\n\t\tthis.sessionInfo.connectionStartTime = Date.now();\n\n\t\treturn new Response(null, {\n\t\t\tstatus: resp.status,\n\t\t\twebSocket: resp.webSocket,\n\t\t\theaders: { \"cf-browser-session-id\": this.name },\n\t\t});\n\t};\n\n\tcloseWebSockets(e?: CloseEvent) {\n\t\tforwardClose(this.legacyServerWs, e);\n\t\tfor (const { chrome, server } of this.wss) {\n\t\t\tforwardClose(chrome, e);\n\t\t\tforwardClose(server, e);\n\t\t}\n\t\tthis.legacyServerWs = undefined;\n\t\tthis.wss = [];\n\t\tif (this.sessionInfo) {\n\t\t\tthis.sessionInfo.connectionId = undefined;\n\t\t\tthis.sessionInfo.connectionStartTime = undefined;\n\t\t}\n\t}\n\n\tcloseSession(e?: CloseEvent) {\n\t\tif (this.#statusTimeout !== undefined) {\n\t\t\tthis.timers.clearTimeout(this.#statusTimeout);\n\t\t\tthis.#statusTimeout = undefined;\n\t\t}\n\t\tthis.closeWebSockets(e);\n\t\tforwardClose(this.chromeWs, e);\n\t\tthis.chromeWs = undefined;\n\t\tthis.sessionInfo = undefined;\n\t}\n\n\tasync #proxyRawWebSocket(targetWsUrl: string): Promise<Response> {\n\t\tconst webSocketPair = new WebSocketPair();\n\t\tconst [client, server] = Object.values(webSocketPair);\n\n\t\tserver.accept();\n\n\t\tconst response = await fetch(targetWsUrl.replace(\"ws://\", \"http://\"), {\n\t\t\theaders: { Upgrade: \"websocket\" },\n\t\t});\n\n\t\tassert(response.webSocket !== null, \"Expected a WebSocket response\");\n\t\tconst chrome = response.webSocket;\n\t\tchrome.accept();\n\n\t\tconst pair = { chrome, server };\n\t\tthis.wss.push(pair);\n\n\t\tchrome.addEventListener(\"message\", (m) => server.send(m.data as string));\n\t\tserver.addEventListener(\"message\", (m) => chrome.send(m.data as string));\n\t\tserver.addEventListener(\"close\", (e) => {\n\t\t\tforwardClose(chrome, e);\n\t\t\tforwardClose(server, e);\n\t\t\tthis.wss = this.wss.filter((p) => p !== pair);\n\t\t});\n\t\tchrome.addEventListener(\"close\", (e) => {\n\t\t\tforwardClose(server, e);\n\t\t\tforwardClose(chrome, e);\n\t\t\tthis.wss = this.wss.filter((p) => p !== pair);\n\t\t});\n\n\t\treturn new Response(null, { status: 101, webSocket: client });\n\t}\n\n\tasync #proxyJsonRequest(\n\t\tchromePath: string,\n\t\tmethod = \"GET\"\n\t): Promise<Response> {\n\t\tif (!this.sessionInfo) {\n\t\t\treturn Response.json({ error: \"Browser not found\" }, { status: 404 });\n\t\t}\n\t\tconst resp = await fetch(\n\t\t\t`${chromeBaseUrl(this.sessionInfo.wsEndpoint)}${chromePath}`,\n\t\t\t{ method }\n\t\t);\n\t\treturn new Response(await resp.text(), {\n\t\t\tstatus: resp.status,\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t});\n\t}\n\n\tasync #checkStatus() {\n\t\tif (this.sessionInfo) {\n\t\t\tconst url = new URL(\"http://localhost/browser/status\");\n\t\t\turl.searchParams.set(\"sessionId\", this.sessionInfo.sessionId);\n\t\t\tconst resp =\n\t\t\t\tawait this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch(url);\n\t\t\tif (!resp.ok) {\n\t\t\t\tthis.closeSession();\n\t\t\t}\n\t\t}\n\t}\n\n\t#scheduleStatusCheck() {\n\t\tif (this.#statusTimeout !== undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#statusTimeout = this.timers.setTimeout(async () => {\n\t\t\tthis.#statusTimeout = undefined;\n\t\t\tawait this.#checkStatus();\n\t\t\tif (this.chromeWs) {\n\t\t\t\tthis.#scheduleStatusCheck();\n\t\t\t}\n\t\t}, 1000);\n\t}\n}\n\nclass BrowserRenderingRouter extends Router {\n\tconstructor(private readonly env: Env) {\n\t\tsuper();\n\t}\n\n\t#callSession(\n\t\tsessionId: string,\n\t\trequest: Request<unknown, unknown>\n\t): Promise<Response> {\n\t\tconst cf: MiniflareDurableObjectCf = { miniflare: { name: sessionId } };\n\t\tconst stub = this.env.BrowserSession.get(\n\t\t\tthis.env.BrowserSession.idFromName(sessionId)\n\t\t);\n\t\treturn stub.fetch(request as Request, {\n\t\t\tcf: cf as Record<string, unknown>,\n\t\t});\n\t}\n\n\t#fetchSession(\n\t\tsessionId: string,\n\t\tpath: string,\n\t\tinit?: RequestInit\n\t): Promise<Response> {\n\t\tconst cf: MiniflareDurableObjectCf = { miniflare: { name: sessionId } };\n\t\tconst stub = this.env.BrowserSession.get(\n\t\t\tthis.env.BrowserSession.idFromName(sessionId)\n\t\t);\n\t\treturn stub.fetch(`http://placeholder${path}`, {\n\t\t\t...init,\n\t\t\tcf: cf as Record<string, unknown>,\n\t\t});\n\t}\n\n\tasync #acquireSession(): Promise<SessionInfo> {\n\t\tconst sessionInfo: SessionInfo = await this.env[\n\t\t\tSharedBindings.MAYBE_SERVICE_LOOPBACK\n\t\t]\n\t\t\t.fetch(\"http://localhost/browser/launch\")\n\t\t\t.then((r) => r.json());\n\t\tawait this.#fetchSession(sessionInfo.sessionId, \"/session-info\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(sessionInfo),\n\t\t});\n\t\treturn sessionInfo;\n\t}\n\n\tasync #getActiveSessions() {\n\t\tconst sessionIds = (await this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK]\n\t\t\t.fetch(\"http://localhost/browser/sessionIds\")\n\t\t\t.then((r) => r.json())) as string[];\n\n\t\tconst sessions = await Promise.all(\n\t\t\tsessionIds.map(async (sessionId) => {\n\t\t\t\tconst resp = await this.#fetchSession(sessionId, \"/session-info\");\n\t\t\t\tif (resp.status === 204) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tconst sessionInfo: SessionInfo = await resp.json();\n\t\t\t\treturn {\n\t\t\t\t\tsessionId: sessionInfo.sessionId,\n\t\t\t\t\tstartTime: sessionInfo.startTime,\n\t\t\t\t\tconnectionId: sessionInfo.connectionId,\n\t\t\t\t\tconnectionStartTime: sessionInfo.connectionStartTime,\n\t\t\t\t};\n\t\t\t})\n\t\t);\n\n\t\treturn sessions.filter(Boolean);\n\t}\n\n\t@GET(\"/v1/acquire\")\n\tacquireRoute: RouteHandler = async () => {\n\t\tconst sessionInfo = await this.#acquireSession();\n\t\treturn Response.json({ sessionId: sessionInfo.sessionId });\n\t};\n\n\t@GET(\"/v1/sessions\")\n\tsessionsRoute: RouteHandler = async () => {\n\t\treturn Response.json({ sessions: await this.#getActiveSessions() });\n\t};\n\n\t@GET(\"/v1/limits\")\n\tlimitsRoute: RouteHandler = async () => {\n\t\treturn Response.json({\n\t\t\tmaxConcurrentSessions: 6,\n\t\t\tallowedBrowserAcquisitions: 6,\n\t\t\ttimeUntilNextAllowedBrowserAcquisition: 0,\n\t\t});\n\t};\n\n\t@GET(\"/v1/history\")\n\thistoryRoute: RouteHandler = async () => {\n\t\treturn Response.json([]);\n\t};\n\n\t@GET(\"/v1/devtools/session\")\n\tsessionListRoute: RouteHandler = async () => {\n\t\treturn Response.json(await this.#getActiveSessions());\n\t};\n\n\t@GET(\"/v1/connectDevtools\")\n\tconnectDevtoolsRoute: RouteHandler = async (req, _params, url) => {\n\t\tconst sessionId = url.searchParams.get(\"browser_session\");\n\t\tif (!sessionId) {\n\t\t\treturn new Response(\"browser_session must be set\", { status: 400 });\n\t\t}\n\t\treturn this.#callSession(sessionId, req);\n\t};\n\n\t@POST(\"/v1/devtools/browser\")\n\tacquireBrowserRoute: RouteHandler = async () => {\n\t\tconst sessionInfo = await this.#acquireSession();\n\t\treturn Response.json({ sessionId: sessionInfo.sessionId });\n\t};\n\n\t@GET(\"/v1/devtools/browser\")\n\tconnectBrowserRoute: RouteHandler = async (req) => {\n\t\tconst sessionInfo = await this.#acquireSession();\n\t\tconst doUrl = new URL(req.url);\n\t\tdoUrl.pathname = `/v1/devtools/browser/${sessionInfo.sessionId}`;\n\t\treturn this.#callSession(\n\t\t\tsessionInfo.sessionId,\n\t\t\tnew Request(doUrl, {\n\t\t\t\tmethod: req.method,\n\t\t\t\theaders: {\n\t\t\t\t\t...Object.fromEntries(req.headers),\n\t\t\t\t\t\"x-session-id\": sessionInfo.sessionId,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t};\n\n\t@GET(\"/v1/devtools/session/:sessionId\")\n\tsessionDetailRoute: RouteHandler<{ sessionId: string }> = async (\n\t\treq,\n\t\tparams\n\t) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@DELETE(\"/v1/devtools/browser/:sessionId\")\n\tcloseBrowserRoute: RouteHandler<{ sessionId: string }> = async (\n\t\treq,\n\t\tparams\n\t) => {\n\t\tconst { sessionId } = params;\n\t\t// The DO sends the kill signal and returns immediately, keeping\n\t\t// it idle so WebSocket close events can propagate to the user.\n\t\tawait this.#callSession(sessionId, req);\n\t\t// Poll until Chrome has exited so the session list is clean\n\t\tfor (let i = 0; i < 50; i++) {\n\t\t\tconst statusUrl = new URL(\"http://localhost/browser/status\");\n\t\t\tstatusUrl.searchParams.set(\"sessionId\", sessionId);\n\t\t\tconst statusResp =\n\t\t\t\tawait this.env[SharedBindings.MAYBE_SERVICE_LOOPBACK].fetch(statusUrl);\n\t\t\tif (statusResp.status === 410) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise((r) => setTimeout(r, 100));\n\t\t}\n\t\treturn Response.json({ status: \"closed\" });\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId\")\n\tconnectBrowserSessionRoute: RouteHandler<{ sessionId: string }> = async (\n\t\treq,\n\t\tparams,\n\t\t_url\n\t) => {\n\t\tconst doUrl = new URL(req.url);\n\t\treturn this.#callSession(params.sessionId, new Request(doUrl, req));\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/version\")\n\tjsonVersionRoute: RouteHandler<{ sessionId: string }> = async (\n\t\treq,\n\t\tparams\n\t) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/list\")\n\tjsonListRoute: RouteHandler<{ sessionId: string }> = async (req, params) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json\")\n\tjsonAliasRoute: RouteHandler<{ sessionId: string }> = async (req, params) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/protocol\")\n\tjsonProtocolRoute: RouteHandler<{ sessionId: string }> = async (\n\t\treq,\n\t\tparams\n\t) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@PUT(\"/v1/devtools/browser/:sessionId/json/new\")\n\tjsonNewRoute: RouteHandler<{ sessionId: string }> = async (req, params) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/activate/:targetId\")\n\tjsonActivateRoute: RouteHandler<{ sessionId: string }> = async (\n\t\treq,\n\t\tparams\n\t) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/json/close/:targetId\")\n\tjsonCloseRoute: RouteHandler<{ sessionId: string }> = async (req, params) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n\n\t@GET(\"/v1/devtools/browser/:sessionId/page/:pageId\")\n\tpageWebSocketRoute: RouteHandler<{ sessionId: string }> = async (\n\t\treq,\n\t\tparams\n\t) => {\n\t\treturn this.#callSession(params.sessionId, req);\n\t};\n}\n\nexport default {\n\tfetch(request: Request, env: Env) {\n\t\treturn new BrowserRenderingRouter(env).fetch(request);\n\t},\n};\n"],
  "mappings": "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",
  "names": []
}
