{
  "version": 3,
  "sources": ["../../../../src/workers/assets/rpc-proxy.worker.ts", "../../../../src/workers/core/dev-registry-proxy-shared.worker.ts"],
  "sourcesContent": ["import { WorkerEntrypoint } from \"cloudflare:workers\";\nimport {\n\ttailEventsReplacer,\n\ttailEventsReviver,\n} from \"../core/dev-registry-proxy-shared.worker\";\nimport type RouterWorker from \"@cloudflare/workers-shared/asset-worker\";\n\ninterface Env {\n\tROUTER_WORKER: Service<RouterWorker>;\n\tUSER_WORKER: Fetcher | Service;\n}\n\n/*\n * The RPCProxyWorker is a Miniflare abstraction of the filter stage used in\n * production Workers + Assets pipelines. It lives in front of the Router Worker,\n * and is meant to redirect incoming `fetch` requests to the Router Worker, and\n * all other RPC requests to the User Worker. It does so via a JSProxy mechanism.\n * The RPCProxyWorker is specifically relevant in the context of\n * Worker <> Worker+Assets service bindings.\n *\n * Please note that this conceptual pipeline architecture is applied only for\n * Workers + Assets and default entrypoints, class or non-class based.\n */\nexport default class RPCProxyWorker extends WorkerEntrypoint<Env> {\n\tasync fetch(request: Request) {\n\t\treturn this.env.ROUTER_WORKER.fetch(request);\n\t}\n\n\t// Forward scheduled events to the User Worker. The proxy itself doesn't run\n\t// any scheduled logic; it just dispatches a real scheduled event to the user\n\t// worker via the Fetcher built-in, then propagates the user worker's noRetry\n\t// decision back onto this controller so the outcome surfaces correctly to\n\t// the caller (e.g. the entry worker's `/cdn-cgi/handler/scheduled` handler).\n\tasync scheduled(controller: ScheduledController) {\n\t\tconst result = await this.env.USER_WORKER.scheduled?.({\n\t\t\tcron: controller.cron,\n\t\t\tscheduledTime: new Date(controller.scheduledTime),\n\t\t});\n\t\tif (result?.noRetry) {\n\t\t\tcontroller.noRetry();\n\t\t}\n\t\tif (result?.outcome !== \"ok\") {\n\t\t\t// Re-throw so workerd surfaces `outcome: \"exception\"` to the caller\n\t\t\t// rather than swallowing the user worker's failure.\n\t\t\tthrow new Error(\n\t\t\t\t`User Worker scheduled handler failed with outcome: ${result?.outcome}`\n\t\t\t);\n\t\t}\n\t}\n\n\ttail(events: TraceItem[]) {\n\t\t// Temporary workaround: the tail events is not serializable over capnproto yet\n\t\t// But they are effectively JSON, so we are serializing them to JSON and parsing it back to make it transferable.\n\t\t// @ts-expect-error FIXME when https://github.com/cloudflare/workerd/pull/4595 lands\n\t\treturn this.env.USER_WORKER.tail(\n\t\t\tJSON.parse(JSON.stringify(events, tailEventsReplacer), tailEventsReviver)\n\t\t);\n\t}\n\n\tconstructor(ctx: ExecutionContext, env: Env) {\n\t\tsuper(ctx, env);\n\t\t/*\n\t\t * Create a proxy of the RPCProxyWorker instance\n\t\t *\n\t\t * see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy\n\t\t * see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect\n\t\t */\n\t\treturn new Proxy(this, {\n\t\t\tget(target, prop) {\n\t\t\t\t/*\n\t\t\t\t * If `prop` is defined on the RPCProxyWorker, then we are\n\t\t\t\t * intentionally meaning to intercept `env.USER_WORKER[prop]`\n\t\t\t\t * calls and override their return value . We should therefore\n\t\t\t\t * return whatever `RPCProxyWorker[prop]` returns\n\t\t\t\t */\n\t\t\t\tif (Reflect.has(target, prop)) {\n\t\t\t\t\treturn Reflect.get(target, prop);\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t * Otherwise, forward to the USER_WORKER and return its response\n\t\t\t\t */\n\t\t\t\treturn Reflect.get(target.env.USER_WORKER, prop);\n\t\t\t},\n\t\t});\n\t}\n}\n", "import { DurableObject } from \"cloudflare:workers\";\n\n/**\n * Represents the workerd debug port's ability to open connections to other\n * workerd instances by address. Mirrors the Cap'n Proto RPC interface exposed\n * by the workerd debug port.\n *\n * @see https://github.com/cloudflare/workerd/blob/main/src/workerd/server/server.c++\n */\nexport interface WorkerdDebugPortConnector {\n\tconnect(address: string): WorkerdDebugPortClient;\n}\n\n/**\n * A connected debug port client that can resolve service entrypoints and\n * Durable Object actors on a remote workerd instance.\n */\nexport interface WorkerdDebugPortClient {\n\tgetEntrypoint(\n\t\tservice: string,\n\t\tentrypoint?: string,\n\t\tprops?: Record<string, unknown>\n\t): Fetcher;\n\tgetActor(service: string, entrypoint: string, actorId: string): Fetcher;\n}\n\n/**\n * A dev registry entry describing how to reach a worker's debug port and\n * which workerd services correspond to its default entrypoint and user code.\n */\nexport interface RegistryEntry {\n\tdebugPortAddress: string;\n\tdefaultEntrypointService: string;\n\tuserWorkerService: string;\n}\n\nlet registry = new Map<string, RegistryEntry>();\n\n/**\n * Replace the in-memory registry with the given entries.\n * Called whenever the Node.js side pushes an updated registry snapshot.\n */\nexport function setRegistry(data: Record<string, RegistryEntry>): void {\n\tregistry = new Map(Object.entries(data));\n}\n\n/**\n * Look up a worker's registry entry by service name.\n */\nexport function resolveTarget(service: string): RegistryEntry | undefined {\n\tconst entry = registry.get(service);\n\tif (!entry || !(\"debugPortAddress\" in entry)) {\n\t\treturn undefined;\n\t}\n\treturn entry;\n}\n\n/**\n * Check whether a registry entry exists for the given service, even if it's\n * from an incompatible wrangler version.\n */\nexport function hasRegistryEntry(service: string): boolean {\n\treturn registry.has(service);\n}\n\n/**\n * Return an appropriate error message for a worker that can't be resolved.\n */\nexport function workerNotFoundMessage(service: string): string {\n\tif (hasRegistryEntry(service)) {\n\t\treturn `Worker \"${service}\" is not compatible with this version of the dev server. Please update all Worker instances to the same version.`;\n\t}\n\treturn `Worker \"${service}\" not found. Make sure it is running locally.`;\n}\n\n/**\n * Connect to a Durable Object actor on a remote workerd instance via the\n * debug port, returning a {@link Fetcher} that proxies requests to it.\n */\nexport function connectToActor(\n\tdebugPort: WorkerdDebugPortConnector,\n\tscriptName: string,\n\tclassName: string,\n\tactorId: string\n): Fetcher | null {\n\tconst target = resolveTarget(scriptName);\n\tif (!target || !target.debugPortAddress) {\n\t\treturn null;\n\t}\n\tconst client = debugPort.connect(target.debugPortAddress);\n\treturn client.getActor(target.userWorkerService, className, actorId);\n}\n\n/**\n * Create a {@link DurableObject} subclass that proxies all method calls\n * and fetch requests to a Durable Object running in a separate workerd\n * instance via the debug port RPC. Uses a {@link Proxy} to forward\n * arbitrary RPC method calls to the remote actor's {@link Fetcher}.\n */\nexport function createProxyDurableObjectClass({\n\tscriptName,\n\tclassName,\n}: {\n\tscriptName: string;\n\tclassName: string;\n}): typeof DurableObject {\n\treturn class extends DurableObject<{\n\t\tDEV_REGISTRY_DEBUG_PORT: WorkerdDebugPortConnector;\n\t}> {\n\t\t_cachedFetcher: Fetcher | undefined;\n\t\t_cachedDebugPortAddress: string | undefined;\n\n\t\t// Lazily resolve and cache. Invalidates when debugPortAddress changes.\n\t\t_resolve(): Fetcher | null {\n\t\t\tconst target = resolveTarget(scriptName);\n\t\t\tif (\n\t\t\t\tthis._cachedFetcher &&\n\t\t\t\ttarget?.debugPortAddress === this._cachedDebugPortAddress\n\t\t\t) {\n\t\t\t\treturn this._cachedFetcher;\n\t\t\t}\n\t\t\tthis._cachedFetcher = undefined;\n\t\t\tthis._cachedDebugPortAddress = undefined;\n\n\t\t\tconst fetcher = connectToActor(\n\t\t\t\tthis.env.DEV_REGISTRY_DEBUG_PORT,\n\t\t\t\tscriptName,\n\t\t\t\tclassName,\n\t\t\t\tthis.ctx.id.toString()\n\t\t\t);\n\t\t\tif (fetcher && target) {\n\t\t\t\tthis._cachedFetcher = fetcher;\n\t\t\t\tthis._cachedDebugPortAddress = target.debugPortAddress;\n\t\t\t}\n\t\t\treturn fetcher;\n\t\t}\n\n\t\tconstructor(\n\t\t\tctx: DurableObjectState,\n\t\t\tenv: { DEV_REGISTRY_DEBUG_PORT: WorkerdDebugPortConnector }\n\t\t) {\n\t\t\tsuper(ctx, env);\n\n\t\t\treturn new Proxy(this, {\n\t\t\t\tget(target, prop) {\n\t\t\t\t\tif (Reflect.has(target, prop)) {\n\t\t\t\t\t\treturn Reflect.get(target, prop);\n\t\t\t\t\t}\n\t\t\t\t\tconst fetcher = target._resolve();\n\t\t\t\t\tif (!fetcher) {\n\t\t\t\t\t\t// Return a function-that-throws rather than throwing immediately:\n\t\t\t\t\t\t// workerd probes DO properties (fetch, alarm, etc.) via the get\n\t\t\t\t\t\t// trap, and throwing here would crash those internal checks.\n\t\t\t\t\t\treturn () => {\n\t\t\t\t\t\t\tthrow new Error(workerNotFoundMessage(scriptName));\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn Reflect.get(fetcher, prop);\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tfetch(request: Request): Promise<Response> {\n\t\t\tconst fetcher = this._resolve();\n\t\t\tif (!fetcher) {\n\t\t\t\treturn Promise.resolve(\n\t\t\t\t\tnew Response(workerNotFoundMessage(scriptName), { status: 503 })\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn fetcher.fetch(request);\n\t\t}\n\t} as unknown as typeof DurableObject;\n}\n\nconst SERIALIZED_DATE = \"___serialized_date___\";\nconst SERIALIZED_BIGINT = \"___serialized_bigint___\";\n\n/**\n * JSON replacer that serializes `Date` and `bigint` values into tagged\n * objects so they survive a JSON round-trip in tail event forwarding.\n */\nexport function tailEventsReplacer(_: string, value: any) {\n\tif (value instanceof Date) {\n\t\treturn { [SERIALIZED_DATE]: value.toISOString() };\n\t} else if (typeof value === \"bigint\") {\n\t\treturn { [SERIALIZED_BIGINT]: value.toString() };\n\t}\n\treturn value;\n}\n\n/**\n * JSON reviver that restores `Date` and `bigint` values from the tagged\n * objects produced by {@link tailEventsReplacer}.\n */\nexport function tailEventsReviver(_: string, value: any) {\n\tif (value && typeof value === \"object\") {\n\t\tif (SERIALIZED_DATE in value) {\n\t\t\treturn new Date(value[SERIALIZED_DATE]);\n\t\t} else if (SERIALIZED_BIGINT in value) {\n\t\t\treturn BigInt(value[SERIALIZED_BIGINT]);\n\t\t}\n\t}\n\treturn value;\n}\n"],
  "mappings": ";AAAA,SAAS,wBAAwB;;;ACAjC,SAAS,qBAAqB;AA8K9B,IAAM,kBAAkB,yBAClB,oBAAoB;AAMnB,SAAS,mBAAmB,GAAW,OAAY;AACzD,SAAI,iBAAiB,OACb,EAAE,CAAC,eAAe,GAAG,MAAM,YAAY,EAAE,IACtC,OAAO,SAAU,WACpB,EAAE,CAAC,iBAAiB,GAAG,MAAM,SAAS,EAAE,IAEzC;AACR;AAMO,SAAS,kBAAkB,GAAW,OAAY;AACxD,MAAI,SAAS,OAAO,SAAU,UAAU;AACvC,QAAI,mBAAmB;AACtB,aAAO,IAAI,KAAK,MAAM,eAAe,CAAC;AAChC,QAAI,qBAAqB;AAC/B,aAAO,OAAO,MAAM,iBAAiB,CAAC;AAAA,EAExC;AACA,SAAO;AACR;;;ADpLA,IAAqB,iBAArB,cAA4C,iBAAsB;AAAA,EACjE,MAAM,MAAM,SAAkB;AAC7B,WAAO,KAAK,IAAI,cAAc,MAAM,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAU,YAAiC;AAChD,QAAM,SAAS,MAAM,KAAK,IAAI,YAAY,YAAY;AAAA,MACrD,MAAM,WAAW;AAAA,MACjB,eAAe,IAAI,KAAK,WAAW,aAAa;AAAA,IACjD,CAAC;AAID,QAHI,QAAQ,WACX,WAAW,QAAQ,GAEhB,QAAQ,YAAY;AAGvB,YAAM,IAAI;AAAA,QACT,sDAAsD,QAAQ,OAAO;AAAA,MACtE;AAAA,EAEF;AAAA,EAEA,KAAK,QAAqB;AAIzB,WAAO,KAAK,IAAI,YAAY;AAAA,MAC3B,KAAK,MAAM,KAAK,UAAU,QAAQ,kBAAkB,GAAG,iBAAiB;AAAA,IACzE;AAAA,EACD;AAAA,EAEA,YAAY,KAAuB,KAAU;AAC5C,iBAAM,KAAK,GAAG,GAOP,IAAI,MAAM,MAAM;AAAA,MACtB,IAAI,QAAQ,MAAM;AAOjB,eAAI,QAAQ,IAAI,QAAQ,IAAI,IACpB,QAAQ,IAAI,QAAQ,IAAI,IAMzB,QAAQ,IAAI,OAAO,IAAI,aAAa,IAAI;AAAA,MAChD;AAAA,IACD,CAAC;AAAA,EACF;AACD;",
  "names": []
}
