@velajs/cloudflare 1.24.0 → 1.28.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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/websocket/websocket-routing.ts","../src/cloudflare-application.ts","../src/cloudflare-factory.ts","../src/storage/storage.tokens.ts","../src/storage/storage-key-claim.ts","../src/storage/r2-storage.driver.ts","../src/storage/storage-manager.service.ts","../src/storage/storage.controller.ts","../src/storage/storage.service.ts","../src/storage/storage.module.ts","../src/services/kv-cache.store.ts","../src/services/flagship-flag.driver.ts","../src/services/kv-flag.driver.ts","../src/decorators/env.ts","../src/decorators/scheduled.ts","../src/decorators/queue-consumer.ts","../src/websocket/cloudflare-websocket.module.ts","../src/websocket/broadcast.ts","../src/rate-limit/cloudflare-rate-limit.store.ts","../src/nonce/durable-object-nonce.store.ts"],"sourcesContent":["import type { VelaContext as Context, VelaHono as Hono } from '@velajs/vela';\nimport { getMetadata, getTrustedRequestIdentity } from '@velajs/vela';\nimport {\n authenticateWebSocketUpgrade,\n resolveGatewayRoomId,\n resolveGatewayRoomParam,\n resolveMaxFrameBytes,\n WS_GATEWAY_METADATA,\n type WebSocketGatewayOptions,\n type WebSocketUpgradeIdentity,\n} from '@velajs/vela/websocket';\nimport { durableObjectRoomName } from './room-id';\n\nexport interface WsGatewayRoute {\n path: string;\n binding: string;\n options: WebSocketGatewayOptions;\n}\n\nconst MAX_IDENTITY_FIELD_BYTES = 2048;\nconst encoder = new TextEncoder();\n\ntype PrincipalType = 'user' | 'service';\n\ninterface ForwardedIdentity extends WebSocketUpgradeIdentity {\n principal: {\n issuer: string;\n subject: string;\n principalType: PrincipalType;\n };\n tenantId: string;\n expiresAtMs: number;\n}\n\nfunction isIdentityField(value: unknown): value is string {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n !value.includes('\\r') &&\n !value.includes('\\n') &&\n encoder.encode(value).byteLength <= MAX_IDENTITY_FIELD_BYTES\n );\n}\n\n/** `null` means an identity was present but violated the transport contract. */\nfunction accessIdentity(c: Context): ForwardedIdentity | null | undefined {\n const value = getTrustedRequestIdentity(c.req.raw);\n if (!value) return undefined;\n const { principal, tenantId, expiresAtMs } = value;\n if (\n !isIdentityField(principal.issuer) ||\n !isIdentityField(principal.subject) ||\n !isIdentityField(tenantId) ||\n typeof expiresAtMs !== 'number' ||\n !Number.isSafeInteger(expiresAtMs) ||\n expiresAtMs <= 0\n )\n return null;\n return { principal, tenantId, expiresAtMs };\n}\n\n/** `null` means two independently verified identities disagree. */\nfunction combineIdentities(\n requestIdentity: ForwardedIdentity | undefined,\n upgradeIdentity: WebSocketUpgradeIdentity | undefined,\n): ForwardedIdentity | null | undefined {\n if (!requestIdentity && !upgradeIdentity) return undefined;\n if (!requestIdentity) return upgradeIdentity;\n if (!upgradeIdentity) return requestIdentity;\n if (\n requestIdentity.principal.issuer !== upgradeIdentity.principal.issuer ||\n requestIdentity.principal.subject !== upgradeIdentity.principal.subject ||\n requestIdentity.principal.principalType !== upgradeIdentity.principal.principalType ||\n requestIdentity.tenantId !== upgradeIdentity.tenantId\n ) {\n return null;\n }\n return {\n principal: { ...upgradeIdentity.principal },\n tenantId: upgradeIdentity.tenantId,\n expiresAtMs: Math.min(requestIdentity.expiresAtMs, upgradeIdentity.expiresAtMs),\n };\n}\n\n/** Read `@WebSocketGateway({ path, binding })` off a resolved instance (CF-hosted gateways only). */\nexport function collectWsGatewayRoutes(instance: object): WsGatewayRoute[] {\n // Decorator metadata is the framework's explicit reflection boundary.\n const options = getMetadata<WebSocketGatewayOptions>(WS_GATEWAY_METADATA, instance.constructor);\n if (!options?.path || !options?.binding) return [];\n resolveGatewayRoomParam(options);\n resolveMaxFrameBytes(options);\n return [{ path: options.path, binding: options.binding, options: { ...options } }];\n}\n\n/**\n * Registers the upgrade routes on the Worker's Hono app. Each route validates\n * the `Upgrade` header, resolves the room's Durable Object, and forwards the raw\n * request — injecting spoof-safe `x-vela-*` headers the DO reads. The DO returns\n * the `101` with the client socket.\n */\nexport function registerWebSocketRoutes(hono: Hono, routes: WsGatewayRoute[]): void {\n for (const route of routes) {\n hono.get(route.path, async (c: Context) => {\n if (c.req.header('upgrade')?.toLowerCase() !== 'websocket') {\n return c.text('Expected WebSocket upgrade', 426);\n }\n\n // Internal transport headers are never application credentials. Remove\n // client-supplied values before even the pre-allocation authorization\n // hook sees the request, then populate trusted values below.\n const headers = new Headers(c.req.raw.headers);\n headers.delete('x-vela-room');\n headers.delete('x-vela-path');\n headers.delete('x-vela-user');\n headers.delete('x-vela-expires-at');\n headers.delete('x-vela-expires-at-ms');\n headers.delete('x-vela-issuer');\n headers.delete('x-vela-subject');\n headers.delete('x-vela-principal-type');\n headers.delete('x-vela-tenant');\n const sanitizedRequest = new Request(c.req.raw, { headers });\n\n let roomId: string;\n try {\n roomId = resolveGatewayRoomId(route.options, (name) => c.req.param(name));\n } catch {\n return c.text('Invalid WebSocket room', 400);\n }\n\n // Origin, application authorization, and ticket/cookie authentication\n // all complete before the gateway Durable Object id is resolved.\n const upgrade = await authenticateWebSocketUpgrade(route.options, sanitizedRequest, roomId);\n if (upgrade === false) return c.text('WebSocket upgrade forbidden', 403);\n\n const requestIdentity = accessIdentity(c);\n if (requestIdentity === null) return c.text('Invalid WebSocket identity', 403);\n const identity = combineIdentities(requestIdentity, upgrade.identity);\n if (identity === null) return c.text('Conflicting WebSocket identities', 403);\n if (identity && identity.expiresAtMs <= Date.now()) {\n return c.text('WebSocket identity expired', 403);\n }\n\n // Populate the ticket-free forwarding request with trusted server values.\n const forwardHeaders = new Headers(upgrade.request.headers);\n forwardHeaders.set('x-vela-room', roomId);\n forwardHeaders.set('x-vela-path', route.path);\n if (identity) {\n forwardHeaders.set('x-vela-user', identity.principal.subject);\n forwardHeaders.set('x-vela-issuer', identity.principal.issuer);\n forwardHeaders.set('x-vela-subject', identity.principal.subject);\n forwardHeaders.set('x-vela-principal-type', identity.principal.principalType);\n forwardHeaders.set('x-vela-tenant', identity.tenantId);\n forwardHeaders.set('x-vela-expires-at-ms', String(identity.expiresAtMs));\n }\n\n return forwardToRoom(\n c.env,\n route.binding,\n route.path,\n roomId,\n new Request(upgrade.request, { headers: forwardHeaders }),\n );\n });\n }\n}\n\n/**\n * Gateway metadata contains a runtime binding name, so the native type is\n * erased. Validate only the operations consumed here and their observable\n * results; never assert that an arbitrary value implements a native namespace.\n */\nasync function forwardToRoom(\n env: unknown,\n binding: string,\n path: string,\n room: string,\n request: Request,\n): Promise<Response> {\n if (typeof env !== 'object' || env === null) throw new Error('Worker environment is missing');\n const namespace: unknown = Reflect.get(env, binding);\n if (typeof namespace !== 'object' || namespace === null) {\n return new Response(`Durable Object binding '${binding}' is not configured`, { status: 500 });\n }\n const idFromName: unknown = Reflect.get(namespace, 'idFromName');\n const get: unknown = Reflect.get(namespace, 'get');\n if (typeof idFromName !== 'function' || typeof get !== 'function') {\n throw new Error('Invalid Durable Object namespace');\n }\n const id: unknown = Reflect.apply(idFromName, namespace, [durableObjectRoomName(path, room)]);\n const stub: unknown = Reflect.apply(get, namespace, [id]);\n if (typeof stub !== 'object' || stub === null) throw new Error('Invalid Durable Object stub');\n const fetch: unknown = Reflect.get(stub, 'fetch');\n if (typeof fetch !== 'function') throw new Error('Durable Object stub has no fetch operation');\n const response: unknown = await Reflect.apply(fetch, stub, [request]);\n if (!(response instanceof Response))\n throw new Error('Durable Object returned an invalid response');\n return response;\n}\n","import type { ExecutionContext } from 'hono';\nimport {\n CRON_METADATA,\n PipelineRunner,\n buildEntrypointExecutionContext,\n registerEntrypointKind,\n getEntrypointModuleId,\n resolveEntrypoint,\n resolveScopedComponentsAsync,\n resolveErrorReporter,\n runInEntrypointScope,\n shouldFilterCatch,\n type VelaApplication,\n} from '@velajs/vela';\nimport type { Entrypoint, ExceptionFilter } from '@velajs/vela';\nimport { readWsEntrypointMeta } from '@velajs/vela/websocket';\nimport { collectWsGatewayRoutes, type WsGatewayRoute } from './websocket/websocket-routing';\nimport { assertCloudflareEnvironment } from './environment';\n\n// vela's own @Cron jobs run via the same Workers cron trigger — declare an\n// entrypoint kind over vela's metadata key (the open-kind system makes\n// cross-package declarations first-class).\nregisterEntrypointKind({ kind: 'cf:vela-cron', metaKey: CRON_METADATA, level: 'method' });\n\n/**\n * Options accepted by {@link CloudflareApplication.mountOpenApi}.\n *\n * Re-exposes vela's `MountOpenApiOptions` type — derived structurally from\n * the underlying `VelaApplication.mountOpenApi` signature so consumers don't\n * have to reach into vela's internal subpaths to type the argument.\n */\nexport type MountOpenApiOptions = Parameters<VelaApplication['mountOpenApi']>[0];\n\nfunction invoke(instance: object, methodName: string | symbol, args: unknown[]): unknown {\n // Decorator metadata names an instance method; inspect it before invoking.\n const method: unknown = Reflect.get(instance, methodName);\n if (typeof method !== 'function') {\n throw new Error(\n `Method '${String(methodName)}' is not a function on ${instance.constructor.name}`,\n );\n }\n return Reflect.apply(method, instance, args);\n}\n\nfunction entrypointString(meta: unknown, property: string): string {\n if (typeof meta !== 'object' || meta === null) throw new Error('Invalid entrypoint metadata.');\n const value: unknown = Reflect.get(meta, property);\n if (typeof value !== 'string')\n throw new Error(`Invalid entrypoint metadata: ${property} must be a string.`);\n return value;\n}\n\n/** Wait for every matching handler, even when one fails before its siblings. */\nasync function settleEntrypoints(work: readonly Promise<void>[]): Promise<void> {\n const outcomes = await Promise.allSettled(work);\n const errors = outcomes.flatMap((outcome) =>\n outcome.status === 'rejected' ? [outcome.reason] : [],\n );\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'Multiple entrypoint handlers failed.');\n}\n\n/**\n * Wraps VelaApplication with Cloudflare-specific handlers:\n * - `fetch` — HTTP request handler (from Hono)\n * - `scheduled` — Cron trigger handler (matches `@Scheduled()` decorators\n * AND vela's own `@Cron()` jobs)\n * - `queue` — Queue consumer handler (matches `@QueueConsumer()` decorators)\n * - `mountOpenApi` — Serve an OpenAPI document (and optional Scalar UI) on\n * the underlying Hono app\n *\n * @example\n * ```ts\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * export default {\n * fetch: app.fetch,\n * scheduled: app.scheduled.bind(app),\n * queue: app.queue.bind(app),\n * };\n * ```\n *\n * @example\n * ```ts\n * // Serve OpenAPI docs alongside your routes\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * const document = createOpenApiDocument(AppModule);\n * app.mountOpenApi({ document, ui: 'scalar' });\n * // GET /openapi.json -> JSON document\n * // GET /scalar -> Scalar UI (loads from CDN)\n * ```\n */\nexport class CloudflareApplication<T extends object = object> {\n readonly #wsGatewayRoutes: WsGatewayRoute[] = [];\n readonly #app: VelaApplication;\n\n constructor(\n app: VelaApplication,\n readonly env: T,\n ) {\n this.#app = app;\n this.get = app.get.bind(app);\n }\n\n readonly fetch = async (request: Request, env: T, ctx?: ExecutionContext): Promise<Response> => {\n assertCloudflareEnvironment(this.env, env);\n return this.#app.fetch(request, env, ctx);\n };\n\n getHonoApp(): ReturnType<VelaApplication['getHonoApp']> {\n return this.#app.getHonoApp();\n }\n\n /**\n * Resolve a provider from the application's DI container (delegates to\n * `VelaApplication.get`). Handy for grabbing a service — e.g. an auth service —\n * to use inside `createCloudflareApp({ middleware: env => [...] })` request middleware,\n * which runs outside the DI request pipeline.\n *\n * @example\n * ```ts\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * const auth = app.get(BetterAuthService);\n * ```\n */\n readonly get: VelaApplication['get'];\n\n get entrypoints(): VelaApplication['entrypoints'] {\n return this.#app.entrypoints;\n }\n\n /**\n * Serve a pre-built OpenAPI document (and optionally a Scalar UI) on the\n * underlying Hono app. Delegates verbatim to `VelaApplication.mountOpenApi`,\n * so the JSON endpoint defaults to `/openapi.json` and the Scalar UI (when\n * opted in) defaults to `/scalar`. Edge-safe — the UI HTML loads Scalar from\n * a CDN at runtime, nothing is bundled server-side.\n *\n * @example\n * ```ts\n * import { createOpenApiDocument } from '@velajs/vela';\n *\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * const document = createOpenApiDocument(AppModule, {\n * info: { title: 'My API', version: '1.0.0' },\n * });\n * app.mountOpenApi({ document, ui: 'scalar' });\n * // GET /openapi.json -> { openapi: '3.1.0', ... }\n * // GET /scalar -> Scalar UI HTML\n * ```\n */\n mountOpenApi(options: MountOpenApiOptions): this {\n this.#app.mountOpenApi(options);\n return this;\n }\n\n /**\n * @internal Upgrade routes come from validated gateway entrypoints, including\n * request-scoped gateways without a bootstrap instance. Retain the instance\n * scan for legacy applications that only declare forwarding metadata.\n */\n scanInstances(instances: unknown[]): void {\n const routes = new Map<string, WsGatewayRoute>();\n for (const ep of this.#app.entrypoints.ofKind('websocket')) {\n if (typeof ep.meta !== 'object' || ep.meta === null || !('dispatcher' in ep.meta)) continue;\n const meta = readWsEntrypointMeta(ep.meta);\n if (meta.options.binding) {\n routes.set(meta.path, {\n path: meta.path,\n binding: meta.options.binding,\n options: { ...meta.options },\n });\n }\n }\n for (const instance of instances) {\n if (!instance || typeof instance !== 'object') continue;\n for (const route of collectWsGatewayRoutes(instance)) {\n if (!routes.has(route.path)) routes.set(route.path, route);\n }\n }\n this.#wsGatewayRoutes.splice(0, this.#wsGatewayRoutes.length, ...routes.values());\n }\n\n /** @internal — upgrade routes discovered from the application's gateways. */\n getWsGatewayRoutes(): WsGatewayRoute[] {\n return [...this.#wsGatewayRoutes];\n }\n\n /**\n * Handle Cloudflare scheduled (cron) events.\n * Matches the event's cron expression to `@Scheduled()` and vela `@Cron()`\n * handlers read from `app.entrypoints`; each handler runs inside a fresh\n * request-scoped child (request-scoped providers rebuild per tick).\n */\n async scheduled(\n event: { cron: string; scheduledTime?: number },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n assertCloudflareEnvironment(this.env, env);\n const handlers = [\n ...this.#app.entrypoints\n .ofKind('cf:scheduled')\n .map((ep) => ({ ep, cron: entrypointString(ep.meta, 'cron') })),\n ...this.#app.entrypoints\n .ofKind('cf:vela-cron')\n .map((ep) => ({ ep, cron: entrypointString(ep.meta, 'expression') })),\n ].filter((h) => h.cron === event.cron);\n\n await settleEntrypoints(handlers.map(({ ep }) => this.dispatchEntrypoint(ep, event, env, ctx)));\n }\n\n /**\n * Run one entrypoint handler inside a fresh request scope, through the\n * shared guard → interceptor pipeline (components declared with\n * `@UseGuards`/`@UseInterceptors`/`@UseFilters` on the consumer class or\n * method). HTTP-global components deliberately do NOT apply — an HTTP auth\n * guard has no business rejecting a queue batch. Unclaimed errors rethrow\n * so the platform's retry semantics stay intact.\n */\n private async dispatchEntrypoint(\n ep: Entrypoint,\n payload: unknown,\n env: T,\n platformContext: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n const targetClass = ep.token;\n if (typeof targetClass !== 'function') throw new Error('Entrypoint token must be a class.');\n if (ep.methodName === undefined) throw new Error('Entrypoint must declare a handler method.');\n const methodName = ep.methodName;\n const reportContext = {\n edge: ep.kind === 'cf:queue' ? ('queue' as const) : ('schedule' as const),\n source: `${targetClass.name}.${String(methodName)}`,\n };\n let reported: { error: unknown } | undefined;\n try {\n await runInEntrypointScope(this.#app.getContainer(), async (scope, lifetime) => {\n const moduleId = getEntrypointModuleId(scope, ep);\n const context = buildEntrypointExecutionContext(\n ep.kind,\n targetClass,\n methodName,\n payload,\n moduleId,\n scope,\n );\n const invocationContext = {\n waitUntil(promise: Promise<unknown>): void {\n lifetime.waitUntil(promise);\n platformContext.waitUntil(promise);\n },\n };\n let filters: ExceptionFilter[] = [];\n try {\n filters = (\n await resolveScopedComponentsAsync('filter', targetClass, methodName, scope, moduleId)\n ).toReversed();\n const guards = await resolveScopedComponentsAsync(\n 'guard',\n targetClass,\n methodName,\n scope,\n moduleId,\n );\n const interceptors = await resolveScopedComponentsAsync(\n 'interceptor',\n targetClass,\n methodName,\n scope,\n moduleId,\n );\n await PipelineRunner.run({\n context,\n guards,\n interceptors,\n resolveArgs: async () => [payload, env, invocationContext],\n invoke: async (args) => {\n const instance = await resolveEntrypoint(scope, ep);\n if (typeof instance !== 'object' || instance === null) {\n throw new Error('Entrypoint must resolve to an object.');\n }\n return invoke(instance, methodName, args);\n },\n });\n } catch (error) {\n resolveErrorReporter(scope).report(error, reportContext);\n for (const filter of filters) {\n if (shouldFilterCatch(filter, error)) {\n // Filters run closest-first; this is the framework catch hook.\n // eslint-disable-next-line no-await-in-loop, promise/valid-params\n await filter.catch(error, context);\n return;\n }\n }\n reported = { error };\n throw error;\n }\n });\n } catch (error) {\n // Managed completion happens after the handler's filter boundary. Report\n // a new completion failure without reporting an already-observed handler\n // failure twice; preserve both errors in the rejected invocation.\n if (!reported || reported.error !== error) {\n const completionError =\n reported && error instanceof AggregateError && error.errors[0] === reported.error\n ? error.errors[1]\n : error;\n resolveErrorReporter(this.#app.getContainer()).report(completionError, reportContext);\n }\n throw error;\n }\n }\n\n /**\n * Handle Cloudflare Queue consumer events.\n * Matches the batch queue name to `@QueueConsumer()` handlers read from\n * `app.entrypoints`; each batch is processed inside a fresh request-scoped\n * child (request-scoped providers rebuild per batch — no boot-time captives).\n */\n async queue(\n batch: { queue: string; messages: readonly unknown[] },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n assertCloudflareEnvironment(this.env, env);\n const handlers = this.#app.entrypoints\n .ofKind('cf:queue')\n .filter((ep) => entrypointString(ep.meta, 'queueName') === batch.queue);\n\n await settleEntrypoints(handlers.map((ep) => this.dispatchEntrypoint(ep, batch, env, ctx)));\n }\n\n async close(signal?: string): Promise<void> {\n return this.#app.close(signal);\n }\n}\n","import type { ExecutionContext } from 'hono';\nimport { getConnInfo } from 'hono/cloudflare-workers';\nimport { VelaFactory } from '@velajs/vela';\nimport type {\n InjectionToken,\n RuntimeAdapter,\n VelaMiddlewareHandler,\n VelaSecurityOptions,\n} from '@velajs/vela';\nimport { CloudflareApplication } from './cloudflare-application';\nimport { assertCloudflareEnvironment, registerCloudflareEnvironment } from './environment';\nimport { registerWebSocketRoutes } from './websocket/websocket-routing';\nimport { resolveCloudflareRoot } from './root-module';\nimport type { CloudflareRoot } from './root-module';\n\nexport interface CloudflareWorkerOptions<T extends object> {\n /** Global typed DI token for the platform's native environment. */\n envToken: InjectionToken<T>;\n globalPrefix?: string;\n security?: VelaSecurityOptions;\n /** Build request middleware from the same typed native environment as DI. */\n middleware?: (env: NoInfer<T>) => VelaMiddlewareHandler[];\n}\n\nexport interface CreateCloudflareAppOptions<T extends object> extends CloudflareWorkerOptions<T> {\n /** Supply the platform environment inside fetch/queue/scheduled or a DO constructor. */\n env: NoInfer<T>;\n}\n\n/** Bind an application to one environment before provider factories and lifecycle hooks. */\nexport function cloudflareAdapter<T extends object>(\n options: CreateCloudflareAppOptions<T>,\n): RuntimeAdapter {\n return {\n name: 'cloudflare',\n requestMiddleware: [\n async (context, next) => {\n assertCloudflareEnvironment(options.env, context.env);\n await next();\n },\n ],\n invocationTransport:\n ({ app }) =>\n (request) =>\n Promise.resolve(app.fetch(request, options.env)),\n getClientIp: (c) => getConnInfo(c).remote.address ?? null,\n configureContainer: (container) => {\n registerCloudflareEnvironment(container, { token: options.envToken, env: options.env });\n },\n };\n}\n\n/** Build an application for one native Workers environment. Call inside a platform event. */\nexport async function createCloudflareApp<T extends object>(\n rootModule: CloudflareRoot<NoInfer<T>>,\n options: CreateCloudflareAppOptions<T>,\n): Promise<CloudflareApplication<T>> {\n const velaApp = await VelaFactory.create(resolveCloudflareRoot(rootModule, options.env), {\n globalPrefix: options.globalPrefix,\n security: options.security,\n middleware: options.middleware?.(options.env),\n adapters: [cloudflareAdapter(options)],\n });\n const app = new CloudflareApplication(velaApp, options.env);\n app.scanInstances(velaApp.getInstances());\n registerWebSocketRoutes(app.getHonoApp(), app.getWsGatewayRoutes());\n return app;\n}\n\n/**\n * Worker entrypoint with one bootstrap per environment identity. Weak keys let\n * obsolete environments and secrets be collected. Concurrent cold events share\n * construction; failed construction is evicted so the next event can retry.\n */\nexport function createCloudflareWorker<T extends object>(\n rootModule: CloudflareRoot<NoInfer<T>>,\n options: CloudflareWorkerOptions<T>,\n) {\n const applications = new WeakMap<T, Promise<CloudflareApplication<T>>>();\n const application = (env: T): Promise<CloudflareApplication<T>> => {\n const existing = applications.get(env);\n if (existing) return existing;\n const pending = createCloudflareApp(rootModule, { ...options, env });\n applications.set(env, pending);\n void pending.catch(() => {\n if (applications.get(env) === pending) applications.delete(env);\n });\n return pending;\n };\n return {\n async fetch(request: Request, env: T, ctx: ExecutionContext): Promise<Response> {\n return (await application(env)).fetch(request, env, ctx);\n },\n async scheduled(\n event: { cron: string; scheduledTime?: number },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n return (await application(env)).scheduled(event, env, ctx);\n },\n async queue(\n batch: { queue: string; messages: readonly unknown[] },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n return (await application(env)).queue(batch, env, ctx);\n },\n };\n}\n","import { InjectionToken } from '@velajs/vela';\nimport type { StorageModuleOptions } from './storage.types';\n\nexport const STORAGE_OPTIONS = new InjectionToken<StorageModuleOptions>('STORAGE_OPTIONS');\n","/** R2-compatible object-key claim bound. Keeps decode work predictably small. */\nexport const MAX_STORAGE_KEY_BYTES = 1024;\n\nconst BASE64URL_RE = /^[A-Za-z0-9_-]+$/;\nconst ROOT_TOKEN_PATTERNS: Record<string, string> = {\n date: '\\\\d{4}-\\\\d{2}-\\\\d{2}',\n year: '\\\\d{4}',\n month: '(?:0[1-9]|1[0-2])',\n day: '(?:0[1-9]|[12]\\\\d|3[01])',\n uuid: '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}',\n};\n\n/** Encode an object key as an opaque, canonical base64url query claim. */\nexport function encodeStorageKeyClaim(key: string): string {\n const bytes = new TextEncoder().encode(key);\n if (bytes.byteLength === 0 || bytes.byteLength > MAX_STORAGE_KEY_BYTES) {\n throw new Error(`Storage key must be 1–${MAX_STORAGE_KEY_BYTES} UTF-8 bytes`);\n }\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/** Decode exactly one canonical base64url layer. Malformed/non-UTF-8 claims return undefined. */\nexport function decodeStorageKeyClaim(claim: string): string | undefined {\n try {\n if (\n claim.length === 0 ||\n claim.length > Math.ceil((MAX_STORAGE_KEY_BYTES * 4) / 3) ||\n !BASE64URL_RE.test(claim) ||\n claim.length % 4 === 1\n ) {\n return undefined;\n }\n const base64 = claim.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(padded);\n const bytes = new Uint8Array(new ArrayBuffer(binary.length));\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n if (bytes.byteLength === 0 || bytes.byteLength > MAX_STORAGE_KEY_BYTES) return undefined;\n const decoded = new TextDecoder('utf-8', { fatal: true, ignoreBOM: false }).decode(bytes);\n return encodeStorageKeyClaim(decoded) === claim ? decoded : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isDotSegment(segment: string): boolean {\n let decoded = segment;\n for (let i = 0; i < 2; i++) {\n if (decoded === '' || decoded === '.' || decoded === '..') return true;\n try {\n const next = decodeURIComponent(decoded);\n if (next === decoded) break;\n decoded = next;\n } catch {\n break;\n }\n }\n return decoded === '' || decoded === '.' || decoded === '..';\n}\n\nfunction rootSegmentPattern(segment: string): string {\n let pattern = '';\n let cursor = 0;\n for (const match of segment.matchAll(/\\{(date|year|month|day|uuid)\\}/g)) {\n pattern += segment.slice(cursor, match.index).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n pattern += ROOT_TOKEN_PATTERNS[match[1]!]!;\n cursor = match.index! + match[0].length;\n }\n pattern += segment.slice(cursor).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return pattern;\n}\n\n/** Assert a canonical key is beneath a static or templated configured root. */\nexport function isStorageKeyWithinRoot(key: string, root: string | undefined): boolean {\n const segments = (root ?? '').split(/[/\\\\]+/).filter((segment) => !isDotSegment(segment));\n if (segments.length === 0) return key.length > 0;\n const rootPattern = segments.map(rootSegmentPattern).join('/');\n return new RegExp(`^(?:${rootPattern})(?:/|$)`).test(key);\n}\n","import {\n signUrl,\n STORAGE_SIGNED_URL_PURPOSE,\n type DownloadResult,\n type PresignedUrlResult,\n type PresignMethod,\n type StorageBody,\n type StorageDriver,\n type UploadOptions,\n type UploadResult,\n} from '@velajs/vela/storage';\nimport { encodeStorageKeyClaim } from './storage-key-claim';\n\n/** Base path of the StorageController presign-proxy route. */\nexport const STORAGE_ROUTE_BASE = '/storage';\n\nexport interface R2StorageDriverConfig {\n disk: string;\n bucket: R2Bucket;\n /** HMAC secret for presigned URLs (typically env.APP_SECRET). */\n secret?: string;\n}\n\n/** {@link StorageDriver} over a Cloudflare R2 bucket. */\nexport class R2StorageDriver implements StorageDriver {\n constructor(private readonly config: R2StorageDriverConfig) {}\n\n async upload(body: StorageBody, path: string, options: UploadOptions): Promise<UploadResult> {\n await this.config.bucket.put(\n path,\n body as ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob | null,\n {\n httpMetadata: options.mimeType ? { contentType: options.mimeType } : undefined,\n customMetadata: options.metadata,\n },\n );\n return {\n path,\n disk: this.config.disk,\n size: options.size,\n mimeType: options.mimeType ?? 'application/octet-stream',\n uploadedAt: new Date(),\n };\n }\n\n async download(path: string): Promise<DownloadResult> {\n const obj = await this.config.bucket.get(path);\n if (!obj) throw new Error(`Storage object not found at \"${path}\".`);\n return {\n toStream: () => obj.body as ReadableStream,\n toArrayBuffer: () => obj.arrayBuffer(),\n toText: () => obj.text(),\n contentType: obj.httpMetadata?.contentType ?? 'application/octet-stream',\n size: obj.size,\n metadata: obj.customMetadata,\n };\n }\n\n async delete(path: string): Promise<void> {\n await this.config.bucket.delete(path);\n }\n\n async exists(path: string): Promise<boolean> {\n return (await this.config.bucket.head(path)) !== null;\n }\n\n async getPresignedUrl(\n path: string,\n method: PresignMethod,\n expiresIn: number,\n ): Promise<PresignedUrlResult> {\n if (!this.config.secret) {\n throw new Error('A signing secret is required for presigned URLs (set APP_SECRET).');\n }\n // Defend the direct-driver path too: a non-finite/non-positive expiry would\n // make signUrl omit `expires`, yielding a never-expiring URL.\n if (!Number.isSafeInteger(expiresIn) || expiresIn <= 0) {\n throw new Error(\n `Invalid presigned URL expiry: ${expiresIn}s (must be a positive safe integer).`,\n );\n }\n // The object key is an opaque signed query claim, never a URL path. This\n // prevents WHATWG path normalization / multi-decode behavior from turning\n // an encoded key into a different storage capability.\n const claim = encodeStorageKeyClaim(path);\n const routePath = `${STORAGE_ROUTE_BASE}/${encodeURIComponent(this.config.disk)}`;\n const query = new URLSearchParams({ key: claim, method });\n const url = await signUrl(`${routePath}?${query}`, this.config.secret, {\n expiresIn,\n method,\n purpose: STORAGE_SIGNED_URL_PURPOSE,\n });\n return { url, method, expiresIn, expiresAt: new Date(Date.now() + expiresIn * 1000) };\n }\n}\n","import { Inject, Injectable } from '@velajs/vela';\nimport { R2StorageDriver } from './r2-storage.driver';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { DiskConfig, StorageModuleOptions } from './storage.types';\n\n@Injectable()\nexport class StorageManagerService {\n constructor(@Inject(STORAGE_OPTIONS) private readonly options: StorageModuleOptions) {}\n\n hasDisk(disk: string): boolean {\n return this.options.disks.some((d) => d.disk === disk);\n }\n\n getDiskConfig(disk: string): DiskConfig {\n const config = this.options.disks.find((d) => d.disk === disk);\n if (!config) throw new Error(`Storage disk \"${disk}\" is not configured.`);\n return config;\n }\n\n getDriver(disk: string): R2StorageDriver {\n const config = this.getDiskConfig(disk);\n return new R2StorageDriver({ disk, bucket: config.bucket, secret: this.options.secret });\n }\n}\n","import { Controller, Get, Inject, Req } from '@velajs/vela';\nimport { joinStoragePath, STORAGE_SIGNED_URL_PURPOSE, verifySignedUrl } from '@velajs/vela/storage';\nimport type { Context } from 'hono';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { StorageModuleOptions } from './storage.types';\nimport { StorageManagerService } from './storage-manager.service';\nimport { decodeStorageKeyClaim, isStorageKeyWithinRoot } from './storage-key-claim';\n\n/**\n * Presign-proxy: serves objects for HMAC-signed URLs produced by\n * `StorageService.url()`. R2 has no native presign, so a signed URL points here;\n * this route verifies the signature (+expiry) before streaming the object.\n * The FULL object key (root already applied at sign time) is carried as an\n * opaque base64url query claim. The signature is verified before the claim is\n * decoded exactly once and checked against the configured disk root.\n */\n@Controller('storage')\nexport class StorageController {\n constructor(\n @Inject(StorageManagerService) private readonly manager: StorageManagerService,\n @Inject(STORAGE_OPTIONS) private readonly options: StorageModuleOptions,\n ) {}\n\n @Get('/:disk')\n async download(@Req() c: Context): Promise<Response> {\n const secret = this.options.secret;\n if (!secret) return new Response('Storage signing is not configured', { status: 500 });\n\n // Verify the complete path/query capability before inspecting the disk or\n // decoding attacker-controlled claims.\n if (\n !(await verifySignedUrl(c.req.url, secret, {\n method: c.req.method,\n purpose: STORAGE_SIGNED_URL_PURPOSE,\n }))\n ) {\n return new Response('Invalid or expired URL', { status: 403 });\n }\n\n // Enforce the signed `method` scope: this proxy only serves reads, so a URL\n // scoped to PUT/DELETE/HEAD must NOT be honored as a GET (it would over-grant\n // read access relative to the token's intended scope). The param is part of\n // the signed payload, so it is trustworthy once the signature verifies.\n const url = new URL(c.req.url);\n if (url.searchParams.get('method') !== 'GET') {\n return new Response('URL is not scoped for reads', { status: 403 });\n }\n\n const disk = c.req.param('disk');\n if (!disk || !this.manager.hasDisk(disk)) return new Response('Unknown disk', { status: 404 });\n\n const claim = url.searchParams.get('key');\n const decoded = claim ? decodeStorageKeyClaim(claim) : undefined;\n if (!decoded) return new Response('Malformed storage key claim', { status: 400 });\n\n // Canonicalize after the one decode. Signed direct-driver callers cannot\n // smuggle dot segments or non-canonical aliases into the proxy contract.\n const fullPath = joinStoragePath(undefined, decoded);\n if (fullPath !== decoded) return new Response('Invalid storage key', { status: 403 });\n\n if (!isStorageKeyWithinRoot(fullPath, this.manager.getDiskConfig(disk).root)) {\n return new Response('Storage key is outside the configured root', { status: 403 });\n }\n\n try {\n const result = await this.manager.getDriver(disk).download(fullPath);\n const filename = fullPath.split('/').at(-1) || 'download';\n return new Response(result.toStream(), {\n headers: {\n 'content-type': result.contentType || 'application/octet-stream',\n // Objects are untrusted user content. The authenticated API origin\n // never renders them inline (especially HTML/SVG), even when the\n // stored Content-Type is attacker controlled.\n 'content-disposition': `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`,\n 'x-content-type-options': 'nosniff',\n },\n });\n } catch {\n return new Response('Not found', { status: 404 });\n }\n }\n}\n","import { Inject, Injectable } from '@velajs/vela';\nimport {\n joinStoragePath,\n type DownloadResult,\n type PresignedUrlResult,\n type PresignMethod,\n type StorageBody,\n type UploadOptions,\n type UploadResult,\n} from '@velajs/vela/storage';\nimport { StorageManagerService } from './storage-manager.service';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { StorageModuleOptions } from './storage.types';\n\nconst DEFAULT_PRESIGN = { defaultExpiry: 3600, maxExpiry: 86400 };\n\n/**\n * Multi-disk storage facade. Applies each disk's (templated) root, resolves the\n * driver, and validates presign expiry. Injectable anywhere via `StorageService`.\n */\n@Injectable()\nexport class StorageService {\n constructor(\n @Inject(STORAGE_OPTIONS) private readonly options: StorageModuleOptions,\n @Inject(StorageManagerService) private readonly manager: StorageManagerService,\n ) {}\n\n put(\n relativePath: string,\n body: StorageBody,\n options: UploadOptions = {},\n disk?: string,\n ): Promise<UploadResult> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).upload(body, this.fullPath(relativePath, name), options);\n }\n\n get(relativePath: string, disk?: string): Promise<DownloadResult> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).download(this.fullPath(relativePath, name));\n }\n\n delete(relativePath: string, disk?: string): Promise<void> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).delete(this.fullPath(relativePath, name));\n }\n\n exists(relativePath: string, disk?: string): Promise<boolean> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).exists(this.fullPath(relativePath, name));\n }\n\n url(\n relativePath: string,\n method: PresignMethod = 'GET',\n expiresIn?: number,\n disk?: string,\n ): Promise<PresignedUrlResult> {\n const name = this.resolveDisk(disk);\n return this.manager\n .getDriver(name)\n .getPresignedUrl(this.fullPath(relativePath, name), method, this.validateExpiry(expiresIn));\n }\n\n private resolveDisk(disk?: string): string {\n const name = disk ?? this.options.defaultDisk;\n if (!this.manager.hasDisk(name)) throw new Error(`Storage disk \"${name}\" is not configured.`);\n return name;\n }\n\n private fullPath(relativePath: string, disk: string): string {\n return joinStoragePath(this.manager.getDiskConfig(disk).root, relativePath);\n }\n\n private validateExpiry(expiresIn?: number): number {\n const cfg = this.options.presignedUrl ?? DEFAULT_PRESIGN;\n const value = expiresIn ?? cfg.defaultExpiry;\n // `Number.isSafeInteger` rejects NaN/fractional/infinite values — otherwise\n // `NaN < 1 || NaN > max` is false,\n // NaN slips through, signUrl omits `expires`, and the URL never expires.\n if (!Number.isSafeInteger(value) || value < 1 || value > cfg.maxExpiry) {\n throw new Error(`Presigned URL expiry ${value}s is out of range (1–${cfg.maxExpiry}s).`);\n }\n return value;\n }\n}\n","import { ConfigurableModuleBuilder, Module } from '@velajs/vela';\nimport { StorageController } from './storage.controller';\nimport { StorageManagerService } from './storage-manager.service';\nimport { StorageService } from './storage.service';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { StorageModuleOptions } from './storage.types';\n\nconst { ConfigurableModuleClass } = new ConfigurableModuleBuilder<StorageModuleOptions>({\n moduleName: 'Storage',\n optionsInjectionToken: STORAGE_OPTIONS,\n}).build();\n\n@Module({\n providers: [StorageManagerService, StorageService],\n controllers: [StorageController],\n exports: [StorageService, StorageManagerService, STORAGE_OPTIONS],\n})\nexport class StorageModule extends ConfigurableModuleClass {}\n","import {\n type AsyncCacheStore,\n type CacheEntryReader,\n type CacheEntryWriter,\n type CacheEntry,\n type CacheInvalidationStore,\n} from '@velajs/vela';\n\n/**\n * Native KV JSON value store. Metadata retains logical expiry even when KV's\n * physical retention rounds up to its 60-second minimum. Legacy values without\n * metadata remain readable, but cannot safely backfill another tier.\n */\nexport class KVCacheStore implements AsyncCacheStore, CacheEntryReader, CacheEntryWriter {\n constructor(private readonly ns: KVNamespace) {}\n\n async get(key: string): Promise<unknown> {\n return (await this.getEntry(key))?.value;\n }\n\n async getEntry(key: string): Promise<{ value: unknown; expiresAt?: number } | undefined> {\n const { value, metadata } = await this.ns.getWithMetadata<unknown, unknown>(key, 'json');\n if (value === null) return undefined;\n if (typeof metadata === 'object' && metadata !== null && 'velaCacheExpiresAt' in metadata) {\n const expiresAt = metadata.velaCacheExpiresAt;\n if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt) || expiresAt <= Date.now())\n return undefined;\n return { value, expiresAt };\n }\n return { value };\n }\n\n async set(key: string, value: unknown, ttl?: number): Promise<void> {\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl < 0))\n throw new TypeError('Cache TTL must be finite and nonnegative.');\n if (ttl !== undefined) return this.setEntry(key, { value, expiresAt: Date.now() + ttl * 1000 });\n await this.ns.put(key, JSON.stringify(value));\n }\n\n async setEntry(key: string, entry: CacheEntry): Promise<void> {\n if (!Number.isFinite(entry.expiresAt)) throw new TypeError('Cache expiry must be finite.');\n const remaining = (entry.expiresAt - Date.now()) / 1000;\n if (remaining <= 0) return this.del(key);\n await this.ns.put(key, JSON.stringify(entry.value), {\n expirationTtl: Math.max(60, Math.ceil(remaining)),\n metadata: { velaCacheExpiresAt: entry.expiresAt },\n });\n }\n\n async del(key: string): Promise<void> {\n await this.ns.delete(key);\n }\n\n /** Namespace-wide, best effort. Use a dedicated value namespace; never use for scoped invalidation. */\n async clear(): Promise<void> {\n let cursor: string | undefined;\n do {\n const list = await this.ns.list(cursor ? { cursor } : undefined);\n await Promise.all(list.keys.map((entry) => this.ns.delete(entry.name)));\n cursor = list.list_complete ? undefined : list.cursor;\n } while (cursor);\n }\n}\n\n/**\n * Optional, eventually consistent generation store. Use a dedicated KV namespace\n * without TTL/lifecycle cleanup. Never delete/reset generations while entries can\n * survive. Concurrent writes and cached/negative reads prevent strong invalidation;\n * this is unsuitable for strict read-after-write or authorization revocation.\n */\nexport class KVCacheInvalidationStore implements CacheInvalidationStore {\n constructor(private readonly ns: KVNamespace) {}\n async getVersion(key: string): Promise<string> {\n const value: unknown = await this.ns.get(key, 'json');\n if (value === null) return 'initial';\n if (typeof value !== 'string' || value.length === 0 || value.length > 2048)\n throw new TypeError('Invalid cache generation.');\n return value;\n }\n async invalidate(key: string): Promise<void> {\n await this.ns.put(key, JSON.stringify(crypto.randomUUID()));\n }\n}\n","import type { FeatureFlagDriver, FlagContext } from '@velajs/feature-flags';\n\n/**\n * The subset of a Cloudflare **Flagship** binding this driver evaluates against\n * — the four typed value methods. The binding itself returns the supplied\n * `defaultValue` on evaluation errors; transport-level failures reject and are\n * left to propagate (never-throw is the service layer's job, not the driver's).\n *\n * @see https://developers.cloudflare.com/flagship/binding/\n */\nexport interface FlagshipBinding {\n getBooleanValue(key: string, defaultValue: boolean, context?: FlagContext): Promise<boolean>;\n getStringValue(key: string, defaultValue: string, context?: FlagContext): Promise<string>;\n getNumberValue(key: string, defaultValue: number, context?: FlagContext): Promise<number>;\n getObjectValue(key: string, defaultValue: object, context?: FlagContext): Promise<unknown>;\n}\n\nexport interface FlagshipFlagDriverOptions {\n /** Driver name used for `use(name)` / default-driver selection. Default `\"flagship\"`. */\n name?: string;\n}\n\n/**\n * {@link FeatureFlagDriver} backed by a Cloudflare Flagship binding.\n *\n * A thin, honest wrapper: each contract method maps 1:1 onto the binding's\n * corresponding value method, forwarding the caller's `fallback` (the binding's\n * `defaultValue`) and evaluation context. The binding resolves the fallback on\n * evaluation errors; anything the binding *rejects* with (e.g. a `remote: true`\n * dev-proxy tunnel dropping) propagates — `@velajs/feature-flags`'s service owns\n * the never-throw guarantee.\n *\n * Build the driver inside a provider factory with the native environment:\n *\n * ```ts\n * FeatureFlagsModule.forRootAsync({\n * inject: [ENV],\n * useFactory: (env: WorkerEnv) => ({ drivers: [flagshipFlagDriver(env.FLAGS)] }),\n * });\n * ```\n *\n * Evaluation ergonomics (the 1:1 binding-method mapping) are ported from the\n * Stratal feature-flags service (MIT, © Temitayo Fadojutimi), reshaped as a\n * bare driver.\n */\nexport class FlagshipFlagDriver implements FeatureFlagDriver {\n readonly name: string;\n private readonly resolve: () => FlagshipBinding;\n\n constructor(\n binding: FlagshipBinding | (() => FlagshipBinding),\n options: FlagshipFlagDriverOptions = {},\n ) {\n this.resolve = typeof binding === 'function' ? binding : () => binding;\n this.name = options.name ?? 'flagship';\n }\n\n getBoolean(key: string, fallback: boolean, ctx?: FlagContext): Promise<boolean> {\n return this.resolve().getBooleanValue(key, fallback, ctx);\n }\n\n getString(key: string, fallback: string, ctx?: FlagContext): Promise<string> {\n return this.resolve().getStringValue(key, fallback, ctx);\n }\n\n getNumber(key: string, fallback: number, ctx?: FlagContext): Promise<number> {\n return this.resolve().getNumberValue(key, fallback, ctx);\n }\n\n getObject(key: string, fallback: object, ctx?: FlagContext): Promise<unknown> {\n return this.resolve().getObjectValue(key, fallback, ctx);\n }\n}\n\n/** Convenience factory for {@link FlagshipFlagDriver}. */\nexport function flagshipFlagDriver(\n binding: FlagshipBinding | (() => FlagshipBinding),\n options?: FlagshipFlagDriverOptions,\n): FlagshipFlagDriver {\n return new FlagshipFlagDriver(binding, options);\n}\n","import type { FeatureFlagDriver, FlagContext } from '@velajs/feature-flags';\n\nexport interface KvFlagDriverOptions {\n /** Driver name used for `use(name)` / default-driver selection. Default `\"kv\"`. */\n name?: string;\n /** Prefix prepended to every flag key before the KV read. Default `\"\"` (none). */\n prefix?: string;\n}\n\n/**\n * Cloudflare KV-backed {@link FeatureFlagDriver}. Flags are stored as JSON\n * values under an optional key prefix and read with `get(key, 'json')`. Reads\n * are type-checked against the requested type: a missing key or a value of the\n * wrong JSON type returns the caller's `fallback`. KV has no targeting, so the\n * evaluation context is ignored.\n *\n * The driver stays honest — it does **not** swallow errors. A KV failure (or a\n * `SyntaxError` from a malformed stored value) propagates; the never-throw\n * guarantee lives in `@velajs/feature-flags`'s service layer.\n *\n * Placed like {@link KVCacheStore}: construct it in a wiring factory over a\n * resolved {@link KVNamespace}.\n *\n * ```ts\n * FeatureFlagsModule.forRootAsync({\n * inject: [ENV],\n * useFactory: (env: WorkerEnv) => ({ drivers: [new KvFlagDriver(env.CACHE, { prefix: 'flag:' })] }),\n * });\n * ```\n */\nexport class KvFlagDriver implements FeatureFlagDriver {\n readonly name: string;\n private readonly prefix: string;\n\n constructor(\n private readonly ns: KVNamespace,\n options: KvFlagDriverOptions = {},\n ) {\n this.name = options.name ?? 'kv';\n this.prefix = options.prefix ?? '';\n }\n\n getBoolean(key: string, fallback: boolean, _ctx?: FlagContext): Promise<boolean> {\n return this.read(key, fallback, (v) => typeof v === 'boolean');\n }\n\n getString(key: string, fallback: string, _ctx?: FlagContext): Promise<string> {\n return this.read(key, fallback, (v) => typeof v === 'string');\n }\n\n getNumber(key: string, fallback: number, _ctx?: FlagContext): Promise<number> {\n return this.read(key, fallback, (v) => typeof v === 'number');\n }\n\n getObject(key: string, fallback: object, _ctx?: FlagContext): Promise<unknown> {\n return this.read(key, fallback, (v) => typeof v === 'object' && v !== null);\n }\n\n /**\n * Reads and JSON-parses the (prefixed) key, returning the parsed value only\n * when `matches` accepts its type; otherwise the caller's fallback. A missing\n * key reads as `null` → fallback. Read/parse errors are left to propagate.\n */\n private async read<T>(\n key: string,\n fallback: T,\n matches: (value: unknown) => value is T,\n ): Promise<T> {\n const value = await this.ns.get(this.prefix + key, 'json');\n if (value === null || value === undefined) return fallback;\n return matches(value) ? value : fallback;\n }\n}\n\n/** Convenience factory for {@link KvFlagDriver}. */\nexport function kvFlagDriver(kv: KVNamespace, options?: KvFlagDriverOptions): KvFlagDriver {\n return new KvFlagDriver(kv, options);\n}\n","import { createParamDecorator } from '@velajs/vela';\n\n/**\n * Parameter decorator to inject Cloudflare environment bindings.\n *\n * Without arguments, returns the entire `env` object.\n * With a binding name, returns that specific binding.\n *\n * @example\n * ```ts\n * @Get()\n * handle(@Env() env: WorkerEnv) { ... }\n *\n * @Get()\n * handle(@Env('MY_KV') kv: KVNamespace) { ... }\n * ```\n */\nexport const Env = createParamDecorator<string | undefined>((bindingName, ctx): unknown => {\n // Hono Context has .env on Cloudflare Workers\n const env: unknown = ctx.getContext().env;\n if (typeof env !== 'object' || env === null) return undefined;\n return bindingName ? Reflect.get(env, bindingName) : env;\n});\n","import { defineMetadata, getMetadata, parseCron, registerEntrypointKind } from '@velajs/vela';\n\nconst SCHEDULED_METADATA_KEY = 'cloudflare:scheduled';\n\n// Open entrypoint kind: adapters enumerate cron handlers via\n// `app.entrypoints.ofKind('cf:scheduled')` — declared next to the decorator.\nregisterEntrypointKind({ kind: 'cf:scheduled', metaKey: SCHEDULED_METADATA_KEY, level: 'method' });\n\nexport interface ScheduledMetadata {\n cron: string;\n methodName: string;\n}\n\n/** Compatible with the existing programmatic scheduled() entrypoint. */\nexport interface ScheduledEvent {\n readonly cron: string;\n readonly scheduledTime?: number;\n}\n\n/** Native controller passed unchanged to a Worker handler. Call noRetry on its receiver. */\nexport interface ScheduledController extends ScheduledEvent {\n readonly scheduledTime: number;\n noRetry(): void;\n}\n\nexport interface ScheduledContext {\n waitUntil(promise: Promise<unknown>): void;\n}\n\nexport type ScheduledHandler<Env extends object = object> = (\n controller: ScheduledController,\n env: Env,\n context: ScheduledContext,\n) => void | Promise<void>;\n\nexport function parseScheduledMetadata(value: unknown): ScheduledMetadata {\n if (\n typeof value !== 'object' ||\n value === null ||\n !('cron' in value) ||\n typeof value.cron !== 'string' ||\n !('methodName' in value) ||\n typeof value.methodName !== 'string' ||\n !parseCron(value.cron, { dialect: 'cloudflare' })\n ) {\n throw new TypeError('Invalid Cloudflare scheduled metadata');\n }\n return { cron: value.cron, methodName: value.methodName };\n}\n\n/**\n * Marks a method as a scheduled (cron) handler.\n *\n * @example\n * ```ts\n * @Injectable()\n * class WorkerService {\n * @Scheduled('0 * * * *')\n * async hourlyCron() {\n * console.log('Running hourly');\n * }\n * }\n * ```\n */\nexport function Scheduled(cron: string): MethodDecorator {\n if (!parseCron(cron, { dialect: 'cloudflare' })) {\n throw new TypeError(`Invalid Cloudflare cron expression: ${cron}`);\n }\n return (target: object, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n // Work with a validated copy rather than mutating the registry's handler list.\n const existing = getScheduledMetadata(target);\n existing.push({ cron, methodName: String(propertyKey) });\n defineMetadata(SCHEDULED_METADATA_KEY, existing, target.constructor);\n };\n}\n\nexport function getScheduledMetadata(target: object): ScheduledMetadata[] {\n const ctor = typeof target === 'function' ? target : target.constructor;\n const value: unknown = getMetadata(SCHEDULED_METADATA_KEY, ctor);\n if (value === undefined) return [];\n if (!Array.isArray(value)) throw new TypeError('Invalid Cloudflare scheduled metadata list');\n return value.map(parseScheduledMetadata);\n}\n","import { defineMetadata, getMetadata, registerEntrypointKind } from '@velajs/vela';\n\nconst QUEUE_CONSUMER_METADATA_KEY = 'cloudflare:queue-consumer';\n\n// Open entrypoint kind: any adapter can enumerate queue consumers via\n// `app.entrypoints.ofKind('cf:queue')` — declared here, next to the decorator,\n// with zero vela-core involvement.\nregisterEntrypointKind({ kind: 'cf:queue', metaKey: QUEUE_CONSUMER_METADATA_KEY, level: 'method' });\n\nexport interface QueueConsumerMetadata {\n queueName: string;\n methodName: string;\n}\n\n/**\n * Marks a method as a queue consumer handler.\n *\n * @example\n * ```ts\n * @Injectable()\n * class WorkerService {\n * @QueueConsumer('email-queue')\n * async processEmails(batch: MessageBatch) {\n * for (const msg of batch.messages) {\n * console.log('Processing:', msg.body);\n * msg.ack();\n * }\n * }\n * }\n * ```\n */\nexport function QueueConsumer(queueName: string): MethodDecorator {\n return (target: object, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n const existing: QueueConsumerMetadata[] =\n (getMetadata(QUEUE_CONSUMER_METADATA_KEY, target.constructor) as QueueConsumerMetadata[]) ??\n [];\n existing.push({ queueName, methodName: String(propertyKey) });\n defineMetadata(QUEUE_CONSUMER_METADATA_KEY, existing, target.constructor);\n };\n}\n\nexport function getQueueConsumerMetadata(target: object): QueueConsumerMetadata[] {\n const ctor = target.constructor ?? target;\n return (getMetadata(QUEUE_CONSUMER_METADATA_KEY, ctor) as QueueConsumerMetadata[]) ?? [];\n}\n","import { defineProvider, type DynamicModule } from '@velajs/vela';\nimport { WsDispatcher, WS_SERVER } from '@velajs/vela/websocket';\nimport { WsServerHolder } from './ws-server-holder';\n\n/**\n * Cloudflare counterpart to the core `WebSocketModule.forRoot()`. Import this in\n * your `AppModule` instead: it provides the gateway dispatcher plus a late-bound\n * `WS_SERVER` (`WsServerHolder`) that the WebSocket Durable Object wires to a\n * ctx-backed server per instance. `useClass` ensures a fresh holder per DI\n * container so colocated DO instances never share a server.\n */\nexport class CloudflareWebSocketModule {\n static forRoot(): DynamicModule {\n const providers = [defineProvider(WS_SERVER, { useClass: WsServerHolder }), WsDispatcher];\n\n return {\n module: CloudflareWebSocketModule,\n providers,\n exports: [WS_SERVER, WsDispatcher],\n };\n }\n}\n","import {\n assertBroadcastCommandFits,\n DEFAULT_WS_MAX_FRAME_BYTES,\n resolveMaxFrameBytes,\n} from '@velajs/vela/websocket';\nimport type { BroadcastCommand } from '@velajs/vela/websocket';\nimport { roomToDurableId } from './room-id';\n\nexport interface WsBroadcastStub {\n broadcast(cmd: BroadcastCommand): Promise<void>;\n}\n\nexport interface BroadcastNamespace {\n idFromName(name: string): DurableObjectId;\n get(id: DurableObjectId): WsBroadcastStub;\n}\n\n/**\n * Push to a room from a Worker HTTP handler / cron / queue consumer (server-\n * initiated emit). Resolves the room's Durable Object and calls its `broadcast`\n * RPC method — the same canonical room→DO mapping the upgrade route uses, so it\n * always reaches the DO holding those sockets.\n *\n * @example\n * ```ts\n * // In a controller — ns from the typed Worker environment\n * await broadcastToRoom(ns, '/orgs/:orgId/ws', `org:${id}`, 'order.created', order);\n * ```\n */\nexport async function broadcastToRoom(\n ns: BroadcastNamespace,\n gatewayPath: string,\n room: string,\n event: string,\n data?: unknown,\n options?: { exceptIds?: string[]; maxFrameBytes?: number },\n): Promise<void> {\n const cmd: BroadcastCommand = {\n rooms: [room],\n exceptIds: options?.exceptIds,\n frame: JSON.stringify({ event, data }),\n };\n const maxFrameBytes = resolveMaxFrameBytes({\n maxFrameBytes: options?.maxFrameBytes ?? DEFAULT_WS_MAX_FRAME_BYTES,\n });\n assertBroadcastCommandFits(cmd, maxFrameBytes);\n const stub = ns.get(roomToDurableId(ns, gatewayPath, room));\n await stub.broadcast(cmd);\n}\n","import type { ThrottlerStorageRecord, ThrottlerStore } from '@velajs/vela';\n\n/** The deliberately small surface exposed by a Workers Rate Limiting binding. */\nexport interface CloudflareRateLimitBinding {\n limit(input: { key: string }): Promise<{ success: boolean }>;\n}\n\nexport interface CloudflareRateLimitStoreOptions {\n /** Must match the binding's configured `simple.limit`. */\n limit: number;\n /** Must match the binding's configured `simple.period`. */\n periodSeconds: 10 | 60;\n /** Bound attacker-influenced tracking keys before calling the platform. */\n maxKeyBytes?: number;\n}\n\n/**\n * Adapt a Cloudflare Workers Rate Limiting binding to Vela's throttler store.\n *\n * The platform binding makes the allow/deny decision. It does not expose exact\n * counters or reset timestamps, so this adapter intentionally omits `remaining`.\n */\nexport function cloudflareRateLimitStore(\n binding: CloudflareRateLimitBinding | (() => CloudflareRateLimitBinding),\n options: CloudflareRateLimitStoreOptions,\n): ThrottlerStore {\n if (!binding || (typeof binding !== 'function' && typeof binding.limit !== 'function')) {\n throw new TypeError('A Cloudflare Rate Limiting binding is required');\n }\n if (\n !Number.isSafeInteger(options.limit) ||\n options.limit <= 0 ||\n options.limit >= Number.MAX_SAFE_INTEGER\n ) {\n throw new RangeError('Rate limit must be a positive safe integer');\n }\n if (options.periodSeconds !== 10 && options.periodSeconds !== 60) {\n throw new RangeError('Cloudflare rate-limit periods must be 10 or 60 seconds');\n }\n\n const maxKeyBytes = options.maxKeyBytes ?? 1_024;\n if (!Number.isSafeInteger(maxKeyBytes) || maxKeyBytes <= 0 || maxKeyBytes > 4_096) {\n throw new RangeError('maxKeyBytes must be between 1 and 4096');\n }\n\n const ttlMs = options.periodSeconds * 1_000;\n const encoder = new TextEncoder();\n const resolveBinding =\n typeof binding === 'function' ? binding : (): CloudflareRateLimitBinding => binding;\n\n return {\n async increment(key: string, requestedTtlMs: number): Promise<ThrottlerStorageRecord> {\n if (requestedTtlMs !== ttlMs) {\n throw new Error(\n `Cloudflare binding period mismatch: expected ${ttlMs}ms, received ${requestedTtlMs}ms`,\n );\n }\n if (\n typeof key !== 'string' ||\n key.length === 0 ||\n /[\\u0000-\\u001f\\u007f]/.test(key) ||\n encoder.encode(key).byteLength > maxKeyBytes\n ) {\n throw new Error('Refusing an invalid or oversized rate-limit key');\n }\n\n const currentBinding = resolveBinding();\n if (!currentBinding || typeof currentBinding.limit !== 'function') {\n throw new Error('Cloudflare Rate Limiting binding is unavailable');\n }\n const decision = await currentBinding.limit({ key });\n if (!decision || typeof decision.success !== 'boolean') {\n throw new Error('Cloudflare rate-limit binding returned an invalid decision');\n }\n\n return {\n // Vela consumes `allowed` as the authoritative platform decision. These\n // sentinel counts preserve compatibility without inventing a counter.\n count: decision.success ? 0 : options.limit + 1,\n ttlMs,\n allowed: decision.success,\n enforcedLimit: options.limit,\n };\n },\n\n reset(): never {\n throw new Error('Cloudflare Rate Limiting bindings do not support counter reset');\n },\n };\n}\n","import type { VelaNonceDurableObject } from './nonce.durable-object';\nimport { MAX_NONCE_BYTES, isCanonicalBoundedText, isValidExpiry } from './nonce-validation';\nimport type { NonceStore } from '@velajs/vela';\n\nconst APP_NAMESPACE_PREFIX = 'vela:nonce:v1:';\nconst MAX_APP_NAMESPACE_BYTES = 128;\n/** The generated Workers binding type for {@link VelaNonceDurableObject}. */\nexport type DurableObjectNonceNamespace = DurableObjectNamespace<VelaNonceDurableObject>;\n\nexport interface DurableObjectNonceStoreOptions {\n /**\n * Stable application/environment boundary (for example `billing-api:prod`).\n * Claims are globally single-use inside this namespace and isolated from all\n * other application namespaces. It must be non-empty, canonical, and at most\n * 128 UTF-8 bytes.\n */\n appNamespace: string;\n\n /**\n * Resolve the Workers Durable Object namespace at claim time. The resolver is\n * intentionally not cached so request-scoped env/binding references stay safe.\n */\n binding: () => DurableObjectNonceNamespace | Promise<DurableObjectNonceNamespace>;\n}\n\n/**\n * Strict, cross-isolate {@link NonceStore} backed by one SQLite Durable Object\n * per explicit application namespace.\n *\n * Invalid input, an unavailable/malformed binding, RPC failure, or a malformed\n * RPC result all deny the claim (`false`). Only the literal boolean `true` from\n * the Durable Object is accepted.\n */\nexport function durableObjectNonceStore(options: DurableObjectNonceStoreOptions): NonceStore {\n if (!options || typeof options !== 'object') {\n throw new TypeError('Durable Object nonce-store options are required');\n }\n if (!isCanonicalBoundedText(options.appNamespace, MAX_APP_NAMESPACE_BYTES)) {\n throw new TypeError(\n `appNamespace must be canonical, non-empty, and at most ${MAX_APP_NAMESPACE_BYTES} UTF-8 bytes`,\n );\n }\n if (typeof options.binding !== 'function') {\n throw new TypeError('A lazy Durable Object namespace binding resolver is required');\n }\n\n const objectName = `${APP_NAMESPACE_PREFIX}${options.appNamespace}`;\n\n return {\n async claim(nonce: string, expEpochSeconds: number): Promise<boolean> {\n const now = Math.floor(Date.now() / 1_000);\n if (!isCanonicalBoundedText(nonce, MAX_NONCE_BYTES) || !isValidExpiry(expEpochSeconds, now)) {\n return false;\n }\n\n try {\n const namespace = await options.binding();\n\n const id = namespace.idFromName(objectName);\n const stub = namespace.get(id);\n const result = await stub.claim(nonce, expEpochSeconds);\n return result === true;\n } catch {\n return false;\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/websocket/websocket-routing.ts","../src/cloudflare-application.ts","../src/cloudflare-factory.ts","../src/storage/storage.tokens.ts","../src/storage/storage-key-claim.ts","../src/storage/r2-storage.driver.ts","../src/storage/storage-manager.service.ts","../src/storage/storage.controller.ts","../src/storage/storage.service.ts","../src/storage/storage.module.ts","../src/services/kv-cache.store.ts","../src/services/flagship-flag.driver.ts","../src/services/kv-flag.driver.ts","../src/decorators/env.ts","../src/decorators/scheduled.ts","../src/decorators/queue-consumer.ts","../src/websocket/cloudflare-websocket.module.ts","../src/websocket/broadcast.ts","../src/rate-limit/cloudflare-rate-limit.store.ts","../src/nonce/durable-object-nonce.store.ts"],"sourcesContent":["import type { VelaContext as Context, VelaHono as Hono } from '@velajs/vela';\nimport { getMetadata, getTrustedRequestIdentity } from '@velajs/vela';\nimport {\n authenticateWebSocketUpgrade,\n resolveGatewayRoomId,\n resolveGatewayRoomParam,\n resolveMaxFrameBytes,\n WS_GATEWAY_METADATA,\n type WebSocketGatewayOptions,\n type WebSocketUpgradeIdentity,\n} from '@velajs/vela/websocket';\nimport { durableObjectRoomName } from './room-id';\n\nexport interface WsGatewayRoute {\n path: string;\n binding: string;\n options: WebSocketGatewayOptions;\n}\n\nconst MAX_IDENTITY_FIELD_BYTES = 2048;\nconst encoder = new TextEncoder();\n\ntype PrincipalType = 'user' | 'service';\n\ninterface ForwardedIdentity extends WebSocketUpgradeIdentity {\n principal: {\n issuer: string;\n subject: string;\n principalType: PrincipalType;\n };\n tenantId: string;\n expiresAtMs: number;\n}\n\nfunction isIdentityField(value: unknown): value is string {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n !value.includes('\\r') &&\n !value.includes('\\n') &&\n encoder.encode(value).byteLength <= MAX_IDENTITY_FIELD_BYTES\n );\n}\n\n/** `null` means an identity was present but violated the transport contract. */\nfunction accessIdentity(c: Context): ForwardedIdentity | null | undefined {\n const value = getTrustedRequestIdentity(c.req.raw);\n if (!value) return undefined;\n const { principal, tenantId, expiresAtMs } = value;\n if (\n !isIdentityField(principal.issuer) ||\n !isIdentityField(principal.subject) ||\n !isIdentityField(tenantId) ||\n typeof expiresAtMs !== 'number' ||\n !Number.isSafeInteger(expiresAtMs) ||\n expiresAtMs <= 0\n )\n return null;\n return { principal, tenantId, expiresAtMs };\n}\n\n/** `null` means two independently verified identities disagree. */\nfunction combineIdentities(\n requestIdentity: ForwardedIdentity | undefined,\n upgradeIdentity: WebSocketUpgradeIdentity | undefined,\n): ForwardedIdentity | null | undefined {\n if (!requestIdentity && !upgradeIdentity) return undefined;\n if (!requestIdentity) return upgradeIdentity;\n if (!upgradeIdentity) return requestIdentity;\n if (\n requestIdentity.principal.issuer !== upgradeIdentity.principal.issuer ||\n requestIdentity.principal.subject !== upgradeIdentity.principal.subject ||\n requestIdentity.principal.principalType !== upgradeIdentity.principal.principalType ||\n requestIdentity.tenantId !== upgradeIdentity.tenantId\n ) {\n return null;\n }\n return {\n principal: { ...upgradeIdentity.principal },\n tenantId: upgradeIdentity.tenantId,\n expiresAtMs: Math.min(requestIdentity.expiresAtMs, upgradeIdentity.expiresAtMs),\n };\n}\n\n/** Read `@WebSocketGateway({ path, binding })` off a resolved instance (CF-hosted gateways only). */\nexport function collectWsGatewayRoutes(instance: object): WsGatewayRoute[] {\n // Decorator metadata is the framework's explicit reflection boundary.\n const options = getMetadata<WebSocketGatewayOptions>(WS_GATEWAY_METADATA, instance.constructor);\n if (!options?.path || !options?.binding) return [];\n resolveGatewayRoomParam(options);\n resolveMaxFrameBytes(options);\n return [{ path: options.path, binding: options.binding, options: { ...options } }];\n}\n\n/**\n * Registers the upgrade routes on the Worker's Hono app. Each route validates\n * the `Upgrade` header, resolves the room's Durable Object, and forwards the raw\n * request — injecting spoof-safe `x-vela-*` headers the DO reads. The DO returns\n * the `101` with the client socket.\n */\nexport function registerWebSocketRoutes(hono: Hono, routes: WsGatewayRoute[]): void {\n for (const route of routes) {\n hono.get(route.path, async (c: Context) => {\n if (c.req.header('upgrade')?.toLowerCase() !== 'websocket') {\n return c.text('Expected WebSocket upgrade', 426);\n }\n\n // Internal transport headers are never application credentials. Remove\n // client-supplied values before even the pre-allocation authorization\n // hook sees the request, then populate trusted values below.\n const headers = new Headers(c.req.raw.headers);\n headers.delete('x-vela-room');\n headers.delete('x-vela-path');\n headers.delete('x-vela-user');\n headers.delete('x-vela-expires-at');\n headers.delete('x-vela-expires-at-ms');\n headers.delete('x-vela-issuer');\n headers.delete('x-vela-subject');\n headers.delete('x-vela-principal-type');\n headers.delete('x-vela-tenant');\n const sanitizedRequest = new Request(c.req.raw, { headers });\n\n let roomId: string;\n try {\n roomId = resolveGatewayRoomId(route.options, (name) => c.req.param(name));\n } catch {\n return c.text('Invalid WebSocket room', 400);\n }\n\n // Origin, application authorization, and ticket/cookie authentication\n // all complete before the gateway Durable Object id is resolved.\n const upgrade = await authenticateWebSocketUpgrade(route.options, sanitizedRequest, roomId);\n if (upgrade === false) return c.text('WebSocket upgrade forbidden', 403);\n\n const requestIdentity = accessIdentity(c);\n if (requestIdentity === null) return c.text('Invalid WebSocket identity', 403);\n const identity = combineIdentities(requestIdentity, upgrade.identity);\n if (identity === null) return c.text('Conflicting WebSocket identities', 403);\n if (identity && identity.expiresAtMs <= Date.now()) {\n return c.text('WebSocket identity expired', 403);\n }\n\n // Populate the ticket-free forwarding request with trusted server values.\n const forwardHeaders = new Headers(upgrade.request.headers);\n forwardHeaders.set('x-vela-room', roomId);\n forwardHeaders.set('x-vela-path', route.path);\n if (identity) {\n forwardHeaders.set('x-vela-user', identity.principal.subject);\n forwardHeaders.set('x-vela-issuer', identity.principal.issuer);\n forwardHeaders.set('x-vela-subject', identity.principal.subject);\n forwardHeaders.set('x-vela-principal-type', identity.principal.principalType);\n forwardHeaders.set('x-vela-tenant', identity.tenantId);\n forwardHeaders.set('x-vela-expires-at-ms', String(identity.expiresAtMs));\n }\n\n return forwardToRoom(\n c.env,\n route.binding,\n route.path,\n roomId,\n new Request(upgrade.request, { headers: forwardHeaders }),\n );\n });\n }\n}\n\n/**\n * Gateway metadata contains a runtime binding name, so the native type is\n * erased. Validate only the operations consumed here and their observable\n * results; never assert that an arbitrary value implements a native namespace.\n */\nasync function forwardToRoom(\n env: unknown,\n binding: string,\n path: string,\n room: string,\n request: Request,\n): Promise<Response> {\n if (typeof env !== 'object' || env === null) throw new Error('Worker environment is missing');\n const namespace: unknown = Reflect.get(env, binding);\n if (typeof namespace !== 'object' || namespace === null) {\n return new Response(`Durable Object binding '${binding}' is not configured`, { status: 500 });\n }\n const idFromName: unknown = Reflect.get(namespace, 'idFromName');\n const get: unknown = Reflect.get(namespace, 'get');\n if (typeof idFromName !== 'function' || typeof get !== 'function') {\n throw new Error('Invalid Durable Object namespace');\n }\n const id: unknown = Reflect.apply(idFromName, namespace, [durableObjectRoomName(path, room)]);\n const stub: unknown = Reflect.apply(get, namespace, [id]);\n if (typeof stub !== 'object' || stub === null) throw new Error('Invalid Durable Object stub');\n const fetch: unknown = Reflect.get(stub, 'fetch');\n if (typeof fetch !== 'function') throw new Error('Durable Object stub has no fetch operation');\n const response: unknown = await Reflect.apply(fetch, stub, [request]);\n if (!(response instanceof Response))\n throw new Error('Durable Object returned an invalid response');\n return response;\n}\n","import type { ExecutionContext } from 'hono';\nimport {\n CRON_METADATA,\n PipelineRunner,\n buildEntrypointExecutionContext,\n registerEntrypointKind,\n getEntrypointModuleId,\n resolveEntrypoint,\n resolveScopedComponentsAsync,\n resolveErrorReporter,\n runInEntrypointScope,\n shouldFilterCatch,\n type VelaApplication,\n} from '@velajs/vela';\nimport type { Entrypoint, ExceptionFilter } from '@velajs/vela';\nimport { readWsEntrypointMeta } from '@velajs/vela/websocket';\nimport { collectWsGatewayRoutes, type WsGatewayRoute } from './websocket/websocket-routing';\nimport { assertCloudflareEnvironment } from './environment';\n\n// vela's own @Cron jobs run via the same Workers cron trigger — declare an\n// entrypoint kind over vela's metadata key (the open-kind system makes\n// cross-package declarations first-class).\nregisterEntrypointKind({ kind: 'cf:vela-cron', metaKey: CRON_METADATA, level: 'method' });\n\n/**\n * Options accepted by {@link CloudflareApplication.mountOpenApi}.\n *\n * Re-exposes vela's `MountOpenApiOptions` type — derived structurally from\n * the underlying `VelaApplication.mountOpenApi` signature so consumers don't\n * have to reach into vela's internal subpaths to type the argument.\n */\nexport type MountOpenApiOptions = Parameters<VelaApplication['mountOpenApi']>[0];\n\nfunction invoke(instance: object, methodName: string | symbol, args: unknown[]): unknown {\n // Decorator metadata names an instance method; inspect it before invoking.\n const method: unknown = Reflect.get(instance, methodName);\n if (typeof method !== 'function') {\n throw new Error(\n `Method '${String(methodName)}' is not a function on ${instance.constructor.name}`,\n );\n }\n return Reflect.apply(method, instance, args);\n}\n\nfunction entrypointString(meta: unknown, property: string): string {\n if (typeof meta !== 'object' || meta === null) throw new Error('Invalid entrypoint metadata.');\n const value: unknown = Reflect.get(meta, property);\n if (typeof value !== 'string')\n throw new Error(`Invalid entrypoint metadata: ${property} must be a string.`);\n return value;\n}\n\n/** Wait for every matching handler, even when one fails before its siblings. */\nasync function settleEntrypoints(work: readonly Promise<void>[]): Promise<void> {\n const outcomes = await Promise.allSettled(work);\n const errors = outcomes.flatMap((outcome) =>\n outcome.status === 'rejected' ? [outcome.reason] : [],\n );\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'Multiple entrypoint handlers failed.');\n}\n\n/**\n * Wraps VelaApplication with Cloudflare-specific handlers:\n * - `fetch` — HTTP request handler (from Hono)\n * - `scheduled` — Cron trigger handler (matches `@Scheduled()` decorators\n * AND vela's own `@Cron()` jobs)\n * - `queue` — Queue consumer handler (matches `@QueueConsumer()` decorators)\n * - `mountOpenApi` — Serve an OpenAPI document (and optional Scalar UI) on\n * the underlying Hono app\n *\n * @example\n * ```ts\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * export default {\n * fetch: app.fetch,\n * scheduled: app.scheduled.bind(app),\n * queue: app.queue.bind(app),\n * };\n * ```\n *\n * @example\n * ```ts\n * // Serve OpenAPI docs alongside your routes\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * const document = createOpenApiDocument(AppModule);\n * app.mountOpenApi({ document, ui: 'scalar' });\n * // GET /openapi.json -> JSON document\n * // GET /scalar -> Scalar UI (loads from CDN)\n * ```\n */\nexport class CloudflareApplication<T extends object = object> {\n readonly #wsGatewayRoutes: WsGatewayRoute[] = [];\n readonly #app: VelaApplication;\n\n constructor(\n app: VelaApplication,\n readonly env: T,\n ) {\n this.#app = app;\n this.get = app.get.bind(app);\n }\n\n readonly fetch = async (request: Request, env: T, ctx?: ExecutionContext): Promise<Response> => {\n assertCloudflareEnvironment(this.env, env);\n return this.#app.fetch(request, env, ctx);\n };\n\n getHonoApp(): ReturnType<VelaApplication['getHonoApp']> {\n return this.#app.getHonoApp();\n }\n\n /**\n * Resolve a provider from the application's DI container (delegates to\n * `VelaApplication.get`). Handy for grabbing a service — e.g. an auth service —\n * to use inside `createCloudflareApp({ middleware: env => [...] })` request middleware,\n * which runs outside the DI request pipeline.\n *\n * @example\n * ```ts\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * const auth = app.get(BetterAuthService);\n * ```\n */\n readonly get: VelaApplication['get'];\n\n get entrypoints(): VelaApplication['entrypoints'] {\n return this.#app.entrypoints;\n }\n\n /**\n * Serve a pre-built OpenAPI document (and optionally a Scalar UI) on the\n * underlying Hono app. Delegates verbatim to `VelaApplication.mountOpenApi`,\n * so the JSON endpoint defaults to `/openapi.json` and the Scalar UI (when\n * opted in) defaults to `/scalar`. Edge-safe — the UI HTML loads Scalar from\n * a CDN at runtime, nothing is bundled server-side.\n *\n * @example\n * ```ts\n * import { createOpenApiDocument } from '@velajs/vela';\n *\n * const app = await createCloudflareApp(AppModule, { env, envToken: ENV });\n * const document = createOpenApiDocument(AppModule, {\n * info: { title: 'My API', version: '1.0.0' },\n * });\n * app.mountOpenApi({ document, ui: 'scalar' });\n * // GET /openapi.json -> { openapi: '3.1.0', ... }\n * // GET /scalar -> Scalar UI HTML\n * ```\n */\n mountOpenApi(options: MountOpenApiOptions): this {\n this.#app.mountOpenApi(options);\n return this;\n }\n\n /**\n * @internal Upgrade routes come from validated gateway entrypoints, including\n * request-scoped gateways without a bootstrap instance. Retain the instance\n * scan for legacy applications that only declare forwarding metadata.\n */\n scanInstances(instances: unknown[]): void {\n const routes = new Map<string, WsGatewayRoute>();\n for (const ep of this.#app.entrypoints.ofKind('websocket')) {\n if (typeof ep.meta !== 'object' || ep.meta === null || !('dispatcher' in ep.meta)) continue;\n const meta = readWsEntrypointMeta(ep.meta);\n if (meta.options.binding) {\n routes.set(meta.path, {\n path: meta.path,\n binding: meta.options.binding,\n options: { ...meta.options },\n });\n }\n }\n for (const instance of instances) {\n if (!instance || typeof instance !== 'object') continue;\n for (const route of collectWsGatewayRoutes(instance)) {\n if (!routes.has(route.path)) routes.set(route.path, route);\n }\n }\n this.#wsGatewayRoutes.splice(0, this.#wsGatewayRoutes.length, ...routes.values());\n }\n\n /** @internal — upgrade routes discovered from the application's gateways. */\n getWsGatewayRoutes(): WsGatewayRoute[] {\n return [...this.#wsGatewayRoutes];\n }\n\n /**\n * Handle Cloudflare scheduled (cron) events.\n * Matches the event's cron expression to `@Scheduled()` and vela `@Cron()`\n * handlers read from `app.entrypoints`; each handler runs inside a fresh\n * request-scoped child (request-scoped providers rebuild per tick).\n */\n async scheduled(\n event: { cron: string; scheduledTime?: number },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n assertCloudflareEnvironment(this.env, env);\n const handlers = [\n ...this.#app.entrypoints\n .ofKind('cf:scheduled')\n .map((ep) => ({ ep, cron: entrypointString(ep.meta, 'cron') })),\n ...this.#app.entrypoints\n .ofKind('cf:vela-cron')\n .map((ep) => ({ ep, cron: entrypointString(ep.meta, 'expression') })),\n ].filter((h) => h.cron === event.cron);\n\n await settleEntrypoints(handlers.map(({ ep }) => this.dispatchEntrypoint(ep, event, env, ctx)));\n }\n\n /**\n * Run one entrypoint handler inside a fresh request scope, through the\n * shared guard → interceptor pipeline (components declared with\n * `@UseGuards`/`@UseInterceptors`/`@UseFilters` on the consumer class or\n * method). HTTP-global components deliberately do NOT apply — an HTTP auth\n * guard has no business rejecting a queue batch. Unclaimed errors rethrow\n * so the platform's retry semantics stay intact.\n */\n private async dispatchEntrypoint(\n ep: Entrypoint,\n payload: unknown,\n env: T,\n platformContext: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n const targetClass = ep.token;\n if (typeof targetClass !== 'function') throw new Error('Entrypoint token must be a class.');\n if (ep.methodName === undefined) throw new Error('Entrypoint must declare a handler method.');\n const methodName = ep.methodName;\n const reportContext = {\n edge: ep.kind.startsWith('cf:queue') ? ('queue' as const) : ('schedule' as const),\n source: `${targetClass.name}.${String(methodName)}`,\n };\n let reported: { error: unknown } | undefined;\n try {\n await runInEntrypointScope(this.#app.getContainer(), async (scope, lifetime) => {\n const moduleId = getEntrypointModuleId(scope, ep);\n const context = buildEntrypointExecutionContext(\n ep.kind,\n targetClass,\n methodName,\n payload,\n moduleId,\n scope,\n );\n const invocationContext = {\n waitUntil(promise: Promise<unknown>): void {\n lifetime.waitUntil(promise);\n platformContext.waitUntil(promise);\n },\n };\n let filters: ExceptionFilter[] = [];\n try {\n filters = (\n await resolveScopedComponentsAsync('filter', targetClass, methodName, scope, moduleId)\n ).toReversed();\n const guards = await resolveScopedComponentsAsync(\n 'guard',\n targetClass,\n methodName,\n scope,\n moduleId,\n );\n const interceptors = await resolveScopedComponentsAsync(\n 'interceptor',\n targetClass,\n methodName,\n scope,\n moduleId,\n );\n await PipelineRunner.run({\n context,\n guards,\n interceptors,\n resolveArgs: async () => [payload, env, invocationContext],\n invoke: async (args) => {\n const instance = await resolveEntrypoint(scope, ep);\n if (typeof instance !== 'object' || instance === null) {\n throw new Error('Entrypoint must resolve to an object.');\n }\n return invoke(instance, methodName, args);\n },\n });\n } catch (error) {\n resolveErrorReporter(scope).report(error, reportContext);\n for (const filter of filters) {\n if (shouldFilterCatch(filter, error)) {\n // Filters run closest-first; this is the framework catch hook.\n // eslint-disable-next-line no-await-in-loop, promise/valid-params\n await filter.catch(error, context);\n return;\n }\n }\n reported = { error };\n throw error;\n }\n });\n } catch (error) {\n // Managed completion happens after the handler's filter boundary. Report\n // a new completion failure without reporting an already-observed handler\n // failure twice; preserve both errors in the rejected invocation.\n if (!reported || reported.error !== error) {\n const completionError =\n reported && error instanceof AggregateError && error.errors[0] === reported.error\n ? error.errors[1]\n : error;\n resolveErrorReporter(this.#app.getContainer()).report(completionError, reportContext);\n }\n throw error;\n }\n }\n\n /**\n * Handle Cloudflare Queue consumer events.\n * Matches the batch queue name to `@QueueConsumer()` handlers read from\n * `app.entrypoints`; each batch is processed inside a fresh request-scoped\n * child (request-scoped providers rebuild per batch — no boot-time captives).\n */\n async queue(\n batch: { queue: string; messages: readonly unknown[] },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n assertCloudflareEnvironment(this.env, env);\n const handlers = [\n ...this.#app.entrypoints.ofKind('cf:queue'),\n ...this.#app.entrypoints.ofKind('cf:queue:module'),\n ].filter((ep) => entrypointString(ep.meta, 'queueName') === batch.queue);\n\n if (handlers.length === 0) throw new Error(`No consumer for queue '${batch.queue}'.`);\n\n await settleEntrypoints(handlers.map((ep) => this.dispatchEntrypoint(ep, batch, env, ctx)));\n }\n\n async close(signal?: string): Promise<void> {\n return this.#app.close(signal);\n }\n}\n","import type { ExecutionContext } from 'hono';\nimport { getConnInfo } from 'hono/cloudflare-workers';\nimport { VelaFactory } from '@velajs/vela';\nimport type {\n InjectionToken,\n RuntimeAdapter,\n VelaMiddlewareHandler,\n VelaSecurityOptions,\n} from '@velajs/vela';\nimport { CloudflareApplication } from './cloudflare-application';\nimport { assertCloudflareEnvironment, registerCloudflareEnvironment } from './environment';\nimport { registerWebSocketRoutes } from './websocket/websocket-routing';\nimport { resolveCloudflareRoot } from './root-module';\nimport type { CloudflareRoot } from './root-module';\n\nexport interface CloudflareWorkerOptions<T extends object> {\n /** Global typed DI token for the platform's native environment. */\n envToken: InjectionToken<T>;\n globalPrefix?: string;\n security?: VelaSecurityOptions;\n /** Build request middleware from the same typed native environment as DI. */\n middleware?: (env: NoInfer<T>) => VelaMiddlewareHandler[];\n}\n\nexport interface CreateCloudflareAppOptions<T extends object> extends CloudflareWorkerOptions<T> {\n /** Supply the platform environment inside fetch/queue/scheduled or a DO constructor. */\n env: NoInfer<T>;\n}\n\n/** Bind an application to one environment before provider factories and lifecycle hooks. */\nexport function cloudflareAdapter<T extends object>(\n options: CreateCloudflareAppOptions<T>,\n): RuntimeAdapter {\n return {\n name: 'cloudflare',\n requestMiddleware: [\n async (context, next) => {\n assertCloudflareEnvironment(options.env, context.env);\n await next();\n },\n ],\n invocationTransport:\n ({ app }) =>\n (request) =>\n Promise.resolve(app.fetch(request, options.env)),\n getClientIp: (c) => getConnInfo(c).remote.address ?? null,\n configureContainer: (container) => {\n registerCloudflareEnvironment(container, { token: options.envToken, env: options.env });\n },\n };\n}\n\n/** Build an application for one native Workers environment. Call inside a platform event. */\nexport async function createCloudflareApp<T extends object>(\n rootModule: CloudflareRoot<NoInfer<T>>,\n options: CreateCloudflareAppOptions<T>,\n): Promise<CloudflareApplication<T>> {\n const velaApp = await VelaFactory.create(await resolveCloudflareRoot(rootModule, options.env), {\n globalPrefix: options.globalPrefix,\n security: options.security,\n middleware: options.middleware?.(options.env),\n adapters: [cloudflareAdapter(options)],\n });\n const app = new CloudflareApplication(velaApp, options.env);\n const consumers = new Map<string, string>();\n for (const entry of [\n ...app.entrypoints.ofKind('cf:queue'),\n ...app.entrypoints.ofKind('cf:queue:module'),\n ]) {\n const meta = entry.meta;\n if (\n typeof meta !== 'object' ||\n meta === null ||\n !('queueName' in meta) ||\n typeof meta.queueName !== 'string'\n ) {\n await app.close();\n throw new TypeError('Invalid queue consumer metadata.');\n }\n const previous = consumers.get(meta.queueName);\n // Existing native fan-out remains available; module routing owns a queue exclusively.\n if (previous && (previous === 'cf:queue:module' || entry.kind === 'cf:queue:module')) {\n await app.close();\n throw new Error(`Ambiguous consumer ownership for queue '${meta.queueName}'.`);\n }\n consumers.set(meta.queueName, entry.kind);\n }\n app.scanInstances(velaApp.getInstances());\n registerWebSocketRoutes(app.getHonoApp(), app.getWsGatewayRoutes());\n return app;\n}\n\n/**\n * Worker entrypoint with one bootstrap per environment identity. Weak keys let\n * obsolete environments and secrets be collected. Concurrent cold events share\n * construction; failed construction is evicted so the next event can retry.\n */\nexport function createCloudflareWorker<T extends object>(\n rootModule: CloudflareRoot<NoInfer<T>>,\n options: CloudflareWorkerOptions<T>,\n) {\n const applications = new WeakMap<T, Promise<CloudflareApplication<T>>>();\n const application = (env: T): Promise<CloudflareApplication<T>> => {\n const existing = applications.get(env);\n if (existing) return existing;\n const pending = createCloudflareApp(rootModule, { ...options, env });\n applications.set(env, pending);\n void pending.catch(() => {\n if (applications.get(env) === pending) applications.delete(env);\n });\n return pending;\n };\n return {\n async fetch(request: Request, env: T, ctx: ExecutionContext): Promise<Response> {\n return (await application(env)).fetch(request, env, ctx);\n },\n async scheduled(\n event: { cron: string; scheduledTime?: number },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n return (await application(env)).scheduled(event, env, ctx);\n },\n async queue(\n batch: { queue: string; messages: readonly unknown[] },\n env: T,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n return (await application(env)).queue(batch, env, ctx);\n },\n };\n}\n","import { InjectionToken } from '@velajs/vela';\nimport type { StorageModuleOptions } from './storage.types';\n\nexport const STORAGE_OPTIONS = new InjectionToken<StorageModuleOptions>('STORAGE_OPTIONS');\n","/** R2-compatible object-key claim bound. Keeps decode work predictably small. */\nexport const MAX_STORAGE_KEY_BYTES = 1024;\n\nconst BASE64URL_RE = /^[A-Za-z0-9_-]+$/;\nconst ROOT_TOKEN_PATTERNS: Record<string, string> = {\n date: '\\\\d{4}-\\\\d{2}-\\\\d{2}',\n year: '\\\\d{4}',\n month: '(?:0[1-9]|1[0-2])',\n day: '(?:0[1-9]|[12]\\\\d|3[01])',\n uuid: '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}',\n};\n\n/** Encode an object key as an opaque, canonical base64url query claim. */\nexport function encodeStorageKeyClaim(key: string): string {\n const bytes = new TextEncoder().encode(key);\n if (bytes.byteLength === 0 || bytes.byteLength > MAX_STORAGE_KEY_BYTES) {\n throw new Error(`Storage key must be 1–${MAX_STORAGE_KEY_BYTES} UTF-8 bytes`);\n }\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/** Decode exactly one canonical base64url layer. Malformed/non-UTF-8 claims return undefined. */\nexport function decodeStorageKeyClaim(claim: string): string | undefined {\n try {\n if (\n claim.length === 0 ||\n claim.length > Math.ceil((MAX_STORAGE_KEY_BYTES * 4) / 3) ||\n !BASE64URL_RE.test(claim) ||\n claim.length % 4 === 1\n ) {\n return undefined;\n }\n const base64 = claim.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(padded);\n const bytes = new Uint8Array(new ArrayBuffer(binary.length));\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n if (bytes.byteLength === 0 || bytes.byteLength > MAX_STORAGE_KEY_BYTES) return undefined;\n const decoded = new TextDecoder('utf-8', { fatal: true, ignoreBOM: false }).decode(bytes);\n return encodeStorageKeyClaim(decoded) === claim ? decoded : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isDotSegment(segment: string): boolean {\n let decoded = segment;\n for (let i = 0; i < 2; i++) {\n if (decoded === '' || decoded === '.' || decoded === '..') return true;\n try {\n const next = decodeURIComponent(decoded);\n if (next === decoded) break;\n decoded = next;\n } catch {\n break;\n }\n }\n return decoded === '' || decoded === '.' || decoded === '..';\n}\n\nfunction rootSegmentPattern(segment: string): string {\n let pattern = '';\n let cursor = 0;\n for (const match of segment.matchAll(/\\{(date|year|month|day|uuid)\\}/g)) {\n pattern += segment.slice(cursor, match.index).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n pattern += ROOT_TOKEN_PATTERNS[match[1]!]!;\n cursor = match.index! + match[0].length;\n }\n pattern += segment.slice(cursor).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return pattern;\n}\n\n/** Assert a canonical key is beneath a static or templated configured root. */\nexport function isStorageKeyWithinRoot(key: string, root: string | undefined): boolean {\n const segments = (root ?? '').split(/[/\\\\]+/).filter((segment) => !isDotSegment(segment));\n if (segments.length === 0) return key.length > 0;\n const rootPattern = segments.map(rootSegmentPattern).join('/');\n return new RegExp(`^(?:${rootPattern})(?:/|$)`).test(key);\n}\n","import {\n signUrl,\n STORAGE_SIGNED_URL_PURPOSE,\n type DownloadResult,\n type PresignedUrlResult,\n type PresignMethod,\n type StorageBody,\n type StorageDriver,\n type UploadOptions,\n type UploadResult,\n} from '@velajs/vela/storage';\nimport { encodeStorageKeyClaim } from './storage-key-claim';\n\n/** Base path of the StorageController presign-proxy route. */\nexport const STORAGE_ROUTE_BASE = '/storage';\n\nexport interface R2StorageDriverConfig {\n disk: string;\n bucket: R2Bucket;\n /** HMAC secret for presigned URLs (typically env.APP_SECRET). */\n secret?: string;\n}\n\n/** {@link StorageDriver} over a Cloudflare R2 bucket. */\nexport class R2StorageDriver implements StorageDriver {\n constructor(private readonly config: R2StorageDriverConfig) {}\n\n async upload(body: StorageBody, path: string, options: UploadOptions): Promise<UploadResult> {\n await this.config.bucket.put(\n path,\n body as ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob | null,\n {\n httpMetadata: options.mimeType ? { contentType: options.mimeType } : undefined,\n customMetadata: options.metadata,\n },\n );\n return {\n path,\n disk: this.config.disk,\n size: options.size,\n mimeType: options.mimeType ?? 'application/octet-stream',\n uploadedAt: new Date(),\n };\n }\n\n async download(path: string): Promise<DownloadResult> {\n const obj = await this.config.bucket.get(path);\n if (!obj) throw new Error(`Storage object not found at \"${path}\".`);\n return {\n toStream: () => obj.body as ReadableStream,\n toArrayBuffer: () => obj.arrayBuffer(),\n toText: () => obj.text(),\n contentType: obj.httpMetadata?.contentType ?? 'application/octet-stream',\n size: obj.size,\n metadata: obj.customMetadata,\n };\n }\n\n async delete(path: string): Promise<void> {\n await this.config.bucket.delete(path);\n }\n\n async exists(path: string): Promise<boolean> {\n return (await this.config.bucket.head(path)) !== null;\n }\n\n async getPresignedUrl(\n path: string,\n method: PresignMethod,\n expiresIn: number,\n ): Promise<PresignedUrlResult> {\n if (!this.config.secret) {\n throw new Error('A signing secret is required for presigned URLs (set APP_SECRET).');\n }\n // Defend the direct-driver path too: a non-finite/non-positive expiry would\n // make signUrl omit `expires`, yielding a never-expiring URL.\n if (!Number.isSafeInteger(expiresIn) || expiresIn <= 0) {\n throw new Error(\n `Invalid presigned URL expiry: ${expiresIn}s (must be a positive safe integer).`,\n );\n }\n // The object key is an opaque signed query claim, never a URL path. This\n // prevents WHATWG path normalization / multi-decode behavior from turning\n // an encoded key into a different storage capability.\n const claim = encodeStorageKeyClaim(path);\n const routePath = `${STORAGE_ROUTE_BASE}/${encodeURIComponent(this.config.disk)}`;\n const query = new URLSearchParams({ key: claim, method });\n const url = await signUrl(`${routePath}?${query}`, this.config.secret, {\n expiresIn,\n method,\n purpose: STORAGE_SIGNED_URL_PURPOSE,\n });\n return { url, method, expiresIn, expiresAt: new Date(Date.now() + expiresIn * 1000) };\n }\n}\n","import { Inject, Injectable } from '@velajs/vela';\nimport { R2StorageDriver } from './r2-storage.driver';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { DiskConfig, StorageModuleOptions } from './storage.types';\n\n@Injectable()\nexport class StorageManagerService {\n constructor(@Inject(STORAGE_OPTIONS) private readonly options: StorageModuleOptions) {}\n\n hasDisk(disk: string): boolean {\n return this.options.disks.some((d) => d.disk === disk);\n }\n\n getDiskConfig(disk: string): DiskConfig {\n const config = this.options.disks.find((d) => d.disk === disk);\n if (!config) throw new Error(`Storage disk \"${disk}\" is not configured.`);\n return config;\n }\n\n getDriver(disk: string): R2StorageDriver {\n const config = this.getDiskConfig(disk);\n return new R2StorageDriver({ disk, bucket: config.bucket, secret: this.options.secret });\n }\n}\n","import { Controller, Get, Inject, Req } from '@velajs/vela';\nimport { joinStoragePath, STORAGE_SIGNED_URL_PURPOSE, verifySignedUrl } from '@velajs/vela/storage';\nimport type { Context } from 'hono';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { StorageModuleOptions } from './storage.types';\nimport { StorageManagerService } from './storage-manager.service';\nimport { decodeStorageKeyClaim, isStorageKeyWithinRoot } from './storage-key-claim';\n\n/**\n * Presign-proxy: serves objects for HMAC-signed URLs produced by\n * `StorageService.url()`. R2 has no native presign, so a signed URL points here;\n * this route verifies the signature (+expiry) before streaming the object.\n * The FULL object key (root already applied at sign time) is carried as an\n * opaque base64url query claim. The signature is verified before the claim is\n * decoded exactly once and checked against the configured disk root.\n */\n@Controller('storage')\nexport class StorageController {\n constructor(\n @Inject(StorageManagerService) private readonly manager: StorageManagerService,\n @Inject(STORAGE_OPTIONS) private readonly options: StorageModuleOptions,\n ) {}\n\n @Get('/:disk')\n async download(@Req() c: Context): Promise<Response> {\n const secret = this.options.secret;\n if (!secret) return new Response('Storage signing is not configured', { status: 500 });\n\n // Verify the complete path/query capability before inspecting the disk or\n // decoding attacker-controlled claims.\n if (\n !(await verifySignedUrl(c.req.url, secret, {\n method: c.req.method,\n purpose: STORAGE_SIGNED_URL_PURPOSE,\n }))\n ) {\n return new Response('Invalid or expired URL', { status: 403 });\n }\n\n // Enforce the signed `method` scope: this proxy only serves reads, so a URL\n // scoped to PUT/DELETE/HEAD must NOT be honored as a GET (it would over-grant\n // read access relative to the token's intended scope). The param is part of\n // the signed payload, so it is trustworthy once the signature verifies.\n const url = new URL(c.req.url);\n if (url.searchParams.get('method') !== 'GET') {\n return new Response('URL is not scoped for reads', { status: 403 });\n }\n\n const disk = c.req.param('disk');\n if (!disk || !this.manager.hasDisk(disk)) return new Response('Unknown disk', { status: 404 });\n\n const claim = url.searchParams.get('key');\n const decoded = claim ? decodeStorageKeyClaim(claim) : undefined;\n if (!decoded) return new Response('Malformed storage key claim', { status: 400 });\n\n // Canonicalize after the one decode. Signed direct-driver callers cannot\n // smuggle dot segments or non-canonical aliases into the proxy contract.\n const fullPath = joinStoragePath(undefined, decoded);\n if (fullPath !== decoded) return new Response('Invalid storage key', { status: 403 });\n\n if (!isStorageKeyWithinRoot(fullPath, this.manager.getDiskConfig(disk).root)) {\n return new Response('Storage key is outside the configured root', { status: 403 });\n }\n\n try {\n const result = await this.manager.getDriver(disk).download(fullPath);\n const filename = fullPath.split('/').at(-1) || 'download';\n return new Response(result.toStream(), {\n headers: {\n 'content-type': result.contentType || 'application/octet-stream',\n // Objects are untrusted user content. The authenticated API origin\n // never renders them inline (especially HTML/SVG), even when the\n // stored Content-Type is attacker controlled.\n 'content-disposition': `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`,\n 'x-content-type-options': 'nosniff',\n },\n });\n } catch {\n return new Response('Not found', { status: 404 });\n }\n }\n}\n","import { Inject, Injectable } from '@velajs/vela';\nimport {\n joinStoragePath,\n type DownloadResult,\n type PresignedUrlResult,\n type PresignMethod,\n type StorageBody,\n type UploadOptions,\n type UploadResult,\n} from '@velajs/vela/storage';\nimport { StorageManagerService } from './storage-manager.service';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { StorageModuleOptions } from './storage.types';\n\nconst DEFAULT_PRESIGN = { defaultExpiry: 3600, maxExpiry: 86400 };\n\n/**\n * Multi-disk storage facade. Applies each disk's (templated) root, resolves the\n * driver, and validates presign expiry. Injectable anywhere via `StorageService`.\n */\n@Injectable()\nexport class StorageService {\n constructor(\n @Inject(STORAGE_OPTIONS) private readonly options: StorageModuleOptions,\n @Inject(StorageManagerService) private readonly manager: StorageManagerService,\n ) {}\n\n put(\n relativePath: string,\n body: StorageBody,\n options: UploadOptions = {},\n disk?: string,\n ): Promise<UploadResult> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).upload(body, this.fullPath(relativePath, name), options);\n }\n\n get(relativePath: string, disk?: string): Promise<DownloadResult> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).download(this.fullPath(relativePath, name));\n }\n\n delete(relativePath: string, disk?: string): Promise<void> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).delete(this.fullPath(relativePath, name));\n }\n\n exists(relativePath: string, disk?: string): Promise<boolean> {\n const name = this.resolveDisk(disk);\n return this.manager.getDriver(name).exists(this.fullPath(relativePath, name));\n }\n\n url(\n relativePath: string,\n method: PresignMethod = 'GET',\n expiresIn?: number,\n disk?: string,\n ): Promise<PresignedUrlResult> {\n const name = this.resolveDisk(disk);\n return this.manager\n .getDriver(name)\n .getPresignedUrl(this.fullPath(relativePath, name), method, this.validateExpiry(expiresIn));\n }\n\n private resolveDisk(disk?: string): string {\n const name = disk ?? this.options.defaultDisk;\n if (!this.manager.hasDisk(name)) throw new Error(`Storage disk \"${name}\" is not configured.`);\n return name;\n }\n\n private fullPath(relativePath: string, disk: string): string {\n return joinStoragePath(this.manager.getDiskConfig(disk).root, relativePath);\n }\n\n private validateExpiry(expiresIn?: number): number {\n const cfg = this.options.presignedUrl ?? DEFAULT_PRESIGN;\n const value = expiresIn ?? cfg.defaultExpiry;\n // `Number.isSafeInteger` rejects NaN/fractional/infinite values — otherwise\n // `NaN < 1 || NaN > max` is false,\n // NaN slips through, signUrl omits `expires`, and the URL never expires.\n if (!Number.isSafeInteger(value) || value < 1 || value > cfg.maxExpiry) {\n throw new Error(`Presigned URL expiry ${value}s is out of range (1–${cfg.maxExpiry}s).`);\n }\n return value;\n }\n}\n","import { ConfigurableModuleBuilder, Module } from '@velajs/vela';\nimport { StorageController } from './storage.controller';\nimport { StorageManagerService } from './storage-manager.service';\nimport { StorageService } from './storage.service';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { StorageModuleOptions } from './storage.types';\n\nconst { ConfigurableModuleClass } = new ConfigurableModuleBuilder<StorageModuleOptions>({\n moduleName: 'Storage',\n optionsInjectionToken: STORAGE_OPTIONS,\n}).build();\n\n@Module({\n providers: [StorageManagerService, StorageService],\n controllers: [StorageController],\n exports: [StorageService, StorageManagerService, STORAGE_OPTIONS],\n})\nexport class StorageModule extends ConfigurableModuleClass {}\n","import {\n type AsyncCacheStore,\n type CacheEntryReader,\n type CacheEntryWriter,\n type CacheEntry,\n type CacheInvalidationStore,\n} from '@velajs/vela';\n\n/**\n * Native KV JSON value store. Metadata retains logical expiry even when KV's\n * physical retention rounds up to its 60-second minimum. Legacy values without\n * metadata remain readable, but cannot safely backfill another tier.\n */\nexport class KVCacheStore implements AsyncCacheStore, CacheEntryReader, CacheEntryWriter {\n constructor(private readonly ns: KVNamespace) {}\n\n async get(key: string): Promise<unknown> {\n return (await this.getEntry(key))?.value;\n }\n\n async getEntry(key: string): Promise<{ value: unknown; expiresAt?: number } | undefined> {\n const { value, metadata } = await this.ns.getWithMetadata<unknown, unknown>(key, 'json');\n if (value === null) return undefined;\n if (typeof metadata === 'object' && metadata !== null && 'velaCacheExpiresAt' in metadata) {\n const expiresAt = metadata.velaCacheExpiresAt;\n if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt) || expiresAt <= Date.now())\n return undefined;\n return { value, expiresAt };\n }\n return { value };\n }\n\n async set(key: string, value: unknown, ttl?: number): Promise<void> {\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl < 0))\n throw new TypeError('Cache TTL must be finite and nonnegative.');\n if (ttl !== undefined) return this.setEntry(key, { value, expiresAt: Date.now() + ttl * 1000 });\n await this.ns.put(key, JSON.stringify(value));\n }\n\n async setEntry(key: string, entry: CacheEntry): Promise<void> {\n if (!Number.isFinite(entry.expiresAt)) throw new TypeError('Cache expiry must be finite.');\n const remaining = (entry.expiresAt - Date.now()) / 1000;\n if (remaining <= 0) return this.del(key);\n await this.ns.put(key, JSON.stringify(entry.value), {\n expirationTtl: Math.max(60, Math.ceil(remaining)),\n metadata: { velaCacheExpiresAt: entry.expiresAt },\n });\n }\n\n async del(key: string): Promise<void> {\n await this.ns.delete(key);\n }\n\n /** Namespace-wide, best effort. Use a dedicated value namespace; never use for scoped invalidation. */\n async clear(): Promise<void> {\n let cursor: string | undefined;\n do {\n const list = await this.ns.list(cursor ? { cursor } : undefined);\n await Promise.all(list.keys.map((entry) => this.ns.delete(entry.name)));\n cursor = list.list_complete ? undefined : list.cursor;\n } while (cursor);\n }\n}\n\n/**\n * Optional, eventually consistent generation store. Use a dedicated KV namespace\n * without TTL/lifecycle cleanup. Never delete/reset generations while entries can\n * survive. Concurrent writes and cached/negative reads prevent strong invalidation;\n * this is unsuitable for strict read-after-write or authorization revocation.\n */\nexport class KVCacheInvalidationStore implements CacheInvalidationStore {\n constructor(private readonly ns: KVNamespace) {}\n async getVersion(key: string): Promise<string> {\n const value: unknown = await this.ns.get(key, 'json');\n if (value === null) return 'initial';\n if (typeof value !== 'string' || value.length === 0 || value.length > 2048)\n throw new TypeError('Invalid cache generation.');\n return value;\n }\n async invalidate(key: string): Promise<void> {\n await this.ns.put(key, JSON.stringify(crypto.randomUUID()));\n }\n}\n","import type { FeatureFlagDriver, FlagContext } from '@velajs/feature-flags';\n\n/**\n * The subset of a Cloudflare **Flagship** binding this driver evaluates against\n * — the four typed value methods. The binding itself returns the supplied\n * `defaultValue` on evaluation errors; transport-level failures reject and are\n * left to propagate (never-throw is the service layer's job, not the driver's).\n *\n * @see https://developers.cloudflare.com/flagship/binding/\n */\nexport interface FlagshipBinding {\n getBooleanValue(key: string, defaultValue: boolean, context?: FlagContext): Promise<boolean>;\n getStringValue(key: string, defaultValue: string, context?: FlagContext): Promise<string>;\n getNumberValue(key: string, defaultValue: number, context?: FlagContext): Promise<number>;\n getObjectValue(key: string, defaultValue: object, context?: FlagContext): Promise<unknown>;\n}\n\nexport interface FlagshipFlagDriverOptions {\n /** Driver name used for `use(name)` / default-driver selection. Default `\"flagship\"`. */\n name?: string;\n}\n\n/**\n * {@link FeatureFlagDriver} backed by a Cloudflare Flagship binding.\n *\n * A thin, honest wrapper: each contract method maps 1:1 onto the binding's\n * corresponding value method, forwarding the caller's `fallback` (the binding's\n * `defaultValue`) and evaluation context. The binding resolves the fallback on\n * evaluation errors; anything the binding *rejects* with (e.g. a `remote: true`\n * dev-proxy tunnel dropping) propagates — `@velajs/feature-flags`'s service owns\n * the never-throw guarantee.\n *\n * Build the driver inside a provider factory with the native environment:\n *\n * ```ts\n * FeatureFlagsModule.forRootAsync({\n * inject: [ENV],\n * useFactory: (env: WorkerEnv) => ({ drivers: [flagshipFlagDriver(env.FLAGS)] }),\n * });\n * ```\n *\n * Evaluation ergonomics (the 1:1 binding-method mapping) are ported from the\n * Stratal feature-flags service (MIT, © Temitayo Fadojutimi), reshaped as a\n * bare driver.\n */\nexport class FlagshipFlagDriver implements FeatureFlagDriver {\n readonly name: string;\n private readonly resolve: () => FlagshipBinding;\n\n constructor(\n binding: FlagshipBinding | (() => FlagshipBinding),\n options: FlagshipFlagDriverOptions = {},\n ) {\n this.resolve = typeof binding === 'function' ? binding : () => binding;\n this.name = options.name ?? 'flagship';\n }\n\n getBoolean(key: string, fallback: boolean, ctx?: FlagContext): Promise<boolean> {\n return this.resolve().getBooleanValue(key, fallback, ctx);\n }\n\n getString(key: string, fallback: string, ctx?: FlagContext): Promise<string> {\n return this.resolve().getStringValue(key, fallback, ctx);\n }\n\n getNumber(key: string, fallback: number, ctx?: FlagContext): Promise<number> {\n return this.resolve().getNumberValue(key, fallback, ctx);\n }\n\n getObject(key: string, fallback: object, ctx?: FlagContext): Promise<unknown> {\n return this.resolve().getObjectValue(key, fallback, ctx);\n }\n}\n\n/** Convenience factory for {@link FlagshipFlagDriver}. */\nexport function flagshipFlagDriver(\n binding: FlagshipBinding | (() => FlagshipBinding),\n options?: FlagshipFlagDriverOptions,\n): FlagshipFlagDriver {\n return new FlagshipFlagDriver(binding, options);\n}\n","import type { FeatureFlagDriver, FlagContext } from '@velajs/feature-flags';\n\nexport interface KvFlagDriverOptions {\n /** Driver name used for `use(name)` / default-driver selection. Default `\"kv\"`. */\n name?: string;\n /** Prefix prepended to every flag key before the KV read. Default `\"\"` (none). */\n prefix?: string;\n}\n\n/**\n * Cloudflare KV-backed {@link FeatureFlagDriver}. Flags are stored as JSON\n * values under an optional key prefix and read with `get(key, 'json')`. Reads\n * are type-checked against the requested type: a missing key or a value of the\n * wrong JSON type returns the caller's `fallback`. KV has no targeting, so the\n * evaluation context is ignored.\n *\n * The driver stays honest — it does **not** swallow errors. A KV failure (or a\n * `SyntaxError` from a malformed stored value) propagates; the never-throw\n * guarantee lives in `@velajs/feature-flags`'s service layer.\n *\n * Placed like {@link KVCacheStore}: construct it in a wiring factory over a\n * resolved {@link KVNamespace}.\n *\n * ```ts\n * FeatureFlagsModule.forRootAsync({\n * inject: [ENV],\n * useFactory: (env: WorkerEnv) => ({ drivers: [new KvFlagDriver(env.CACHE, { prefix: 'flag:' })] }),\n * });\n * ```\n */\nexport class KvFlagDriver implements FeatureFlagDriver {\n readonly name: string;\n private readonly prefix: string;\n\n constructor(\n private readonly ns: KVNamespace,\n options: KvFlagDriverOptions = {},\n ) {\n this.name = options.name ?? 'kv';\n this.prefix = options.prefix ?? '';\n }\n\n getBoolean(key: string, fallback: boolean, _ctx?: FlagContext): Promise<boolean> {\n return this.read(key, fallback, (v) => typeof v === 'boolean');\n }\n\n getString(key: string, fallback: string, _ctx?: FlagContext): Promise<string> {\n return this.read(key, fallback, (v) => typeof v === 'string');\n }\n\n getNumber(key: string, fallback: number, _ctx?: FlagContext): Promise<number> {\n return this.read(key, fallback, (v) => typeof v === 'number');\n }\n\n getObject(key: string, fallback: object, _ctx?: FlagContext): Promise<unknown> {\n return this.read(key, fallback, (v) => typeof v === 'object' && v !== null);\n }\n\n /**\n * Reads and JSON-parses the (prefixed) key, returning the parsed value only\n * when `matches` accepts its type; otherwise the caller's fallback. A missing\n * key reads as `null` → fallback. Read/parse errors are left to propagate.\n */\n private async read<T>(\n key: string,\n fallback: T,\n matches: (value: unknown) => value is T,\n ): Promise<T> {\n const value = await this.ns.get(this.prefix + key, 'json');\n if (value === null || value === undefined) return fallback;\n return matches(value) ? value : fallback;\n }\n}\n\n/** Convenience factory for {@link KvFlagDriver}. */\nexport function kvFlagDriver(kv: KVNamespace, options?: KvFlagDriverOptions): KvFlagDriver {\n return new KvFlagDriver(kv, options);\n}\n","import { createParamDecorator } from '@velajs/vela';\n\n/**\n * Parameter decorator to inject Cloudflare environment bindings.\n *\n * Without arguments, returns the entire `env` object.\n * With a binding name, returns that specific binding.\n *\n * @example\n * ```ts\n * @Get()\n * handle(@Env() env: WorkerEnv) { ... }\n *\n * @Get()\n * handle(@Env('MY_KV') kv: KVNamespace) { ... }\n * ```\n */\nexport const Env = createParamDecorator<string | undefined>((bindingName, ctx): unknown => {\n // Hono Context has .env on Cloudflare Workers\n const env: unknown = ctx.getContext().env;\n if (typeof env !== 'object' || env === null) return undefined;\n return bindingName ? Reflect.get(env, bindingName) : env;\n});\n","import { defineMetadata, getMetadata, parseCron, registerEntrypointKind } from '@velajs/vela';\n\nconst SCHEDULED_METADATA_KEY = 'cloudflare:scheduled';\n\n// Open entrypoint kind: adapters enumerate cron handlers via\n// `app.entrypoints.ofKind('cf:scheduled')` — declared next to the decorator.\nregisterEntrypointKind({ kind: 'cf:scheduled', metaKey: SCHEDULED_METADATA_KEY, level: 'method' });\n\nexport interface ScheduledMetadata {\n cron: string;\n methodName: string;\n}\n\n/** Compatible with the existing programmatic scheduled() entrypoint. */\nexport interface ScheduledEvent {\n readonly cron: string;\n readonly scheduledTime?: number;\n}\n\n/** Native controller passed unchanged to a Worker handler. Call noRetry on its receiver. */\nexport interface ScheduledController extends ScheduledEvent {\n readonly scheduledTime: number;\n noRetry(): void;\n}\n\nexport interface ScheduledContext {\n waitUntil(promise: Promise<unknown>): void;\n}\n\nexport type ScheduledHandler<Env extends object = object> = (\n controller: ScheduledController,\n env: Env,\n context: ScheduledContext,\n) => void | Promise<void>;\n\nexport function parseScheduledMetadata(value: unknown): ScheduledMetadata {\n if (\n typeof value !== 'object' ||\n value === null ||\n !('cron' in value) ||\n typeof value.cron !== 'string' ||\n !('methodName' in value) ||\n typeof value.methodName !== 'string' ||\n !parseCron(value.cron, { dialect: 'cloudflare' })\n ) {\n throw new TypeError('Invalid Cloudflare scheduled metadata');\n }\n return { cron: value.cron, methodName: value.methodName };\n}\n\n/**\n * Marks a method as a scheduled (cron) handler.\n *\n * @example\n * ```ts\n * @Injectable()\n * class WorkerService {\n * @Scheduled('0 * * * *')\n * async hourlyCron() {\n * console.log('Running hourly');\n * }\n * }\n * ```\n */\nexport function Scheduled(cron: string): MethodDecorator {\n if (!parseCron(cron, { dialect: 'cloudflare' })) {\n throw new TypeError(`Invalid Cloudflare cron expression: ${cron}`);\n }\n return (target: object, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n // Work with a validated copy rather than mutating the registry's handler list.\n const existing = getScheduledMetadata(target);\n existing.push({ cron, methodName: String(propertyKey) });\n defineMetadata(SCHEDULED_METADATA_KEY, existing, target.constructor);\n };\n}\n\nexport function getScheduledMetadata(target: object): ScheduledMetadata[] {\n const ctor = typeof target === 'function' ? target : target.constructor;\n const value: unknown = getMetadata(SCHEDULED_METADATA_KEY, ctor);\n if (value === undefined) return [];\n if (!Array.isArray(value)) throw new TypeError('Invalid Cloudflare scheduled metadata list');\n return value.map(parseScheduledMetadata);\n}\n","import { defineMetadata, getMetadata, registerEntrypointKind } from '@velajs/vela';\n\nconst QUEUE_CONSUMER_METADATA_KEY = 'cloudflare:queue-consumer';\n\n// Open entrypoint kind: any adapter can enumerate queue consumers via\n// `app.entrypoints.ofKind('cf:queue')` — declared here, next to the decorator,\n// with zero vela-core involvement.\nregisterEntrypointKind({ kind: 'cf:queue', metaKey: QUEUE_CONSUMER_METADATA_KEY, level: 'method' });\n\nexport interface QueueConsumerMetadata {\n queueName: string;\n methodName: string;\n}\n\n/**\n * Marks a method as a queue consumer handler.\n *\n * @example\n * ```ts\n * @Injectable()\n * class WorkerService {\n * @QueueConsumer('email-queue')\n * async processEmails(batch: MessageBatch) {\n * for (const msg of batch.messages) {\n * console.log('Processing:', msg.body);\n * msg.ack();\n * }\n * }\n * }\n * ```\n */\nexport function QueueConsumer(queueName: string): MethodDecorator {\n return (target: object, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n const existing: QueueConsumerMetadata[] =\n (getMetadata(QUEUE_CONSUMER_METADATA_KEY, target.constructor) as QueueConsumerMetadata[]) ??\n [];\n existing.push({ queueName, methodName: String(propertyKey) });\n defineMetadata(QUEUE_CONSUMER_METADATA_KEY, existing, target.constructor);\n };\n}\n\nexport function getQueueConsumerMetadata(target: object): QueueConsumerMetadata[] {\n const ctor = target.constructor ?? target;\n return (getMetadata(QUEUE_CONSUMER_METADATA_KEY, ctor) as QueueConsumerMetadata[]) ?? [];\n}\n","import { defineProvider, type DynamicModule } from '@velajs/vela';\nimport { WsDispatcher, WS_SERVER } from '@velajs/vela/websocket';\nimport { WsServerHolder } from './ws-server-holder';\n\n/**\n * Cloudflare counterpart to the core `WebSocketModule.forRoot()`. Import this in\n * your `AppModule` instead: it provides the gateway dispatcher plus a late-bound\n * `WS_SERVER` (`WsServerHolder`) that the WebSocket Durable Object wires to a\n * ctx-backed server per instance. `useClass` ensures a fresh holder per DI\n * container so colocated DO instances never share a server.\n */\nexport class CloudflareWebSocketModule {\n static forRoot(): DynamicModule {\n const providers = [defineProvider(WS_SERVER, { useClass: WsServerHolder }), WsDispatcher];\n\n return {\n module: CloudflareWebSocketModule,\n providers,\n exports: [WS_SERVER, WsDispatcher],\n };\n }\n}\n","import {\n assertBroadcastCommandFits,\n DEFAULT_WS_MAX_FRAME_BYTES,\n resolveMaxFrameBytes,\n} from '@velajs/vela/websocket';\nimport type { BroadcastCommand } from '@velajs/vela/websocket';\nimport { roomToDurableId } from './room-id';\n\nexport interface WsBroadcastStub {\n broadcast(cmd: BroadcastCommand): Promise<void>;\n}\n\nexport interface BroadcastNamespace {\n idFromName(name: string): DurableObjectId;\n get(id: DurableObjectId): WsBroadcastStub;\n}\n\n/**\n * Push to a room from a Worker HTTP handler / cron / queue consumer (server-\n * initiated emit). Resolves the room's Durable Object and calls its `broadcast`\n * RPC method — the same canonical room→DO mapping the upgrade route uses, so it\n * always reaches the DO holding those sockets.\n *\n * @example\n * ```ts\n * // In a controller — ns from the typed Worker environment\n * await broadcastToRoom(ns, '/orgs/:orgId/ws', `org:${id}`, 'order.created', order);\n * ```\n */\nexport async function broadcastToRoom(\n ns: BroadcastNamespace,\n gatewayPath: string,\n room: string,\n event: string,\n data?: unknown,\n options?: { exceptIds?: string[]; maxFrameBytes?: number },\n): Promise<void> {\n const cmd: BroadcastCommand = {\n rooms: [room],\n exceptIds: options?.exceptIds,\n frame: JSON.stringify({ event, data }),\n };\n const maxFrameBytes = resolveMaxFrameBytes({\n maxFrameBytes: options?.maxFrameBytes ?? DEFAULT_WS_MAX_FRAME_BYTES,\n });\n assertBroadcastCommandFits(cmd, maxFrameBytes);\n const stub = ns.get(roomToDurableId(ns, gatewayPath, room));\n await stub.broadcast(cmd);\n}\n","import type { ThrottlerStorageRecord, ThrottlerStore } from '@velajs/vela';\n\n/** The deliberately small surface exposed by a Workers Rate Limiting binding. */\nexport interface CloudflareRateLimitBinding {\n limit(input: { key: string }): Promise<{ success: boolean }>;\n}\n\nexport interface CloudflareRateLimitStoreOptions {\n /** Must match the binding's configured `simple.limit`. */\n limit: number;\n /** Must match the binding's configured `simple.period`. */\n periodSeconds: 10 | 60;\n /** Bound attacker-influenced tracking keys before calling the platform. */\n maxKeyBytes?: number;\n}\n\n/**\n * Adapt a Cloudflare Workers Rate Limiting binding to Vela's throttler store.\n *\n * The platform binding makes the allow/deny decision. It does not expose exact\n * counters or reset timestamps, so this adapter intentionally omits `remaining`.\n */\nexport function cloudflareRateLimitStore(\n binding: CloudflareRateLimitBinding | (() => CloudflareRateLimitBinding),\n options: CloudflareRateLimitStoreOptions,\n): ThrottlerStore {\n if (!binding || (typeof binding !== 'function' && typeof binding.limit !== 'function')) {\n throw new TypeError('A Cloudflare Rate Limiting binding is required');\n }\n if (\n !Number.isSafeInteger(options.limit) ||\n options.limit <= 0 ||\n options.limit >= Number.MAX_SAFE_INTEGER\n ) {\n throw new RangeError('Rate limit must be a positive safe integer');\n }\n if (options.periodSeconds !== 10 && options.periodSeconds !== 60) {\n throw new RangeError('Cloudflare rate-limit periods must be 10 or 60 seconds');\n }\n\n const maxKeyBytes = options.maxKeyBytes ?? 1_024;\n if (!Number.isSafeInteger(maxKeyBytes) || maxKeyBytes <= 0 || maxKeyBytes > 4_096) {\n throw new RangeError('maxKeyBytes must be between 1 and 4096');\n }\n\n const ttlMs = options.periodSeconds * 1_000;\n const encoder = new TextEncoder();\n const resolveBinding =\n typeof binding === 'function' ? binding : (): CloudflareRateLimitBinding => binding;\n\n return {\n async increment(key: string, requestedTtlMs: number): Promise<ThrottlerStorageRecord> {\n if (requestedTtlMs !== ttlMs) {\n throw new Error(\n `Cloudflare binding period mismatch: expected ${ttlMs}ms, received ${requestedTtlMs}ms`,\n );\n }\n if (\n typeof key !== 'string' ||\n key.length === 0 ||\n /[\\u0000-\\u001f\\u007f]/.test(key) ||\n encoder.encode(key).byteLength > maxKeyBytes\n ) {\n throw new Error('Refusing an invalid or oversized rate-limit key');\n }\n\n const currentBinding = resolveBinding();\n if (!currentBinding || typeof currentBinding.limit !== 'function') {\n throw new Error('Cloudflare Rate Limiting binding is unavailable');\n }\n const decision = await currentBinding.limit({ key });\n if (!decision || typeof decision.success !== 'boolean') {\n throw new Error('Cloudflare rate-limit binding returned an invalid decision');\n }\n\n return {\n // Vela consumes `allowed` as the authoritative platform decision. These\n // sentinel counts preserve compatibility without inventing a counter.\n count: decision.success ? 0 : options.limit + 1,\n ttlMs,\n allowed: decision.success,\n enforcedLimit: options.limit,\n };\n },\n\n reset(): never {\n throw new Error('Cloudflare Rate Limiting bindings do not support counter reset');\n },\n };\n}\n","import type { VelaNonceDurableObject } from './nonce.durable-object';\nimport { MAX_NONCE_BYTES, isCanonicalBoundedText, isValidExpiry } from './nonce-validation';\nimport type { NonceStore } from '@velajs/vela';\n\nconst APP_NAMESPACE_PREFIX = 'vela:nonce:v1:';\nconst MAX_APP_NAMESPACE_BYTES = 128;\n/** The generated Workers binding type for {@link VelaNonceDurableObject}. */\nexport type DurableObjectNonceNamespace = DurableObjectNamespace<VelaNonceDurableObject>;\n\nexport interface DurableObjectNonceStoreOptions {\n /**\n * Stable application/environment boundary (for example `billing-api:prod`).\n * Claims are globally single-use inside this namespace and isolated from all\n * other application namespaces. It must be non-empty, canonical, and at most\n * 128 UTF-8 bytes.\n */\n appNamespace: string;\n\n /**\n * Resolve the Workers Durable Object namespace at claim time. The resolver is\n * intentionally not cached so request-scoped env/binding references stay safe.\n */\n binding: () => DurableObjectNonceNamespace | Promise<DurableObjectNonceNamespace>;\n}\n\n/**\n * Strict, cross-isolate {@link NonceStore} backed by one SQLite Durable Object\n * per explicit application namespace.\n *\n * Invalid input, an unavailable/malformed binding, RPC failure, or a malformed\n * RPC result all deny the claim (`false`). Only the literal boolean `true` from\n * the Durable Object is accepted.\n */\nexport function durableObjectNonceStore(options: DurableObjectNonceStoreOptions): NonceStore {\n if (!options || typeof options !== 'object') {\n throw new TypeError('Durable Object nonce-store options are required');\n }\n if (!isCanonicalBoundedText(options.appNamespace, MAX_APP_NAMESPACE_BYTES)) {\n throw new TypeError(\n `appNamespace must be canonical, non-empty, and at most ${MAX_APP_NAMESPACE_BYTES} UTF-8 bytes`,\n );\n }\n if (typeof options.binding !== 'function') {\n throw new TypeError('A lazy Durable Object namespace binding resolver is required');\n }\n\n const objectName = `${APP_NAMESPACE_PREFIX}${options.appNamespace}`;\n\n return {\n async claim(nonce: string, expEpochSeconds: number): Promise<boolean> {\n const now = Math.floor(Date.now() / 1_000);\n if (!isCanonicalBoundedText(nonce, MAX_NONCE_BYTES) || !isValidExpiry(expEpochSeconds, now)) {\n return false;\n }\n\n try {\n const namespace = await options.binding();\n\n const id = namespace.idFromName(objectName);\n const stub = namespace.get(id);\n const result = await stub.claim(nonce, expEpochSeconds);\n return result === true;\n } catch {\n return false;\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Injectable, defineProvider } from "@velajs/vela";
1
+ import { Injectable, Module, defineProvider } from "@velajs/vela";
2
2
  import { DEFAULT_WS_MAX_FRAME_BYTES, DEFAULT_WS_MAX_JOINED_ROOMS, WebSocketSendGate, assertWebSocketRoomId, resolveMaxFrameBytes } from "@velajs/vela/websocket";
3
3
  import { LIVE_CURSOR_LOG, LIVE_DRIVER, LiveEngine, readPersistedLiveSubscriptions } from "@velajs/vela/live";
4
4
  //#region src/websocket/room-id.ts
@@ -40,8 +40,12 @@ function assertCloudflareEnvironment(expected, actual) {
40
40
  }
41
41
  //#endregion
42
42
  //#region src/root-module.ts
43
- function resolveCloudflareRoot(root, env) {
44
- return typeof root === "function" ? root : root.create(env);
43
+ async function resolveCloudflareRoot(root, env) {
44
+ const resolved = typeof root === "object" && "create" in root ? await root.create(env) : root;
45
+ if (typeof resolved === "function") return resolved;
46
+ class WorkerRoot {}
47
+ Module({ imports: [resolved] })(WorkerRoot);
48
+ return WorkerRoot;
45
49
  }
46
50
  //#endregion
47
51
  //#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
@@ -510,4 +514,4 @@ function isValidExpiry(expEpochSeconds, nowEpochSeconds) {
510
514
  //#endregion
511
515
  export { durableObjectRoomName as C, connTag as S, roomToDurableId as T, readDoPitrBookmark as _, durableObjectLive as a, assertCloudflareEnvironment as b, liveInvalidateToRoom as c, rejectedAttachment as d, socketAttachment as f, isDoPitrUnavailable as g, armDoPitr as h, durableObjectCursorLog as i, CfWsClient as l, DoPitrUnavailableError as m, isValidExpiry as n, initDoLive as o, WsServerHolder as p, DoCursorLog as r, initializeDoLiveResources as s, isCanonicalBoundedText as t, MAX_WS_ATTACHMENT_BYTES as u, __decorate as v, roomTag as w, registerCloudflareEnvironment as x, resolveCloudflareRoot as y };
512
516
 
513
- //# sourceMappingURL=nonce-validation-Bcqf3FvY.js.map
517
+ //# sourceMappingURL=nonce-validation-CeVihShV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nonce-validation-CeVihShV.js","names":["encoder","encoder"],"sources":["../src/websocket/room-id.ts","../src/environment.ts","../src/root-module.ts","../src/websocket/do-pitr.ts","../src/websocket/ws-server-holder.ts","../src/websocket/ws-attachment.ts","../src/websocket/do-state.ts","../src/websocket/cf-ws-client.ts","../src/websocket/do-live.ts","../src/nonce/nonce-validation.ts"],"sourcesContent":["// Canonical room ↔ Durable Object mappings. The SAME functions are used by the\n// Worker upgrade route (to pick the DO) and by every server-initiated emit — so\n// a connection and a later broadcast always resolve to the same DO instance.\n\n/** Hibernation tag marking a socket's hub room (set at accept; immutable after). */\nexport function roomTag(roomId: string): string {\n return `room:${roomId}`;\n}\n\n/** Hibernation tag addressing one connection directly. */\nexport function connTag(connId: string): string {\n return `conn:${connId}`;\n}\n\nconst DO_ROOM_NAME_PREFIX = 'vela:ws:v2:';\nconst MAX_DO_ROOM_NAME_BYTES = 1_024;\nconst encoder = new TextEncoder();\n\n/** Stable, collision-free Durable Object name for one gateway's room. */\nexport function durableObjectRoomName(gatewayPath: string, roomId: string): string {\n if (\n typeof gatewayPath !== 'string' ||\n gatewayPath.length === 0 ||\n typeof roomId !== 'string' ||\n roomId.length === 0 ||\n /[\\u0000-\\u001f\\u007f]/.test(gatewayPath) ||\n /[\\u0000-\\u001f\\u007f]/.test(roomId)\n ) {\n throw new Error('A non-empty, control-free gateway path and room id are required');\n }\n const name = `${DO_ROOM_NAME_PREFIX}${encodeURIComponent(gatewayPath)}:${encodeURIComponent(roomId)}`;\n if (encoder.encode(name).byteLength > MAX_DO_ROOM_NAME_BYTES) {\n throw new Error('The gateway/room Durable Object name exceeds 1024 bytes');\n }\n return name;\n}\n\n/** One Durable Object instance per gateway + room, addressed by name. */\nexport function roomToDurableId(\n ns: Pick<DurableObjectNamespace, 'idFromName'>,\n gatewayPath: string,\n roomId: string,\n): DurableObjectId {\n return ns.idFromName(durableObjectRoomName(gatewayPath, roomId));\n}\n","import { defineProvider, InjectionToken } from '@velajs/vela';\nimport type { Container } from '@velajs/vela/internal';\n\n/** An application's native Workers environment, including bindings and secrets. */\nexport interface CloudflareEnvironment<T extends object> {\n /** Typed token used by @Inject and provider factories. */\n readonly token: InjectionToken<T>;\n /** The environment supplied by the current platform event or DO constructor. */\n readonly env: T;\n}\n\n/**\n * Register native bindings before provider factories or lifecycle hooks run.\n * No platform I/O is performed here; callers create applications inside an event.\n */\nexport function registerCloudflareEnvironment<T extends object>(\n container: Container,\n environment: CloudflareEnvironment<T>,\n): void {\n container.register(defineProvider(environment.token, { useValue: environment.env }));\n container.markGlobalToken(environment.token);\n}\n\n/** Reject accidental reuse of an application with another event's environment. */\nexport function assertCloudflareEnvironment<T extends object>(expected: T, actual: T): void {\n if (actual !== expected) {\n throw new Error(\n 'This Cloudflare application belongs to a different environment. ' +\n 'Create an application with the current event environment.',\n );\n }\n}\n","import { Module, type DynamicModule, type Type } from '@velajs/vela';\n\n/** A static module, or a module graph built from this Worker's native environment. */\nexport type CloudflareRoot<T extends object> =\n | Type\n | DynamicModule\n | { create(env: T): Type | DynamicModule | Promise<Type | DynamicModule> };\n\nexport async function resolveCloudflareRoot<T extends object>(\n root: CloudflareRoot<T>,\n env: T,\n): Promise<Type> {\n const resolved = typeof root === 'object' && 'create' in root ? await root.create(env) : root;\n if (typeof resolved === 'function') return resolved;\n // Preserve the dynamic root's imports, providers, exports and instance key.\n class WorkerRoot {}\n Module({ imports: [resolved] })(WorkerRoot);\n return WorkerRoot;\n}\n","/**\n * Durable Object point-in-time recovery (PITR) — thin, testable wrappers over a\n * SQLite-backed DO's native bookmark API. A SQLite Durable Object exposes three\n * storage methods (last-30-days PITR):\n *\n * - `getCurrentBookmark()` — an opaque bookmark for the storage's current state.\n * - `getBookmarkForTime(t)` — the bookmark closest to a wall-clock instant.\n * - `onNextSessionRestoreBookmark(b)` — arm a restore to bookmark `b`; the DO\n * restores to it the next time it starts a session, and the call RETURNS a\n * bookmark for the state JUST BEFORE the restore (the undo handle).\n *\n * These methods are ABSENT on a non-SQLite DO (key-value storage) and in some\n * local-dev runtimes, so this module models storage structurally with all three\n * methods OPTIONAL and degrades to a typed {@link DoPitrUnavailableError} (a\n * `code: 'PITR_UNAVAILABLE'`, HTTP 409 error) rather than an\n * `undefined is not a function` TypeError when a needed method is missing.\n *\n * Neither wrapper aborts the DO — `armDoPitr` only ARMS the restore and returns\n * the undo bookmark; the caller (the WS-DO RPC method) decides whether to\n * `ctx.abort()` to apply it immediately vs. on the next natural restart.\n *\n * This file is `cloudflare:workers`-free and pulls in NOTHING from `@velajs/vela`\n * or `@velajs/studio` — it is the raw capability the studio `TimeTravelPort`\n * wraps. Dependency direction is one-way: studio → cloudflare, never the reverse.\n */\n\n/**\n * The subset of `DurableObjectStorage` this module touches, with every method\n * OPTIONAL so it structurally models a non-SQLite DO whose storage has none of\n * them. A real `DurableObjectStorage` (whose methods are required) is assignable\n * to this shape.\n */\nexport interface DoPitrStorage {\n getCurrentBookmark?(): Promise<string>;\n getBookmarkForTime?(timestamp: number | Date): Promise<string>;\n onNextSessionRestoreBookmark?(bookmark: string): Promise<string>;\n}\n\n/** A read of a DO's current bookmark (+ the by-time bookmark when a time is given). */\nexport interface DoPitrBookmarkRead {\n /** The bookmark for the DO storage's current state. */\n current: string;\n /** The bookmark closest to the requested time (only when `time` was passed). */\n forTime?: string;\n}\n\n/** Arming input for {@link armDoPitr}: a target (bookmark WINS over time) + restart intent. */\nexport interface DoPitrArmOptions {\n /** An explicit target bookmark. Takes precedence over `time`. */\n bookmark?: string;\n /** A wall-clock target (epoch ms, ISO string, or Date), resolved to a bookmark. */\n time?: number | string | Date;\n /** Caller intent to restart-now; recorded on the result. `armDoPitr` never aborts. */\n restart?: boolean;\n}\n\n/** The result of arming a PITR restore (before any restart is applied). */\nexport interface DoPitrArmResult {\n /** The bookmark the restore is armed to. */\n restoredTo: string;\n /** The bookmark for the pre-restore state — restore to this to undo. */\n undoBookmark: string;\n /** Whether a restart-now was requested (the RPC layer performs the actual abort). */\n restarted: boolean;\n}\n\n/** The RPC surface a PITR-capable Vela WebSocket DO stub exposes to a Worker. */\nexport interface VelaDoPitrRpc {\n pitrCurrentBookmark(): Promise<DoPitrBookmarkRead>;\n pitrBookmarkForTime(time: number | string): Promise<DoPitrBookmarkRead>;\n pitrArmRestore(opts: DoPitrArmOptions): Promise<DoPitrArmResult>;\n}\n\n/** Structural view of a DO id (avoids depending on `@cloudflare/workers-types` downstream). */\nexport interface DoPitrId {\n toString(): string;\n readonly name?: string | null;\n}\n\n/**\n * Structural view of a DO namespace binding whose stubs speak the PITR RPC. A\n * downstream (the studio `@velajs/studio/cloudflare` port) types the app's\n * namespace binding as this shape to reach the PITR methods without importing\n * `@cloudflare/workers-types`.\n */\nexport interface DoPitrNamespace {\n idFromName(name: string): DoPitrId;\n get(id: DoPitrId): VelaDoPitrRpc;\n}\n\nconst PITR_UNAVAILABLE_CODE = 'PITR_UNAVAILABLE';\n\n/**\n * Thrown when a DO's storage lacks the SQLite bookmark API (non-SQLite DO, or a\n * local runtime without PITR). Carries a stable `code` + HTTP 409 `status`, and\n * a recognizable `name`/message so the studio port can map it to\n * `TIMETRAVEL_UNAVAILABLE` even after the error crosses the Worker→DO RPC hop\n * (which preserves `name` + `message`, not arbitrary own-properties).\n */\nexport class DoPitrUnavailableError extends Error {\n readonly code = PITR_UNAVAILABLE_CODE;\n readonly status = 409;\n\n constructor(message = 'Durable Object point-in-time recovery is unavailable on this storage') {\n super(`${PITR_UNAVAILABLE_CODE}: ${message}`);\n this.name = 'DoPitrUnavailableError';\n }\n}\n\n/**\n * True when `error` signals DO PITR unavailability. Robust across the Worker→DO\n * RPC hop: checks the `code` own-property (same process) AND the `name` / message\n * sentinel (survive RPC serialization) so a downstream can classify it either way.\n */\nexport function isDoPitrUnavailable(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false;\n const record = error as { code?: unknown; name?: unknown; message?: unknown };\n if (record.code === PITR_UNAVAILABLE_CODE) return true;\n if (record.name === 'DoPitrUnavailableError') return true;\n return (\n typeof record.message === 'string' && record.message.startsWith(`${PITR_UNAVAILABLE_CODE}:`)\n );\n}\n\n/** Normalize an epoch-ms number / ISO string / Date to the `number | Date` the DO API accepts. */\nfunction toStorageTime(time: number | string | Date): number | Date {\n if (typeof time === 'number') return time;\n if (time instanceof Date) return time;\n const asNumber = Number(time);\n return time.trim() !== '' && Number.isFinite(asNumber) ? asNumber : new Date(time);\n}\n\n/**\n * Read a DO's current bookmark, and — when `time` is given — the bookmark closest\n * to that instant. Throws {@link DoPitrUnavailableError} when a needed method is\n * absent, never `undefined is not a function`.\n */\nexport async function readDoPitrBookmark(\n storage: DoPitrStorage,\n time?: number | string | Date,\n): Promise<DoPitrBookmarkRead> {\n const getCurrent = storage.getCurrentBookmark;\n if (typeof getCurrent !== 'function') throw new DoPitrUnavailableError();\n const current = await getCurrent.call(storage);\n if (time === undefined) return { current };\n const getForTime = storage.getBookmarkForTime;\n if (typeof getForTime !== 'function') throw new DoPitrUnavailableError();\n const forTime = await getForTime.call(storage, toStorageTime(time));\n return { current, forTime };\n}\n\n/**\n * Arm a PITR restore. Resolves the target (an explicit `bookmark` WINS over\n * `time`), arms it via `onNextSessionRestoreBookmark`, and returns the undo\n * bookmark the DO reports for the pre-restore state. Does NOT abort — the caller\n * decides whether to restart now. Throws {@link DoPitrUnavailableError} when the\n * arming API (or the by-time resolver a `time` target needs) is absent.\n */\nexport async function armDoPitr(\n storage: DoPitrStorage,\n opts: DoPitrArmOptions,\n): Promise<DoPitrArmResult> {\n const armRestore = storage.onNextSessionRestoreBookmark;\n if (typeof armRestore !== 'function') throw new DoPitrUnavailableError();\n\n let target: string;\n if (opts.bookmark !== undefined) {\n target = opts.bookmark;\n } else if (opts.time !== undefined) {\n const getForTime = storage.getBookmarkForTime;\n if (typeof getForTime !== 'function') throw new DoPitrUnavailableError();\n target = await getForTime.call(storage, toStorageTime(opts.time));\n } else {\n throw new DoPitrUnavailableError('a target bookmark or time is required to arm a restore');\n }\n\n const undoBookmark = await armRestore.call(storage, target);\n return { restoredTo: target, undoBookmark, restarted: opts.restart === true };\n}\n","import { Injectable } from '@velajs/vela';\nimport { resolveMaxFrameBytes } from '@velajs/vela/websocket';\nimport type { BroadcastOperator, WsServer } from '@velajs/vela/websocket';\n\n/**\n * Late-bound `WsServer`. Provided as `WS_SERVER` (one per DI container, i.e. per\n * Durable Object instance), then pointed at the ctx-backed server once the DO\n * builds. Gateways inject it via `@WebSocketServer()`; it throws if used before\n * a runtime binds it (e.g. from the stateless Worker isolate).\n */\n@Injectable()\nexport class WsServerHolder implements WsServer {\n private target?: WsServer;\n private maxFrameBytes?: number;\n\n setTarget(server: WsServer): void {\n this.target = server;\n if (this.maxFrameBytes !== undefined) server.setOutboundFrameLimit?.(this.maxFrameBytes);\n }\n\n setOutboundFrameLimit(maxFrameBytes: number): void {\n const resolved = resolveMaxFrameBytes({ maxFrameBytes });\n this.maxFrameBytes =\n this.maxFrameBytes === undefined ? resolved : Math.max(this.maxFrameBytes, resolved);\n this.target?.setOutboundFrameLimit?.(this.maxFrameBytes);\n }\n\n private get resolved(): WsServer {\n if (!this.target) {\n throw new Error(\n 'WebSocket server is only available inside a WebSocket Durable Object. To ' +\n 'push from a Worker HTTP handler, use broadcastToRoom(namespace, gatewayPath, room, ...).',\n );\n }\n return this.target;\n }\n\n emit(event: string, data?: unknown): void | Promise<void> {\n return this.resolved.emit(event, data);\n }\n to(room: string): BroadcastOperator {\n return this.resolved.to(room);\n }\n in(room: string): BroadcastOperator {\n return this.resolved.in(room);\n }\n except(room: string): BroadcastOperator {\n return this.resolved.except(room);\n }\n}\n","import { assertWebSocketRoomId, DEFAULT_WS_MAX_JOINED_ROOMS } from '@velajs/vela/websocket';\nimport type { WsAttachment, WsLike } from './do-state';\n\nconst record = (value: unknown): value is Record<string, unknown> => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return (\n (prototype === Object.prototype || prototype === null) &&\n Reflect.ownKeys(value).every((key) => {\n const property = Object.getOwnPropertyDescriptor(value, key);\n return property !== undefined && 'value' in property;\n })\n );\n};\nconst positive = (value: unknown): value is number =>\n typeof value === 'number' && Number.isSafeInteger(value) && value > 0;\nconst text = (value: unknown): value is string =>\n typeof value === 'string' &&\n value.length > 0 &&\n new TextEncoder().encode(value).byteLength <= 2048;\n\n/** Versionless 1.x records remain readable; malformed/future versions fail closed. */\nexport function readWsAttachment(value: unknown): WsAttachment | undefined {\n if (!record(value) || (value.version !== undefined && value.version !== 1)) return undefined;\n if (\n !text(value.connId) ||\n typeof value.path !== 'string' ||\n value.path.length > 8192 ||\n (value.state !== 'pending' && value.state !== 'active' && value.state !== 'rejected') ||\n !Array.isArray(value.rooms) ||\n value.rooms.length > DEFAULT_WS_MAX_JOINED_ROOMS ||\n !record(value.data)\n )\n return undefined;\n const rooms: string[] = [];\n for (let index = 0; index < value.rooms.length; index++) {\n const descriptor = Object.getOwnPropertyDescriptor(value.rooms, index);\n if (!descriptor || !('value' in descriptor) || typeof descriptor.value !== 'string')\n return undefined;\n const room: string = descriptor.value;\n try {\n assertWebSocketRoomId(room);\n } catch {\n return undefined;\n }\n if (rooms.includes(room)) return undefined;\n rooms.push(room);\n }\n if (value.maxFrameBytes !== undefined && !positive(value.maxFrameBytes)) return undefined;\n if (value.expiresAtMs !== undefined && !positive(value.expiresAtMs)) return undefined;\n if (value.userId !== undefined && !text(value.userId)) return undefined;\n if (value.tenantId !== undefined && !text(value.tenantId)) return undefined;\n let principal: WsAttachment['principal'];\n if (value.principal !== undefined) {\n const p = value.principal;\n if (\n !record(p) ||\n !text(p.issuer) ||\n !text(p.subject) ||\n (p.principalType !== 'user' && p.principalType !== 'service')\n )\n return undefined;\n principal = { issuer: p.issuer, subject: p.subject, principalType: p.principalType };\n if (value.userId !== undefined && value.userId !== p.subject) return undefined;\n }\n return {\n version: 1,\n connId: value.connId,\n state: value.state,\n path: value.path,\n rooms,\n data: { ...value.data },\n ...(principal ? { principal } : {}),\n ...(typeof value.userId === 'string' ? { userId: value.userId } : {}),\n ...(typeof value.tenantId === 'string' ? { tenantId: value.tenantId } : {}),\n ...(typeof value.expiresAtMs === 'number' ? { expiresAtMs: value.expiresAtMs } : {}),\n ...(typeof value.maxFrameBytes === 'number' ? { maxFrameBytes: value.maxFrameBytes } : {}),\n };\n}\n\nexport function socketAttachment(ws: WsLike): WsAttachment | undefined {\n try {\n return readWsAttachment(ws.deserializeAttachment());\n } catch {\n return undefined;\n }\n}\n\nexport function rejectedAttachment(): WsAttachment {\n return { version: 1, connId: '', state: 'rejected', path: '', rooms: [], data: {} };\n}\n","// Minimal structural views of the Durable Object runtime, so the transport\n// logic is unit-testable in Node with fakes. Real `DurableObjectState` and\n// `WebSocket` (from @cloudflare/workers-types) satisfy these structurally.\n\n/** Cloudflare's serialized WebSocket hibernation attachment ceiling. */\nexport const MAX_WS_ATTACHMENT_BYTES = 16_384;\n\nexport interface WsLike {\n readonly readyState?: number;\n readonly bufferedAmount?: number;\n send(message: string | ArrayBuffer): void;\n close(code?: number, reason?: string): void;\n serializeAttachment(value: unknown): void;\n deserializeAttachment(): unknown;\n}\n\n/** Structural view of the DO's SQLite handle (`ctx.storage.sql`, requires `new_sqlite_classes`). */\nexport interface SqlStorageLike {\n exec(query: string, ...bindings: unknown[]): { toArray(): Record<string, unknown>[] };\n}\n\nexport interface DoStateLike {\n readonly id: { toString(): string; readonly name?: string | null };\n acceptWebSocket(ws: WsLike, tags?: string[]): void;\n getWebSockets(tag?: string): WsLike[];\n setWebSocketAutoResponse?(pair: unknown): void;\n /** Present on SQLite-backed DOs — the live cursor log lives here. */\n readonly storage?: { sql?: SqlStorageLike };\n}\n\n/** Per-connection metadata persisted in the hibernation attachment (≤ 16 KiB). */\nexport interface WsAttachment {\n /** Absent on 1.x attachments created before versioned validation. */\n version?: 1;\n connId: string;\n /** Only active sockets may dispatch frames or receive fan-out. */\n state: 'pending' | 'active' | 'rejected';\n userId?: string;\n /** Verified, issuer-qualified connection principal. */\n principal?: {\n issuer: string;\n subject: string;\n principalType: 'user' | 'service';\n };\n /** Trusted server-derived tenant boundary for this connection. */\n tenantId?: string;\n /** Verified auth credential expiry in epoch milliseconds. */\n expiresAtMs?: number;\n /** The gateway route path this socket belongs to — used to route messages. */\n path: string;\n /** Validated inbound/outbound gateway frame ceiling, persisted across hibernation. */\n maxFrameBytes?: number;\n /** Dynamically-joined room names (the hub room is also a hibernation tag). */\n rooms: string[];\n data: Record<string, unknown>;\n}\n","import { socketAttachment, rejectedAttachment } from './ws-attachment';\nimport type { WebSocketSendResult, WsClient } from '@velajs/vela/websocket';\nimport {\n assertWebSocketRoomId,\n DEFAULT_WS_MAX_FRAME_BYTES,\n DEFAULT_WS_MAX_JOINED_ROOMS,\n WebSocketSendGate,\n} from '@velajs/vela/websocket';\nimport {\n MAX_WS_ATTACHMENT_BYTES,\n type DoStateLike,\n type WsAttachment,\n type WsLike,\n} from './do-state';\nconst encoder = new TextEncoder();\n\n/**\n * Core `WsClient` over a native Cloudflare `WebSocket` inside a Durable Object.\n * Per-connection state lives in the hibernation attachment (survives eviction),\n * so a fresh `CfWsClient` is reconstructed per message with no in-memory state.\n */\nexport class CfWsClient<\n TData extends Record<string, unknown> = Record<string, unknown>,\n> implements WsClient<TData> {\n readonly #attachment: WsAttachment;\n\n constructor(\n private readonly ctx: DoStateLike,\n private readonly ws: WsLike,\n private readonly sendGate = new WebSocketSendGate(),\n ) {\n this.#attachment = socketAttachment(ws) ?? rejectedAttachment();\n }\n\n get id(): string {\n return this.#attachment.connId;\n }\n\n /** The gateway route path this socket connected on (used to route messages). */\n get path(): string {\n return this.#attachment.path;\n }\n\n get rooms(): ReadonlySet<string> {\n return new Set(this.#attachment.rooms);\n }\n\n get data(): TData {\n return this.#attachment.data as TData;\n }\n\n set data(value: TData) {\n this.#attachment.data = value;\n }\n\n get raw(): unknown {\n return this.ws;\n }\n\n get maxFrameBytes(): number {\n const value = this.#attachment.maxFrameBytes;\n return typeof value === 'number' && Number.isSafeInteger(value) && value > 0\n ? value\n : DEFAULT_WS_MAX_FRAME_BYTES;\n }\n\n send(event: string, data?: unknown, id?: string): void {\n this.sendRaw(JSON.stringify(id !== undefined ? { id, event, data } : { event, data }));\n }\n\n sendRaw(payload: string): void {\n this.trySendRaw(payload);\n }\n\n trySendRaw(payload: string): WebSocketSendResult {\n if (this.#attachment.state === 'rejected') return 'closed';\n return this.sendGate.trySend(this.ws, payload, this.maxFrameBytes);\n }\n\n join(room: string): void {\n assertWebSocketRoomId(room);\n if (!this.#attachment.rooms.includes(room)) {\n if (this.#attachment.rooms.length >= DEFAULT_WS_MAX_JOINED_ROOMS) {\n throw new Error(`A WebSocket may join at most ${DEFAULT_WS_MAX_JOINED_ROOMS} rooms`);\n }\n this.#attachment.rooms.push(room);\n this.persist();\n }\n }\n\n leave(room: string): void {\n const next = this.#attachment.rooms.filter((r) => r !== room);\n if (next.length !== this.#attachment.rooms.length) {\n this.#attachment.rooms = next;\n this.persist();\n }\n }\n\n /** Persist `data`/room mutations to the hibernation attachment. */\n commit(): void {\n this.persist();\n }\n\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason);\n }\n\n private persist(): void {\n if (this.#attachment.state === 'rejected') throw new Error('Invalid WebSocket attachment');\n const serialized = JSON.stringify(this.#attachment);\n if (encoder.encode(serialized).length > MAX_WS_ATTACHMENT_BYTES) {\n throw new Error(\n `WebSocket attachment exceeds the 16 KiB Cloudflare limit. Store large ` +\n `per-connection state in Durable Object storage keyed by connId instead.`,\n );\n }\n this.ws.serializeAttachment(this.#attachment);\n }\n}\n","import type { CfRoomRegistry } from './cf-room-registry';\nimport type { Container } from '@velajs/vela';\nimport {\n LIVE_CURSOR_LOG,\n LIVE_DRIVER,\n LiveEngine,\n readPersistedLiveSubscriptions,\n} from '@velajs/vela/live';\nimport type {\n CommitStamp,\n CursorLog,\n InvalidationCommand,\n LiveDriver,\n LiveInvalidationSink,\n ResumeVerdict,\n} from '@velajs/vela/live';\nimport { CfWsClient } from './cf-ws-client';\nimport type { DoStateLike, SqlStorageLike } from './do-state';\nimport { roomToDurableId } from './room-id';\n\nconst DEFAULT_ROOM = 'default';\nconst DEFAULT_MAX_LOG_ROWS = 4096;\n\n/**\n * The durable `CursorLog`: an append-only tag-invalidation log in the DO's\n * SQLite (`__vela_live_log`, AUTOINCREMENT seq = cursor) plus an epoch UUID in\n * `__vela_live_meta`. Because the cursor survives hibernation AND trims (it is\n * read from `sqlite_sequence`, lunora's `ctx-db-cdc.ts` trick), a reconnecting\n * client whose gap the log still covers gets a tiny `resume` instead of a\n * re-run — the real-resume half of the live protocol.\n *\n * Constructed un-initialized at module-composition time (the same app module\n * bootstraps in the Worker AND in each DO); `initDoLive` wires the SQLite\n * handle inside the DO. In the Worker isolate it stays un-initialized — and is\n * never consulted there, because `durableObjectLive()` routes every\n * invalidation to the room DO's log (one log scope per room, exactly the\n * protocol's model).\n */\nexport class DoCursorLog implements CursorLog {\n private sql?: SqlStorageLike;\n private epoch?: string;\n\n constructor(private readonly maxRows = DEFAULT_MAX_LOG_ROWS) {}\n\n /** @internal — called by `initDoLive` with the DO's `ctx.storage.sql`. */\n _initialize(sql: SqlStorageLike): void {\n this.sql = sql;\n sql.exec(\n 'CREATE TABLE IF NOT EXISTS __vela_live_log (seq INTEGER PRIMARY KEY AUTOINCREMENT, ts REAL NOT NULL, tags TEXT NOT NULL)',\n );\n sql.exec('CREATE TABLE IF NOT EXISTS __vela_live_meta (k TEXT PRIMARY KEY, v TEXT NOT NULL)');\n const row = sql.exec(\"SELECT v FROM __vela_live_meta WHERE k = 'epoch'\").toArray()[0];\n if (row && typeof row.v === 'string') {\n this.epoch = row.v;\n } else {\n this.epoch = crypto.randomUUID();\n sql.exec(\"INSERT INTO __vela_live_meta (k, v) VALUES ('epoch', ?)\", this.epoch);\n }\n }\n\n append(tags: string[]): CommitStamp {\n const sql = this.assertReady();\n sql.exec(\n 'INSERT INTO __vela_live_log (ts, tags) VALUES (?, ?)',\n Date.now(),\n JSON.stringify(tags),\n );\n const stamp = this.current();\n // Bounded retention: trimmed gaps degrade to snapshot-on-reconnect.\n if (stamp.cursor > this.maxRows) {\n sql.exec('DELETE FROM __vela_live_log WHERE seq <= ?', stamp.cursor - this.maxRows);\n }\n return stamp;\n }\n\n current(): CommitStamp {\n const sql = this.assertReady();\n // sqlite_sequence survives DELETE-based trims, so the cursor never\n // rewinds. The table itself only materializes on the first AUTOINCREMENT\n // insert — before that the log is empty and the cursor is 0.\n let cursor = 0;\n try {\n const row = sql\n .exec(\"SELECT seq FROM sqlite_sequence WHERE name = '__vela_live_log'\")\n .toArray()[0];\n cursor = typeof row?.seq === 'number' ? row.seq : Number(row?.seq ?? 0);\n } catch {\n cursor = 0;\n }\n if (!this.epoch) throw new Error('DoCursorLog epoch is not initialized.');\n return { cursor, epoch: this.epoch };\n }\n\n evaluateResume(\n sinceCursor: number,\n sinceEpoch: string,\n subscriptionTags: string[],\n ): ResumeVerdict {\n const sql = this.assertReady();\n const { cursor, epoch } = this.current();\n if (sinceEpoch !== epoch) return 'snapshot'; // forked timeline (reset/recreated DO)\n if (sinceCursor > cursor) return 'snapshot'; // rollback guard\n if (sinceCursor === cursor) return 'resume';\n\n const minRow = sql.exec('SELECT MIN(seq) AS m FROM __vela_live_log').toArray()[0];\n const min = minRow?.m == null ? undefined : Number(minRow.m);\n // The log must still cover (sinceCursor, cursor] — a trimmed gap cannot be reasoned about.\n if (min === undefined || min > sinceCursor + 1) return 'snapshot';\n\n const subTags = new Set(subscriptionTags);\n for (const row of sql\n .exec('SELECT tags FROM __vela_live_log WHERE seq > ?', sinceCursor)\n .toArray()) {\n let tags: unknown;\n try {\n tags = JSON.parse(String(row.tags));\n } catch {\n return 'snapshot';\n }\n if (\n Array.isArray(tags) &&\n tags.some((tag: unknown) => typeof tag === 'string' && subTags.has(tag))\n )\n return 'rerun';\n }\n return 'resume';\n }\n\n private assertReady(): SqlStorageLike {\n if (!this.sql) {\n throw new Error(\n 'DoCursorLog is not initialized. It only runs inside a SQLite-backed Durable Object ' +\n '(wrangler: new_sqlite_classes) — Worker-side invalidations must go through durableObjectLive(), ' +\n \"which routes them to the room DO's log.\",\n );\n }\n return this.sql;\n }\n}\n\nexport interface DurableObjectLiveOptions {\n /** Native, RPC-typed namespace supplied by the application's environment. */\n namespace: LiveNamespace;\n /** Exact `@WebSocketGateway()` path sharing this room/log namespace. */\n gatewayPath: string;\n /** Room used when an invalidation names none. Matches the client default. */\n defaultRoom?: string;\n}\n\nexport interface LiveInvalidateStub {\n invalidate(cmd: InvalidationCommand): Promise<CommitStamp | undefined>;\n}\n\n/** Only the native namespace operations required for live invalidation. */\nexport interface LiveNamespace {\n idFromName(name: string): DurableObjectId;\n get(id: DurableObjectId): LiveInvalidateStub;\n}\n\n/** One driver per application; construct from a LiveModule driver factory. */\nexport class CfLiveDriver implements LiveDriver {\n readonly kind = 'durable-object';\n private sink: LiveInvalidationSink | undefined;\n private localMode = false;\n\n constructor(private readonly options: DurableObjectLiveOptions) {}\n\n bind(sink: LiveInvalidationSink): void {\n this.sink = sink;\n }\n\n /** @internal — a DO dispatches to its own engine and SQLite log. */\n _setLocalMode(): void {\n this.localMode = true;\n }\n\n dispatch(cmd: InvalidationCommand): Promise<CommitStamp | undefined> | CommitStamp | undefined {\n if (this.localMode) return this.sink?.applyInvalidation(cmd);\n const { namespace, gatewayPath, defaultRoom } = this.options;\n const room = cmd.room ?? defaultRoom ?? DEFAULT_ROOM;\n return namespace\n .get(roomToDurableId(namespace, gatewayPath, room))\n .invalidate({ ...cmd, room });\n }\n}\n\n/** Use in LiveModule.forRootAsync: driver: () => durableObjectLive({ namespace: env.ROOMS, ... }). */\nexport function durableObjectLive(options: DurableObjectLiveOptions): CfLiveDriver {\n return new CfLiveDriver(options);\n}\n\n/** The app-facing surface of the engine reached through `app.entrypoints.ofKind('live')`. */\ninterface EntrypointsApp {\n entrypoints: { ofKind(kind: string): Array<{ meta: unknown }> };\n}\n\n/** @internal — prepare per-DO resources before user lifecycle hooks can invalidate. */\nexport function initializeDoLiveResources(container: Container, ctx: DoStateLike): void {\n if (container.has(LIVE_CURSOR_LOG)) {\n const log = container.resolve(LIVE_CURSOR_LOG);\n if (log instanceof DoCursorLog) {\n const sql = ctx.storage?.sql;\n if (!sql) {\n throw new Error(\n 'DoCursorLog requires a SQLite-backed Durable Object: add this class to ' +\n \"wrangler's `migrations[].new_sqlite_classes`. Falling back is not possible — \" +\n 'either enable SQLite or drop the `log: () => durableObjectCursorLog()` option ' +\n '(snapshot-on-reconnect semantics).',\n );\n }\n log._initialize(sql);\n }\n }\n\n if (container.has(LIVE_DRIVER)) {\n const driver = container.resolve(LIVE_DRIVER);\n if (driver instanceof CfLiveDriver) driver._setLocalMode();\n }\n}\n\n/**\n * DO-side wiring after lifecycle, called from `buildDoRuntime`: replay every hibernation-persisted\n * subscription into the (fresh) engine so an eviction is invisible to\n * subscribers. Returns the engine for the `invalidate` RPC, or undefined when\n * the app doesn't use LiveModule.\n */\nexport function initDoLive(\n app: EntrypointsApp,\n ctx: DoStateLike,\n registry?: CfRoomRegistry,\n): LiveEngine | undefined {\n const entry = app.entrypoints.ofKind('live')[0];\n if (!entry) return undefined;\n if (typeof entry.meta !== 'object' || entry.meta === null || !('engine' in entry.meta)) {\n throw new Error('Invalid live entrypoint metadata.');\n }\n const engine = entry.meta.engine;\n if (!(engine instanceof LiveEngine)) throw new Error('Invalid live entrypoint engine.');\n\n // Wake-time replay: subscriptions ride the hibernation attachments.\n for (const ws of ctx.getWebSockets()) {\n const client = registry?.clientFor(ws) ?? new CfWsClient(ctx, ws);\n if (!client.id) continue;\n for (const record of readPersistedLiveSubscriptions(client)) {\n engine.restoreSubscription(client.path, client, record);\n }\n }\n\n return engine;\n}\n\n/** Ergonomic alias: the log option for `LiveModule.forRoot` on Cloudflare. */\nexport function durableObjectCursorLog(maxRows?: number): DoCursorLog {\n return new DoCursorLog(maxRows);\n}\n\n/**\n * Invalidate live tags in a room from a Worker (controller / cron / queue\n * consumer) — the live sibling of `broadcastToRoom`. Returns the room log\n * scope's commit stamp for `Vela-Commit-Cursor` stamping.\n */\nexport async function liveInvalidateToRoom(\n ns: LiveNamespace,\n gatewayPath: string,\n room: string,\n tags: string[],\n): Promise<CommitStamp | undefined> {\n const stub = ns.get(roomToDurableId(ns, gatewayPath, room));\n return stub.invalidate({ room, tags });\n}\n","const encoder = new TextEncoder();\nexport const MAX_NONCE_BYTES = 512;\nexport function isCanonicalBoundedText(value: unknown, maxBytes: number): value is string {\n if (typeof value !== 'string') return false;\n for (const character of value) {\n const codePoint = character.codePointAt(0);\n if (\n codePoint !== undefined &&\n (codePoint <= 0x1f || codePoint === 0x7f || (codePoint >= 0xd800 && codePoint <= 0xdfff))\n ) {\n return false;\n }\n }\n return value.length > 0 && value === value.trim() && encoder.encode(value).byteLength <= maxBytes;\n}\n\nexport function isValidExpiry(\n expEpochSeconds: unknown,\n nowEpochSeconds: number,\n): expEpochSeconds is number {\n return (\n typeof expEpochSeconds === 'number' &&\n Number.isSafeInteger(expEpochSeconds) &&\n expEpochSeconds > 0 &&\n expEpochSeconds >= nowEpochSeconds\n );\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import { Type } from "@velajs/vela";
1
+ import { DynamicModule, Type } from "@velajs/vela";
2
2
  import { DurableObject } from "cloudflare:workers";
3
3
  //#region src/root-module.d.ts
4
4
  /** A static module, or a module graph built from this Worker's native environment. */
5
- type CloudflareRoot<T extends object> = Type | {
6
- create(env: T): Type;
5
+ type CloudflareRoot<T extends object> = Type | DynamicModule | {
6
+ create(env: T): Type | DynamicModule | Promise<Type | DynamicModule>;
7
7
  };
8
8
  //#endregion
9
9
  //#region src/websocket/do-pitr.d.ts
@@ -138,4 +138,4 @@ declare class VelaNonceDurableObject extends DurableObject<Record<string, unknow
138
138
  }
139
139
  //#endregion
140
140
  export { DoPitrId as a, DoPitrUnavailableError as c, isDoPitrUnavailable as d, readDoPitrBookmark as f, DoPitrBookmarkRead as i, VelaDoPitrRpc as l, DoPitrArmOptions as n, DoPitrNamespace as o, CloudflareRoot as p, DoPitrArmResult as r, DoPitrStorage as s, VelaNonceDurableObject as t, armDoPitr as u };
141
- //# sourceMappingURL=nonce.durable-object-Df3_42Sy.d.ts.map
141
+ //# sourceMappingURL=nonce.durable-object-DffHMRnU.d.ts.map