@kiwa-test/edge 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +866 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +519 -1
- package/dist/index.d.ts +519 -1
- package/dist/index.js +828 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/invoke-edge-handler.ts","../src/kv-mock.ts"],"sourcesContent":["// Edge runtime fetch handler test helper for kiwa (Issue #522).\n//\n// Cloudflare Workers / Vercel Edge / generic ESM-style handlers expose a\n// `fetch(request, env, ctx)` entry point. kiwa provides a simulated env\n// (binding bag: KV namespaces, R2 buckets, D1 databases, vars) + an\n// ExecutionContext stub that captures `waitUntil` / `passThroughOnException`\n// calls so tests can assert on background promises without real Workers\n// scheduler.\n\nimport type { KVNamespace } from './kv-mock.js';\n\nexport interface SimulatedExecutionContext {\n waitUntil(promise: Promise<unknown>): void;\n passThroughOnException(): void;\n readonly waitedPromises: Promise<unknown>[];\n passThroughCalled: boolean;\n}\n\nexport interface EdgeEnvBindings {\n readonly [bindingName: string]: KVNamespace | Record<string, unknown> | string | undefined;\n}\n\nexport type EdgeFetchHandler<TEnv extends EdgeEnvBindings = EdgeEnvBindings> = (\n request: Request,\n env: TEnv,\n ctx: SimulatedExecutionContext,\n) => Promise<Response> | Response;\n\nexport interface InvokeEdgeHandlerOptions<TEnv extends EdgeEnvBindings = EdgeEnvBindings> {\n readonly handler: EdgeFetchHandler<TEnv>;\n readonly url: string;\n readonly method?: string;\n readonly headers?: Record<string, string>;\n readonly formData?: Record<string, string>;\n readonly jsonBody?: unknown;\n readonly env: TEnv;\n}\n\nexport interface InvokeEdgeHandlerResult {\n readonly response: Response;\n readonly redirect: { url: string; status: number } | null;\n readonly ctx: SimulatedExecutionContext;\n readonly error: unknown;\n}\n\nfunction buildRequest(opts: {\n readonly url: string;\n readonly method?: string;\n readonly headers?: Record<string, string>;\n readonly formData?: Record<string, string>;\n readonly jsonBody?: unknown;\n}): Request {\n const headers = new Headers();\n for (const [name, value] of Object.entries(opts.headers ?? {})) {\n headers.set(name, value);\n }\n let body: BodyInit | null = null;\n if (typeof opts.formData !== 'undefined') {\n const fd = new FormData();\n for (const [name, value] of Object.entries(opts.formData)) {\n fd.set(name, value);\n }\n body = fd;\n } else if (typeof opts.jsonBody !== 'undefined') {\n body = JSON.stringify(opts.jsonBody);\n if (!headers.has('content-type')) headers.set('content-type', 'application/json');\n }\n const method = opts.method ?? (body === null ? 'GET' : 'POST');\n return new Request(opts.url, body === null ? { method, headers } : { method, headers, body });\n}\n\nfunction createCtx(): SimulatedExecutionContext {\n const waitedPromises: Promise<unknown>[] = [];\n const ctx: SimulatedExecutionContext = {\n waitedPromises,\n passThroughCalled: false,\n waitUntil(promise) {\n waitedPromises.push(promise);\n },\n passThroughOnException() {\n ctx.passThroughCalled = true;\n },\n };\n return ctx;\n}\n\n/**\n * Invoke an edge runtime fetch handler in isolation and capture the returned\n * Response + ExecutionContext side effects. The caller supplies `env` so KV /\n * R2 / vars stay explicit in each test (no global state).\n */\nexport async function invokeEdgeHandler<TEnv extends EdgeEnvBindings = EdgeEnvBindings>(\n opts: InvokeEdgeHandlerOptions<TEnv>,\n): Promise<InvokeEdgeHandlerResult> {\n const reqOpts: {\n readonly url: string;\n readonly method?: string;\n readonly headers?: Record<string, string>;\n readonly formData?: Record<string, string>;\n readonly jsonBody?: unknown;\n } = {\n url: opts.url,\n ...(typeof opts.method !== 'undefined' ? { method: opts.method } : {}),\n ...(typeof opts.headers !== 'undefined' ? { headers: opts.headers } : {}),\n ...(typeof opts.formData !== 'undefined' ? { formData: opts.formData } : {}),\n ...(typeof opts.jsonBody !== 'undefined' ? { jsonBody: opts.jsonBody } : {}),\n };\n const request = buildRequest(reqOpts);\n const ctx = createCtx();\n let response: Response;\n let redirect: { url: string; status: number } | null = null;\n let error: unknown;\n try {\n response = await opts.handler(request, opts.env, ctx);\n if (response.status >= 300 && response.status < 400) {\n redirect = {\n url: response.headers.get('location') ?? '',\n status: response.status,\n };\n }\n } catch (caught) {\n response = new Response(null, { status: 500 });\n error = caught;\n }\n return { response, redirect, ctx, error };\n}\n","// Minimal Cloudflare KV namespace mock for kiwa edge tests.\n//\n// Implements the subset that production Workers code touches in practice:\n// - `get(key)` / `get(key, { type: 'json' | 'text' | 'arrayBuffer' })`\n// - `put(key, value, options?)` (TTL captured but ignored)\n// - `delete(key)`\n// - `list({ prefix?, limit? })` (no cursor pagination)\n//\n// Real Workers KV is eventually consistent and has a 1KB/key/24h propagation;\n// kiwa's mock is strongly consistent because tests need determinism.\n\nexport interface KVNamespacePutOptions {\n readonly expirationTtl?: number;\n readonly metadata?: Record<string, unknown>;\n}\n\nexport interface KVNamespaceListOptions {\n readonly prefix?: string;\n readonly limit?: number;\n}\n\nexport interface KVNamespaceListResult {\n readonly keys: ReadonlyArray<{ readonly name: string; readonly metadata?: Record<string, unknown> }>;\n readonly list_complete: true;\n}\n\nexport interface KVNamespace {\n get(key: string): Promise<string | null>;\n get(key: string, type: 'text'): Promise<string | null>;\n get<T>(key: string, type: 'json'): Promise<T | null>;\n get(key: string, type: 'arrayBuffer'): Promise<ArrayBuffer | null>;\n put(key: string, value: string, options?: KVNamespacePutOptions): Promise<void>;\n delete(key: string): Promise<void>;\n list(options?: KVNamespaceListOptions): Promise<KVNamespaceListResult>;\n}\n\nexport interface KVMockEntry {\n readonly value: string;\n readonly metadata?: Record<string, unknown>;\n}\n\nexport function createKvNamespace(initial: Record<string, string> = {}): KVNamespace {\n const store = new Map<string, KVMockEntry>();\n for (const [key, value] of Object.entries(initial)) {\n store.set(key, { value });\n }\n async function getImpl(key: string, type?: 'text' | 'json' | 'arrayBuffer'): Promise<unknown> {\n const entry = store.get(key);\n if (typeof entry === 'undefined') return null;\n if (type === 'json') return JSON.parse(entry.value) as unknown;\n if (type === 'arrayBuffer') {\n const enc = new TextEncoder().encode(entry.value);\n return enc.buffer.slice(enc.byteOffset, enc.byteOffset + enc.byteLength) as ArrayBuffer;\n }\n return entry.value;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const get = getImpl as any;\n return {\n get,\n async put(key: string, value: string, options?: KVNamespacePutOptions): Promise<void> {\n const metadata = options?.metadata;\n store.set(key, typeof metadata === 'undefined' ? { value } : { value, metadata });\n },\n async delete(key: string): Promise<void> {\n store.delete(key);\n },\n async list(options?: KVNamespaceListOptions): Promise<KVNamespaceListResult> {\n const prefix = options?.prefix ?? '';\n const limit = options?.limit ?? 1000;\n const keys: Array<{ name: string; metadata?: Record<string, unknown> }> = [];\n for (const [name, entry] of store.entries()) {\n if (!name.startsWith(prefix)) continue;\n if (keys.length >= limit) break;\n keys.push(typeof entry.metadata === 'undefined' ? { name } : { name, metadata: entry.metadata });\n }\n return { keys, list_complete: true };\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/invoke-edge-handler.ts","../src/kv-mock.ts","../src/semantics/types.ts","../src/semantics/fidelity.ts","../src/semantics/durable-object.ts","../src/semantics/websocket-edge.ts","../src/semantics/edge-kv.ts","../src/semantics/geo-replicated.ts","../src/semantics/cron-trigger.ts","../src/semantics/subrequest-limit.ts","../src/semantics/cpu-time-limit.ts","../src/semantics/streaming-response.ts"],"sourcesContent":["// Edge runtime fetch handler test helper for kiwa (Issue #522).\n//\n// Cloudflare Workers / Vercel Edge / generic ESM-style handlers expose a\n// `fetch(request, env, ctx)` entry point. kiwa provides a simulated env\n// (binding bag: KV namespaces, R2 buckets, D1 databases, vars) + an\n// ExecutionContext stub that captures `waitUntil` / `passThroughOnException`\n// calls so tests can assert on background promises without real Workers\n// scheduler.\n\nimport type { KVNamespace } from './kv-mock.js';\n\nexport interface SimulatedExecutionContext {\n waitUntil(promise: Promise<unknown>): void;\n passThroughOnException(): void;\n readonly waitedPromises: Promise<unknown>[];\n passThroughCalled: boolean;\n}\n\nexport interface EdgeEnvBindings {\n readonly [bindingName: string]: KVNamespace | Record<string, unknown> | string | undefined;\n}\n\nexport type EdgeFetchHandler<TEnv extends EdgeEnvBindings = EdgeEnvBindings> = (\n request: Request,\n env: TEnv,\n ctx: SimulatedExecutionContext,\n) => Promise<Response> | Response;\n\nexport interface InvokeEdgeHandlerOptions<TEnv extends EdgeEnvBindings = EdgeEnvBindings> {\n readonly handler: EdgeFetchHandler<TEnv>;\n readonly url: string;\n readonly method?: string;\n readonly headers?: Record<string, string>;\n readonly formData?: Record<string, string>;\n readonly jsonBody?: unknown;\n readonly env: TEnv;\n}\n\nexport interface InvokeEdgeHandlerResult {\n readonly response: Response;\n readonly redirect: { url: string; status: number } | null;\n readonly ctx: SimulatedExecutionContext;\n readonly error: unknown;\n}\n\nfunction buildRequest(opts: {\n readonly url: string;\n readonly method?: string;\n readonly headers?: Record<string, string>;\n readonly formData?: Record<string, string>;\n readonly jsonBody?: unknown;\n}): Request {\n const headers = new Headers();\n for (const [name, value] of Object.entries(opts.headers ?? {})) {\n headers.set(name, value);\n }\n let body: BodyInit | null = null;\n if (typeof opts.formData !== 'undefined') {\n const fd = new FormData();\n for (const [name, value] of Object.entries(opts.formData)) {\n fd.set(name, value);\n }\n body = fd;\n } else if (typeof opts.jsonBody !== 'undefined') {\n body = JSON.stringify(opts.jsonBody);\n if (!headers.has('content-type')) headers.set('content-type', 'application/json');\n }\n const method = opts.method ?? (body === null ? 'GET' : 'POST');\n return new Request(opts.url, body === null ? { method, headers } : { method, headers, body });\n}\n\nfunction createCtx(): SimulatedExecutionContext {\n const waitedPromises: Promise<unknown>[] = [];\n const ctx: SimulatedExecutionContext = {\n waitedPromises,\n passThroughCalled: false,\n waitUntil(promise) {\n waitedPromises.push(promise);\n },\n passThroughOnException() {\n ctx.passThroughCalled = true;\n },\n };\n return ctx;\n}\n\n/**\n * Invoke an edge runtime fetch handler in isolation and capture the returned\n * Response + ExecutionContext side effects. The caller supplies `env` so KV /\n * R2 / vars stay explicit in each test (no global state).\n */\nexport async function invokeEdgeHandler<TEnv extends EdgeEnvBindings = EdgeEnvBindings>(\n opts: InvokeEdgeHandlerOptions<TEnv>,\n): Promise<InvokeEdgeHandlerResult> {\n const reqOpts: {\n readonly url: string;\n readonly method?: string;\n readonly headers?: Record<string, string>;\n readonly formData?: Record<string, string>;\n readonly jsonBody?: unknown;\n } = {\n url: opts.url,\n ...(typeof opts.method !== 'undefined' ? { method: opts.method } : {}),\n ...(typeof opts.headers !== 'undefined' ? { headers: opts.headers } : {}),\n ...(typeof opts.formData !== 'undefined' ? { formData: opts.formData } : {}),\n ...(typeof opts.jsonBody !== 'undefined' ? { jsonBody: opts.jsonBody } : {}),\n };\n const request = buildRequest(reqOpts);\n const ctx = createCtx();\n let response: Response;\n let redirect: { url: string; status: number } | null = null;\n let error: unknown;\n try {\n response = await opts.handler(request, opts.env, ctx);\n if (response.status >= 300 && response.status < 400) {\n redirect = {\n url: response.headers.get('location') ?? '',\n status: response.status,\n };\n }\n } catch (caught) {\n response = new Response(null, { status: 500 });\n error = caught;\n }\n return { response, redirect, ctx, error };\n}\n","// Minimal Cloudflare KV namespace mock for kiwa edge tests.\n//\n// Implements the subset that production Workers code touches in practice:\n// - `get(key)` / `get(key, { type: 'json' | 'text' | 'arrayBuffer' })`\n// - `put(key, value, options?)` (TTL captured but ignored)\n// - `delete(key)`\n// - `list({ prefix?, limit? })` (no cursor pagination)\n//\n// Real Workers KV is eventually consistent and has a 1KB/key/24h propagation;\n// kiwa's mock is strongly consistent because tests need determinism.\n\nexport interface KVNamespacePutOptions {\n readonly expirationTtl?: number;\n readonly metadata?: Record<string, unknown>;\n}\n\nexport interface KVNamespaceListOptions {\n readonly prefix?: string;\n readonly limit?: number;\n}\n\nexport interface KVNamespaceListResult {\n readonly keys: ReadonlyArray<{ readonly name: string; readonly metadata?: Record<string, unknown> }>;\n readonly list_complete: true;\n}\n\nexport interface KVNamespace {\n get(key: string): Promise<string | null>;\n get(key: string, type: 'text'): Promise<string | null>;\n get<T>(key: string, type: 'json'): Promise<T | null>;\n get(key: string, type: 'arrayBuffer'): Promise<ArrayBuffer | null>;\n put(key: string, value: string, options?: KVNamespacePutOptions): Promise<void>;\n delete(key: string): Promise<void>;\n list(options?: KVNamespaceListOptions): Promise<KVNamespaceListResult>;\n}\n\nexport interface KVMockEntry {\n readonly value: string;\n readonly metadata?: Record<string, unknown>;\n}\n\nexport function createKvNamespace(initial: Record<string, string> = {}): KVNamespace {\n const store = new Map<string, KVMockEntry>();\n for (const [key, value] of Object.entries(initial)) {\n store.set(key, { value });\n }\n async function getImpl(key: string, type?: 'text' | 'json' | 'arrayBuffer'): Promise<unknown> {\n const entry = store.get(key);\n if (typeof entry === 'undefined') return null;\n if (type === 'json') return JSON.parse(entry.value) as unknown;\n if (type === 'arrayBuffer') {\n const enc = new TextEncoder().encode(entry.value);\n return enc.buffer.slice(enc.byteOffset, enc.byteOffset + enc.byteLength) as ArrayBuffer;\n }\n return entry.value;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const get = getImpl as any;\n return {\n get,\n async put(key: string, value: string, options?: KVNamespacePutOptions): Promise<void> {\n const metadata = options?.metadata;\n store.set(key, typeof metadata === 'undefined' ? { value } : { value, metadata });\n },\n async delete(key: string): Promise<void> {\n store.delete(key);\n },\n async list(options?: KVNamespaceListOptions): Promise<KVNamespaceListResult> {\n const prefix = options?.prefix ?? '';\n const limit = options?.limit ?? 1000;\n const keys: Array<{ name: string; metadata?: Record<string, unknown> }> = [];\n for (const [name, entry] of store.entries()) {\n if (!name.startsWith(prefix)) continue;\n if (keys.length >= limit) break;\n keys.push(typeof entry.metadata === 'undefined' ? { name } : { name, metadata: entry.metadata });\n }\n return { keys, list_complete: true };\n },\n };\n}\n","/**\n * Advanced edge semantics — platform-neutral axis SSOT.\n *\n * v0.1 edge mocks only carried fetch invocation + lightweight KV helpers.\n * v0.2 adds 8 production semantics that edge runtimes expose differently —\n * Durable Objects, websocket upgrades, edge KV, geo replication, cron triggers,\n * subrequest limits, CPU time limits, and streaming responses. Each axis is\n * expressed as a small pure state-machine helper that returns a neutral\n * envelope, so downstream tests can drive the axis without knowing the\n * platform's payload dialect.\n */\nexport type EdgePlatform = 'cloudflare' | 'vercel' | 'deno';\n\nexport type EdgeAxis =\n | 'durable-object'\n | 'websocket-edge'\n | 'edge-kv'\n | 'geo-replicated'\n | 'cron-trigger'\n | 'subrequest-limit'\n | 'cpu-time-limit'\n | 'streaming-response';\n\n/**\n * Platform-neutral event names used inside the axis helpers. Real edge\n * platforms expose different string ids (Cloudflare `durable_object.fetch`,\n * Vercel `edge_function.session_affinity`, Deno Deploy `deploy.stateful_fetch`)\n * — the {@link platformEventName} map handles the translation. Tests can\n * assert on the neutral name via `step.neutralEvent` or on the\n * platform-specific one via `step.platformEvent`.\n */\nexport type NeutralEventName =\n // durable object / stateful affinity\n | 'durable-object.created'\n | 'durable-object.requested'\n | 'durable-object.alarm-fired'\n | 'durable-object.storage-written'\n // websocket edge\n | 'websocket.upgrade-requested'\n | 'websocket.accepted'\n | 'websocket.message'\n | 'websocket.closed'\n // edge KV\n | 'kv.read'\n | 'kv.write'\n | 'kv.cache-hit'\n | 'kv.cache-miss'\n // geo replication\n | 'geo.primary-write'\n | 'geo.replica-lagged'\n | 'geo.replica-synced'\n | 'geo.conflict-resolved'\n // cron trigger\n | 'cron.scheduled'\n | 'cron.started'\n | 'cron.completed'\n | 'cron.failed'\n // subrequest limit\n | 'subrequest.started'\n | 'subrequest.counted'\n | 'subrequest.limited'\n | 'subrequest.completed'\n // CPU time limit\n | 'cpu.started'\n | 'cpu.budget-warning'\n | 'cpu.limited'\n | 'cpu.completed'\n // streaming response\n | 'stream.opened'\n | 'stream.chunk-sent'\n | 'stream.backpressure'\n | 'stream.closed';\n\n/**\n * Platform-specific event name lookup. When a runtime has a distinct string\n * for the same semantic (e.g. Cloudflare Durable Objects vs Vercel's closest\n * session-affine edge function analogue) the mock emits the platform dialect\n * so tests wired to runtime-specific telemetry still see recognisable names.\n */\nconst dialect: Record<EdgePlatform, Partial<Record<NeutralEventName, string>>> = {\n cloudflare: {\n 'durable-object.created': 'durable_object.created',\n 'durable-object.requested': 'durable_object.fetch',\n 'durable-object.alarm-fired': 'durable_object.alarm',\n 'durable-object.storage-written': 'durable_object.storage.put',\n 'websocket.upgrade-requested': 'websocket_upgrade.requested',\n 'websocket.accepted': 'websocket_upgrade.accepted',\n 'websocket.message': 'websocket.message',\n 'websocket.closed': 'websocket.close',\n 'kv.read': 'kv_get',\n 'kv.write': 'kv_put',\n 'kv.cache-hit': 'kv_cache.hit',\n 'kv.cache-miss': 'kv_cache.miss',\n 'geo.primary-write': 'smart_placement.primary_write',\n 'geo.replica-lagged': 'kv_replication.lagged',\n 'geo.replica-synced': 'kv_replication.synced',\n 'geo.conflict-resolved': 'durable_object.conflict_resolved',\n 'cron.scheduled': 'scheduled_event.enqueued',\n 'cron.started': 'scheduled_event.started',\n 'cron.completed': 'scheduled_event.completed',\n 'cron.failed': 'scheduled_event.failed',\n 'subrequest.started': 'subrequest.fetch',\n 'subrequest.counted': 'subrequest.counted',\n 'subrequest.limited': 'subrequest.limit_exceeded',\n 'subrequest.completed': 'subrequest.completed',\n 'cpu.started': 'worker.cpu.started',\n 'cpu.budget-warning': 'worker.cpu.warning',\n 'cpu.limited': 'worker.cpu.limit_exceeded',\n 'cpu.completed': 'worker.cpu.completed',\n 'stream.opened': 'response_stream.opened',\n 'stream.chunk-sent': 'response_stream.chunk',\n 'stream.backpressure': 'response_stream.backpressure',\n 'stream.closed': 'response_stream.closed',\n },\n vercel: {\n 'durable-object.created': 'edge_function.session_affinity.created',\n 'durable-object.requested': 'edge_function.session_affinity.request',\n 'durable-object.alarm-fired': 'edge_function.background_timer',\n 'durable-object.storage-written': 'edge_config.write',\n 'websocket.upgrade-requested': 'edge_websocket_upgrade.requested',\n 'websocket.accepted': 'edge_websocket_upgrade.accepted',\n 'websocket.message': 'edge_websocket.message',\n 'websocket.closed': 'edge_websocket.close',\n 'kv.read': 'edge_config.get',\n 'kv.write': 'edge_config.set',\n 'kv.cache-hit': 'edge_config.cache_hit',\n 'kv.cache-miss': 'edge_config.cache_miss',\n 'geo.primary-write': 'edge_config.primary_write',\n 'geo.replica-lagged': 'edge_config.replica_lagged',\n 'geo.replica-synced': 'edge_config.replica_synced',\n 'geo.conflict-resolved': 'edge_config.conflict_resolved',\n 'cron.scheduled': 'vercel_cron.scheduled',\n 'cron.started': 'vercel_cron.started',\n 'cron.completed': 'vercel_cron.completed',\n 'cron.failed': 'vercel_cron.failed',\n 'subrequest.started': 'edge_function.fetch',\n 'subrequest.counted': 'edge_function.subrequest_counted',\n 'subrequest.limited': 'edge_function.subrequest_limited',\n 'subrequest.completed': 'edge_function.fetch_completed',\n 'cpu.started': 'edge_function.cpu_started',\n 'cpu.budget-warning': 'edge_function.cpu_warning',\n 'cpu.limited': 'edge_function.cpu_limited',\n 'cpu.completed': 'edge_function.cpu_completed',\n 'stream.opened': 'edge_function.stream_opened',\n 'stream.chunk-sent': 'edge_function.stream_chunk',\n 'stream.backpressure': 'edge_function.stream_backpressure',\n 'stream.closed': 'edge_function.stream_closed',\n },\n deno: {\n 'durable-object.created': 'deploy.stateful_object.created',\n 'durable-object.requested': 'deploy.stateful_fetch',\n 'durable-object.alarm-fired': 'deploy.cron.timer',\n 'durable-object.storage-written': 'deno_kv.atomic_write',\n 'websocket.upgrade-requested': 'deno_websocket_upgrade.requested',\n 'websocket.accepted': 'deno_websocket_upgrade.accepted',\n 'websocket.message': 'deno_websocket.message',\n 'websocket.closed': 'deno_websocket.close',\n 'kv.read': 'deno_kv.get',\n 'kv.write': 'deno_kv.set',\n 'kv.cache-hit': 'deno_kv.cache_hit',\n 'kv.cache-miss': 'deno_kv.cache_miss',\n 'geo.primary-write': 'deno_kv.primary_write',\n 'geo.replica-lagged': 'deno_kv.replica_lagged',\n 'geo.replica-synced': 'deno_kv.replica_synced',\n 'geo.conflict-resolved': 'deno_kv.conflict_resolved',\n 'cron.scheduled': 'deploy.cron.scheduled',\n 'cron.started': 'deploy.cron.started',\n 'cron.completed': 'deploy.cron.completed',\n 'cron.failed': 'deploy.cron.failed',\n 'subrequest.started': 'deploy.fetch.started',\n 'subrequest.counted': 'deploy.fetch.counted',\n 'subrequest.limited': 'deploy.fetch.limited',\n 'subrequest.completed': 'deploy.fetch.completed',\n 'cpu.started': 'deploy.cpu.started',\n 'cpu.budget-warning': 'deploy.cpu.warning',\n 'cpu.limited': 'deploy.cpu.limited',\n 'cpu.completed': 'deploy.cpu.completed',\n 'stream.opened': 'deploy.stream.opened',\n 'stream.chunk-sent': 'deploy.stream.chunk',\n 'stream.backpressure': 'deploy.stream.backpressure',\n 'stream.closed': 'deploy.stream.closed',\n },\n};\n\n/**\n * Translate a neutral event name to the platform dialect. Falls back to the\n * neutral name if the platform has no specific dialect entry — this makes\n * the map partial-safe without silent typos.\n */\nexport function platformEventName(\n platform: EdgePlatform,\n neutral: NeutralEventName,\n): string {\n return dialect[platform][neutral] ?? neutral;\n}\n\n/**\n * Axis result envelope returned by every state-machine step. Edge semantics\n * are pure helpers (no adapters); the envelope surfaces the next state\n * transition metadata so tests can drive the next call without re-reading\n * runtime-specific telemetry.\n */\nexport interface AxisStep<TState> {\n neutralEvent: NeutralEventName;\n platformEvent: string;\n state: TState;\n platform: EdgePlatform;\n metadata: Record<string, string | number | boolean>;\n}\n","import { platformEventName, type EdgeAxis, type EdgePlatform, type NeutralEventName } from './types.js';\n\n/**\n * Fidelity harness — collects the platform × axis coverage grid that\n * downstream release-gate reports on. Not a runner (no side effect emit);\n * pure inspection so tests / release-gate can assert \"3 platform × 8 axis\"\n * without walking every neutral event by hand.\n */\nexport interface FidelityRow {\n platform: EdgePlatform;\n axis: EdgeAxis;\n neutralEvents: NeutralEventName[];\n platformEvents: string[];\n}\n\nexport interface FidelityCoverage {\n platforms: EdgePlatform[];\n axes: EdgeAxis[];\n rows: FidelityRow[];\n}\n\nexport const AXIS_TO_EVENTS: Record<EdgeAxis, NeutralEventName[]> = {\n 'durable-object': [\n 'durable-object.created',\n 'durable-object.requested',\n 'durable-object.alarm-fired',\n 'durable-object.storage-written',\n ],\n 'websocket-edge': [\n 'websocket.upgrade-requested',\n 'websocket.accepted',\n 'websocket.message',\n 'websocket.closed',\n ],\n 'edge-kv': ['kv.read', 'kv.write', 'kv.cache-hit', 'kv.cache-miss'],\n 'geo-replicated': [\n 'geo.primary-write',\n 'geo.replica-lagged',\n 'geo.replica-synced',\n 'geo.conflict-resolved',\n ],\n 'cron-trigger': ['cron.scheduled', 'cron.started', 'cron.completed', 'cron.failed'],\n 'subrequest-limit': [\n 'subrequest.started',\n 'subrequest.counted',\n 'subrequest.limited',\n 'subrequest.completed',\n ],\n 'cpu-time-limit': ['cpu.started', 'cpu.budget-warning', 'cpu.limited', 'cpu.completed'],\n 'streaming-response': [\n 'stream.opened',\n 'stream.chunk-sent',\n 'stream.backpressure',\n 'stream.closed',\n ],\n};\n\n/**\n * Collect the platform × axis coverage grid. `platforms` is the list of\n * platforms to inspect — usually all 3 (`cloudflare`, `vercel`, `deno`).\n *\n * The output is a flat row list `platforms.length * 8 = 24` for the default\n * setup, plus `platforms` + `axes` roll-up lists so callers can assert on\n * the grid dimensions.\n */\nexport function collectFidelityCoverage(platforms: EdgePlatform[]): FidelityCoverage {\n const axes = Object.keys(AXIS_TO_EVENTS) as EdgeAxis[];\n const rows: FidelityRow[] = [];\n for (const platform of platforms) {\n for (const axis of axes) {\n const neutralEvents = AXIS_TO_EVENTS[axis];\n const platformEvents = neutralEvents.map((n) => platformEventName(platform, n));\n rows.push({\n platform,\n axis,\n neutralEvents,\n platformEvents,\n });\n }\n }\n return { platforms, axes, rows };\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * Durable Object — stateful, single-instance actor pinned to one edge\n * location. Cloudflare Durable Objects are the canonical example; Vercel's\n * closest analogue is a session-affine edge function, Deno Deploy exposes\n * stateful objects backed by Deno KV. The mock reproduces the user-observable\n * lifecycle: an instance is created once, receives fetch requests (which pin\n * it \"active\"), can wake on a scheduled alarm, and persists to transactional\n * storage. Hibernation / eviction is intentionally out of scope for v0.2 — the\n * axis only exposes the 4 neutral events the fidelity grid tracks.\n *\n * State transitions:\n * created → 'initialized'\n * requestDurableObject → 'active' (from initialized or active)\n * fireAlarm → 'active' (an alarm wakes the object)\n * writeStorage → 'active' (a storage write implies an active handler)\n */\nexport type DoState = 'initialized' | 'active' | 'hibernated' | 'terminated';\n\nexport interface DurableObjectSession {\n id: string;\n platform: EdgePlatform;\n state: DoState;\n requestCount: number;\n storageKeys: Map<string, string>;\n scheduledAlarmAt: number | null;\n history: AxisStep<DoState>[];\n}\n\n/** Push a fully-formed step onto the session history and return it. */\nfunction record(session: DurableObjectSession, step: AxisStep<DoState>): AxisStep<DoState> {\n session.history.push(step);\n return step;\n}\n\n/**\n * Create a durable object instance. State starts at 'initialized' and no\n * request has been served yet. Emits `durable-object.created`.\n */\nexport function createDurableObject(input: {\n id: string;\n platform: EdgePlatform;\n}): DurableObjectSession {\n const session: DurableObjectSession = {\n id: input.id,\n platform: input.platform,\n state: 'initialized',\n requestCount: 0,\n storageKeys: new Map(),\n scheduledAlarmAt: null,\n history: [],\n };\n record(session, {\n neutralEvent: 'durable-object.created',\n platformEvent: platformEventName(input.platform, 'durable-object.created'),\n state: 'initialized',\n platform: input.platform,\n metadata: { id: input.id },\n });\n return session;\n}\n\n/**\n * Route a fetch request to the object. Pins the instance 'active' and bumps\n * the request counter. Emits `durable-object.requested`.\n */\nexport function requestDurableObject(\n session: DurableObjectSession,\n input: { url: string },\n): AxisStep<DoState> {\n if (session.state === 'terminated') {\n throw new Error('requestDurableObject: object is terminated');\n }\n session.state = 'active';\n session.requestCount += 1;\n return record(session, {\n neutralEvent: 'durable-object.requested',\n platformEvent: platformEventName(session.platform, 'durable-object.requested'),\n state: session.state,\n platform: session.platform,\n metadata: { url: input.url, requestCount: session.requestCount },\n });\n}\n\n/**\n * Fire the scheduled alarm. Wakes the object into 'active' regardless of the\n * prior state and clears the pending alarm. Emits `durable-object.alarm-fired`.\n */\nexport function fireAlarm(session: DurableObjectSession): AxisStep<DoState> {\n if (session.state === 'terminated') {\n throw new Error('fireAlarm: object is terminated');\n }\n const firedAt = session.scheduledAlarmAt;\n session.scheduledAlarmAt = null;\n session.state = 'active';\n return record(session, {\n neutralEvent: 'durable-object.alarm-fired',\n platformEvent: platformEventName(session.platform, 'durable-object.alarm-fired'),\n state: session.state,\n platform: session.platform,\n metadata: { firedAt: firedAt ?? 0, scheduled: firedAt !== null },\n });\n}\n\n/**\n * Write a key to transactional storage. Implies an active handler, so the\n * object stays 'active'. Emits `durable-object.storage-written`.\n */\nexport function writeStorage(\n session: DurableObjectSession,\n input: { key: string; value: string },\n): AxisStep<DoState> {\n if (session.state === 'terminated') {\n throw new Error('writeStorage: object is terminated');\n }\n session.storageKeys.set(input.key, input.value);\n session.state = 'active';\n return record(session, {\n neutralEvent: 'durable-object.storage-written',\n platformEvent: platformEventName(session.platform, 'durable-object.storage-written'),\n state: session.state,\n platform: session.platform,\n metadata: { key: input.key, size: input.value.length, keyCount: session.storageKeys.size },\n });\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * WebSocket at the edge — the HTTP-upgrade handshake plus the message /\n * close lifecycle. All three runtimes accept a `101 Switching Protocols`\n * upgrade (Cloudflare `WebSocketPair`, Vercel edge websockets, Deno\n * `Deno.upgradeWebSocket`) but expose different telemetry strings. The mock\n * drives the neutral lifecycle so a test can assert the handshake ordering\n * without a live socket.\n *\n * State transitions:\n * requestWebSocketUpgrade → 'pending'\n * acceptWebSocket → 'open' (only from 'pending')\n * sendMessage → 'open' (only while 'open')\n * closeWebSocket → 'closed'\n */\nexport type WsState = 'pending' | 'open' | 'closing' | 'closed';\n\nexport interface WebSocketSession {\n id: string;\n platform: EdgePlatform;\n state: WsState;\n messages: string[];\n history: AxisStep<WsState>[];\n}\n\n/** Push a fully-formed step onto the session history and return it. */\nfunction record(session: WebSocketSession, step: AxisStep<WsState>): AxisStep<WsState> {\n session.history.push(step);\n return step;\n}\n\n/**\n * Begin the upgrade handshake. State starts 'pending' until the server\n * accepts. Emits `websocket.upgrade-requested`.\n */\nexport function requestWebSocketUpgrade(input: {\n id: string;\n platform: EdgePlatform;\n}): WebSocketSession {\n const session: WebSocketSession = {\n id: input.id,\n platform: input.platform,\n state: 'pending',\n messages: [],\n history: [],\n };\n record(session, {\n neutralEvent: 'websocket.upgrade-requested',\n platformEvent: platformEventName(input.platform, 'websocket.upgrade-requested'),\n state: 'pending',\n platform: input.platform,\n metadata: { id: input.id },\n });\n return session;\n}\n\n/**\n * Accept the pending upgrade, moving the socket 'open'. Rejects if the socket\n * is not awaiting acceptance. Emits `websocket.accepted`.\n */\nexport function acceptWebSocket(session: WebSocketSession): AxisStep<WsState> {\n if (session.state !== 'pending') {\n throw new Error(`acceptWebSocket: socket is ${session.state}, expected pending`);\n }\n session.state = 'open';\n return record(session, {\n neutralEvent: 'websocket.accepted',\n platformEvent: platformEventName(session.platform, 'websocket.accepted'),\n state: session.state,\n platform: session.platform,\n metadata: { id: session.id },\n });\n}\n\n/**\n * Send a frame over the open socket. Rejects unless the socket is 'open'.\n * Emits `websocket.message`.\n */\nexport function sendMessage(\n session: WebSocketSession,\n input: { data: string },\n): AxisStep<WsState> {\n if (session.state !== 'open') {\n throw new Error(`sendMessage: socket is ${session.state}, expected open`);\n }\n session.messages.push(input.data);\n return record(session, {\n neutralEvent: 'websocket.message',\n platformEvent: platformEventName(session.platform, 'websocket.message'),\n state: session.state,\n platform: session.platform,\n metadata: { size: input.data.length, index: session.messages.length - 1 },\n });\n}\n\n/**\n * Close the socket with a status code. Rejects if already closed. Emits\n * `websocket.closed`.\n */\nexport function closeWebSocket(\n session: WebSocketSession,\n input: { code: number },\n): AxisStep<WsState> {\n if (session.state === 'closed') {\n throw new Error('closeWebSocket: socket already closed');\n }\n session.state = 'closed';\n return record(session, {\n neutralEvent: 'websocket.closed',\n platformEvent: platformEventName(session.platform, 'websocket.closed'),\n state: session.state,\n platform: session.platform,\n metadata: { code: input.code, totalMessages: session.messages.length },\n });\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * Edge KV — a globally replicated key/value store with a read-through cache.\n * Cloudflare KV, Vercel Edge Config, and Deno KV all trade strong consistency\n * for low-latency edge reads: a write may take time to propagate, and reads\n * are served from a per-POP cache when warm. The mock models the observable\n * surface: a backing `store`, a `cache` layer that a read populates and a\n * write invalidates, and a range query over a key prefix.\n *\n * There is no state machine per se — the store is always usable. `state`\n * records the consistency model the caller declared so downstream tests can\n * assert on it. The 4 neutral events distinguish a cold read, a write, a warm\n * cache hit, and a miss on an absent key.\n */\nexport type KvState = 'consistent' | 'eventually-consistent';\n\nexport interface EdgeKvSession {\n platform: EdgePlatform;\n store: Map<string, string>;\n cache: Map<string, string>;\n state: KvState;\n history: AxisStep<KvState>[];\n}\n\n/** Push a fully-formed step onto the session history and return it. */\nfunction record(session: EdgeKvSession, step: AxisStep<KvState>): AxisStep<KvState> {\n session.history.push(step);\n return step;\n}\n\n/**\n * Construct a KV session. No event is emitted — the store is simply opened.\n * Defaults to eventual consistency, the common edge-KV replication model.\n */\nexport function createEdgeKvSession(input: {\n platform: EdgePlatform;\n state?: KvState;\n}): EdgeKvSession {\n return {\n platform: input.platform,\n store: new Map(),\n cache: new Map(),\n state: input.state ?? 'eventually-consistent',\n history: [],\n };\n}\n\n/**\n * Read a key. Three outcomes:\n * - cache warm → `kv.cache-hit`\n * - store only → `kv.read` and the cache is populated (read-through)\n * - absent → `kv.cache-miss`\n */\nexport function kvRead(session: EdgeKvSession, input: { key: string }): AxisStep<KvState> {\n let neutral: 'kv.read' | 'kv.cache-hit' | 'kv.cache-miss';\n let hit: boolean;\n if (session.cache.has(input.key)) {\n neutral = 'kv.cache-hit';\n hit = true;\n } else if (session.store.has(input.key)) {\n session.cache.set(input.key, session.store.get(input.key)!);\n neutral = 'kv.read';\n hit = false;\n } else {\n neutral = 'kv.cache-miss';\n hit = false;\n }\n return record(session, {\n neutralEvent: neutral,\n platformEvent: platformEventName(session.platform, neutral),\n state: session.state,\n platform: session.platform,\n metadata: { key: input.key, hit },\n });\n}\n\n/**\n * Write a key. Updates the backing store and invalidates the cache entry so\n * the next read goes through to the store. Emits `kv.write`.\n */\nexport function kvWrite(\n session: EdgeKvSession,\n input: { key: string; value: string },\n): AxisStep<KvState> {\n session.store.set(input.key, input.value);\n session.cache.delete(input.key);\n return record(session, {\n neutralEvent: 'kv.write',\n platformEvent: platformEventName(session.platform, 'kv.write'),\n state: session.state,\n platform: session.platform,\n metadata: { key: input.key, size: input.value.length },\n });\n}\n\n/**\n * Range query over a key prefix. Returns the matching keys (sorted, up to\n * `limit`) alongside the emitted step. Emits `kv.read` since a range scan is a\n * store read. `limit` defaults to no cap.\n */\nexport function kvRangeQuery(\n session: EdgeKvSession,\n input: { prefix: string; limit?: number },\n): { matches: string[]; step: AxisStep<KvState> } {\n const limit = input.limit ?? Number.POSITIVE_INFINITY;\n const matches = [...session.store.keys()]\n .filter((k) => k.startsWith(input.prefix))\n .sort()\n .slice(0, limit);\n const step = record(session, {\n neutralEvent: 'kv.read',\n platformEvent: platformEventName(session.platform, 'kv.read'),\n state: session.state,\n platform: session.platform,\n metadata: {\n prefix: input.prefix,\n matched: matches.length,\n limit: Number.isFinite(limit) ? limit : 0,\n },\n });\n return { matches, step };\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * Geo-replicated store — a primary region that accepts writes and N replica\n * regions that catch up asynchronously. This is the multi-region consistency\n * model behind Cloudflare Smart Placement + KV replication, Vercel Edge Config\n * replication, and Deno KV's primary/replica topology. The mock exposes the\n * observable lifecycle a test cares about: a primary write bumps a version and\n * leaves replicas lagging, each replica is marked lagged then synced, and a\n * write conflict can be explicitly resolved.\n *\n * State transitions:\n * createGeoReplicatedSession → 'in-sync' (version 0, no lag)\n * geoPrimaryWrite → 'lagging' (replicas fall behind)\n * markReplicaLagged → 'lagging'\n * syncReplica → 'in-sync' (only once every replica lag = 0)\n * resolveConflict → 'in-sync'\n */\nexport type GeoRegion = string;\n\nexport type GeoState = 'in-sync' | 'lagging' | 'conflict-detected';\n\nexport interface GeoReplicatedSession {\n platform: EdgePlatform;\n primaryRegion: GeoRegion;\n replicaRegions: GeoRegion[];\n state: GeoState;\n version: number;\n lagMs: Record<GeoRegion, number>;\n history: AxisStep<GeoState>[];\n}\n\n/** Lag (ms) assigned to every replica immediately after a primary write. */\nconst POST_WRITE_LAG_MS = 100;\n\n/** Push a fully-formed step onto the session history and return it. */\nfunction record(session: GeoReplicatedSession, step: AxisStep<GeoState>): AxisStep<GeoState> {\n session.history.push(step);\n return step;\n}\n\n/**\n * Construct a geo-replicated session. Starts 'in-sync' at version 0 with every\n * replica at zero lag. No event is emitted.\n */\nexport function createGeoReplicatedSession(input: {\n platform: EdgePlatform;\n primaryRegion: GeoRegion;\n replicaRegions: GeoRegion[];\n}): GeoReplicatedSession {\n const lagMs: Record<GeoRegion, number> = {};\n for (const region of input.replicaRegions) lagMs[region] = 0;\n return {\n platform: input.platform,\n primaryRegion: input.primaryRegion,\n replicaRegions: [...input.replicaRegions],\n state: 'in-sync',\n version: 0,\n lagMs,\n history: [],\n };\n}\n\n/**\n * Write to the primary region. Bumps the version and marks every replica as\n * lagging (they have not yet received the new version). Emits\n * `geo.primary-write`.\n */\nexport function geoPrimaryWrite(\n session: GeoReplicatedSession,\n input: { data: string },\n): AxisStep<GeoState> {\n session.version += 1;\n session.state = 'lagging';\n for (const region of session.replicaRegions) session.lagMs[region] = POST_WRITE_LAG_MS;\n return record(session, {\n neutralEvent: 'geo.primary-write',\n platformEvent: platformEventName(session.platform, 'geo.primary-write'),\n state: session.state,\n platform: session.platform,\n metadata: { version: session.version, region: session.primaryRegion, size: input.data.length },\n });\n}\n\n/**\n * Report replication lag for a specific replica. Rejects an unknown region.\n * Emits `geo.replica-lagged`.\n */\nexport function markReplicaLagged(\n session: GeoReplicatedSession,\n input: { region: GeoRegion; lagMs: number },\n): AxisStep<GeoState> {\n if (!session.replicaRegions.includes(input.region)) {\n throw new Error(`markReplicaLagged: ${input.region} is not a replica region`);\n }\n session.lagMs[input.region] = input.lagMs;\n session.state = 'lagging';\n return record(session, {\n neutralEvent: 'geo.replica-lagged',\n platformEvent: platformEventName(session.platform, 'geo.replica-lagged'),\n state: session.state,\n platform: session.platform,\n metadata: { region: input.region, lagMs: input.lagMs },\n });\n}\n\n/**\n * Mark a replica caught up (lag → 0). When every replica has zero lag the\n * session returns 'in-sync'. Rejects an unknown region. Emits\n * `geo.replica-synced`.\n */\nexport function syncReplica(\n session: GeoReplicatedSession,\n input: { region: GeoRegion },\n): AxisStep<GeoState> {\n if (!session.replicaRegions.includes(input.region)) {\n throw new Error(`syncReplica: ${input.region} is not a replica region`);\n }\n session.lagMs[input.region] = 0;\n const allSynced = session.replicaRegions.every((r) => session.lagMs[r] === 0);\n if (allSynced) session.state = 'in-sync';\n return record(session, {\n neutralEvent: 'geo.replica-synced',\n platformEvent: platformEventName(session.platform, 'geo.replica-synced'),\n state: session.state,\n platform: session.platform,\n metadata: { region: input.region, allSynced },\n });\n}\n\n/**\n * Resolve a write conflict for a region by picking a winning version. Rejects\n * an unknown region. Adopts the chosen version, clears every replica's lag and\n * forces the session back to 'in-sync'. Emits `geo.conflict-resolved`.\n */\nexport function resolveConflict(\n session: GeoReplicatedSession,\n input: { region: GeoRegion; chosenVersion: number },\n): AxisStep<GeoState> {\n if (!session.replicaRegions.includes(input.region)) {\n throw new Error(`resolveConflict: ${input.region} is not a replica region`);\n }\n session.version = input.chosenVersion;\n for (const region of session.replicaRegions) session.lagMs[region] = 0;\n session.state = 'in-sync';\n return record(session, {\n neutralEvent: 'geo.conflict-resolved',\n platformEvent: platformEventName(session.platform, 'geo.conflict-resolved'),\n state: session.state,\n platform: session.platform,\n metadata: { region: input.region, chosenVersion: input.chosenVersion },\n });\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * Cron trigger — scheduled invocation lifecycle. Edge platforms fire scheduled\n * handlers from distinct sources (Cloudflare Cron Triggers + Queue consumers +\n * Email routing, Vercel Cron jobs, Deno Deploy cron) yet share the same\n * observable lifecycle: an event is scheduled, starts running, then either\n * completes or fails. A failed run re-enters the schedule until `maxRetries`\n * is exhausted, at which point it terminates in `failed`.\n */\nexport type CronState = 'scheduled' | 'running' | 'completed' | 'failed';\n\n/** Which trigger source fired the scheduled handler. */\nexport type CronTriggerType = 'scheduled' | 'queue' | 'email';\n\nexport interface CronSession {\n id: string;\n platform: EdgePlatform;\n triggerType: CronTriggerType;\n cronSpec: string;\n state: CronState;\n startedAt: number | null;\n retryCount: number;\n maxRetries: number;\n history: AxisStep<CronState>[];\n}\n\n/**\n * Schedule a cron invocation. Emits `cron.scheduled` and seeds the session in\n * the `scheduled` state. `triggerType` defaults to `scheduled` (a plain time\n * trigger) and `maxRetries` defaults to 3.\n */\nexport function scheduleCron(input: {\n id: string;\n platform: EdgePlatform;\n triggerType?: CronTriggerType;\n cronSpec: string;\n maxRetries?: number;\n}): CronSession {\n const triggerType = input.triggerType ?? 'scheduled';\n const maxRetries = input.maxRetries ?? 3;\n const session: CronSession = {\n id: input.id,\n platform: input.platform,\n triggerType,\n cronSpec: input.cronSpec,\n state: 'scheduled',\n startedAt: null,\n retryCount: 0,\n maxRetries,\n history: [],\n };\n const step: AxisStep<CronState> = {\n neutralEvent: 'cron.scheduled',\n platformEvent: platformEventName(input.platform, 'cron.scheduled'),\n state: 'scheduled',\n platform: input.platform,\n metadata: { triggerType, cronSpec: input.cronSpec, maxRetries },\n };\n session.history.push(step);\n return session;\n}\n\n/**\n * Begin executing a scheduled invocation. Transitions `scheduled` → `running`,\n * stamps `startedAt`, and emits `cron.started`. Rejects if the session is not\n * currently `scheduled` (already running / terminal).\n */\nexport function startCron(session: CronSession): AxisStep<CronState> {\n if (session.state !== 'scheduled') {\n throw new Error(`startCron: session is ${session.state}, expected scheduled`);\n }\n session.state = 'running';\n session.startedAt = Date.now();\n const step: AxisStep<CronState> = {\n neutralEvent: 'cron.started',\n platformEvent: platformEventName(session.platform, 'cron.started'),\n state: 'running',\n platform: session.platform,\n metadata: { startedAt: session.startedAt, triggerType: session.triggerType },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Finish a running invocation successfully. Transitions `running` →\n * `completed` and emits `cron.completed`. Rejects if not `running`.\n */\nexport function completeCron(\n session: CronSession,\n input: { durationMs: number },\n): AxisStep<CronState> {\n if (session.state !== 'running') {\n throw new Error(`completeCron: session is ${session.state}, expected running`);\n }\n session.state = 'completed';\n const step: AxisStep<CronState> = {\n neutralEvent: 'cron.completed',\n platformEvent: platformEventName(session.platform, 'cron.completed'),\n state: 'completed',\n platform: session.platform,\n metadata: { durationMs: input.durationMs, triggerType: session.triggerType },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Fail a running invocation. Increments `retryCount`; if retries remain the\n * session re-enters the `scheduled` state (to be picked up again), otherwise it\n * terminates in `failed`. Emits `cron.failed` with `willRetry` reflecting the\n * decision. Rejects if the session already `completed`.\n */\nexport function failCron(\n session: CronSession,\n input: { reason: string },\n): AxisStep<CronState> {\n if (session.state !== 'running') {\n throw new Error(`failCron: session is ${session.state}, expected running`);\n }\n session.retryCount += 1;\n const willRetry = session.retryCount < session.maxRetries;\n session.state = willRetry ? 'scheduled' : 'failed';\n const step: AxisStep<CronState> = {\n neutralEvent: 'cron.failed',\n platformEvent: platformEventName(session.platform, 'cron.failed'),\n state: session.state,\n platform: session.platform,\n metadata: {\n reason: input.reason,\n retryCount: session.retryCount,\n willRetry,\n triggerType: session.triggerType,\n },\n };\n session.history.push(step);\n return step;\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * Subrequest limit — outbound fetch budget per invocation. Edge runtimes cap\n * how many subrequests a single handler may issue (Cloudflare Workers default\n * 50 on the free plan, Vercel + Deno enforce comparable ceilings). The axis\n * tracks a running count against the limit: below a warning threshold the\n * session is `ok`, at the threshold it is `approaching-limit`, and once the\n * count reaches the hard limit it is `limited` and further fetches are refused.\n */\nexport type SubrequestState = 'ok' | 'approaching-limit' | 'limited';\n\nexport interface SubrequestSession {\n platform: EdgePlatform;\n count: number;\n limit: number;\n warningThreshold: number;\n state: SubrequestState;\n history: AxisStep<SubrequestState>[];\n}\n\n/**\n * Open a subrequest budget. `limit` defaults to 50 (Workers free-plan default)\n * and `warningThreshold` to 40 (80% of the default limit). Emits nothing — the\n * budget is inert until the first {@link startSubrequest}.\n */\nexport function startSubrequestBudget(input: {\n platform: EdgePlatform;\n limit?: number;\n warningThreshold?: number;\n}): SubrequestSession {\n return {\n platform: input.platform,\n count: 0,\n limit: input.limit ?? 50,\n warningThreshold: input.warningThreshold ?? 40,\n state: 'ok',\n history: [],\n };\n}\n\n/**\n * Announce an outbound subrequest. Emits `subrequest.started` but does not\n * advance the count (starting is distinct from counting — a started request\n * only counts once it is admitted via {@link countSubrequest}). Rejects when\n * the budget is already `limited`.\n */\nexport function startSubrequest(\n session: SubrequestSession,\n input: { url: string },\n): AxisStep<SubrequestState> {\n if (session.state === 'limited') {\n throw new Error('startSubrequest: budget is limited, cannot start');\n }\n const step: AxisStep<SubrequestState> = {\n neutralEvent: 'subrequest.started',\n platformEvent: platformEventName(session.platform, 'subrequest.started'),\n state: session.state,\n platform: session.platform,\n metadata: { url: input.url, currentCount: session.count },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Count an admitted subrequest against the budget. Increments the count and\n * emits `subrequest.limited` when the count reaches the hard limit (state →\n * `limited`), otherwise `subrequest.counted` — flipping to `approaching-limit`\n * once the warning threshold is crossed.\n */\nexport function countSubrequest(session: SubrequestSession): AxisStep<SubrequestState> {\n if (session.state === 'limited') {\n throw new Error('countSubrequest: budget is limited, cannot count further');\n }\n session.count += 1;\n if (session.count >= session.limit) {\n session.state = 'limited';\n const step: AxisStep<SubrequestState> = {\n neutralEvent: 'subrequest.limited',\n platformEvent: platformEventName(session.platform, 'subrequest.limited'),\n state: 'limited',\n platform: session.platform,\n metadata: { count: session.count, limit: session.limit },\n };\n session.history.push(step);\n return step;\n }\n if (session.count >= session.warningThreshold) {\n session.state = 'approaching-limit';\n }\n const step: AxisStep<SubrequestState> = {\n neutralEvent: 'subrequest.counted',\n platformEvent: platformEventName(session.platform, 'subrequest.counted'),\n state: session.state,\n platform: session.platform,\n metadata: {\n count: session.count,\n limit: session.limit,\n remaining: session.limit - session.count,\n },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Mark an outbound subrequest as finished. Emits `subrequest.completed` with\n * the final count. Does not mutate state — a completed request that already\n * tripped the limit stays `limited`.\n */\nexport function completeSubrequest(\n session: SubrequestSession,\n input: { url: string; durationMs: number },\n): AxisStep<SubrequestState> {\n const step: AxisStep<SubrequestState> = {\n neutralEvent: 'subrequest.completed',\n platformEvent: platformEventName(session.platform, 'subrequest.completed'),\n state: session.state,\n platform: session.platform,\n metadata: {\n url: input.url,\n durationMs: input.durationMs,\n totalCount: session.count,\n },\n };\n session.history.push(step);\n return step;\n}\n\n/** Remaining subrequest budget (never negative). */\nexport function remainingBudget(session: SubrequestSession): number {\n return Math.max(0, session.limit - session.count);\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * CPU time limit — per-invocation compute budget. Edge runtimes bill wall-clock\n * loosely but enforce a hard CPU budget (Cloudflare Workers 50ms on the free\n * plan, Vercel + Deno enforce comparable ceilings). The axis accumulates\n * elapsed CPU time across ticks: below a warning threshold it is `running`, at\n * the threshold it flips to `warning`, and once the budget is exhausted the\n * invocation is `throttled` and no further work is admitted.\n */\nexport type CpuState = 'idle' | 'running' | 'warning' | 'throttled' | 'completed';\n\nexport interface CpuSession {\n platform: EdgePlatform;\n budgetMs: number;\n warningAtMs: number;\n elapsedMs: number;\n state: CpuState;\n history: AxisStep<CpuState>[];\n}\n\n/**\n * Open a CPU budget. `budgetMs` defaults to 50 (Workers free-plan default) and\n * `warningAtMs` to 40 (80% of the default budget). Emits nothing — the budget\n * is `idle` until {@link startCpu}.\n */\nexport function startCpuBudget(input: {\n platform: EdgePlatform;\n budgetMs?: number;\n warningAtMs?: number;\n}): CpuSession {\n return {\n platform: input.platform,\n budgetMs: input.budgetMs ?? 50,\n warningAtMs: input.warningAtMs ?? 40,\n elapsedMs: 0,\n state: 'idle',\n history: [],\n };\n}\n\n/**\n * Begin consuming the CPU budget. Transitions `idle` → `running` and emits\n * `cpu.started`. Rejects if the session is not `idle`.\n */\nexport function startCpu(session: CpuSession): AxisStep<CpuState> {\n if (session.state !== 'idle') {\n throw new Error(`startCpu: session is ${session.state}, expected idle`);\n }\n session.state = 'running';\n const step: AxisStep<CpuState> = {\n neutralEvent: 'cpu.started',\n platformEvent: platformEventName(session.platform, 'cpu.started'),\n state: 'running',\n platform: session.platform,\n metadata: { budgetMs: session.budgetMs },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Advance the CPU clock by `deltaMs`. Emits `cpu.limited` when the accumulated\n * time reaches the budget (state → `throttled`), `cpu.budget-warning` when it\n * crosses the warning threshold (state → `warning`), otherwise a `cpu.started`\n * heartbeat carrying the remaining budget. Rejects once the session is\n * `throttled` or `completed`.\n */\nexport function tickCpu(\n session: CpuSession,\n input: { deltaMs: number },\n): AxisStep<CpuState> {\n if (session.state === 'idle') {\n throw new Error('tickCpu: session is idle, call startCpu first');\n }\n if (session.state === 'throttled' || session.state === 'completed') {\n throw new Error(`tickCpu: session is ${session.state}, cannot tick`);\n }\n session.elapsedMs += input.deltaMs;\n if (session.elapsedMs >= session.budgetMs) {\n session.state = 'throttled';\n const step: AxisStep<CpuState> = {\n neutralEvent: 'cpu.limited',\n platformEvent: platformEventName(session.platform, 'cpu.limited'),\n state: 'throttled',\n platform: session.platform,\n metadata: {\n elapsedMs: session.elapsedMs,\n budgetMs: session.budgetMs,\n overshootMs: session.elapsedMs - session.budgetMs,\n },\n };\n session.history.push(step);\n return step;\n }\n if (session.elapsedMs >= session.warningAtMs) {\n session.state = 'warning';\n const step: AxisStep<CpuState> = {\n neutralEvent: 'cpu.budget-warning',\n platformEvent: platformEventName(session.platform, 'cpu.budget-warning'),\n state: 'warning',\n platform: session.platform,\n metadata: {\n elapsedMs: session.elapsedMs,\n warningAtMs: session.warningAtMs,\n remaining: session.budgetMs - session.elapsedMs,\n },\n };\n session.history.push(step);\n return step;\n }\n const step: AxisStep<CpuState> = {\n neutralEvent: 'cpu.started',\n platformEvent: platformEventName(session.platform, 'cpu.started'),\n state: session.state,\n platform: session.platform,\n metadata: {\n elapsedMs: session.elapsedMs,\n budgetMs: session.budgetMs,\n remaining: session.budgetMs - session.elapsedMs,\n },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Finish the invocation. Transitions to `completed` and emits `cpu.completed`\n * with the used ratio. Rejects if the session never started (`idle`).\n */\nexport function completeCpu(session: CpuSession): AxisStep<CpuState> {\n if (session.state === 'idle') {\n throw new Error('completeCpu: session is idle, cannot complete');\n }\n session.state = 'completed';\n const step: AxisStep<CpuState> = {\n neutralEvent: 'cpu.completed',\n platformEvent: platformEventName(session.platform, 'cpu.completed'),\n state: 'completed',\n platform: session.platform,\n metadata: {\n elapsedMs: session.elapsedMs,\n budgetMs: session.budgetMs,\n usedRatio: session.elapsedMs / session.budgetMs,\n },\n };\n session.history.push(step);\n return step;\n}\n","import { platformEventName, type AxisStep, type EdgePlatform } from './types.js';\n\n/**\n * Streaming response — chunked / SSE / websocket body delivery with\n * backpressure. Edge runtimes stream responses through a bounded buffer: while\n * buffered bytes stay under the high-water mark the stream is `open` and chunks\n * flow freely; once the mark is exceeded the stream enters `backpressure` and\n * the producer must wait for the consumer to drain before resuming.\n */\nexport type StreamState = 'open' | 'backpressure' | 'closed';\n\n/** Delivery mechanism for the streamed body. */\nexport type StreamKind = 'chunked' | 'sse' | 'websocket';\n\nexport interface StreamSession {\n id: string;\n platform: EdgePlatform;\n kind: StreamKind;\n state: StreamState;\n chunksSent: number;\n bytesSent: number;\n highWaterMark: number;\n history: AxisStep<StreamState>[];\n}\n\n/**\n * Open a response stream. `kind` defaults to `chunked` and `highWaterMark` to\n * 65536 bytes (64 KiB). Emits `stream.opened` and seeds counters at zero.\n */\nexport function openStream(input: {\n id: string;\n platform: EdgePlatform;\n kind?: StreamKind;\n highWaterMark?: number;\n}): StreamSession {\n const kind = input.kind ?? 'chunked';\n const highWaterMark = input.highWaterMark ?? 65536;\n const session: StreamSession = {\n id: input.id,\n platform: input.platform,\n kind,\n state: 'open',\n chunksSent: 0,\n bytesSent: 0,\n highWaterMark,\n history: [],\n };\n const step: AxisStep<StreamState> = {\n neutralEvent: 'stream.opened',\n platformEvent: platformEventName(input.platform, 'stream.opened'),\n state: 'open',\n platform: input.platform,\n metadata: { id: input.id, kind, highWaterMark },\n };\n session.history.push(step);\n return session;\n}\n\n/**\n * Write a chunk to the stream. Advances `chunksSent` + `bytesSent`; when the\n * buffered byte total exceeds the high-water mark the stream flips to\n * `backpressure` and emits `stream.backpressure`, otherwise `stream.chunk-sent`.\n * Rejects if the stream is already `closed`.\n */\nexport function sendChunk(\n session: StreamSession,\n input: { data: string },\n): AxisStep<StreamState> {\n if (session.state === 'closed') {\n throw new Error('sendChunk: stream is closed');\n }\n session.chunksSent += 1;\n session.bytesSent += input.data.length;\n if (session.bytesSent > session.highWaterMark) {\n session.state = 'backpressure';\n const step: AxisStep<StreamState> = {\n neutralEvent: 'stream.backpressure',\n platformEvent: platformEventName(session.platform, 'stream.backpressure'),\n state: 'backpressure',\n platform: session.platform,\n metadata: {\n bytesSent: session.bytesSent,\n highWaterMark: session.highWaterMark,\n chunksSent: session.chunksSent,\n },\n };\n session.history.push(step);\n return step;\n }\n const step: AxisStep<StreamState> = {\n neutralEvent: 'stream.chunk-sent',\n platformEvent: platformEventName(session.platform, 'stream.chunk-sent'),\n state: session.state,\n platform: session.platform,\n metadata: {\n bytesSent: session.bytesSent,\n chunksSent: session.chunksSent,\n size: input.data.length,\n },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Resume a back-pressured stream after the consumer drained. Transitions\n * `backpressure` → `open`, drains one high-water mark worth of buffered bytes,\n * and re-emits `stream.chunk-sent` tagged `resumed: true` (there is no distinct\n * neutral resume event). Rejects unless the stream is `backpressure`.\n */\nexport function resumeStream(session: StreamSession): AxisStep<StreamState> {\n if (session.state !== 'backpressure') {\n throw new Error(`resumeStream: stream is ${session.state}, expected backpressure`);\n }\n session.state = 'open';\n session.bytesSent = Math.max(0, session.bytesSent - session.highWaterMark);\n const step: AxisStep<StreamState> = {\n neutralEvent: 'stream.chunk-sent',\n platformEvent: platformEventName(session.platform, 'stream.chunk-sent'),\n state: 'open',\n platform: session.platform,\n metadata: {\n resumed: true,\n chunksSent: session.chunksSent,\n bytesSent: session.bytesSent,\n },\n };\n session.history.push(step);\n return step;\n}\n\n/**\n * Close the stream. Transitions to `closed` and emits `stream.closed` with the\n * final chunk + byte totals. Rejects if the stream is already `closed`.\n */\nexport function closeStream(\n session: StreamSession,\n input: { reason: string },\n): AxisStep<StreamState> {\n if (session.state === 'closed') {\n throw new Error('closeStream: stream already closed');\n }\n session.state = 'closed';\n const step: AxisStep<StreamState> = {\n neutralEvent: 'stream.closed',\n platformEvent: platformEventName(session.platform, 'stream.closed'),\n state: 'closed',\n platform: session.platform,\n metadata: {\n reason: input.reason,\n totalChunks: session.chunksSent,\n totalBytes: session.bytesSent,\n },\n };\n session.history.push(step);\n return step;\n}\n"],"mappings":"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","names":["record","record","record","step","step","step"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kiwa-test/edge",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Edge runtime fetch handler test adapter for kiwa — invoke Cloudflare Workers / Vercel Edge / generic edge handlers with simulated env (KV / R2 / D1 / DurableObject minimal mocks) + ExecutionContext (waitUntil / passThroughOnException) without a running Miniflare or workerd (part of the kiwa test framework family)",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Edge runtime fetch handler test adapter for kiwa with advanced edge semantics — invoke Cloudflare Workers / Vercel Edge / generic edge handlers with simulated env (KV / R2 / D1 / DurableObject minimal mocks) + ExecutionContext (waitUntil / passThroughOnException) without a running Miniflare or workerd (part of the kiwa test framework family)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "cardene",
|
|
@@ -49,8 +49,7 @@
|
|
|
49
49
|
"README.md"
|
|
50
50
|
],
|
|
51
51
|
"publishConfig": {
|
|
52
|
-
"access": "public"
|
|
53
|
-
"provenance": false
|
|
52
|
+
"access": "public"
|
|
54
53
|
},
|
|
55
54
|
"engines": {
|
|
56
55
|
"node": ">=20"
|
|
@@ -73,7 +72,7 @@
|
|
|
73
72
|
"scripts": {
|
|
74
73
|
"build": "tsup",
|
|
75
74
|
"test": "node -e \"require('node:fs').rmSync('.vitest-dist',{recursive:true,force:true})\" && tsc -p tsconfig.vitest.json && vitest run .vitest-dist/tests --environment node",
|
|
76
|
-
"test:cov": "node -e \"require('node:fs').rmSync('.vitest-dist',{recursive:true,force:true})\" && tsc -p tsconfig.vitest.json && vitest run .vitest-dist/tests --environment node --coverage --coverage.provider=v8 --coverage.reporter=json --coverage.reporter=json-summary --coverage.reporter=text --coverage.reportsDirectory=coverage --coverage.include='.vitest-dist/src/invoke-edge-handler.js' --coverage.include='.vitest-dist/src/kv-mock.js' --coverage.exclude='.vitest-dist/tests/**' --coverage.exclude='.vitest-dist/src/index.js'",
|
|
75
|
+
"test:cov": "node -e \"require('node:fs').rmSync('.vitest-dist',{recursive:true,force:true})\" && tsc -p tsconfig.vitest.json && vitest run .vitest-dist/tests --environment node --coverage --coverage.provider=v8 --coverage.reporter=json --coverage.reporter=json-summary --coverage.reporter=text --coverage.reportsDirectory=coverage --coverage.include='.vitest-dist/src/invoke-edge-handler.js' --coverage.include='.vitest-dist/src/kv-mock.js' --coverage.include='.vitest-dist/src/semantics/**' --coverage.exclude='.vitest-dist/tests/**' --coverage.exclude='.vitest-dist/src/index.js' --coverage.exclude='.vitest-dist/src/semantics/index.js'",
|
|
77
76
|
"test:mutation": "stryker run",
|
|
78
77
|
"typecheck": "tsc --noEmit"
|
|
79
78
|
}
|