@velajs/cloudflare 1.9.0 → 1.10.1
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/CHANGELOG.md +8 -3
- package/dist/index.d.ts +805 -39
- package/dist/index.js +1645 -37
- package/dist/index.js.map +1 -0
- package/package.json +55 -41
- package/dist/binding-ref.d.ts +0 -8
- package/dist/binding-ref.js +0 -19
- package/dist/cloudflare-application.d.ts +0 -125
- package/dist/cloudflare-application.js +0 -186
- package/dist/cloudflare-factory.d.ts +0 -88
- package/dist/cloudflare-factory.js +0 -101
- package/dist/decorators/env.d.ts +0 -16
- package/dist/decorators/env.js +0 -22
- package/dist/decorators/queue-consumer.d.ts +0 -23
- package/dist/decorators/queue-consumer.js +0 -40
- package/dist/decorators/scheduled.d.ts +0 -20
- package/dist/decorators/scheduled.js +0 -36
- package/dist/env-ref.d.ts +0 -10
- package/dist/env-ref.js +0 -13
- package/dist/modules/ai.module.d.ts +0 -1
- package/dist/modules/ai.module.js +0 -8
- package/dist/modules/create-binding-module.d.ts +0 -14
- package/dist/modules/create-binding-module.js +0 -42
- package/dist/modules/d1.module.d.ts +0 -1
- package/dist/modules/d1.module.js +0 -8
- package/dist/modules/durable-object.module.d.ts +0 -1
- package/dist/modules/durable-object.module.js +0 -8
- package/dist/modules/env.module.d.ts +0 -17
- package/dist/modules/env.module.js +0 -35
- package/dist/modules/hyperdrive.module.d.ts +0 -1
- package/dist/modules/hyperdrive.module.js +0 -8
- package/dist/modules/kv.module.d.ts +0 -1
- package/dist/modules/kv.module.js +0 -8
- package/dist/modules/queue.module.d.ts +0 -1
- package/dist/modules/queue.module.js +0 -8
- package/dist/modules/r2.module.d.ts +0 -1
- package/dist/modules/r2.module.js +0 -8
- package/dist/modules/vectorize.module.d.ts +0 -1
- package/dist/modules/vectorize.module.js +0 -8
- package/dist/services/ai.service.d.ts +0 -6
- package/dist/services/ai.service.js +0 -33
- package/dist/services/d1.service.d.ts +0 -6
- package/dist/services/d1.service.js +0 -33
- package/dist/services/durable-object.service.d.ts +0 -6
- package/dist/services/durable-object.service.js +0 -33
- package/dist/services/env.service.d.ts +0 -31
- package/dist/services/env.service.js +0 -36
- package/dist/services/flagship-flag.driver.d.ts +0 -57
- package/dist/services/flagship-flag.driver.js +0 -49
- package/dist/services/hyperdrive.service.d.ts +0 -12
- package/dist/services/hyperdrive.service.js +0 -51
- package/dist/services/kv-cache.store.d.ts +0 -19
- package/dist/services/kv-cache.store.js +0 -58
- package/dist/services/kv-flag.driver.d.ts +0 -48
- package/dist/services/kv-flag.driver.js +0 -62
- package/dist/services/kv.service.d.ts +0 -11
- package/dist/services/kv.service.js +0 -33
- package/dist/services/queue.service.d.ts +0 -6
- package/dist/services/queue.service.js +0 -33
- package/dist/services/r2.service.d.ts +0 -6
- package/dist/services/r2.service.js +0 -33
- package/dist/services/vectorize.service.d.ts +0 -6
- package/dist/services/vectorize.service.js +0 -33
- package/dist/storage/index.d.ts +0 -7
- package/dist/storage/index.js +0 -6
- package/dist/storage/r2-storage.driver.d.ts +0 -19
- package/dist/storage/r2-storage.driver.js +0 -61
- package/dist/storage/storage-manager.service.d.ts +0 -16
- package/dist/storage/storage-manager.service.js +0 -56
- package/dist/storage/storage.controller.d.ts +0 -16
- package/dist/storage/storage.controller.js +0 -88
- package/dist/storage/storage.module.d.ts +0 -7
- package/dist/storage/storage.module.js +0 -37
- package/dist/storage/storage.service.d.ts +0 -20
- package/dist/storage/storage.service.js +0 -78
- package/dist/storage/storage.tokens.d.ts +0 -3
- package/dist/storage/storage.tokens.js +0 -2
- package/dist/storage/storage.types.d.ts +0 -17
- package/dist/storage/storage.types.js +0 -1
- package/dist/tokens.d.ts +0 -12
- package/dist/tokens.js +0 -12
- package/dist/types.d.ts +0 -13
- package/dist/types.js +0 -1
- package/dist/websocket/broadcast.d.ts +0 -15
- package/dist/websocket/broadcast.js +0 -26
- package/dist/websocket/cf-room-registry.d.ts +0 -23
- package/dist/websocket/cf-room-registry.js +0 -65
- package/dist/websocket/cf-ws-client.d.ts +0 -28
- package/dist/websocket/cf-ws-client.js +0 -83
- package/dist/websocket/cloudflare-websocket.module.d.ts +0 -11
- package/dist/websocket/cloudflare-websocket.module.js +0 -27
- package/dist/websocket/do-bootstrap.d.ts +0 -21
- package/dist/websocket/do-bootstrap.js +0 -50
- package/dist/websocket/do-state.d.ts +0 -25
- package/dist/websocket/do-state.js +0 -4
- package/dist/websocket/do-websocket-host.d.ts +0 -28
- package/dist/websocket/do-websocket-host.js +0 -69
- package/dist/websocket/index.d.ts +0 -13
- package/dist/websocket/index.js +0 -13
- package/dist/websocket/room-id.d.ts +0 -6
- package/dist/websocket/room-id.js +0 -12
- package/dist/websocket/websocket-routing.d.ts +0 -14
- package/dist/websocket/websocket-routing.js +0 -45
- package/dist/websocket/websocket.durable-object.d.ts +0 -15
- package/dist/websocket/websocket.durable-object.js +0 -72
- package/dist/websocket/ws-server-holder.d.ts +0 -16
- package/dist/websocket/ws-server-holder.js +0 -34
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/binding-ref.ts","../src/websocket/room-id.ts","../src/websocket/websocket-routing.ts","../src/cloudflare-application.ts","../src/env-ref.ts","../src/websocket/cf-ws-client.ts","../src/websocket/do-live.ts","../src/cloudflare-factory.ts","../src/tokens.ts","../src/services/kv.service.ts","../src/modules/create-binding-module.ts","../src/modules/kv.module.ts","../src/services/d1.service.ts","../src/modules/d1.module.ts","../src/services/r2.service.ts","../src/modules/r2.module.ts","../src/services/queue.service.ts","../src/modules/queue.module.ts","../src/services/durable-object.service.ts","../src/modules/durable-object.module.ts","../src/services/ai.service.ts","../src/modules/ai.module.ts","../src/services/vectorize.service.ts","../src/modules/vectorize.module.ts","../src/services/hyperdrive.service.ts","../src/modules/hyperdrive.module.ts","../src/services/env.service.ts","../src/modules/env.module.ts","../src/storage/r2-storage.driver.ts","../src/storage/storage.tokens.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/cf-room-registry.ts","../src/websocket/ws-server-holder.ts","../src/websocket/do-bootstrap.ts","../src/websocket/do-websocket-host.ts","../src/websocket/websocket.durable-object.ts","../src/websocket/cloudflare-websocket.module.ts","../src/websocket/broadcast.ts"],"sourcesContent":["// Mutable holder for a Cloudflare binding value. Created by each module's\n// forRoot() and populated by createCloudflareApp's one-time middleware on\n// the first request. Services access the binding lazily via .value.\nexport class BindingRef<T = unknown> {\n private _value: T | undefined;\n\n constructor(public readonly bindingName: string) {}\n\n get value(): T {\n if (this._value === undefined) {\n throw new Error(\n `Cloudflare binding '${this.bindingName}' not initialized. ` +\n `Ensure createCloudflareApp() is used and a request has been made.`,\n );\n }\n return this._value;\n }\n\n /** @internal — called by createCloudflareApp middleware */\n _initialize(value: T): void {\n this._value = value;\n }\n}\n","// 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\n/** One Durable Object instance per room, addressed by name. */\nexport function roomToDurableId(ns: DurableObjectNamespace, roomId: string): DurableObjectId {\n return ns.idFromName(roomId);\n}\n","import type { Context, Hono } from 'hono';\nimport { getMetadata } from '@velajs/vela';\nimport { WS_GATEWAY_METADATA } from '@velajs/vela/websocket';\nimport type { WebSocketGatewayOptions } from '@velajs/vela/websocket';\nimport { roomToDurableId } from './room-id';\n\nexport interface WsGatewayRoute {\n path: string;\n binding: string;\n}\n\n/** Read `@WebSocketGateway({ path, binding })` off a resolved instance (CF-hosted gateways only). */\nexport function collectWsGatewayRoutes(instance: object): WsGatewayRoute[] {\n const options = getMetadata(WS_GATEWAY_METADATA, instance.constructor) as\n | WebSocketGatewayOptions\n | undefined;\n if (!options?.path || !options?.binding) return [];\n return [{ path: options.path, binding: options.binding }];\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 const ns = (c.env as Record<string, unknown>)[route.binding] as\n | DurableObjectNamespace\n | undefined;\n if (!ns) {\n return c.text(`Durable Object binding '${route.binding}' is not configured`, 500);\n }\n\n const roomId = c.req.param('id') ?? route.path;\n const stub = ns.get(roomToDurableId(ns, roomId));\n\n // Strip any client-supplied x-vela-* (anti-spoof), then set server values.\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.set('x-vela-room', roomId);\n headers.set('x-vela-path', route.path);\n const userId = c.get('userId' as never) as string | undefined;\n if (userId) headers.set('x-vela-user', String(userId));\n\n return stub.fetch(new Request(c.req.raw, { headers }));\n });\n }\n}\n","import type { Hono } from 'hono';\nimport {\n CRON_METADATA,\n PipelineRunner,\n buildEntrypointExecutionContext,\n registerEntrypointKind,\n runInEntrypointScope,\n shouldFilterCatch,\n type VelaApplication,\n} from '@velajs/vela';\nimport type { CronMetadata, Entrypoint, Type } from '@velajs/vela';\nimport { ComponentManager } from '@velajs/vela/internal';\nimport type { ScheduledMetadata } from './decorators/scheduled';\nimport type { QueueConsumerMetadata } from './decorators/queue-consumer';\nimport { collectWsGatewayRoutes, type WsGatewayRoute } from './websocket/websocket-routing';\nimport type { CloudflareEnv } from './types';\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\ntype Method = (...args: unknown[]) => unknown;\n\nfunction invoke(instance: object, methodName: string, args: unknown[]): unknown {\n const method = (instance as Record<string, unknown>)[methodName];\n if (typeof method !== 'function') {\n throw new Error(`Method '${methodName}' is not a function on ${instance.constructor.name}`);\n }\n return (method as Method).apply(instance, args);\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);\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);\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 {\n private wsGatewayRoutes: WsGatewayRoute[] = [];\n\n constructor(private app: VelaApplication) {}\n\n get fetch(): Hono['fetch'] {\n return this.app.fetch;\n }\n\n getHonoApp(): Hono {\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: [...] })` request middleware,\n * which runs outside the DI request pipeline.\n *\n * @example\n * ```ts\n * const app = await createCloudflareApp(AppModule);\n * const auth = app.get<BetterAuthService>(BetterAuthService);\n * ```\n */\n get<T>(token: Parameters<VelaApplication['get']>[0]): T {\n return this.app.get(token) as T;\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);\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 — scans instances for `@WebSocketGateway({ path, binding })`\n * upgrade routes. Queue/scheduled handlers are NOT scanned anymore: they\n * come from `app.entrypoints` (`cf:queue` / `cf:scheduled` / `cf:vela-cron`\n * kinds) at dispatch time.\n */\n scanInstances(instances: unknown[]): void {\n for (const instance of instances) {\n if (!instance || typeof instance !== 'object') continue;\n this.wsGatewayRoutes.push(...collectWsGatewayRoutes(instance));\n }\n }\n\n /** @internal — upgrade routes discovered from `@WebSocketGateway({ path, binding })`. */\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: CloudflareEnv,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n const handlers = [\n ...this.app.entrypoints\n .ofKind<ScheduledMetadata>('cf:scheduled')\n .map((ep) => ({ ep, cron: ep.meta.cron })),\n ...this.app.entrypoints\n .ofKind<CronMetadata>('cf:vela-cron')\n .map((ep) => ({ ep, cron: ep.meta.expression })),\n ].filter((h) => h.cron === event.cron);\n\n await Promise.all(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(ep: Entrypoint, args: unknown[]): Promise<void> {\n const targetClass = ep.token as Type;\n const methodName = String(ep.methodName);\n const context = buildEntrypointExecutionContext(ep.kind, targetClass, methodName, args[0]);\n\n await runInEntrypointScope(this.app.getContainer(), async (scope) => {\n const instance = scope.resolve(ep.token) as object;\n const guards = ComponentManager.resolveGuards(\n ComponentManager.getScopedComponents('guard', targetClass, methodName),\n scope,\n );\n const interceptors = ComponentManager.resolveInterceptors(\n ComponentManager.getScopedComponents('interceptor', targetClass, methodName),\n scope,\n );\n // Closest-first, mirroring the HTTP/WS dispatchers.\n const filters = ComponentManager.resolveFilters(\n [...ComponentManager.getScopedComponents('filter', targetClass, methodName)].reverse(),\n scope,\n );\n\n try {\n await PipelineRunner.run({\n context,\n guards,\n interceptors,\n resolveArgs: async () => args,\n invoke: async (resolved) => invoke(instance, methodName, resolved),\n });\n } catch (error) {\n for (const filter of filters) {\n if (shouldFilterCatch(filter, error)) {\n await filter.catch(error, context);\n return;\n }\n }\n throw error;\n }\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: unknown[] },\n env: CloudflareEnv,\n ctx: { waitUntil: (promise: Promise<unknown>) => void },\n ): Promise<void> {\n const handlers = this.app.entrypoints\n .ofKind<QueueConsumerMetadata>('cf:queue')\n .filter((ep) => ep.meta.queueName === batch.queue);\n\n await Promise.all(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 { BindingRef } from './binding-ref';\n\n// Sentinel binding name for the whole-env holder — never used as an env key.\nconst ENV_SENTINEL = '__cf_env__';\n\n/**\n * Holds the entire Cloudflare Worker `env` record (bindings + vars/secrets),\n * not a single binding. Subclasses {@link BindingRef} so createCloudflareApp's\n * binding-init middleware collects and initializes it through the same path;\n * the factory special-cases it to pass the full `env` instead of one binding.\n */\nexport class EnvRef extends BindingRef<Record<string, unknown>> {\n constructor() {\n super(ENV_SENTINEL);\n }\n}\n","import type { WsClient } from '@velajs/vela/websocket';\nimport type { DoStateLike, WsAttachment, WsLike } from './do-state';\n\nconst MAX_ATTACHMENT_BYTES = 16_384; // Cloudflare hibernation attachment limit (16 KiB).\nconst encoder = new TextEncoder();\n\nconst EMPTY: WsAttachment = { connId: '', path: '', rooms: [], data: {} };\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 private readonly attachment: WsAttachment;\n\n constructor(\n private readonly ctx: DoStateLike,\n private readonly ws: WsLike,\n ) {\n const raw = ws.deserializeAttachment() as WsAttachment | null;\n this.attachment = raw ?? { ...EMPTY, data: {} };\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 send(event: string, data?: unknown, id?: string): void {\n this.ws.send(JSON.stringify(id !== undefined ? { id, event, data } : { event, data }));\n }\n\n sendRaw(payload: string): void {\n this.ws.send(payload);\n }\n\n join(room: string): void {\n if (!this.attachment.rooms.includes(room)) {\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 const serialized = JSON.stringify(this.attachment);\n if (encoder.encode(serialized).length > MAX_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 { Container } from '@velajs/vela';\nimport { LIVE_CURSOR_LOG, LIVE_DRIVER, readPersistedLiveSubscriptions } from '@velajs/vela/live';\nimport type {\n CommitStamp,\n CursorLog,\n InvalidationCommand,\n LiveDriver,\n LiveEngine,\n LiveEntrypointMeta,\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 return { cursor, epoch: this.epoch as string };\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 (Array.isArray(tags) && tags.some((tag) => subTags.has(tag as string))) 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 /** The wrangler binding name of the WebSocket DO namespace (e.g. `'CHAT_ROOM'`). */\n binding: string;\n /** Room used when an invalidation names none. Matches the client default. */\n defaultRoom?: string;\n}\n\ninterface LiveInvalidateStub {\n invalidate(cmd: InvalidationCommand): Promise<CommitStamp | undefined>;\n}\n\nexport interface CfLiveDriver extends LiveDriver {\n /** @internal — Worker isolate: capture `env` so the namespace binding resolves per dispatch. */\n _initializeEnv(env: Record<string, unknown>): void;\n /** @internal — DO isolate: deliver invalidations straight to this DO's engine. */\n _setLocalMode(): void;\n}\n\n/**\n * The Cloudflare `LiveDriver`. Dual-mode, because the SAME app module\n * bootstraps in both isolates:\n *\n * - **Worker** (HTTP mutations, queue consumers, crons): route the command to\n * the room's Durable Object over the `invalidate` RPC — the same canonical\n * `roomToDurableId` mapping the upgrade route and `broadcastToRoom` use —\n * and return THAT log scope's commit stamp (what `Vela-Commit-Cursor`\n * must carry).\n * - **DO** (writes issued from inside the object): apply to the local engine.\n */\nexport function durableObjectLive(options: DurableObjectLiveOptions): CfLiveDriver {\n let sink: LiveInvalidationSink | undefined;\n let env: Record<string, unknown> | undefined;\n let localMode = false;\n\n return {\n kind: 'durable-object',\n bind(boundSink) {\n sink = boundSink;\n },\n _initializeEnv(capturedEnv) {\n env = capturedEnv;\n },\n _setLocalMode() {\n localMode = true;\n },\n dispatch(cmd) {\n if (localMode) return sink?.applyInvalidation(cmd);\n const namespace = env?.[options.binding] as DurableObjectNamespace | undefined;\n if (!namespace) {\n throw new Error(\n `durableObjectLive: binding '${options.binding}' is not available. In a Worker, ` +\n 'createCloudflareApp() captures env on the first request; check the wrangler binding name.',\n );\n }\n const room = cmd.room ?? options.defaultRoom ?? DEFAULT_ROOM;\n const stub = namespace.get(roomToDurableId(namespace, room)) as unknown as LiveInvalidateStub;\n return stub.invalidate({ ...cmd, room });\n },\n };\n}\n\nconst isCfLiveDriver = (value: unknown): value is CfLiveDriver =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as CfLiveDriver)._setLocalMode === 'function' &&\n typeof (value as CfLiveDriver)._initializeEnv === 'function';\n\n/** Worker-side wiring, called from `cloudflareAdapter`'s first-request middleware. */\nexport function initializeWorkerLive(container: Container, env: Record<string, unknown>): void {\n let driver: unknown;\n try {\n driver = container.resolve(LIVE_DRIVER);\n } catch {\n return; // LiveModule not imported\n }\n if (isCfLiveDriver(driver)) driver._initializeEnv(env);\n}\n\n/** The app-facing surface of the engine reached through `app.entrypoints.ofKind('live')`. */\ninterface EntrypointsApp {\n entrypoints: { ofKind<M>(kind: string): Array<{ meta: M }> };\n}\n\n/**\n * DO-side wiring, called from `buildDoRuntime`: initialize the SQLite cursor\n * log, flip the driver to local mode, and 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 container: Container,\n ctx: DoStateLike,\n): LiveEngine | undefined {\n const entry = app.entrypoints.ofKind<LiveEntrypointMeta>('live')[0];\n if (!entry) return undefined;\n const engine = entry.meta.engine as LiveEngine;\n\n try {\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 } catch (err) {\n // Surface misconfiguration loudly — a silently un-initialized log would\n // throw on the first subscribe instead.\n if (err instanceof Error && err.message.includes('new_sqlite_classes')) throw err;\n }\n\n try {\n const driver = container.resolve(LIVE_DRIVER);\n if (isCfLiveDriver(driver)) driver._setLocalMode();\n } catch {\n // LiveModule always provides LIVE_DRIVER when the engine exists; defensive only.\n }\n\n // Wake-time replay: subscriptions ride the hibernation attachments.\n for (const ws of ctx.getWebSockets()) {\n const client = new CfWsClient(ctx, ws);\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: DurableObjectNamespace,\n room: string,\n tags: string[],\n): Promise<CommitStamp | undefined> {\n const stub = ns.get(roomToDurableId(ns, room)) as unknown as LiveInvalidateStub;\n return stub.invalidate({ room, tags });\n}\n","import type { MiddlewareHandler } from 'hono';\nimport { VelaFactory } from '@velajs/vela';\nimport type { RuntimeAdapter, Type } from '@velajs/vela';\nimport { Container } from '@velajs/vela/internal';\nimport { BindingRef } from './binding-ref';\nimport { CloudflareApplication } from './cloudflare-application';\nimport { EnvRef } from './env-ref';\nimport { initializeWorkerLive } from './websocket/do-live';\nimport { registerWebSocketRoutes } from './websocket/websocket-routing';\n\n// Walks every provider registered in the container and pulls out the\n// BindingRef instances. Replaces the old module-level `bindingsRegistry`\n// global so two CloudflareApplication instances in one process don't\n// share state.\nfunction collectBindingRefs(container: Container): BindingRef[] {\n // Enumerate per-instance useValue providers across ALL module buckets. Two\n // same-type binding modules (e.g. KVModule.forRoot for CACHE and SESSIONS)\n // share one token but live in distinct buckets — resolving the token would\n // return only the first, leaving the others uninitialized.\n const refs: BindingRef[] = [];\n for (const value of container.getUseValues()) {\n if (value instanceof BindingRef) refs.push(value);\n }\n return refs;\n}\n\n/**\n * Options for {@link createCloudflareApp}.\n *\n * Mirrors a tight subset of vela's `BootstrapOptions` — only the surface\n * that makes sense for a Workers consumer is re-exposed.\n */\nexport interface CreateCloudflareAppOptions {\n /**\n * Forwarded to `VelaFactory.create({ globalPrefix })`. Prepended to every\n * route registered by `@Controller(...)` (and any other route emitter)\n * inside the application, so a value of `'/v1'` turns `@Controller('/users')`\n * into `/v1/users`.\n *\n * @example\n * ```ts\n * const app = await createCloudflareApp(AppModule, { globalPrefix: '/v1' });\n * ```\n */\n globalPrefix?: string;\n\n /**\n * Extra Hono middleware to register on the underlying Hono app. Runs\n * AFTER the one-time binding-init middleware this adapter mounts\n * internally, so any handler in `middleware` can safely read from\n * `BindingRef` instances and Cloudflare env bindings.\n *\n * @example\n * ```ts\n * const app = await createCloudflareApp(AppModule, {\n * middleware: [\n * async (c, next) => {\n * c.set('requestId', crypto.randomUUID());\n * await next();\n * },\n * ],\n * });\n * ```\n */\n middleware?: MiddlewareHandler[];\n}\n\n/**\n * Create a Cloudflare Workers application.\n *\n * Sets up a one-time Hono middleware that captures `c.env` on the first\n * request and initializes all configured binding refs. Optional\n * {@link CreateCloudflareAppOptions} are forwarded to the underlying\n * `VelaFactory.create` so consumers don't have to wrap the resulting\n * application in an outer Hono just to set a `globalPrefix` or attach\n * extra request middleware.\n *\n * @example\n * ```ts\n * // Minimal — backwards compatible\n * const app = await createCloudflareApp(AppModule);\n * export default app; // has .fetch, .scheduled, .queue\n * ```\n *\n * @example\n * ```ts\n * // With a global prefix and outer middleware\n * const app = await createCloudflareApp(AppModule, {\n * globalPrefix: '/v1',\n * middleware: [\n * async (c, next) => {\n * c.set('tenantId', c.req.header('x-tenant-id') ?? 'public');\n * await next();\n * },\n * ],\n * });\n * ```\n */\n/**\n * The Cloudflare platform binding as a vela {@link RuntimeAdapter}: a one-time\n * request middleware captures `c.env` on the first request and initializes\n * every `BindingRef`/`EnvRef` (collected at `onBootstrap`, before any request\n * can arrive). Adapter `requestMiddleware` is prepended to the global chain by\n * `VelaFactory.create`, so user middleware can safely read binding refs.\n *\n * Exposed so consumers composing `VelaFactory.create` themselves can opt in:\n *\n * ```ts\n * const app = await VelaFactory.create(AppModule, { adapters: [cloudflareAdapter()] });\n * ```\n */\nexport function cloudflareAdapter(): RuntimeAdapter {\n let initialized = false;\n let refs: BindingRef[] = [];\n let liveContainer: Container | undefined;\n\n return {\n name: 'cloudflare',\n requestMiddleware: [\n async (c, next) => {\n if (!initialized) {\n initialized = true;\n const env = (c.env as Record<string, unknown>) ?? {};\n for (const ref of refs) {\n // EnvRef holds the whole env; every other ref holds one binding.\n if (ref instanceof EnvRef) ref._initialize(env);\n else ref._initialize(env[ref.bindingName]);\n }\n // Live queries: hand the durableObjectLive() driver its env so\n // Worker-side invalidations can resolve the room DO namespace.\n if (liveContainer) initializeWorkerLive(liveContainer, env);\n }\n await next();\n },\n ],\n onBootstrap: ({ container }) => {\n liveContainer = container;\n refs = collectBindingRefs(container);\n },\n };\n}\n\nexport async function createCloudflareApp(\n rootModule: Type,\n options: CreateCloudflareAppOptions = {},\n): Promise<CloudflareApplication> {\n const velaApp = await VelaFactory.create(rootModule, {\n globalPrefix: options.globalPrefix,\n middleware: options.middleware,\n adapters: [cloudflareAdapter()],\n });\n\n const cfApp = new CloudflareApplication(velaApp);\n cfApp.scanInstances(velaApp.getInstances());\n\n // Register WebSocket upgrade routes for any @WebSocketGateway({ path, binding }).\n // Each forwards the upgrade to the room's Durable Object (which owns the socket).\n registerWebSocketRoutes(cfApp.getHonoApp(), cfApp.getWsGatewayRoutes());\n\n return cfApp;\n}\n","import { InjectionToken } from '@velajs/vela';\nimport type { BindingRef } from './binding-ref';\nimport type { EnvRef } from './env-ref';\n\n// Tokens for binding refs — used by services to receive the binding value.\nexport const KV_BINDING_REF = new InjectionToken<BindingRef>('CF_KV_BINDING_REF');\nexport const D1_BINDING_REF = new InjectionToken<BindingRef>('CF_D1_BINDING_REF');\nexport const R2_BINDING_REF = new InjectionToken<BindingRef>('CF_R2_BINDING_REF');\nexport const QUEUE_BINDING_REF = new InjectionToken<BindingRef>('CF_QUEUE_BINDING_REF');\nexport const DO_BINDING_REF = new InjectionToken<BindingRef>('CF_DO_BINDING_REF');\nexport const AI_BINDING_REF = new InjectionToken<BindingRef>('CF_AI_BINDING_REF');\nexport const VECTORIZE_BINDING_REF = new InjectionToken<BindingRef>('CF_VECTORIZE_BINDING_REF');\nexport const HYPERDRIVE_BINDING_REF = new InjectionToken<BindingRef>('CF_HYPERDRIVE_BINDING_REF');\n\n// Token for the whole-env holder (full c.env), backing EnvService.\nexport const ENV_REF = new InjectionToken<EnvRef>('CF_ENV_REF');\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { KV_BINDING_REF } from '../tokens';\n\n/**\n * Wrapper around a Cloudflare KV namespace binding.\n * Use `kv.namespace.get(...)`, `kv.namespace.put(...)`, etc. — the namespace\n * is the standard @cloudflare/workers-types `KVNamespace`.\n */\n@Injectable()\nexport class KVService {\n constructor(@Inject(KV_BINDING_REF) private ref: BindingRef<KVNamespace>) {}\n\n get namespace(): KVNamespace {\n return this.ref.value;\n }\n}\n","import {\n defineConfigurableModule,\n type DynamicModule,\n type InjectionToken,\n type Type,\n} from '@velajs/vela';\nimport { BindingRef } from '../binding-ref';\n\ninterface CreateBindingModuleOptions<TService> {\n name: string;\n serviceClass: Type<TService>;\n bindingRefToken: InjectionToken<BindingRef>;\n}\n\nexport interface BindingModuleStatic {\n forRoot(options: { binding: string }): DynamicModule;\n}\n\n// Single factory for every Cloudflare binding module (KV, D1, R2, ...).\n// Each binding module is just a bag of (token, service); this generates the\n// canonical forRoot() shape via vela's `defineConfigurableModule` engine.\n//\n// Identity model (post vela audit #2):\n// - One real module class is declared per binding TYPE (KV, D1, R2, ...).\n// Its `name` property is set so error messages and diagnostics carry\n// the friendly name (e.g. `KVModule`).\n// - Each `forRoot({ binding })` returns `{ module, key: binding, ... }`.\n// Vela dedups by (module, key), so two `KVModule.forRoot({...})` calls\n// with different bindings coexist as distinct module instances; two\n// calls with the same binding dedup.\nexport function createBindingModule<TService>(\n opts: CreateBindingModuleOptions<TService>,\n): BindingModuleStatic {\n // Fresh module class per binding TYPE (one KVModule, one D1Module, ...).\n // The computed-property-name idiom is the canonical JS way to give a\n // class expression a dynamic `name`: NamedEvaluation reads the property\n // key and stamps it on the class at creation, instead of patching the\n // (configurable, non-writable) `name` slot via Object.defineProperty.\n const className = `${opts.name}Module`;\n const moduleClass: Type = { [className]: class {} }[className]!;\n\n return defineConfigurableModule<{ binding: string }>({\n module: moduleClass,\n methodName: 'forRoot',\n keyFrom: ({ binding }) => binding,\n providers: ({ binding }) => [\n { provide: opts.bindingRefToken, useValue: new BindingRef(binding) },\n opts.serviceClass,\n ],\n exports: [opts.serviceClass, opts.bindingRefToken],\n }) as unknown as BindingModuleStatic;\n}\n","import { KVService } from '../services/kv.service';\nimport { KV_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const KVModule = createBindingModule({\n name: 'KV',\n serviceClass: KVService,\n bindingRefToken: KV_BINDING_REF,\n});\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { D1_BINDING_REF } from '../tokens';\n\n@Injectable()\nexport class D1Service {\n constructor(@Inject(D1_BINDING_REF) private ref: BindingRef<D1Database>) {}\n\n get database(): D1Database {\n return this.ref.value;\n }\n}\n","import { D1Service } from '../services/d1.service';\nimport { D1_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const D1Module = createBindingModule({\n name: 'D1',\n serviceClass: D1Service,\n bindingRefToken: D1_BINDING_REF,\n});\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { R2_BINDING_REF } from '../tokens';\n\n@Injectable()\nexport class R2Service {\n constructor(@Inject(R2_BINDING_REF) private ref: BindingRef<R2Bucket>) {}\n\n get bucket(): R2Bucket {\n return this.ref.value;\n }\n}\n","import { R2Service } from '../services/r2.service';\nimport { R2_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const R2Module = createBindingModule({\n name: 'R2',\n serviceClass: R2Service,\n bindingRefToken: R2_BINDING_REF,\n});\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { QUEUE_BINDING_REF } from '../tokens';\n\n@Injectable()\nexport class QueueService<Body = unknown> {\n constructor(@Inject(QUEUE_BINDING_REF) private ref: BindingRef<Queue<Body>>) {}\n\n get queue(): Queue<Body> {\n return this.ref.value;\n }\n}\n","import { QueueService } from '../services/queue.service';\nimport { QUEUE_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const QueueModule = createBindingModule({\n name: 'Queue',\n serviceClass: QueueService,\n bindingRefToken: QUEUE_BINDING_REF,\n});\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { DO_BINDING_REF } from '../tokens';\n\n@Injectable()\nexport class DurableObjectService {\n constructor(@Inject(DO_BINDING_REF) private ref: BindingRef<DurableObjectNamespace>) {}\n\n get namespace(): DurableObjectNamespace {\n return this.ref.value;\n }\n}\n","import { DurableObjectService } from '../services/durable-object.service';\nimport { DO_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const DurableObjectModule = createBindingModule({\n name: 'DurableObject',\n serviceClass: DurableObjectService,\n bindingRefToken: DO_BINDING_REF,\n});\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { AI_BINDING_REF } from '../tokens';\n\n@Injectable()\nexport class AIService {\n constructor(@Inject(AI_BINDING_REF) private ref: BindingRef<Ai>) {}\n\n get binding(): Ai {\n return this.ref.value;\n }\n}\n","import { AIService } from '../services/ai.service';\nimport { AI_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const AIModule = createBindingModule({\n name: 'AI',\n serviceClass: AIService,\n bindingRefToken: AI_BINDING_REF,\n});\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { VECTORIZE_BINDING_REF } from '../tokens';\n\n@Injectable()\nexport class VectorizeService {\n constructor(@Inject(VECTORIZE_BINDING_REF) private ref: BindingRef<VectorizeIndex>) {}\n\n get index(): VectorizeIndex {\n return this.ref.value;\n }\n}\n","import { VectorizeService } from '../services/vectorize.service';\nimport { VECTORIZE_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const VectorizeModule = createBindingModule({\n name: 'Vectorize',\n serviceClass: VectorizeService,\n bindingRefToken: VECTORIZE_BINDING_REF,\n});\n","import { Injectable, Inject } from '@velajs/vela';\nimport type { BindingRef } from '../binding-ref';\nimport { HYPERDRIVE_BINDING_REF } from '../tokens';\n\n@Injectable()\nexport class HyperdriveService {\n constructor(@Inject(HYPERDRIVE_BINDING_REF) private ref: BindingRef<Hyperdrive>) {}\n\n get binding(): Hyperdrive {\n return this.ref.value;\n }\n\n get connectionString(): string {\n return this.binding.connectionString;\n }\n\n get host(): string {\n return this.binding.host;\n }\n\n get port(): number {\n return this.binding.port;\n }\n\n get user(): string {\n return this.binding.user;\n }\n\n get password(): string {\n return this.binding.password;\n }\n\n get database(): string {\n return this.binding.database;\n }\n}\n","import { HyperdriveService } from '../services/hyperdrive.service';\nimport { HYPERDRIVE_BINDING_REF } from '../tokens';\nimport { createBindingModule } from './create-binding-module';\n\nexport const HyperdriveModule = createBindingModule({\n name: 'Hyperdrive',\n serviceClass: HyperdriveService,\n bindingRefToken: HYPERDRIVE_BINDING_REF,\n});\n","import { Inject, Injectable } from '@velajs/vela';\nimport type { EnvRef } from '../env-ref';\nimport { ENV_REF } from '../tokens';\n\n/**\n * Injectable access to the full Cloudflare Worker `env` (bindings + vars +\n * secrets).\n *\n * The per-binding services (`D1Service`, `KVService`, …) each expose a single\n * binding, and the `@Env()` param decorator only works inside a request-scoped\n * controller handler. `EnvService` fills the gap: it can be injected into\n * PROVIDER FACTORIES — e.g. `SomeModule.forRootAsync({ inject: [EnvService] })`\n * — so a factory can read secrets/origins without reaching for the request.\n *\n * Reads are lazy. `env` only exists per request, so a factory (which runs at\n * bootstrap) must capture the `EnvService` and read inside its callback:\n *\n * ```ts\n * AuthModule.forRootAsync({\n * inject: [EnvService],\n * useFactory: (env: EnvService) => buildAuth(() => env.get<string>('AUTH_SECRET')),\n * });\n * ```\n *\n * Reading eagerly at bootstrap (`env.get(...)` before any request) throws.\n */\n@Injectable()\nexport class EnvService {\n constructor(@Inject(ENV_REF) private ref: EnvRef) {}\n\n /** The full env record. Throws if read before the first request. */\n get env(): Record<string, unknown> {\n return this.ref.value;\n }\n\n /** Read a single env entry (binding, var, or secret) by name. */\n get<T = unknown>(key: string): T | undefined {\n return this.ref.value[key] as T | undefined;\n }\n}\n","import type { DynamicModule } from '@velajs/vela';\nimport { EnvRef } from '../env-ref';\nimport { EnvService } from '../services/env.service';\nimport { ENV_REF } from '../tokens';\n\n/**\n * Provides {@link EnvService} GLOBALLY so any module's provider factories can\n * `inject: [EnvService]`. Register once on the root module:\n *\n * ```ts\n * @Module({ imports: [EnvModule.forRoot(), AuthModule.forRootAsync({ ... })] })\n * class AppModule {}\n * ```\n *\n * The {@link EnvRef} it provides is collected and initialized by\n * createCloudflareApp's binding-init middleware on the first request (the\n * factory passes it the full `env`, not a single binding).\n */\nexport class EnvModule {\n static forRoot(): DynamicModule {\n const ref = new EnvRef();\n return {\n module: EnvModule,\n global: true,\n providers: [{ provide: ENV_REF, useValue: ref }, EnvService],\n exports: [EnvService, ENV_REF],\n };\n }\n}\n","import {\n signUrl,\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';\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.isFinite(expiresIn) || expiresIn <= 0) {\n throw new Error(`Invalid presigned URL expiry: ${expiresIn}s (must be a positive number).`);\n }\n const routePath = `${STORAGE_ROUTE_BASE}/${this.config.disk}/${path}`;\n const url = await signUrl(`${routePath}?method=${method}`, this.config.secret, { expiresIn });\n return { url, method, expiresIn, expiresAt: new Date(Date.now() + expiresIn * 1000) };\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","import { Inject, Injectable } from '@velajs/vela';\nimport { EnvService } from '../services/env.service';\nimport { R2StorageDriver } from './r2-storage.driver';\nimport { STORAGE_OPTIONS } from './storage.tokens';\nimport type { DiskConfig, StorageModuleOptions } from './storage.types';\n\n/**\n * Resolves R2 buckets by binding NAME (via {@link EnvService}) so multiple disks\n * coexist without registering N R2Modules. Drivers are created per call — cheap,\n * and avoids caching a per-request env value on this singleton.\n */\n@Injectable()\nexport class StorageManagerService {\n constructor(\n @Inject(STORAGE_OPTIONS) private readonly options: StorageModuleOptions,\n @Inject(EnvService) private readonly env: EnvService,\n ) {}\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 const bucket = this.env.get<R2Bucket>(config.binding);\n if (!bucket) {\n throw new Error(`R2 binding \"${config.binding}\" for disk \"${disk}\" was not found in env.`);\n }\n return new R2StorageDriver({ disk, bucket, secret: this.env.get<string>('APP_SECRET') });\n }\n}\n","import { Controller, Get, Inject, Req } from '@velajs/vela';\nimport { verifySignedUrl } from '@velajs/vela/storage';\nimport type { Context } from 'hono';\nimport { EnvService } from '../services/env.service';\nimport { StorageManagerService } from './storage-manager.service';\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 wildcard is the FULL object path (root already applied at sign time), so\n * it is passed straight to the driver.\n */\n@Controller('storage')\nexport class StorageController {\n constructor(\n @Inject(StorageManagerService) private readonly manager: StorageManagerService,\n @Inject(EnvService) private readonly env: EnvService,\n ) {}\n\n @Get('/:disk/*')\n async download(@Req() c: Context): Promise<Response> {\n const secret = this.env.get<string>('APP_SECRET');\n if (!secret) return new Response('Storage signing is not configured', { status: 500 });\n\n const disk = c.req.param('disk');\n if (!disk || !this.manager.hasDisk(disk)) return new Response('Unknown disk', { status: 404 });\n\n if (!(await verifySignedUrl(c.req.url, secret))) {\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') !== 'GET') {\n return new Response('URL is not scoped for reads', { status: 403 });\n }\n\n // The object key is everything after `/storage/:disk/` (Hono doesn't expose\n // the `*` wildcard via param()). The key already includes the disk root.\n const { pathname } = url;\n const prefix = `/storage/${disk}/`;\n const idx = pathname.indexOf(prefix);\n const fullPath = idx >= 0 ? decodeURIComponent(pathname.slice(idx + prefix.length)) : '';\n try {\n const result = await this.manager.getDriver(disk).download(fullPath);\n return new Response(result.toStream(), { headers: { 'content-type': result.contentType } });\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.isFinite` rejects NaN — otherwise `NaN < 1 || NaN > max` is false,\n // NaN slips through, signUrl omits `expires`, and the URL never expires.\n if (!Number.isFinite(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 { EnvModule } from '../modules/env.module';\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// EnvModule.forRoot() is global + dedups by default key, so importing it here is\n// safe whether or not the root app also imports it — it guarantees EnvService\n// (bucket-by-name resolution) is available.\n@Module({\n imports: [EnvModule.forRoot()],\n providers: [StorageManagerService, StorageService],\n controllers: [StorageController],\n exports: [StorageService, StorageManagerService, STORAGE_OPTIONS],\n})\nexport class StorageModule extends ConfigurableModuleClass {}\n","import { Inject, Injectable, type AsyncCacheStore } from '@velajs/vela';\nimport { KVService } from './kv.service';\n\n/**\n * Cloudflare KV-backed {@link CacheStore}. Values are JSON-encoded. Intended as\n * the slow tier under a `TieredCacheStore` (memory L1 → KV L2), but usable\n * standalone as `CacheModule.forRootAsync({ inject: [KVService], useFactory: (kv) => ({ store: new KVCacheStore(kv) }) })`.\n *\n * Note: Cloudflare KV requires `expirationTtl >= 60s`, so sub-minute TTLs are\n * clamped up. Keep short TTLs on the memory tier; use KV for longer-lived entries.\n */\n@Injectable()\nexport class KVCacheStore implements AsyncCacheStore {\n constructor(@Inject(KVService) private readonly kv: KVService) {}\n\n private get ns(): KVNamespace {\n return this.kv.namespace;\n }\n\n async get<T = unknown>(key: string): Promise<T | undefined> {\n const value = await this.ns.get<T>(key, 'json');\n return value === null ? undefined : value;\n }\n\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n // KV enforces a 60s minimum expirationTtl; clamp up. Omit for no-TTL.\n const options =\n ttl !== undefined ? { expirationTtl: Math.max(60, Math.floor(ttl)) } : undefined;\n await this.ns.put(key, JSON.stringify(value), options);\n }\n\n async del(key: string): Promise<void> {\n await this.ns.delete(key);\n }\n\n async clear(): Promise<void> {\n // KV has no native clear — page through and delete. Best-effort.\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","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<T extends object>(key: string, defaultValue: T, context?: FlagContext): Promise<T>;\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 * The binding only exists per request in a Worker, so pass a lazy accessor when\n * wiring from a bootstrap factory (mirroring how {@link EnvService} reads are\n * deferred); a resolved binding may be passed directly in tests.\n *\n * ```ts\n * FeatureFlagsModule.forRootAsync({\n * inject: [EnvService],\n * useFactory: (env: EnvService) => ({\n * drivers: [flagshipFlagDriver(() => env.get<FlagshipBinding>('FLAGS')!)],\n * }),\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<T extends object>(key: string, fallback: T, ctx?: FlagContext): Promise<T> {\n return this.resolve().getObjectValue<T>(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 { Inject, Injectable } from '@velajs/vela';\nimport type { FeatureFlagDriver, FlagContext } from '@velajs/feature-flags';\nimport { KVService } from './kv.service';\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 KVService}.\n *\n * ```ts\n * FeatureFlagsModule.forRootAsync({\n * inject: [KVService],\n * useFactory: (kv: KVService) => ({ drivers: [new KvFlagDriver(kv, { prefix: 'flag:' })] }),\n * });\n * ```\n */\n@Injectable()\nexport class KvFlagDriver implements FeatureFlagDriver {\n readonly name: string;\n private readonly prefix: string;\n\n constructor(\n @Inject(KVService) private readonly kv: KVService,\n options: KvFlagDriverOptions = {},\n ) {\n this.name = options.name ?? 'kv';\n this.prefix = options.prefix ?? '';\n }\n\n private get ns(): KVNamespace {\n return this.kv.namespace;\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<T extends object>(key: string, fallback: T, _ctx?: FlagContext): Promise<T> {\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) => boolean,\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 as T) : fallback;\n }\n}\n\n/** Convenience factory for {@link KvFlagDriver}. */\nexport function kvFlagDriver(kv: KVService, 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: CloudflareEnv) { ... }\n *\n * @Get()\n * handle(@Env('MY_KV') kv: KVNamespace) { ... }\n * ```\n */\nexport const Env = createParamDecorator<string | undefined>((bindingName, ctx) => {\n // Hono Context has .env on Cloudflare Workers\n const c = ctx.getContext<{ env?: Record<string, unknown> }>();\n const env = c.env;\n if (!env) return undefined;\n return bindingName ? env[bindingName] : env;\n});\n","import { defineMetadata, getMetadata, 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/**\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 return (target: object, propertyKey: string | symbol, _descriptor: PropertyDescriptor) => {\n const existing: ScheduledMetadata[] =\n (getMetadata(SCHEDULED_METADATA_KEY, target.constructor) as ScheduledMetadata[]) ?? [];\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 = target.constructor ?? target;\n return (getMetadata(SCHEDULED_METADATA_KEY, ctor) as ScheduledMetadata[]) ?? [];\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 type { BroadcastCommand, RoomRegistry, WsClient } from '@velajs/vela/websocket';\nimport type { DoStateLike, WsAttachment, WsLike } from './do-state';\nimport { CfWsClient } from './cf-ws-client';\n\n/**\n * Core `RoomRegistry` backed by a Durable Object's hibernatable sockets. Room\n * membership lives in tags (hub room, set at accept) + the attachment (dynamic\n * `join()`), never in DO instance fields — so it survives hibernation with zero\n * rehydration.\n */\nexport class CfRoomRegistry implements RoomRegistry {\n constructor(private readonly ctx: DoStateLike) {}\n\n // CF sockets are registered with the DO by `acceptWebSocket`; nothing to track.\n register(_client: WsClient): void {}\n leaveAll(_client: WsClient): void {}\n\n join(client: WsClient, room: string): void | Promise<void> {\n return client.join(room);\n }\n\n leave(client: WsClient, room: string): void | Promise<void> {\n return client.leave(room);\n }\n\n localIdsInRoom(room: string): string[] {\n return this.socketsForRoom(room).map((ws) => this.attachmentOf(ws).connId);\n }\n\n deliverLocal(cmd: BroadcastCommand): void {\n const excludeIds = new Set(cmd.exceptIds ?? []);\n const excludeRooms = cmd.exceptRooms ?? [];\n\n // Empty `rooms` => GLOBAL (every socket in this DO). Otherwise the union of\n // targeted rooms, deduped per connection.\n const targets =\n cmd.rooms.length === 0 ? this.ctx.getWebSockets() : this.collectRooms(cmd.rooms);\n\n const seen = new Set<string>();\n for (const ws of targets) {\n const att = this.attachmentOf(ws);\n if (seen.has(att.connId)) continue;\n seen.add(att.connId);\n if (excludeIds.has(att.connId)) continue;\n if (excludeRooms.some((r) => att.rooms.includes(r))) continue;\n ws.send(cmd.frame);\n }\n }\n\n private collectRooms(rooms: string[]): WsLike[] {\n const set = new Set<WsLike>();\n for (const room of rooms) for (const ws of this.socketsForRoom(room)) set.add(ws);\n return [...set];\n }\n\n private socketsForRoom(room: string): WsLike[] {\n // Membership is the attachment's `rooms`, NOT the hibernation tag: tags are\n // immutable after acceptWebSocket, so a socket that left its hub room still\n // carries the tag. Since one DO ≈ one room, scanning all sockets in the DO\n // and filtering by attachment is both correct and cheap.\n return this.ctx.getWebSockets().filter((ws) => this.attachmentOf(ws).rooms.includes(room));\n }\n\n private attachmentOf(ws: WsLike): WsAttachment {\n return (\n (ws.deserializeAttachment() as WsAttachment | null) ?? {\n connId: '',\n path: '',\n rooms: [],\n data: {},\n }\n );\n }\n\n /** Reconstruct a `WsClient` for a raw socket (e.g. inside gateway lifecycle scans). */\n clientFor(ws: WsLike): WsClient {\n return new CfWsClient(this.ctx, ws);\n }\n}\n","import { Injectable } from '@velajs/vela';\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\n setTarget(server: WsServer): void {\n this.target = server;\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, 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 { bootstrap, VelaApplication } from '@velajs/vela';\nimport type { Type } from '@velajs/vela';\nimport { local, WsDispatcher, WsServerImpl, WS_SERVER } from '@velajs/vela/websocket';\nimport type { WsEntrypointMeta, WsServer } from '@velajs/vela/websocket';\nimport type { LiveEngine } from '@velajs/vela/live';\nimport { BindingRef } from '../binding-ref';\nimport { EnvRef } from '../env-ref';\nimport { CfRoomRegistry } from './cf-room-registry';\nimport { initDoLive } from './do-live';\nimport type { DoStateLike } from './do-state';\nimport { WsServerHolder } from './ws-server-holder';\n\nexport interface DoRuntime {\n dispatcher: WsDispatcher;\n registry: CfRoomRegistry;\n server: WsServer;\n /** Gateway paths from `app.entrypoints.ofKind('websocket')` (discovery order). */\n gatewayPaths: string[];\n /** The live-query engine (undefined when the app doesn't import LiveModule). */\n live?: LiveEngine;\n close(signal?: string): Promise<void>;\n}\n\n/**\n * Slim DI bootstrap for the Durable Object isolate: wires the container and runs\n * `OnModuleInit`/`OnApplicationBootstrap` (so `WsDispatcher` discovers gateways)\n * WITHOUT building the Hono app/routes the DO never serves. Cloudflare binding\n * refs are initialized straight from the DO's `env`, and the ctx-backed server\n * is bound before bootstrap lifecycle so gateway `afterInit`/handlers see it.\n */\nexport async function buildDoRuntime(\n rootModule: Type,\n ctx: DoStateLike,\n env: Record<string, unknown>,\n): Promise<DoRuntime> {\n const { container, routeManager, loader } = await bootstrap(rootModule);\n\n // Init binding refs from env directly (no request middleware inside a DO).\n // Enumerate per-instance useValue providers across ALL module buckets — two\n // same-type binding modules share one token but live in distinct buckets, so\n // resolving the token would return only the first and leave the rest uninitialized.\n for (const value of container.getUseValues()) {\n if (value instanceof EnvRef) value._initialize(env);\n else if (value instanceof BindingRef) value._initialize(env[value.bindingName]);\n }\n\n const registry = new CfRoomRegistry(ctx);\n const driver = local();\n driver.bind(registry);\n const server = new WsServerImpl(driver);\n\n try {\n const holder = container.resolve(WS_SERVER);\n if (holder instanceof WsServerHolder) holder.setTarget(server);\n } catch {\n // CloudflareWebSocketModule not imported — gateways won't have a server.\n }\n\n const app = new VelaApplication(container, routeManager);\n app.setInstances(await loader.resolveAllInstances());\n await app.callOnModuleInit();\n await app.callOnApplicationBootstrap();\n\n // The entrypoint registry is the transport contract: one 'websocket' entry\n // per discovered gateway ({ meta: { path, dispatcher } }). Built by\n // callOnApplicationBootstrap(), so this slim no-routes path has it too.\n const wsEntrypoints = app.entrypoints.ofKind<WsEntrypointMeta>('websocket');\n\n // Live queries: wire the SQLite cursor log + local driver mode and replay\n // hibernation-persisted subscriptions into the fresh engine.\n const live = initDoLive(app, container, ctx);\n\n return {\n // Zero gateways still yields a live dispatcher (module imported, nothing\n // decorated) — fall back to resolving it directly.\n dispatcher: wsEntrypoints[0]?.meta.dispatcher ?? app.get(WsDispatcher),\n registry,\n server,\n gatewayPaths: wsEntrypoints.map((ep) => ep.meta.path),\n live,\n close: (signal?: string) => app.close(signal),\n };\n}\n","import type { BroadcastCommand, WsDispatcher } from '@velajs/vela/websocket';\nimport { CfWsClient } from './cf-ws-client';\nimport type { CfRoomRegistry } from './cf-room-registry';\nimport type { DoStateLike, WsAttachment, WsLike } from './do-state';\nimport { connTag, roomTag } from './room-id';\n\n/**\n * The socket lifecycle inside a WebSocket Durable Object, decoupled from the\n * `cloudflare:workers` base class so it is unit-testable with fakes. The thin\n * `VelaWebSocketDurableObject` shell forwards its hibernation callbacks here.\n */\nexport class DoWebSocketHost {\n constructor(\n private readonly ctx: DoStateLike,\n private readonly dispatcher: WsDispatcher,\n private readonly registry: CfRoomRegistry,\n private readonly gatewayPaths: readonly string[] = [],\n ) {}\n\n /** The single registered gateway's path — a fallback when the Worker didn't forward `x-vela-path`. */\n defaultPath(): string | undefined {\n return this.gatewayPaths[0];\n }\n\n /**\n * Accept a hibernatable socket: tag it with its hub room + connection id,\n * persist the attachment, then fire `OnGatewayConnection` WITHOUT blocking the\n * 101 response (the caller returns it immediately).\n */\n accept(ws: WsLike, path: string, roomId: string, userId?: string): void {\n const connId = crypto.randomUUID();\n this.ctx.acceptWebSocket(ws, [roomTag(roomId), connTag(connId)]);\n\n const attachment: WsAttachment = {\n connId,\n userId,\n path,\n rooms: [roomId],\n data: userId ? { userId } : {},\n };\n ws.serializeAttachment(attachment);\n\n void Promise.resolve(this.dispatcher.handleOpen(path, new CfWsClient(this.ctx, ws))).catch(\n (err) => console.warn('[vela] websocket handleConnection failed:', err),\n );\n }\n\n async onMessage(ws: WsLike, message: string | ArrayBuffer): Promise<void> {\n const client = new CfWsClient(this.ctx, ws);\n await this.dispatcher.dispatchMessage(client.path, client, message);\n }\n\n async onClose(ws: WsLike, code: number, reason: string): Promise<void> {\n const client = new CfWsClient(this.ctx, ws);\n await this.dispatcher.handleClose(client.path, client, code, reason);\n // Complete the closing handshake. Only 1000 and 3000-4999 are valid for\n // close(); reserved/abnormal codes (1005/1006/1015, etc.) throw a RangeError,\n // so fall back to a codeless close on those.\n try {\n if (code === 1000 || (code >= 3000 && code <= 4999)) ws.close(code, reason);\n else ws.close();\n } catch {\n // socket already closed\n }\n }\n\n async onError(ws: WsLike, err: unknown): Promise<void> {\n const client = new CfWsClient(this.ctx, ws);\n await this.dispatcher.handleError(client.path, client, err);\n }\n\n /** Deliver a broadcast command to this DO's local sockets (RPC entry point). */\n broadcast(cmd: BroadcastCommand): void {\n this.registry.deliverLocal(cmd);\n }\n}\n","import { DurableObject } from 'cloudflare:workers';\nimport type { Type } from '@velajs/vela';\nimport type { BroadcastCommand } from '@velajs/vela/websocket';\nimport type { CommitStamp, InvalidationCommand, LiveEngine } from '@velajs/vela/live';\nimport { buildDoRuntime } from './do-bootstrap';\nimport { DoWebSocketHost } from './do-websocket-host';\nimport type { WsLike } from './do-state';\n\nconst PING = '{\"event\":\"ping\"}';\nconst PONG = '{\"event\":\"pong\"}';\n\n/**\n * Base class for the WebSocket Durable Object. The user exports a named subclass\n * (matching their `wrangler.toml` `class_name`) built from their `AppModule`:\n *\n * ```ts\n * export class ChatRoom extends VelaWebSocketDurableObject(AppModule) {}\n * ```\n *\n * It owns the raw hibernation socket lifecycle (Hono's `upgradeWebSocket` cannot\n * bridge DO hibernation) and forwards every event into the runtime-agnostic\n * `WsDispatcher` via {@link DoWebSocketHost}.\n */\nexport function VelaWebSocketDurableObject(\n rootModule: Type,\n): new (\n ctx: DurableObjectState,\n env: Record<string, unknown>,\n) => DurableObject<Record<string, unknown>> {\n return class VelaWsDurableObject extends DurableObject<Record<string, unknown>> {\n private host!: DoWebSocketHost;\n private liveEngine?: LiveEngine;\n private readonly ready: Promise<void>;\n\n constructor(ctx: DurableObjectState, env: Record<string, unknown>) {\n super(ctx, env);\n // Application-level ping/pong answered WITHOUT waking a hibernated DO.\n try {\n ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair(PING, PONG));\n } catch {\n // Older runtimes without auto-response — fine, protocol pings still work.\n }\n this.ready = ctx.blockConcurrencyWhile(async () => {\n const runtime = await buildDoRuntime(rootModule, ctx, env);\n this.host = new DoWebSocketHost(\n ctx,\n runtime.dispatcher,\n runtime.registry,\n runtime.gatewayPaths,\n );\n this.liveEngine = runtime.live;\n });\n }\n\n override async fetch(request: Request): Promise<Response> {\n await this.ready;\n if (request.headers.get('upgrade')?.toLowerCase() !== 'websocket') {\n return new Response('Expected WebSocket upgrade', { status: 426 });\n }\n\n const { 0: client, 1: server } = new WebSocketPair();\n const url = new URL(request.url);\n // Headers are primary (carry auth + multi-gateway routing); fall back to the\n // DO's own name (set via idFromName(room)) and the single gateway path so a\n // plain `stub.fetch(request)` forward still works.\n const roomId = request.headers.get('x-vela-room') ?? this.ctx.id.name ?? url.pathname;\n const path = request.headers.get('x-vela-path') ?? this.host.defaultPath() ?? url.pathname;\n const userId = request.headers.get('x-vela-user') || undefined;\n\n this.host.accept(server as unknown as WsLike, path, roomId, userId);\n return new Response(null, { status: 101, webSocket: client });\n }\n\n override async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {\n await this.ready;\n await this.host.onMessage(ws as unknown as WsLike, message);\n }\n\n override async webSocketClose(ws: WebSocket, code: number, reason: string): Promise<void> {\n await this.ready;\n await this.host.onClose(ws as unknown as WsLike, code, reason);\n }\n\n override async webSocketError(ws: WebSocket, error: unknown): Promise<void> {\n await this.ready;\n await this.host.onError(ws as unknown as WsLike, error);\n }\n\n /** DO RPC — server-initiated broadcast forwarded from a Worker (see `broadcastToRoom`). */\n async broadcast(cmd: BroadcastCommand): Promise<void> {\n await this.ready;\n this.host.broadcast(cmd);\n }\n\n /**\n * DO RPC — live tag invalidation forwarded from a Worker (durableObjectLive /\n * liveInvalidateToRoom). Appends to THIS log scope's cursor log and returns\n * the commit stamp (what `Vela-Commit-Cursor` carries); the subscription\n * refreshes fan out asynchronously.\n */\n async invalidate(cmd: InvalidationCommand): Promise<CommitStamp | undefined> {\n await this.ready;\n return this.liveEngine?.applyInvalidation(cmd);\n }\n };\n}\n","import type { DynamicModule, ProviderOptions, Type } 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: Array<Type | ProviderOptions> = [\n { provide: WS_SERVER, useClass: WsServerHolder },\n WsDispatcher,\n ];\n\n return {\n module: CloudflareWebSocketModule,\n providers,\n exports: [WS_SERVER, WsDispatcher],\n };\n }\n}\n","import type { BroadcastCommand } from '@velajs/vela/websocket';\nimport { roomToDurableId } from './room-id';\n\ninterface WsBroadcastStub {\n broadcast(cmd: BroadcastCommand): Promise<void>;\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 DurableObjectService.namespace\n * await broadcastToRoom(ns, `org:${id}`, 'order.created', order);\n * ```\n */\nexport async function broadcastToRoom(\n ns: DurableObjectNamespace,\n room: string,\n event: string,\n data?: unknown,\n options?: { exceptIds?: string[] },\n): Promise<void> {\n const cmd: BroadcastCommand = {\n rooms: [room],\n exceptIds: options?.exceptIds,\n frame: JSON.stringify({ event, data }),\n };\n const stub = ns.get(roomToDurableId(ns, room)) as unknown as WsBroadcastStub;\n await stub.broadcast(cmd);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,52 +1,65 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velajs/cloudflare",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "Cloudflare Workers integration for Vela framework",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"import": "./dist/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"README.md",
|
|
17
|
-
"LICENSE",
|
|
18
|
-
"CHANGELOG.md"
|
|
19
|
-
],
|
|
20
|
-
"sideEffects": false,
|
|
21
5
|
"keywords": [
|
|
22
|
-
"vela",
|
|
23
6
|
"cloudflare",
|
|
24
7
|
"cloudflare-workers",
|
|
25
|
-
"kv",
|
|
26
8
|
"d1",
|
|
27
|
-
"
|
|
28
|
-
"queues",
|
|
9
|
+
"decorators",
|
|
29
10
|
"edge",
|
|
30
11
|
"framework",
|
|
31
|
-
"
|
|
12
|
+
"kv",
|
|
13
|
+
"queues",
|
|
14
|
+
"r2",
|
|
15
|
+
"vela"
|
|
32
16
|
],
|
|
33
|
-
"
|
|
17
|
+
"homepage": "https://github.com/velajs/cloudflare#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/velajs/cloudflare/issues"
|
|
20
|
+
},
|
|
34
21
|
"license": "MIT",
|
|
22
|
+
"author": "ksh",
|
|
35
23
|
"repository": {
|
|
36
24
|
"type": "git",
|
|
37
25
|
"url": "git+https://github.com/velajs/cloudflare.git"
|
|
38
26
|
},
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
"
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"CHANGELOG.md"
|
|
32
|
+
],
|
|
33
|
+
"type": "module",
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"main": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js"
|
|
41
|
+
}
|
|
42
42
|
},
|
|
43
|
-
"
|
|
44
|
-
"
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
45
|
+
"@changesets/cli": "^2.31.0",
|
|
46
|
+
"@cloudflare/workers-types": "^4.20260624.1",
|
|
47
|
+
"@swc/core": "^1.15.43",
|
|
48
|
+
"@velajs/feature-flags": "^0.1.0",
|
|
49
|
+
"@velajs/vela": "^1.17.0",
|
|
50
|
+
"hono": "^4.12.27",
|
|
51
|
+
"oxfmt": "^0.58.0",
|
|
52
|
+
"oxlint": "^1.73.0",
|
|
53
|
+
"publint": "^0.3.21",
|
|
54
|
+
"tsdown": "^0.22.4",
|
|
55
|
+
"typescript": "^7.0.2",
|
|
56
|
+
"unplugin-swc": "^1.5.9",
|
|
57
|
+
"vitest": "^4.1.10"
|
|
45
58
|
},
|
|
46
59
|
"peerDependencies": {
|
|
47
60
|
"@cloudflare/workers-types": ">=4",
|
|
48
61
|
"@velajs/feature-flags": "^0.1.0",
|
|
49
|
-
"@velajs/vela": ">=1.
|
|
62
|
+
"@velajs/vela": ">=1.17.0",
|
|
50
63
|
"hono": ">=4"
|
|
51
64
|
},
|
|
52
65
|
"peerDependenciesMeta": {
|
|
@@ -54,20 +67,21 @@
|
|
|
54
67
|
"optional": true
|
|
55
68
|
}
|
|
56
69
|
},
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"@swc/cli": "^0.8.1",
|
|
60
|
-
"@swc/core": "^1.15.43",
|
|
61
|
-
"@velajs/feature-flags": "^0.1.0",
|
|
62
|
-
"@velajs/vela": "^1.12.0",
|
|
63
|
-
"hono": "^4.12.27",
|
|
64
|
-
"typescript": "^6.0.3",
|
|
65
|
-
"unplugin-swc": "^1.5.9",
|
|
66
|
-
"vitest": "^4.1.9"
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=24"
|
|
67
72
|
},
|
|
68
73
|
"scripts": {
|
|
69
|
-
"build": "
|
|
74
|
+
"build": "tsdown",
|
|
70
75
|
"test": "vitest run",
|
|
71
|
-
"typecheck": "tsc --noEmit"
|
|
76
|
+
"typecheck": "tsc --noEmit",
|
|
77
|
+
"lint": "oxlint .",
|
|
78
|
+
"format": "oxfmt .",
|
|
79
|
+
"format:check": "oxfmt --check .",
|
|
80
|
+
"publint": "publint",
|
|
81
|
+
"attw": "attw --pack . --profile esm-only",
|
|
82
|
+
"changeset": "changeset",
|
|
83
|
+
"version-packages": "changeset version",
|
|
84
|
+
"release": "pnpm build && changeset publish",
|
|
85
|
+
"verify": "pnpm lint && pnpm format:check && pnpm build && pnpm typecheck && pnpm test && pnpm publint && pnpm attw"
|
|
72
86
|
}
|
|
73
87
|
}
|
package/dist/binding-ref.d.ts
DELETED
package/dist/binding-ref.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// Mutable holder for a Cloudflare binding value. Created by each module's
|
|
2
|
-
// forRoot() and populated by createCloudflareApp's one-time middleware on
|
|
3
|
-
// the first request. Services access the binding lazily via .value.
|
|
4
|
-
export class BindingRef {
|
|
5
|
-
bindingName;
|
|
6
|
-
_value;
|
|
7
|
-
constructor(bindingName){
|
|
8
|
-
this.bindingName = bindingName;
|
|
9
|
-
}
|
|
10
|
-
get value() {
|
|
11
|
-
if (this._value === undefined) {
|
|
12
|
-
throw new Error(`Cloudflare binding '${this.bindingName}' not initialized. ` + `Ensure createCloudflareApp() is used and a request has been made.`);
|
|
13
|
-
}
|
|
14
|
-
return this._value;
|
|
15
|
-
}
|
|
16
|
-
/** @internal — called by createCloudflareApp middleware */ _initialize(value) {
|
|
17
|
-
this._value = value;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import type { Hono } from 'hono';
|
|
2
|
-
import { type VelaApplication } from '@velajs/vela';
|
|
3
|
-
import { type WsGatewayRoute } from './websocket/websocket-routing';
|
|
4
|
-
import type { CloudflareEnv } from './types';
|
|
5
|
-
/**
|
|
6
|
-
* Options accepted by {@link CloudflareApplication.mountOpenApi}.
|
|
7
|
-
*
|
|
8
|
-
* Re-exposes vela's `MountOpenApiOptions` type — derived structurally from
|
|
9
|
-
* the underlying `VelaApplication.mountOpenApi` signature so consumers don't
|
|
10
|
-
* have to reach into vela's internal subpaths to type the argument.
|
|
11
|
-
*/
|
|
12
|
-
export type MountOpenApiOptions = Parameters<VelaApplication['mountOpenApi']>[0];
|
|
13
|
-
/**
|
|
14
|
-
* Wraps VelaApplication with Cloudflare-specific handlers:
|
|
15
|
-
* - `fetch` — HTTP request handler (from Hono)
|
|
16
|
-
* - `scheduled` — Cron trigger handler (matches `@Scheduled()` decorators
|
|
17
|
-
* AND vela's own `@Cron()` jobs)
|
|
18
|
-
* - `queue` — Queue consumer handler (matches `@QueueConsumer()` decorators)
|
|
19
|
-
* - `mountOpenApi` — Serve an OpenAPI document (and optional Scalar UI) on
|
|
20
|
-
* the underlying Hono app
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* const app = await createCloudflareApp(AppModule);
|
|
25
|
-
* export default {
|
|
26
|
-
* fetch: app.fetch,
|
|
27
|
-
* scheduled: app.scheduled.bind(app),
|
|
28
|
-
* queue: app.queue.bind(app),
|
|
29
|
-
* };
|
|
30
|
-
* ```
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```ts
|
|
34
|
-
* // Serve OpenAPI docs alongside your routes
|
|
35
|
-
* const app = await createCloudflareApp(AppModule);
|
|
36
|
-
* const document = createOpenApiDocument(AppModule);
|
|
37
|
-
* app.mountOpenApi({ document, ui: 'scalar' });
|
|
38
|
-
* // GET /openapi.json -> JSON document
|
|
39
|
-
* // GET /scalar -> Scalar UI (loads from CDN)
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export declare class CloudflareApplication {
|
|
43
|
-
private app;
|
|
44
|
-
private wsGatewayRoutes;
|
|
45
|
-
constructor(app: VelaApplication);
|
|
46
|
-
get fetch(): Hono['fetch'];
|
|
47
|
-
getHonoApp(): Hono;
|
|
48
|
-
/**
|
|
49
|
-
* Resolve a provider from the application's DI container (delegates to
|
|
50
|
-
* `VelaApplication.get`). Handy for grabbing a service — e.g. an auth service —
|
|
51
|
-
* to use inside `createCloudflareApp({ middleware: [...] })` request middleware,
|
|
52
|
-
* which runs outside the DI request pipeline.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```ts
|
|
56
|
-
* const app = await createCloudflareApp(AppModule);
|
|
57
|
-
* const auth = app.get<BetterAuthService>(BetterAuthService);
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
get<T>(token: Parameters<VelaApplication['get']>[0]): T;
|
|
61
|
-
/**
|
|
62
|
-
* Serve a pre-built OpenAPI document (and optionally a Scalar UI) on the
|
|
63
|
-
* underlying Hono app. Delegates verbatim to `VelaApplication.mountOpenApi`,
|
|
64
|
-
* so the JSON endpoint defaults to `/openapi.json` and the Scalar UI (when
|
|
65
|
-
* opted in) defaults to `/scalar`. Edge-safe — the UI HTML loads Scalar from
|
|
66
|
-
* a CDN at runtime, nothing is bundled server-side.
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```ts
|
|
70
|
-
* import { createOpenApiDocument } from '@velajs/vela';
|
|
71
|
-
*
|
|
72
|
-
* const app = await createCloudflareApp(AppModule);
|
|
73
|
-
* const document = createOpenApiDocument(AppModule, {
|
|
74
|
-
* info: { title: 'My API', version: '1.0.0' },
|
|
75
|
-
* });
|
|
76
|
-
* app.mountOpenApi({ document, ui: 'scalar' });
|
|
77
|
-
* // GET /openapi.json -> { openapi: '3.1.0', ... }
|
|
78
|
-
* // GET /scalar -> Scalar UI HTML
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
mountOpenApi(options: MountOpenApiOptions): this;
|
|
82
|
-
/**
|
|
83
|
-
* @internal — scans instances for `@WebSocketGateway({ path, binding })`
|
|
84
|
-
* upgrade routes. Queue/scheduled handlers are NOT scanned anymore: they
|
|
85
|
-
* come from `app.entrypoints` (`cf:queue` / `cf:scheduled` / `cf:vela-cron`
|
|
86
|
-
* kinds) at dispatch time.
|
|
87
|
-
*/
|
|
88
|
-
scanInstances(instances: unknown[]): void;
|
|
89
|
-
/** @internal — upgrade routes discovered from `@WebSocketGateway({ path, binding })`. */
|
|
90
|
-
getWsGatewayRoutes(): WsGatewayRoute[];
|
|
91
|
-
/**
|
|
92
|
-
* Handle Cloudflare scheduled (cron) events.
|
|
93
|
-
* Matches the event's cron expression to `@Scheduled()` and vela `@Cron()`
|
|
94
|
-
* handlers read from `app.entrypoints`; each handler runs inside a fresh
|
|
95
|
-
* request-scoped child (request-scoped providers rebuild per tick).
|
|
96
|
-
*/
|
|
97
|
-
scheduled(event: {
|
|
98
|
-
cron: string;
|
|
99
|
-
scheduledTime?: number;
|
|
100
|
-
}, env: CloudflareEnv, ctx: {
|
|
101
|
-
waitUntil: (promise: Promise<unknown>) => void;
|
|
102
|
-
}): Promise<void>;
|
|
103
|
-
/**
|
|
104
|
-
* Run one entrypoint handler inside a fresh request scope, through the
|
|
105
|
-
* shared guard → interceptor pipeline (components declared with
|
|
106
|
-
* `@UseGuards`/`@UseInterceptors`/`@UseFilters` on the consumer class or
|
|
107
|
-
* method). HTTP-global components deliberately do NOT apply — an HTTP auth
|
|
108
|
-
* guard has no business rejecting a queue batch. Unclaimed errors rethrow
|
|
109
|
-
* so the platform's retry semantics stay intact.
|
|
110
|
-
*/
|
|
111
|
-
private dispatchEntrypoint;
|
|
112
|
-
/**
|
|
113
|
-
* Handle Cloudflare Queue consumer events.
|
|
114
|
-
* Matches the batch queue name to `@QueueConsumer()` handlers read from
|
|
115
|
-
* `app.entrypoints`; each batch is processed inside a fresh request-scoped
|
|
116
|
-
* child (request-scoped providers rebuild per batch — no boot-time captives).
|
|
117
|
-
*/
|
|
118
|
-
queue(batch: {
|
|
119
|
-
queue: string;
|
|
120
|
-
messages: unknown[];
|
|
121
|
-
}, env: CloudflareEnv, ctx: {
|
|
122
|
-
waitUntil: (promise: Promise<unknown>) => void;
|
|
123
|
-
}): Promise<void>;
|
|
124
|
-
close(signal?: string): Promise<void>;
|
|
125
|
-
}
|