UNPKG

@cloudflare/vitest-pool-workers

Version:

Workers Vitest integration for writing Vitest unit and integration tests that run inside the Workers runtime

1 lines 97.3 kB
{"version":3,"file":"test-internal.mjs","names":["sameIsolatedNamespaces: DurableObjectNamespace[] | undefined","env","errors: unknown[]","timeoutId: ReturnType<typeof setTimeout> | undefined","globalWaitUntil: unknown[]","exports","releaseStarted: (() => void) | undefined","runtimeEnv","env","DurableObjectClass","#controller","timestamp: Date","attempts: number","metadata: MessageBatchMetadata","retryMessages: QueueRetryMessage[]","explicitAcks: string[]","#workflow","#instanceId","#instanceModifierPromise","#instanceModifier","InstanceStatusNumber","modifierCallbacks: ModifierCallback[]","instanceIntrospectors: WorkflowInstanceIntrospector[]","env","#modifierCallbacks","#instanceIntrospectors","#disposeCallback"],"sources":["../../../../src/worker/fetch-mock.ts","../../../../src/worker/d1.ts","../../../../src/worker/env.ts","../../../../src/worker/durable-objects.ts","../../../../src/worker/wait-until.ts","../../../../src/worker/patch-ctx.ts","../../../../src/worker/entrypoints.ts","../../../../src/worker/events.ts","../../../../src/worker/reset.ts","../../../../src/worker/secrets-store.ts","../../../../../workflows-shared/src/instance.ts","../../../../src/worker/workflows.ts"],"sourcesContent":["const originalFetch = fetch;\n\n// Monkeypatch `fetch()`. This looks like a no-op, but it's not. It allows MSW to intercept fetch calls using it's Fetch interceptor.\nglobalThis.fetch = async (input, init) => {\n\treturn originalFetch.call(globalThis, input, init);\n};\n","import type { D1Migration } from \"../shared/d1\";\n\nfunction isD1Database(v: unknown): v is D1Database {\n\treturn (\n\t\ttypeof v === \"object\" &&\n\t\tv !== null &&\n\t\tv.constructor.name === \"D1Database\" &&\n\t\t\"prepare\" in v &&\n\t\ttypeof v.prepare === \"function\" &&\n\t\t\"batch\" in v &&\n\t\ttypeof v.batch === \"function\" &&\n\t\t\"exec\" in v &&\n\t\ttypeof v.exec === \"function\"\n\t);\n}\n\nfunction isD1Migration(v: unknown): v is D1Migration {\n\treturn (\n\t\ttypeof v === \"object\" &&\n\t\tv !== null &&\n\t\t\"name\" in v &&\n\t\ttypeof v.name === \"string\" &&\n\t\t\"queries\" in v &&\n\t\tArray.isArray(v.queries) &&\n\t\tv.queries.every((query) => typeof query === \"string\")\n\t);\n}\nfunction isD1Migrations(v: unknown): v is D1Migration[] {\n\treturn Array.isArray(v) && v.every(isD1Migration);\n}\n\nexport async function applyD1Migrations(\n\tdb: D1Database,\n\tmigrations: D1Migration[],\n\tmigrationsTableName = \"d1_migrations\"\n) {\n\tif (!isD1Database(db)) {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'applyD1Migrations': parameter 1 is not of type 'D1Database'.\"\n\t\t);\n\t}\n\tif (!isD1Migrations(migrations)) {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'applyD1Migrations': parameter 2 is not of type 'D1Migration[]'.\"\n\t\t);\n\t}\n\t// noinspection SuspiciousTypeOfGuard\n\tif (typeof migrationsTableName !== \"string\") {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'applyD1Migrations': parameter 3 is not of type 'string'.\"\n\t\t);\n\t}\n\n\t// Create migrations table if it doesn't exist\n\tconst schema = `CREATE TABLE IF NOT EXISTS ${migrationsTableName} (\n\t\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\t\tname TEXT UNIQUE,\n\t\tapplied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL\n\t);`;\n\tawait db.prepare(schema).run();\n\n\t// Find applied migrations\n\tconst appliedMigrationNamesResult = await db\n\t\t.prepare(`SELECT name FROM ${migrationsTableName};`)\n\t\t.all<{ name: string }>();\n\tconst appliedMigrationNames = appliedMigrationNamesResult.results.map(\n\t\t({ name }) => name\n\t);\n\n\t// Apply un-applied migrations\n\tconst insertMigrationStmt = db.prepare(\n\t\t`INSERT INTO ${migrationsTableName} (name) VALUES (?);`\n\t);\n\tfor (const migration of migrations) {\n\t\tif (appliedMigrationNames.includes(migration.name)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst queries = migration.queries.map((query) => db.prepare(query));\n\t\tqueries.push(insertMigrationStmt.bind(migration.name));\n\t\tawait db.batch(queries);\n\t}\n}\n","import assert from \"node:assert\";\nimport { exports } from \"cloudflare:workers\";\n\nexport { env } from \"cloudflare:workers\";\n\n/**\n * For reasons that aren't clear to me, just `SELF = exports.default` ends up with SELF being\n * undefined in a test. This Proxy solution works.\n */\nexport const SELF = new Proxy(\n\t{},\n\t{\n\t\tget(_, p) {\n\t\t\tconst target = exports.default as unknown as Record<\n\t\t\t\tstring | symbol,\n\t\t\t\tunknown\n\t\t\t>;\n\t\t\tconst value = target[p];\n\t\t\treturn typeof value === \"function\" ? value.bind(target) : value;\n\t\t},\n\t}\n);\n\nexport function getSerializedOptions(): SerializedOptions {\n\tassert(typeof __vitest_worker__ === \"object\", \"Expected global Vitest state\");\n\tconst options = __vitest_worker__.providedContext.cloudflarePoolOptions;\n\t// `options` should always be defined when running tests\n\n\tassert(\n\t\toptions !== undefined,\n\t\t\"Expected serialised options, got keys: \" +\n\t\t\tObject.keys(__vitest_worker__.providedContext).join(\", \")\n\t);\n\tconst parsedOptions = JSON.parse(options);\n\treturn {\n\t\t...parsedOptions,\n\t\tdurableObjectBindingDesignators: new Map(\n\t\t\tparsedOptions.durableObjectBindingDesignators\n\t\t),\n\t};\n}\n\nexport function getResolvedMainPath(\n\tforBindingType: \"service\" | \"Durable Object\"\n): string {\n\tconst options = getSerializedOptions();\n\tif (options.main === undefined) {\n\t\tthrow new Error(\n\t\t\t`Using ${forBindingType} bindings to the current worker requires \\`poolOptions.workers.main\\` to be set to your worker's entrypoint: ${JSON.stringify(options)}`\n\t\t);\n\t}\n\treturn options.main;\n}\n","import assert from \"node:assert\";\nimport { env, exports } from \"cloudflare:workers\";\nimport { getSerializedOptions } from \"./env\";\nimport type { __VITEST_POOL_WORKERS_RUNNER_DURABLE_OBJECT__ } from \"./index\";\n\nconst CF_KEY_ACTION = \"vitestPoolWorkersDurableObjectAction\";\n\nlet nextActionId = 0;\nconst kUseResponse = Symbol(\"kUseResponse\");\nconst actionResults = new Map<number /* id */, unknown>();\n\nfunction isDurableObjectNamespace(v: unknown): v is DurableObjectNamespace {\n\treturn (\n\t\tv instanceof Object &&\n\t\t/^(?:Loopback)?DurableObjectNamespace$/.test(v.constructor.name) &&\n\t\t\"newUniqueId\" in v &&\n\t\ttypeof v.newUniqueId === \"function\" &&\n\t\t\"idFromName\" in v &&\n\t\ttypeof v.idFromName === \"function\" &&\n\t\t\"idFromString\" in v &&\n\t\ttypeof v.idFromString === \"function\" &&\n\t\t\"get\" in v &&\n\t\ttypeof v.get === \"function\"\n\t);\n}\nfunction isDurableObjectStub(v: unknown): v is DurableObjectStub {\n\treturn (\n\t\ttypeof v === \"object\" &&\n\t\tv !== null &&\n\t\t(v.constructor.name === \"DurableObject\" ||\n\t\t\tv.constructor.name === \"WorkerRpc\") &&\n\t\t\"fetch\" in v &&\n\t\ttypeof v.fetch === \"function\" &&\n\t\t\"id\" in v &&\n\t\ttypeof v.id === \"object\"\n\t);\n}\n\n// Whilst `sameIsolatedNamespaces` depends on `getSerializedOptions()`,\n// `durableObjectBindingDesignators` is derived from the user Durable Object\n// config. If this were to change, the Miniflare options would change too\n// restarting this worker. This means we only need to compute this once, as it\n// will automatically invalidate when needed.\nlet sameIsolatedNamespaces: DurableObjectNamespace[] | undefined;\nfunction getSameIsolateNamespaces(): DurableObjectNamespace[] {\n\tif (sameIsolatedNamespaces !== undefined) {\n\t\treturn sameIsolatedNamespaces;\n\t}\n\tsameIsolatedNamespaces = [];\n\n\tconst options = getSerializedOptions();\n\tif (options.durableObjectBindingDesignators === undefined) {\n\t\treturn sameIsolatedNamespaces;\n\t}\n\n\tfor (const [key, designator] of options.durableObjectBindingDesignators) {\n\t\t// We're assuming the user isn't able to guess the current worker name, so\n\t\t// if a `scriptName` is set, the designator is for another worker.\n\t\tif (designator.scriptName !== undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst namespace = env[key] ?? (exports as Record<string, unknown>)?.[key];\n\t\tassert(\n\t\t\tisDurableObjectNamespace(namespace),\n\t\t\t`Expected ${key} to be a DurableObjectNamespace binding`\n\t\t);\n\t\tsameIsolatedNamespaces.push(namespace);\n\t}\n\n\treturn sameIsolatedNamespaces;\n}\n\nfunction assertSameIsolate(stub: DurableObjectStub) {\n\t// Make sure our special `cf` requests get handled correctly and aren't\n\t// routed to user fetch handlers\n\tconst idString = stub.id.toString();\n\tconst namespaces = getSameIsolateNamespaces();\n\t// Try to recreate the stub's ID using each same-isolate namespace.\n\t// `idFromString()` will throw if the ID is not for that namespace.\n\t// If a call succeeds, we know the ID is for an object in this isolate.\n\tfor (const namespace of namespaces) {\n\t\ttry {\n\t\t\tnamespace.idFromString(idString);\n\t\t\treturn;\n\t\t} catch {}\n\t}\n\t// If no calls succeed, we know the ID is for an object outside this isolate,\n\t// and we won't be able to use the `actionResults` map to share data.\n\tthrow new Error(\n\t\t\"Durable Object test helpers can only be used with stubs pointing to objects defined within the same worker.\"\n\t);\n}\n\nasync function runInStub<O extends DurableObject, R>(\n\tstub: Fetcher,\n\tcallback: (instance: O, state: DurableObjectState) => R | Promise<R>\n): Promise<R> {\n\tconst id = nextActionId++;\n\tactionResults.set(id, callback);\n\n\tconst response = await stub.fetch(\"http://x\", {\n\t\tcf: { [CF_KEY_ACTION]: id },\n\t\t// Prevent the runtime from following redirects returned by the callback,\n\t\t// which would re-enter `maybeHandleRunRequest` with a consumed action ID.\n\t\tredirect: \"manual\",\n\t});\n\n\t// `result` may be `undefined`\n\tassert(actionResults.has(id), `Expected action result for ${id}`);\n\tconst result = actionResults.get(id);\n\tactionResults.delete(id);\n\n\tif (result === kUseResponse) {\n\t\treturn response as R;\n\t} else if (response.ok) {\n\t\treturn result as R;\n\t} else {\n\t\tthrow result;\n\t}\n}\n\n// See public facing `cloudflare:test` types for docs\n// (`async` so it throws asynchronously/rejects)\nexport async function runInDurableObject<O extends DurableObject, R>(\n\tstub: DurableObjectStub,\n\tcallback: (instance: O, state: DurableObjectState) => R | Promise<R>\n): Promise<R> {\n\tif (!isDurableObjectStub(stub)) {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'runInDurableObject': parameter 1 is not of type 'DurableObjectStub'.\"\n\t\t);\n\t}\n\tif (typeof callback !== \"function\") {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'runInDurableObject': parameter 2 is not of type 'function'.\"\n\t\t);\n\t}\n\n\tassertSameIsolate(stub);\n\treturn runInStub(stub, callback);\n}\n\nasync function runAlarm(instance: DurableObject, state: DurableObjectState) {\n\tconst alarm = await state.storage.getAlarm();\n\tif (alarm === null) {\n\t\treturn false;\n\t}\n\tawait state.storage.deleteAlarm();\n\tawait instance.alarm?.();\n\treturn true;\n}\n// See public facing `cloudflare:test` types for docs\n// (`async` so it throws asynchronously/rejects)\nexport async function runDurableObjectAlarm(\n\tstub: DurableObjectStub\n): Promise<boolean /* ran */> {\n\tif (!isDurableObjectStub(stub)) {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'runDurableObjectAlarm': parameter 1 is not of type 'DurableObjectStub'.\"\n\t\t);\n\t}\n\treturn await runInDurableObject(stub, runAlarm);\n}\n\n/**\n * Internal method for running `callback` inside the I/O context of the\n * Runner Durable Object.\n *\n * Tests run in this context by default. This is required for performing\n * operations that use Vitest's RPC mechanism as the Durable Object\n * owns the RPC WebSocket. For example, importing modules or sending logs.\n * Trying to perform those operations from a different context (e.g. within\n * a `export default { fetch() {} }` handler or user Durable Object's `fetch()`\n * handler) without using this function will result in a `Cannot perform I/O on\n * behalf of a different request` error.\n */\nexport function runInRunnerObject<R>(\n\tcallback: (\n\t\tinstance: __VITEST_POOL_WORKERS_RUNNER_DURABLE_OBJECT__\n\t) => R | Promise<R>\n): Promise<R> {\n\t// Runner DO is ephemeral (ColoLocalActorNamespace), which has .get(name)\n\t// instead of the standard idFromName()/get(id) API.\n\tconst ns = env[\"__VITEST_POOL_WORKERS_RUNNER_OBJECT\"] as unknown as {\n\t\tget(name: string): Fetcher;\n\t};\n\tconst stub = ns.get(\"singleton\");\n\treturn runInStub(stub, callback);\n}\n\nexport async function maybeHandleRunRequest(\n\trequest: Request,\n\tinstance: unknown,\n\tstate?: DurableObjectState\n): Promise<Response | undefined> {\n\tconst actionId = request.cf?.[CF_KEY_ACTION];\n\tif (actionId === undefined) {\n\t\treturn;\n\t}\n\n\tassert(typeof actionId === \"number\", `Expected numeric ${CF_KEY_ACTION}`);\n\ttry {\n\t\tconst callback = actionResults.get(actionId);\n\t\tassert(typeof callback === \"function\", `Expected callback for ${actionId}`);\n\t\tconst result = await callback(instance, state);\n\t\t// If the callback returns a `Response`, we can't pass it back to the\n\t\t// caller through `actionResults`. If we did that, we'd get a `Cannot\n\t\t// perform I/O on behalf of a different Durable Object` error if we\n\t\t// tried to use it. Instead, we set a flag in `actionResults` that\n\t\t// instructs the caller to use the `Response` returned by\n\t\t// `DurableObjectStub#fetch()` directly.\n\t\tif (result instanceof Response) {\n\t\t\tactionResults.set(actionId, kUseResponse);\n\t\t\treturn result;\n\t\t} else {\n\t\t\tactionResults.set(actionId, result);\n\t\t}\n\t\treturn new Response(null, { status: 204 });\n\t} catch (e) {\n\t\tactionResults.set(actionId, e);\n\t\treturn new Response(null, { status: 500 });\n\t}\n}\n\nexport async function listDurableObjectIds(\n\tnamespace: DurableObjectNamespace\n): Promise<DurableObjectId[]> {\n\tif (!isDurableObjectNamespace(namespace)) {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'listDurableObjectIds': parameter 1 is not of type 'DurableObjectNamespace'.\"\n\t\t);\n\t}\n\n\t// To get an instance of `DurableObjectNamespace`, the user must've bound the\n\t// namespace to the test runner worker, since `DurableObjectNamespace` has no\n\t// user-accessible constructor. This means `namespace` must be in `globalEnv`.\n\t// We can use this to find the bound name for this binding. We inject a\n\t// mapping between bound names and unique keys for namespaces. We then use\n\t// this to get a unique key and find all IDs on disk.\n\tconst boundName = Object.entries(env).find(\n\t\t(entry) => namespace === entry[1]\n\t)?.[0];\n\tassert(boundName !== undefined, \"Expected to find bound name for namespace\");\n\n\tconst options = getSerializedOptions();\n\tconst designator = options.durableObjectBindingDesignators?.get(boundName);\n\tassert(designator !== undefined, \"Expected to find designator for namespace\");\n\n\tlet uniqueKey = designator.unsafeUniqueKey;\n\tif (uniqueKey === undefined) {\n\t\tconst scriptName = designator.scriptName ?? options.selfName;\n\t\tconst className = designator.className;\n\t\tuniqueKey = `${scriptName}-${className}`;\n\t}\n\n\tconst url = `http://placeholder/durable-objects?unique_key=${encodeURIComponent(\n\t\tuniqueKey\n\t)}`;\n\tconst res = await env.__VITEST_POOL_WORKERS_LOOPBACK_SERVICE.fetch(url);\n\tassert.strictEqual(res.status, 200);\n\tconst ids = await res.json();\n\tassert(Array.isArray(ids));\n\treturn ids.map((id) => {\n\t\tassert(typeof id === \"string\");\n\t\treturn namespace.idFromString(id);\n\t});\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * In production, Workers have a 30-second limit for `waitUntil` promises.\n * We use the same limit here. If promises are still pending after this,\n * they almost certainly indicate a bug (e.g. a `waitUntil` promise that\n * will never resolve). We log a warning and move on so the test suite\n * doesn't hang indefinitely.\n */\nlet WAIT_UNTIL_TIMEOUT = 30_000;\n\n/** @internal — only exposed for tests */\nexport function setWaitUntilTimeout(ms: number): void {\n\tWAIT_UNTIL_TIMEOUT = ms;\n}\n\nconst kTimedOut = Symbol(\"kTimedOut\");\n\n/**\n * Empty array and wait for all promises to resolve until no more added.\n * If a single promise rejects, the rejection will be passed-through.\n * If multiple promises reject, the rejections will be aggregated.\n *\n * If any batch of promises hasn't settled after {@link WAIT_UNTIL_TIMEOUT}ms,\n * a warning is logged and the remaining promises are abandoned.\n */\nexport async function waitForWaitUntil(\n\t/* mut */ waitUntil: unknown[]\n): Promise<void> {\n\tconst errors: unknown[] = [];\n\n\twhile (waitUntil.length > 0) {\n\t\tconst batch = waitUntil.splice(0);\n\t\tlet timeoutId: ReturnType<typeof setTimeout> | undefined;\n\t\tconst result = await Promise.race([\n\t\t\tPromise.allSettled(batch).then((results) => ({ results })),\n\t\t\tnew Promise<typeof kTimedOut>(\n\t\t\t\t(resolve) =>\n\t\t\t\t\t(timeoutId = setTimeout(() => resolve(kTimedOut), WAIT_UNTIL_TIMEOUT))\n\t\t\t),\n\t\t]);\n\t\tclearTimeout(timeoutId);\n\n\t\tif (result === kTimedOut) {\n\t\t\t__console.warn(\n\t\t\t\t`[vitest-pool-workers] ${batch.length} waitUntil promise(s) did not ` +\n\t\t\t\t\t`resolve within ${WAIT_UNTIL_TIMEOUT / 1000}s and will be abandoned. ` +\n\t\t\t\t\t`This normally means your Worker's waitUntil handler has a bug ` +\n\t\t\t\t\t`that prevents it from settling (e.g. a fetch that never completes ` +\n\t\t\t\t\t`or a missing resolve/reject call).`\n\t\t\t);\n\t\t\t// Stop draining — any promises added during this batch are also abandoned\n\t\t\twaitUntil.length = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\t// Record all rejected promises\n\t\tfor (const settled of result.results) {\n\t\t\tif (settled.status === \"rejected\") {\n\t\t\t\terrors.push(settled.reason);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (errors.length === 1) {\n\t\t// If there was only one rejection, rethrow it\n\t\tthrow errors[0];\n\t} else if (errors.length > 1) {\n\t\t// If there were more rejections, rethrow them all\n\t\tthrow new AggregateError(errors);\n\t}\n}\n\n// If isolated storage is enabled, we ensure all `waitUntil()`s are `await`ed at\n// the end of each test, as these may contain storage calls (e.g. caching\n// responses). Note we can't wait at the end of `.concurrent` tests, as we can't\n// track which `waitUntil()`s belong to which tests.\n//\n// If isolated storage is disabled, we ensure all `waitUntil()`s are `await`ed\n// at the end of each test *file*. This ensures we don't try to dispose the\n// runtime until all `waitUntil()`s complete.\nconst globalWaitUntil: unknown[] = [];\nexport function registerGlobalWaitUntil(promise: unknown) {\n\tglobalWaitUntil.push(promise);\n}\nexport function waitForGlobalWaitUntil(): Promise<void> {\n\treturn waitForWaitUntil(globalWaitUntil);\n}\n\nexport const handlerContextStore = new AsyncLocalStorage<ExecutionContext>();\nexport function registerHandlerAndGlobalWaitUntil(promise: Promise<unknown>) {\n\tconst handlerContext = handlerContextStore.getStore();\n\tif (handlerContext === undefined) {\n\t\tregisterGlobalWaitUntil(promise);\n\t} else {\n\t\t// `patchAndRunWithHandlerContext()` ensures handler `waitUntil()` calls\n\t\t// `registerGlobalWaitUntil()` too\n\t\thandlerContext.waitUntil(promise);\n\t}\n}\n","import { handlerContextStore, registerGlobalWaitUntil } from \"./wait-until\";\n\nconst patchedHandlerContexts = new WeakSet<ExecutionContext>();\n\n/**\n * Executes the given callback within the provided ExecutionContext,\n * patching the context to ensure that:\n *\n * - waitUntil calls are registered globally\n * - ctx.exports shows a warning if accessing missing exports\n */\nexport function patchAndRunWithHandlerContext<T>(\n\t/* mut */ ctx: ExecutionContext,\n\tcallback: () => T\n): T {\n\t// Ensure calls to `ctx.waitUntil()` registered with global wait-until\n\tif (!patchedHandlerContexts.has(ctx)) {\n\t\tpatchedHandlerContexts.add(ctx);\n\n\t\t// Patch `ctx.waitUntil()`\n\t\tconst originalWaitUntil = ctx.waitUntil;\n\t\tctx.waitUntil = (promise: Promise<unknown>) => {\n\t\t\tregisterGlobalWaitUntil(promise);\n\t\t\treturn originalWaitUntil.call(ctx, promise);\n\t\t};\n\n\t\t// Patch `ctx.exports`\n\t\tif (isCtxExportsEnabled(ctx.exports)) {\n\t\t\tObject.defineProperty(ctx, \"exports\", {\n\t\t\t\tvalue: getCtxExportsProxy(ctx.exports),\n\t\t\t});\n\t\t}\n\t}\n\treturn handlerContextStore.run(ctx, callback);\n}\n\n/**\n * Creates a proxy to the `ctx.exports` object that will warn the user if they attempt\n * to access an undefined property. This could be a valid mistake by the user or\n * it could mean that our static analysis of the main Worker's exports missed something.\n */\nexport function getCtxExportsProxy(\n\texports: Cloudflare.Exports\n): Cloudflare.Exports {\n\treturn new Proxy(exports, {\n\t\tget(target, p: keyof Cloudflare.Exports) {\n\t\t\tif (p in target) {\n\t\t\t\treturn target[p];\n\t\t\t}\n\t\t\tconsole.warn(\n\t\t\t\t`Attempted to access 'ctx.exports.${p}', which was not defined for the main Worker.\\n` +\n\t\t\t\t\t`Check that '${p}' is exported as an entry-point from the Worker.\\n` +\n\t\t\t\t\t`The '@cloudflare/vitest-pool-workers' integration tries to infer these exports by analyzing the source code of the main Worker.\\n`\n\t\t\t);\n\t\t\treturn undefined;\n\t\t},\n\t});\n}\n\n/**\n * Returns true if `ctx.exports` is enabled via compatibility flags.\n */\nexport function isCtxExportsEnabled(\n\texports: Cloudflare.Exports | undefined\n): exports is Cloudflare.Exports {\n\treturn (\n\t\t(globalThis as unknown as { Cloudflare: Cloudflare }).Cloudflare\n\t\t\t?.compatibilityFlags.enable_ctx_exports && exports !== undefined\n\t);\n}\n","import assert from \"node:assert\";\nimport {\n\tDurableObject as DurableObjectClass,\n\tenv as runtimeEnv,\n\tWorkerEntrypoint,\n\tWorkflowEntrypoint,\n} from \"cloudflare:workers\";\nimport { maybeHandleRunRequest, runInRunnerObject } from \"./durable-objects\";\nimport { getResolvedMainPath } from \"./env\";\nimport { patchAndRunWithHandlerContext } from \"./patch-ctx\";\n\n// =============================================================================\n// Common Entrypoint Helpers\n// =============================================================================\n\n/**\n * Internal method for importing a module using Vite's transformation and\n * execution pipeline. Can be called from any I/O context, and will ensure the\n * request is run from within the `__VITEST_POOL_WORKERS_RUNNER_DURABLE_OBJECT__`.\n */\nasync function importModule(\n\tspecifier: string\n): Promise<Record<string, unknown>> {\n\t/**\n\t * We need to run this import inside the Runner Object, or we get errors like:\n\t * - The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response. Refer to: https://developers.cloudflare.com/workers/observability/errors/\n\t * - Cannot perform I/O on behalf of a different Durable Object. I/O objects (such as streams, request/response bodies, and others) created in the context of one Durable Object cannot be accessed from a different Durable Object in the same isolate. This is a limitation of Cloudflare Workers which allows us to improve overall performance.\n\t */\n\treturn runInRunnerObject(() => {\n\t\treturn __vitest_mocker__.moduleRunner.import(specifier);\n\t});\n}\n\nconst IGNORED_KEYS = [\"self\"];\n\n/**\n * Create a class extending `superClass` with a `Proxy` as a `prototype`.\n * Unknown accesses on the `prototype` will defer to `getUnknownPrototypeKey()`.\n * `workerd` will only look for RPC methods/properties on the prototype, not the\n * instance. This helps avoid accidentally exposing things over RPC, but makes\n * things a little trickier for us...\n */\nfunction createProxyPrototypeClass<\n\tT extends\n\t\t| typeof WorkerEntrypoint\n\t\t| typeof DurableObjectClass\n\t\t| typeof WorkflowEntrypoint,\n\tExtraPrototype = unknown,\n>(\n\tsuperClass: T,\n\tgetUnknownPrototypeKey: (key: string) => unknown\n): T & { prototype: ExtraPrototype } {\n\t// Build a class with a \"Proxy\"-prototype, so we can intercept RPC calls\n\tfunction Class(...args: ConstructorParameters<typeof superClass>) {\n\t\t// Delay proxying prototype until construction, so workerd sees this as a\n\t\t// regular class when introspecting it. This check fails if we don't do this:\n\t\t// https://github.com/cloudflare/workerd/blob/9e915ed637d65adb3c57522607d2cd8b8d692b6b/src/workerd/io/worker.c%2B%2B#L1920-L1921\n\t\tClass.prototype = new Proxy(Class.prototype, {\n\t\t\tget(target, key, receiver) {\n\t\t\t\tconst value = Reflect.get(target, key, receiver);\n\t\t\t\tif (value !== undefined) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t\t// noinspection SuspiciousTypeOfGuard\n\t\t\t\tif (typeof key === \"symbol\" || IGNORED_KEYS.includes(key)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn getUnknownPrototypeKey.call(receiver, key as string);\n\t\t\t},\n\t\t});\n\n\t\treturn Reflect.construct(superClass, args, Class);\n\t}\n\n\tReflect.setPrototypeOf(Class.prototype, superClass.prototype);\n\tReflect.setPrototypeOf(Class, superClass);\n\n\treturn Class as unknown as T & { prototype: ExtraPrototype };\n}\n\n/**\n * Only properties and methods declared on the prototype can be accessed over\n * RPC. This function gets a property from the prototype if it's defined, and\n * throws a helpful error message if not. Note we need to distinguish between a\n * property that returns `undefined` and something not being defined at all.\n */\nfunction getRPCProperty(\n\tctor: WorkerEntrypointConstructor | DurableObjectConstructor,\n\tinstance:\n\t\t| WorkerEntrypoint<Record<string, unknown> | Cloudflare.Env>\n\t\t| DurableObjectClass<Record<string, unknown> | Cloudflare.Env>,\n\tkey: string\n): unknown {\n\tconst prototypeHasKey = Reflect.has(ctor.prototype, key);\n\tif (!prototypeHasKey) {\n\t\tconst quotedKey = JSON.stringify(key);\n\t\tconst instanceHasKey = Reflect.has(instance, key);\n\t\tlet message = \"\";\n\t\tif (instanceHasKey) {\n\t\t\tmessage = [\n\t\t\t\t`The RPC receiver's prototype does not implement ${quotedKey}, but the receiver instance does.`,\n\t\t\t\t\"Only properties and methods defined on the prototype can be accessed over RPC.\",\n\t\t\t\t`Ensure properties are declared like \\`get ${key}() { ... }\\` instead of \\`${key} = ...\\`,`,\n\t\t\t\t`and methods are declared like \\`${key}() { ... }\\` instead of \\`${key} = () => { ... }\\`.`,\n\t\t\t].join(\"\\n\");\n\t\t} else {\n\t\t\tmessage = `The RPC receiver does not implement ${quotedKey}.`;\n\t\t}\n\t\tthrow new TypeError(message);\n\t}\n\n\t// `receiver` is the value of `this` provided if a getter is encountered\n\treturn Reflect.get(/* target */ ctor.prototype, key, /* receiver */ instance);\n}\n\ntype RPCInvocationQueueOwner =\n\t| WorkerEntrypoint<Cloudflare.Env>\n\t| DurableObjectClass<Cloudflare.Env>\n\t| WorkflowEntrypoint<Cloudflare.Env>;\n\n/**\n * When calling RPC methods dynamically, we don't know whether the `property`\n * returned from `getSELFRPCProperty()` or `getDurableObjectRPCProperty()` below\n * is just a property or a method. If we just returned `property`, but the\n * client tried to call it as a method, `workerd` would throw an \"x is not a\n * function\" error.\n *\n * Instead, we return a *callable, custom thenable*. This behaves like a\n * function and a `Promise`! If `workerd` calls it, we'll wait for the promise\n * to resolve then forward the call. Otherwise, this just appears like a regular\n * async property. Note all client calls are async, so converting sync\n * properties and methods to async is fine here.\n *\n * Unfortunately, wrapping `property` with a `Proxy` and an `apply()` trap gives\n * `TypeError: Method Promise.prototype.then called on incompatible receiver #<Promise>`. :(\n */\nfunction getRPCPropertyCallableThenable(\n\tkey: string,\n\tproperty: Promise<unknown>,\n\tqueueOwner: RPCInvocationQueueOwner\n) {\n\tconst fn = async function (...args: unknown[]) {\n\t\treturn enqueueRPCInvocation(queueOwner, async (release) => {\n\t\t\ttry {\n\t\t\t\tconst maybeFn = await property;\n\t\t\t\tif (typeof maybeFn === \"function\") {\n\t\t\t\t\treturn maybeFn(...args);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new TypeError(`${JSON.stringify(key)} is not a function.`);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\trelease();\n\t\t\t}\n\t\t});\n\t} as Promise<unknown> & ((...args: unknown[]) => Promise<unknown>);\n\tfn.then = (onFulfilled, onRejected) => property.then(onFulfilled, onRejected);\n\tfn.catch = (onRejected) => property.catch(onRejected);\n\tfn.finally = (onFinally) => property.finally(onFinally);\n\treturn fn;\n}\n\nconst rpcInvocationQueues = new WeakMap<\n\tRPCInvocationQueueOwner,\n\tPromise<void>\n>();\n\n/**\n * Preserve the order in which dynamically-wrapped RPC methods begin executing.\n *\n * Resolving a property like `stub.method` may need to import user modules or\n * instantiate wrapper objects. If several calls are fired synchronously, those\n * async steps can otherwise complete out of order before the actual user method\n * is invoked. The queue is released as soon as invocation starts, so async RPC\n * completions can still run concurrently.\n */\nasync function enqueueRPCInvocation<T>(\n\towner: RPCInvocationQueueOwner,\n\tcallback: (release: () => void) => Promise<T>\n): Promise<T> {\n\tconst previous = rpcInvocationQueues.get(owner) ?? Promise.resolve();\n\tlet releaseStarted: (() => void) | undefined;\n\tconst started = new Promise<void>((resolve) => {\n\t\treleaseStarted = resolve;\n\t});\n\tconst release = () => {\n\t\tconst releaseStartedFn = releaseStarted;\n\t\tif (releaseStartedFn !== undefined) {\n\t\t\treleaseStartedFn();\n\t\t}\n\t};\n\tconst result = previous.catch(() => {}).then(() => callback(release));\n\trpcInvocationQueues.set(owner, started);\n\treturn result;\n}\n\n/**\n * `ctx` and `env` are defined as `protected` within `WorkerEntrypoint` and\n * `DurableObjectClass`. Usually this isn't a problem, as `protected` members\n * can be accessed from subclasses defined with `class extends` keywords.\n * Unfortunately, we have to define our classes with a `Proxy` prototype to\n * support forwarding RPC. This prevents us accessing `protected` members.\n * Instead, we define this function to extract these members, and provide type\n * safety for callers.\n */\nfunction getEntrypointState(instance: WorkerEntrypoint<Cloudflare.Env>): {\n\tctx: ExecutionContext;\n\tenv: Cloudflare.Env;\n};\nfunction getEntrypointState(instance: DurableObjectClass<Cloudflare.Env>): {\n\tctx: DurableObjectState;\n\tenv: Cloudflare.Env;\n};\nfunction getEntrypointState(\n\tinstance:\n\t\t| WorkerEntrypoint<Cloudflare.Env>\n\t\t| DurableObjectClass<Cloudflare.Env>\n) {\n\treturn instance as unknown as {\n\t\tctx: ExecutionContext | DurableObjectState;\n\t\tenv: Cloudflare.Env;\n\t};\n}\n\nconst WORKER_ENTRYPOINT_KEYS = [\n\t\"connect\",\n\t\"tailStream\",\n\t\"fetch\",\n\t\"tail\",\n\t\"trace\",\n\t\"scheduled\",\n\t\"queue\",\n\t\"test\",\n\t\"email\",\n] as const;\nconst DURABLE_OBJECT_KEYS = [\n\t\"connect\",\n\t\"fetch\",\n\t\"alarm\",\n\t\"webSocketMessage\",\n\t\"webSocketClose\",\n\t\"webSocketError\",\n] as const;\n\n// This type will grab the keys from T and remove \"branded\" keys\ntype UnbrandedKeys<T> = Exclude<keyof T, `__${string}_BRAND`>;\n\n// Check that we've included all possible keys\n// noinspection JSUnusedLocalSymbols\nconst _workerEntrypointExhaustive: (typeof WORKER_ENTRYPOINT_KEYS)[number] =\n\tundefined as unknown as UnbrandedKeys<WorkerEntrypoint<Cloudflare.Env>>;\n// noinspection JSUnusedLocalSymbols\nconst _durableObjectExhaustive: (typeof DURABLE_OBJECT_KEYS)[number] =\n\tundefined as unknown as UnbrandedKeys<DurableObjectClass<Cloudflare.Env>>;\n\n// =============================================================================\n// `WorkerEntrypoint` wrappers\n// =============================================================================\n\n// `WorkerEntrypoint` is `abstract`, so we need to cast before constructing\ntype WorkerEntrypointConstructor = {\n\tnew (\n\t\t...args: ConstructorParameters<typeof WorkerEntrypoint>\n\t): WorkerEntrypoint;\n};\n\n/**\n * Get the export to use for `entrypoint`. This is used for the `SELF` service\n * binding in `cloudflare:test`, which sets `entrypoint` to \"default\".\n * This requires importing the `main` module with Vite.\n */\nasync function getWorkerEntrypointExport(\n\tenv: Cloudflare.Env,\n\tentrypoint: string\n): Promise<{ mainPath: string; entrypointValue: unknown }> {\n\tconst mainPath = getResolvedMainPath(\"service\");\n\tconst mainModule = await importModule(mainPath);\n\tconst entrypointValue =\n\t\ttypeof mainModule === \"object\" &&\n\t\tmainModule !== null &&\n\t\tentrypoint in mainModule &&\n\t\tmainModule[entrypoint];\n\tif (!entrypointValue) {\n\t\tconst message =\n\t\t\t`${mainPath} does not export a ${entrypoint} entrypoint. \\`@cloudflare/vitest-pool-workers\\` does not support service workers or named entrypoints for \\`SELF\\`.\\n` +\n\t\t\t\"If you're using service workers, please migrate to the modules format: https://developers.cloudflare.com/workers/reference/migrate-to-module-workers.\";\n\t\tthrow new TypeError(message);\n\t}\n\treturn { mainPath, entrypointValue };\n}\n\n/**\n * Get a property named `key` from the user's `WorkerEntrypoint`. `wrapper` here\n * is an instance of a `WorkerEntrypoint` wrapper (i.e. the return value of\n * `createWorkerEntrypointWrapper()`). This requires importing the `main` module\n * with Vite, so will always return a `Promise.`\n */\nasync function getWorkerEntrypointRPCProperty(\n\twrapper: WorkerEntrypoint<Cloudflare.Env>,\n\tentrypoint: string,\n\tkey: string\n): Promise<unknown> {\n\tconst { ctx } = getEntrypointState(wrapper);\n\tconst { mainPath, entrypointValue } = await getWorkerEntrypointExport(\n\t\truntimeEnv as Cloudflare.Env,\n\t\tentrypoint\n\t);\n\t// Ensure constructor and properties execute with ctx `AsyncLocalStorage` set\n\treturn patchAndRunWithHandlerContext(ctx, () => {\n\t\t// Use the dynamic env from `cloudflare:workers` to respect `withEnv()`\n\t\tconst env = runtimeEnv as Cloudflare.Env;\n\t\tconst expectedWorkerEntrypointMessage = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \\`WorkerEntrypoint\\` for RPC`;\n\t\tif (typeof entrypointValue !== \"function\") {\n\t\t\tthrow new TypeError(expectedWorkerEntrypointMessage);\n\t\t}\n\t\tconst ctor = entrypointValue as WorkerEntrypointConstructor;\n\t\tconst instance = new ctor(ctx, env);\n\t\t// noinspection SuspiciousTypeOfGuard\n\t\tif (!(instance instanceof WorkerEntrypoint)) {\n\t\t\tthrow new TypeError(expectedWorkerEntrypointMessage);\n\t\t}\n\n\t\tconst value = getRPCProperty(ctor, instance, key);\n\t\tif (typeof value === \"function\") {\n\t\t\t// If this is a function, ensure it executes with ctx `AsyncLocalStorage`\n\t\t\t// set, and with a correctly bound `this`\n\t\t\treturn (...args: unknown[]) =>\n\t\t\t\tpatchAndRunWithHandlerContext(ctx, () => value.apply(instance, args));\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t});\n}\n\nexport function createWorkerEntrypointWrapper(\n\tentrypoint: string\n): typeof WorkerEntrypoint {\n\tconst Wrapper = createProxyPrototypeClass(\n\t\tWorkerEntrypoint,\n\t\tfunction (this: WorkerEntrypoint<Cloudflare.Env>, key) {\n\t\t\t// All `ExportedHandler` keys are reserved and cannot be called over RPC\n\t\t\tif ((DURABLE_OBJECT_KEYS as readonly string[]).includes(key)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst property = getWorkerEntrypointRPCProperty(this, entrypoint, key);\n\t\t\treturn getRPCPropertyCallableThenable(key, property, this);\n\t\t}\n\t);\n\n\t// Add prototype methods for all default handlers\n\tfor (const key of WORKER_ENTRYPOINT_KEYS) {\n\t\tWrapper.prototype[key] = async function (\n\t\t\tthis: WorkerEntrypoint<Cloudflare.Env>,\n\t\t\tthing: unknown\n\t\t) {\n\t\t\tconst { mainPath, entrypointValue } = await getWorkerEntrypointExport(\n\t\t\t\tthis.env,\n\t\t\t\tentrypoint\n\t\t\t);\n\n\t\t\treturn patchAndRunWithHandlerContext(this.ctx, () => {\n\t\t\t\tif (typeof entrypointValue === \"object\" && entrypointValue !== null) {\n\t\t\t\t\t// Assuming the user has defined an `ExportedHandler`\n\t\t\t\t\tconst maybeFn = (entrypointValue as Record<string, unknown>)[key];\n\t\t\t\t\tif (typeof maybeFn === \"function\") {\n\t\t\t\t\t\treturn maybeFn.call(entrypointValue, thing, runtimeEnv, this.ctx);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst message = `Expected ${entrypoint} export of ${mainPath} to define a \\`${key}()\\` function`;\n\t\t\t\t\t\tthrow new TypeError(message);\n\t\t\t\t\t}\n\t\t\t\t} else if (typeof entrypointValue === \"function\") {\n\t\t\t\t\t// Assuming the user has defined a `WorkerEntrypoint` subclass\n\t\t\t\t\tconst ctor = entrypointValue as WorkerEntrypointConstructor;\n\t\t\t\t\tconst instance = new ctor(this.ctx, runtimeEnv);\n\t\t\t\t\t// noinspection SuspiciousTypeOfGuard\n\t\t\t\t\tif (!(instance instanceof WorkerEntrypoint)) {\n\t\t\t\t\t\tconst message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \\`WorkerEntrypoint\\``;\n\t\t\t\t\t\tthrow new TypeError(message);\n\t\t\t\t\t}\n\t\t\t\t\tconst maybeFn = instance[key];\n\t\t\t\t\tif (typeof maybeFn === \"function\") {\n\t\t\t\t\t\treturn (maybeFn as (arg: unknown) => unknown).call(instance, thing);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst message = `Expected ${entrypoint} export of ${mainPath} to define a \\`${key}()\\` method`;\n\t\t\t\t\t\tthrow new TypeError(message);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Assuming the user has messed up\n\t\t\t\t\tconst message = `Expected ${entrypoint} export of ${mainPath} to be an object or a class, got ${entrypointValue}`;\n\t\t\t\t\tthrow new TypeError(message);\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\t}\n\treturn Wrapper;\n}\n\n// =============================================================================\n// `DurableObject` wrappers\n// =============================================================================\n\ntype DurableObjectConstructor = {\n\tnew (\n\t\t...args: ConstructorParameters<typeof DurableObjectClass>\n\t): DurableObject | DurableObjectClass;\n};\n\nconst kInstanceConstructor = Symbol(\"kInstanceConstructor\");\nconst kInstance = Symbol(\"kInstance\");\nconst kEnsureInstance = Symbol(\"kEnsureInstance\");\ntype DurableObjectWrapperExtraPrototype = {\n\t[kInstanceConstructor]: DurableObjectConstructor;\n\t[kInstance]:\n\t\t| DurableObject\n\t\t| DurableObjectClass<Record<string, unknown> | Cloudflare.Env>;\n\t[kEnsureInstance](): Promise<{\n\t\tmainPath: string;\n\t\tinstanceCtor: DurableObjectConstructor;\n\t\tinstance:\n\t\t\t| DurableObject\n\t\t\t| DurableObjectClass<Record<string, unknown> | Cloudflare.Env>;\n\t}>;\n};\ntype DurableObjectWrapper = DurableObjectClass<Cloudflare.Env> &\n\tDurableObjectWrapperExtraPrototype;\n\nasync function getDurableObjectRPCProperty(\n\twrapper: DurableObjectWrapper,\n\tclassName: string,\n\tkey: string\n): Promise<unknown> {\n\tconst { mainPath, instanceCtor, instance } = await wrapper[kEnsureInstance]();\n\tif (!(instance instanceof DurableObjectClass)) {\n\t\tconst message = `Expected ${className} exported by ${mainPath} be a subclass of \\`DurableObject\\` for RPC`;\n\t\tthrow new TypeError(message);\n\t}\n\tconst value = getRPCProperty(instanceCtor, instance, key);\n\tif (typeof value === \"function\") {\n\t\t// If this is a function, ensure correctly bound `this`\n\t\treturn value.bind(instance);\n\t} else {\n\t\treturn value;\n\t}\n}\n\nexport function createDurableObjectWrapper(\n\tclassName: string\n): typeof DurableObjectClass {\n\tconst Wrapper = createProxyPrototypeClass<\n\t\ttypeof DurableObjectClass,\n\t\tDurableObjectWrapperExtraPrototype\n\t>(DurableObjectClass, function (this: DurableObjectWrapper, key) {\n\t\t// All `ExportedHandler` keys are reserved and cannot be called over RPC\n\t\tif ((WORKER_ENTRYPOINT_KEYS as readonly string[]).includes(key)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst property = getDurableObjectRPCProperty(this, className, key);\n\t\treturn getRPCPropertyCallableThenable(key, property, this);\n\t});\n\n\tWrapper.prototype[kEnsureInstance] = async function (\n\t\tthis: DurableObjectWrapper\n\t) {\n\t\tconst { ctx, env } = getEntrypointState(this);\n\t\tconst mainPath = getResolvedMainPath(\"Durable Object\");\n\t\t// `ensureInstance()` may be called multiple times concurrently.\n\t\t// We're assuming `importModule()` will only import the module once.\n\t\tconst mainModule = await importModule(mainPath);\n\t\tconst constructor = mainModule[className];\n\t\tif (typeof constructor !== \"function\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`${mainPath} does not export a ${className} Durable Object`\n\t\t\t);\n\t\t}\n\t\tthis[kInstanceConstructor] ??= constructor as DurableObjectConstructor;\n\t\tif (this[kInstanceConstructor] !== constructor) {\n\t\t\t// This would be if the module was invalidated\n\t\t\t// (i.e. source file changed), then the Durable Object was `fetch()`ed\n\t\t\t// again. We reset all Durable Object instances between each test, so it's\n\t\t\t// unlikely multiple constructors would be used by the same instance,\n\t\t\t// unless the user did something funky with Durable Objects outside tests.\n\t\t\tawait ctx.blockConcurrencyWhile<never>(() => {\n\t\t\t\t// Throw inside `blockConcurrencyWhile()` to abort this object\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${mainPath} changed, invalidating this Durable Object. ` +\n\t\t\t\t\t\t\"Please retry the `DurableObjectStub#fetch()` call.\"\n\t\t\t\t);\n\t\t\t});\n\t\t\tassert.fail(\"Unreachable\");\n\t\t}\n\t\tif (this[kInstance] === undefined) {\n\t\t\tthis[kInstance] = new this[kInstanceConstructor](ctx, env);\n\t\t\t// Wait for any `blockConcurrencyWhile()`s in the constructor to complete\n\t\t\tawait ctx.blockConcurrencyWhile(async () => {});\n\t\t}\n\t\treturn {\n\t\t\tmainPath,\n\t\t\tinstanceCtor: this[kInstanceConstructor],\n\t\t\tinstance: this[kInstance],\n\t\t};\n\t};\n\n\t// Add prototype method for `fetch` handler to handle `runInDurableObject()`s\n\tWrapper.prototype.fetch = async function (\n\t\tthis: DurableObjectWrapper,\n\t\trequest: Request\n\t) {\n\t\tconst { ctx } = getEntrypointState(this);\n\n\t\t// Make sure we've initialised user code\n\t\tconst { mainPath, instance } = await this[kEnsureInstance]();\n\n\t\t// If this is an internal Durable Object action, handle it...\n\t\tconst response = await maybeHandleRunRequest(request, instance, ctx);\n\t\tif (response !== undefined) {\n\t\t\treturn response;\n\t\t}\n\n\t\t// Otherwise, pass through to the user code\n\t\tif (instance.fetch === undefined) {\n\t\t\tconst message = `${className} exported by ${mainPath} does not define a \\`fetch()\\` method`;\n\t\t\tthrow new TypeError(message);\n\t\t}\n\t\treturn instance.fetch(request);\n\t};\n\n\t// Add prototype methods for all other default handlers\n\tfor (const key of DURABLE_OBJECT_KEYS) {\n\t\tif (key === \"fetch\") {\n\t\t\tcontinue;\n\t\t} // `fetch()` has special handling above\n\t\tWrapper.prototype[key] = async function (\n\t\t\tthis: DurableObjectWrapper,\n\t\t\t...args: unknown[]\n\t\t) {\n\t\t\tconst { mainPath, instance } = await this[kEnsureInstance]();\n\t\t\tconst maybeFn = instance[key];\n\t\t\tif (typeof maybeFn === \"function\") {\n\t\t\t\treturn (maybeFn as (...a: unknown[]) => void).apply(instance, args);\n\t\t\t} else {\n\t\t\t\tconst message = `${className} exported by ${mainPath} does not define a \\`${key}()\\` method`;\n\t\t\t\tthrow new TypeError(message);\n\t\t\t}\n\t\t};\n\t}\n\n\treturn Wrapper;\n}\n\n// =============================================================================\n// `WorkflowEntrypoint` wrappers\n// =============================================================================\n\ntype WorkflowEntrypointConstructor = {\n\tnew (\n\t\t...args: ConstructorParameters<typeof WorkflowEntrypoint>\n\t): WorkflowEntrypoint;\n};\n\nexport function createWorkflowEntrypointWrapper(entrypoint: string) {\n\tconst Wrapper = createProxyPrototypeClass(\n\t\tWorkflowEntrypoint,\n\t\tfunction (this: WorkflowEntrypoint<Cloudflare.Env>, key) {\n\t\t\t// only Workflow `run` should be exposed over RPC\n\t\t\tif (![\"run\"].includes(key)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst property = getWorkerEntrypointRPCProperty(\n\t\t\t\tthis as unknown as WorkerEntrypoint<Cloudflare.Env>,\n\t\t\t\tentrypoint,\n\t\t\t\tkey\n\t\t\t);\n\t\t\treturn getRPCPropertyCallableThenable(key, property, this);\n\t\t}\n\t);\n\n\tWrapper.prototype.run = async function (\n\t\tthis: WorkflowEntrypoint<Cloudflare.Env>,\n\t\t...args\n\t) {\n\t\tconst { mainPath, entrypointValue } = await getWorkerEntrypointExport(\n\t\t\truntimeEnv,\n\t\t\tentrypoint\n\t\t);\n\t\t// workflow entrypoint value should always be a constructor\n\t\tif (typeof entrypointValue === \"function\") {\n\t\t\t// Assuming the user has defined a `WorkflowEntrypoint` subclass\n\t\t\tconst ctor = entrypointValue as WorkflowEntrypointConstructor;\n\t\t\tconst instance = new ctor(this.ctx, runtimeEnv);\n\t\t\t// noinspection SuspiciousTypeOfGuard\n\t\t\tif (!(instance instanceof WorkflowEntrypoint)) {\n\t\t\t\tconst message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \\`WorkflowEntrypoint\\``;\n\t\t\t\tthrow new TypeError(message);\n\t\t\t}\n\t\t\tconst maybeFn = instance[\"run\"];\n\t\t\tif (typeof maybeFn === \"function\") {\n\t\t\t\treturn patchAndRunWithHandlerContext(this.ctx, () =>\n\t\t\t\t\tmaybeFn.call(instance, ...args)\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconst message = `Expected ${entrypoint} export of ${mainPath} to define a \\`run()\\` method, but got ${typeof maybeFn}`;\n\t\t\t\tthrow new TypeError(message);\n\t\t\t}\n\t\t} else {\n\t\t\t// Assuming the user has messed up\n\t\t\tconst message = `Expected ${entrypoint} export of ${mainPath} to be a subclass of \\`WorkflowEntrypoint\\`, but got ${entrypointValue}`;\n\t\t\tthrow new TypeError(message);\n\t\t}\n\t};\n\n\treturn Wrapper;\n}\n","import { exports } from \"cloudflare:workers\";\nimport { env } from \"./env\";\nimport { getCtxExportsProxy, isCtxExportsEnabled } from \"./patch-ctx\";\nimport { registerGlobalWaitUntil, waitForWaitUntil } from \"./wait-until\";\n\n// `workerd` doesn't allow these internal classes to be constructed directly.\n// To replicate this behaviour require this unique symbol to be specified as the\n// first constructor argument. If this is missing, throw `Illegal invocation`.\nconst kConstructFlag = Symbol(\"kConstructFlag\");\n\n// See public facing `cloudflare:test` types for docs.\n\n// =============================================================================\n// `ExecutionContext`\n// =============================================================================\n\nconst kWaitUntil = Symbol(\"kWaitUntil\");\nclass ExecutionContext {\n\t// https://github.com/cloudflare/workerd/blob/v1.20231218.0/src/workerd/api/global-scope.h#L168\n\t[kWaitUntil]: unknown[] = [];\n\n\tconstructor(flag: typeof kConstructFlag) {\n\t\tif (flag !== kConstructFlag) {\n\t\t\tthrow new TypeError(\"Illegal constructor\");\n\t\t}\n\t}\n\n\t// Expose the ctx.exports from the main \"SELF\" Worker if there is one.\n\treadonly exports = isCtxExportsEnabled(exports)\n\t\t? getCtxExportsProxy(exports)\n\t\t: undefined;\n\n\twaitUntil(promise: unknown) {\n\t\tif (!(this instanceof ExecutionContext)) {\n\t\t\tthrow new TypeError(\"Illegal invocation\");\n\t\t}\n\t\tthis[kWaitUntil].push(promise);\n\t\tregisterGlobalWaitUntil(promise);\n\t}\n\n\tpassThroughOnException(): void {}\n}\nexport function createExecutionContext(): ExecutionContext {\n\treturn new ExecutionContext(kConstructFlag);\n}\n\nfunction isExecutionContextLike(v: unknown): v is { [kWaitUntil]: unknown[] } {\n\treturn (\n\t\ttypeof v === \"object\" &&\n\t\tv !== null &&\n\t\tkWaitUntil in v &&\n\t\tArray.isArray(v[kWaitUntil])\n\t);\n}\nexport async function waitOnExecutionContext(ctx: unknown): Promise<void> {\n\tif (!isExecutionContextLike(ctx)) {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'getWaitUntil': parameter 1 is not of type 'ExecutionContext'.\\n\" +\n\t\t\t\t\"You must call 'createExecutionContext()' or 'createPagesEventContext()' to get an 'ExecutionContext' instance.\"\n\t\t);\n\t}\n\treturn waitForWaitUntil(ctx[kWaitUntil]);\n}\n\n// =============================================================================\n// `ScheduledController`\n// =============================================================================\n\nclass ScheduledController {\n\t// https://github.com/cloudflare/workerd/blob/v1.20231218.0/src/workerd/api/scheduled.h#L35\n\treadonly scheduledTime!: number;\n\treadonly cron!: string;\n\n\tconstructor(flag: typeof kConstructFlag, options?: FetcherScheduledOptions) {\n\t\tif (flag !== kConstructFlag) {\n\t\t\tthrow new TypeError(\"Illegal constructor\");\n\t\t}\n\n\t\tconst scheduledTime = Number(options?.scheduledTime ?? Date.now());\n\t\tconst cron = String(options?.cron ?? \"\");\n\n\t\t// Match `JSG_READONLY_INSTANCE_PROPERTY` behaviour\n\t\tObject.defineProperties(this, {\n\t\t\tscheduledTime: {\n\t\t\t\tget() {\n\t\t\t\t\treturn scheduledTime;\n\t\t\t\t},\n\t\t\t},\n\t\t\tcron: {\n\t\t\t\tget() {\n\t\t\t\t\treturn cron;\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\tnoRetry(): void {\n\t\tif (!(this instanceof ScheduledController)) {\n\t\t\tthrow new TypeError(\"Illegal invocation\");\n\t\t}\n\t}\n}\nexport function createScheduledController(\n\toptions?: FetcherScheduledOptions\n): ScheduledController {\n\tif (options !== undefined && typeof options !== \"object\") {\n\t\tthrow new TypeError(\n\t\t\t\"Failed to execute 'createScheduledController': parameter 1 is not of type 'ScheduledOptions'.\"\n\t