stratal 0.0.23 → 0.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache/index.d.mts +1 -1
- package/dist/cache/index.mjs +2 -2
- package/dist/{command-CPhFHjG3.d.mts → command-4HnKnC-G.d.mts} +2 -2
- package/dist/{command-CPhFHjG3.d.mts.map → command-4HnKnC-G.d.mts.map} +1 -1
- package/dist/config/index.d.mts +1 -1
- package/dist/config/index.mjs +2 -2
- package/dist/{controller.decorator-C5UVeJS3.mjs → controller.decorator-DKeZ71aP.mjs} +3 -3
- package/dist/{controller.decorator-C5UVeJS3.mjs.map → controller.decorator-DKeZ71aP.mjs.map} +1 -1
- package/dist/cron/index.d.mts +1 -1
- package/dist/cron/index.mjs +1 -1
- package/dist/{cron.module-Bgzq5hiT.mjs → cron.module-DgxLe8Xy.mjs} +3 -3
- package/dist/{cron.module-Bgzq5hiT.mjs.map → cron.module-DgxLe8Xy.mjs.map} +1 -1
- package/dist/di/index.d.mts +1 -1
- package/dist/di/index.mjs +1 -1
- package/dist/{di-DseMn-z9.mjs → di-B0NXIdRF.mjs} +17 -1
- package/dist/di-B0NXIdRF.mjs.map +1 -0
- package/dist/email/index.d.mts +2 -2
- package/dist/email/index.mjs +3 -3
- package/dist/errors/index.d.mts +1 -1
- package/dist/errors/index.mjs +2 -2
- package/dist/{errors-mXYxG0XB.mjs → errors-EUtwVfNm.mjs} +3 -3
- package/dist/{errors-mXYxG0XB.mjs.map → errors-EUtwVfNm.mjs.map} +1 -1
- package/dist/events/index.d.mts +8 -0
- package/dist/events/index.d.mts.map +1 -1
- package/dist/events/index.mjs +1 -1
- package/dist/{events-BXJGZjpG.mjs → events-zbCMY_Gf.mjs} +5 -2
- package/dist/events-zbCMY_Gf.mjs.map +1 -0
- package/dist/{exception-context-kEoMFwze.mjs → exception-context-Bd5Hk2c_.mjs} +2 -2
- package/dist/{exception-context-kEoMFwze.mjs.map → exception-context-Bd5Hk2c_.mjs.map} +1 -1
- package/dist/{gateway-context-TMu_AlJt.mjs → gateway-context-I0tKgGfh.mjs} +4 -4
- package/dist/{gateway-context-TMu_AlJt.mjs.map → gateway-context-I0tKgGfh.mjs.map} +1 -1
- package/dist/guards/index.d.mts +1 -1
- package/dist/{hono-app-CvV3hOfT.mjs → hono-app-C7-1m9eK.mjs} +6 -6
- package/dist/{hono-app-CvV3hOfT.mjs.map → hono-app-C7-1m9eK.mjs.map} +1 -1
- package/dist/{http-method.decorator-ByWZb9DO.mjs → http-method.decorator-xCuGoZPC.mjs} +2 -2
- package/dist/{http-method.decorator-ByWZb9DO.mjs.map → http-method.decorator-xCuGoZPC.mjs.map} +1 -1
- package/dist/i18n/index.d.mts +1 -1
- package/dist/i18n/index.mjs +3 -3
- package/dist/{i18n.module-DRQAZoSZ.mjs → i18n.module-JOPUNpvi.mjs} +3 -3
- package/dist/{i18n.module-DRQAZoSZ.mjs.map → i18n.module-JOPUNpvi.mjs.map} +1 -1
- package/dist/{index-B5JBRcWD.d.mts → index-BPJSBHhq.d.mts} +2 -2
- package/dist/{index-B5JBRcWD.d.mts.map → index-BPJSBHhq.d.mts.map} +1 -1
- package/dist/{index-B_JoEl3V.d.mts → index-C_t8VVQD.d.mts} +12 -1
- package/dist/index-C_t8VVQD.d.mts.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/{lazy-module-loader-Ib383jH_.d.mts → lazy-module-loader-DZQxOgRZ.d.mts} +2 -2
- package/dist/{lazy-module-loader-Ib383jH_.d.mts.map → lazy-module-loader-DZQxOgRZ.d.mts.map} +1 -1
- package/dist/{locale-path.service-D-dHiIPc.mjs → locale-path.service-DzA01Kvc.mjs} +3 -3
- package/dist/{locale-path.service-D-dHiIPc.mjs.map → locale-path.service-DzA01Kvc.mjs.map} +1 -1
- package/dist/{locale-url.service-C2EWmGdq.mjs → locale-url.service-DwTXZid3.mjs} +2 -2
- package/dist/{locale-url.service-C2EWmGdq.mjs.map → locale-url.service-DwTXZid3.mjs.map} +1 -1
- package/dist/logger/index.mjs +1 -1
- package/dist/module/index.d.mts +2 -2
- package/dist/module/index.mjs +2 -2
- package/dist/{module-registry-Dm-pqHd3.mjs → module-registry-MfWmniZ7.mjs} +4 -4
- package/dist/{module-registry-Dm-pqHd3.mjs.map → module-registry-MfWmniZ7.mjs.map} +1 -1
- package/dist/openapi/index.d.mts +2 -2
- package/dist/openapi/index.mjs +1 -1
- package/dist/{openapi-CstuTM8S.mjs → openapi-BKDwQKh-.mjs} +3 -3
- package/dist/{openapi-CstuTM8S.mjs.map → openapi-BKDwQKh-.mjs.map} +1 -1
- package/dist/{openapi.service-YhTiJ1bO.d.mts → openapi.service-CM40bnBB.d.mts} +2 -2
- package/dist/{openapi.service-YhTiJ1bO.d.mts.map → openapi.service-CM40bnBB.d.mts.map} +1 -1
- package/dist/quarry/index.d.mts +3 -3
- package/dist/quarry/index.mjs +1 -1
- package/dist/quarry/runner.d.mts +6 -6
- package/dist/quarry/runner.mjs +5 -5
- package/dist/{quarry-registry-CXg0RFXq.d.mts → quarry-registry-CsStq0DB.d.mts} +3 -3
- package/dist/{quarry-registry-CXg0RFXq.d.mts.map → quarry-registry-CsStq0DB.d.mts.map} +1 -1
- package/dist/{quarry.module-BuRPGMDm.mjs → quarry.module-BOgcNJMU.mjs} +3 -3
- package/dist/{quarry.module-BuRPGMDm.mjs.map → quarry.module-BOgcNJMU.mjs.map} +1 -1
- package/dist/queue/index.d.mts +1 -1
- package/dist/queue/index.mjs +2 -2
- package/dist/{queue.module-nddvxzCB.mjs → queue.module-DSAH88gZ.mjs} +3 -3
- package/dist/{queue.module-nddvxzCB.mjs.map → queue.module-DSAH88gZ.mjs.map} +1 -1
- package/dist/{r2-storage.provider-DCxQt9dD.mjs → r2-storage.provider-BJ4j23W6.mjs} +2 -2
- package/dist/{r2-storage.provider-DCxQt9dD.mjs.map → r2-storage.provider-BJ4j23W6.mjs.map} +1 -1
- package/dist/{rate-limit.decorator-BPAie_p3.mjs → rate-limit.decorator-B35jBEVD.mjs} +2 -2
- package/dist/{rate-limit.decorator-BPAie_p3.mjs.map → rate-limit.decorator-B35jBEVD.mjs.map} +1 -1
- package/dist/rate-limiter/index.d.mts +1 -1
- package/dist/rate-limiter/index.mjs +3 -3
- package/dist/{route-registration.service-D6vSwiKP.mjs → route-registration.service-HN8WgIis.mjs} +9 -9
- package/dist/{route-registration.service-D6vSwiKP.mjs.map → route-registration.service-HN8WgIis.mjs.map} +1 -1
- package/dist/{route-registry-CYqLp2Nj.mjs → route-registry-CtW26Suv.mjs} +3 -3
- package/dist/{route-registry-CYqLp2Nj.mjs.map → route-registry-CtW26Suv.mjs.map} +1 -1
- package/dist/router/index.d.mts +1 -1
- package/dist/router/index.mjs +13 -13
- package/dist/{router-CWGBD-Bg.mjs → router-OCnf4VB6.mjs} +13 -13
- package/dist/{router-CWGBD-Bg.mjs.map → router-OCnf4VB6.mjs.map} +1 -1
- package/dist/{router-resolver-D4YlPNlm.mjs → router-resolver-CMNuw-s0.mjs} +2 -2
- package/dist/{router-resolver-D4YlPNlm.mjs.map → router-resolver-CMNuw-s0.mjs.map} +1 -1
- package/dist/seeder/index.d.mts +2 -2
- package/dist/seeder/index.mjs +3 -3
- package/dist/{seeder-7ubkms-Y.mjs → seeder-DI-rUoZx.mjs} +4 -4
- package/dist/{seeder-7ubkms-Y.mjs.map → seeder-DI-rUoZx.mjs.map} +1 -1
- package/dist/{seeder-registry-CyUmKsJq.mjs → seeder-registry-B5FwBeCU.mjs} +3 -3
- package/dist/{seeder-registry-CyUmKsJq.mjs.map → seeder-registry-B5FwBeCU.mjs.map} +1 -1
- package/dist/{seeder.module-CYYwk3Qk.mjs → seeder.module-DaY0RYoB.mjs} +2 -2
- package/dist/{seeder.module-CYYwk3Qk.mjs.map → seeder.module-DaY0RYoB.mjs.map} +1 -1
- package/dist/storage/index.d.mts +1 -1
- package/dist/storage/index.mjs +2 -2
- package/dist/storage/providers/index.mjs +1 -1
- package/dist/{storage-MDZypIE9.mjs → storage-BE6-kzaN.mjs} +7 -7
- package/dist/{storage-MDZypIE9.mjs.map → storage-BE6-kzaN.mjs.map} +1 -1
- package/dist/{storage.error-Dnib4VHc.mjs → storage.error-Dai3rShJ.mjs} +2 -2
- package/dist/{storage.error-Dnib4VHc.mjs.map → storage.error-Dai3rShJ.mjs.map} +1 -1
- package/dist/{stratal-DwDJPY9N.d.mts → stratal-Bmc6WT3k.d.mts} +2 -2
- package/dist/{stratal-DwDJPY9N.d.mts.map → stratal-Bmc6WT3k.d.mts.map} +1 -1
- package/dist/{stratal-DL9M38_s.mjs → stratal-DtAj21uF.mjs} +21 -20
- package/dist/stratal-DtAj21uF.mjs.map +1 -0
- package/dist/{uri-h7Q8Jug9.mjs → uri-h6ITRpqr.mjs} +3 -3
- package/dist/{uri-h7Q8Jug9.mjs.map → uri-h6ITRpqr.mjs.map} +1 -1
- package/dist/{versioning.service-C6aHky8-.mjs → versioning.service-B4rtmgMQ.mjs} +3 -3
- package/dist/{versioning.service-C6aHky8-.mjs.map → versioning.service-B4rtmgMQ.mjs.map} +1 -1
- package/dist/websocket/index.d.mts +1 -1
- package/dist/websocket/index.mjs +1 -1
- package/dist/workers/index.d.mts +1 -1
- package/dist/workers/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/di-DseMn-z9.mjs.map +0 -1
- package/dist/events-BXJGZjpG.mjs.map +0 -1
- package/dist/index-B_JoEl3V.d.mts.map +0 -1
- package/dist/stratal-DL9M38_s.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-zbCMY_Gf.mjs","names":[],"sources":["../src/events/constants.ts","../src/events/decorators/listener.decorator.ts","../src/events/decorators/on.decorator.ts","../src/events/event-registry.ts","../src/events/events.module.ts"],"sourcesContent":["/**\n * Metadata keys for event listener decorators.\n *\n * Uses `Symbol.for()` (global symbol registry) so that both core and\n * framework packages can reference the same symbols without cross-imports.\n */\nexport const LISTENER_METADATA_KEYS = {\n IS_LISTENER: Symbol.for('stratal:listener'),\n EVENT_HANDLERS: Symbol.for('stratal:listener:handlers'),\n} as const\n","import { Transient } from '../../di/decorators'\nimport { defineMetadata, getMetadata } from '../../di/metadata'\nimport type { Constructor } from '../../types'\nimport { LISTENER_METADATA_KEYS } from '../constants'\n\n/**\n * Mark a class as an event listener.\n *\n * Applies `@Transient()` for DI and sets metadata so the module system\n * can auto-discover and wire listener handlers at bootstrap time.\n *\n * @example\n * ```typescript\n * @Listener()\n * export class UserCreatedListener {\n * @On('after.User.create')\n * async sendWelcomeEmail(context: EventContext<'after.User.create'>) {\n * // ...\n * }\n * }\n * ```\n */\nexport function Listener() {\n return function <T extends Constructor>(target: T) {\n Transient()(target)\n defineMetadata(LISTENER_METADATA_KEYS.IS_LISTENER, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is decorated with `@Listener()`\n */\nexport function isListener(target: Constructor): boolean {\n return getMetadata(LISTENER_METADATA_KEYS.IS_LISTENER, target) === true\n}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { LISTENER_METADATA_KEYS } from '../constants'\nimport type { EventName, EventOptions, ListenerHandlerMetadata } from '../types'\n\n/**\n * Register a method as an event handler within a `@Listener()` class.\n *\n * Accumulates handler metadata on the class so the framework can\n * auto-wire handlers with the EventRegistry at bootstrap time.\n *\n * @param event - Event name to listen for (fully typed with autocomplete)\n * @param options - Optional handler options (priority, blocking)\n *\n * @example\n * ```typescript\n * @Listener()\n * export class AuditListener {\n * @On('after.User.create')\n * async logCreate(context: EventContext<'after.User.create'>) { ... }\n *\n * @On('after.User.delete', { priority: 10 })\n * async logDelete(context: EventContext<'after.User.delete'>) { ... }\n * }\n * ```\n */\nexport function On<E extends EventName>(event: E, options?: EventOptions) {\n return function (\n target: object,\n propertyKey: string,\n _descriptor: PropertyDescriptor\n ) {\n const existingHandlers: ListenerHandlerMetadata[] =\n getMetadata<ListenerHandlerMetadata[]>(LISTENER_METADATA_KEYS.EVENT_HANDLERS, target.constructor) ?? []\n\n existingHandlers.push({\n methodName: propertyKey,\n event: event as string,\n options,\n })\n\n defineMetadata(\n LISTENER_METADATA_KEYS.EVENT_HANDLERS,\n existingHandlers,\n target.constructor\n )\n }\n}\n\n/**\n * Get all `@On()` handler metadata from a listener class\n */\nexport function getListenerHandlers(target: object): ListenerHandlerMetadata[] {\n const metadataTarget = typeof target === 'function' ? target : target.constructor\n return getMetadata<ListenerHandlerMetadata[]>(LISTENER_METADATA_KEYS.EVENT_HANDLERS, metadataTarget) ?? []\n}\n","import { inject } from '../di'\nimport { Singleton } from '../di/decorators'\nimport { DI_TOKENS } from '../di/tokens'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport type {\n EventContext,\n EventHandler,\n EventName,\n EventOptions,\n IEventRegistry,\n RegisteredHandler\n} from './types'\n\n@Singleton(DI_TOKENS.EventRegistry)\nexport class EventRegistry implements IEventRegistry {\n private handlers = new Map<string, RegisteredHandler[]>()\n\n constructor(\n @inject(DI_TOKENS.ExecutionContext) private readonly ctx: ExecutionContext,\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService\n ) { }\n\n on<E extends EventName>(event: E, handler: EventHandler<E>, options?: EventOptions): void {\n const registered: RegisteredHandler = {\n handler: handler as EventHandler,\n priority: options?.priority ?? 0,\n blocking: options?.blocking\n }\n\n const existingHandlers = this.handlers.get(event) ?? []\n existingHandlers.push(registered)\n this.handlers.set(event, existingHandlers)\n\n this.logger.debug('Event handler registered', {\n event,\n priority: registered.priority,\n blocking: registered.blocking\n })\n }\n\n async emit<E extends EventName>(\n event: E,\n context?: Partial<EventContext<E>>\n ): Promise<void> {\n // Build full context with caller-provided fields\n const fullContext = {\n ...context\n } as EventContext<E>\n\n // Find matching handlers using pattern matching\n const matchingHandlers = this.findMatchingHandlers(event)\n\n if (matchingHandlers.length === 0) {\n return\n }\n\n // Sort by priority (higher first)\n const sortedHandlers = [...matchingHandlers].sort(\n (a, b) => b.priority - a.priority\n )\n\n // Determine if we should use waitUntil\n const shouldUseWaitUntil = this.shouldUseWaitUntil(event, sortedHandlers)\n\n // Execute handlers\n const promises = sortedHandlers.map((registered) =>\n this.executeHandler(registered.handler, fullContext, event)\n )\n\n if (shouldUseWaitUntil) {\n // Non-blocking: use ctx.waitUntil\n this.ctx.waitUntil(Promise.all(promises))\n } else {\n // Blocking: await all handlers\n await Promise.all(promises)\n }\n }\n\n off<E extends EventName>(event: E, handler: EventHandler<E>): void {\n const existingHandlers = this.handlers.get(event)\n if (!existingHandlers) return\n\n const filtered = existingHandlers.filter((h) => h.handler !== handler)\n if (filtered.length > 0) {\n this.handlers.set(event, filtered)\n } else {\n this.handlers.delete(event)\n }\n\n this.logger.debug('Event handler unregistered', { event })\n }\n\n hasListeners(event: EventName): boolean {\n return this.findMatchingHandlers(event).length > 0\n }\n\n once<E extends EventName>(event: E, handler: EventHandler<E>, options?: EventOptions): void {\n const wrappedHandler = (async (context: EventContext<E>) => {\n await handler(context)\n this.off(event, wrappedHandler)\n }) as EventHandler<E>\n\n this.on(event, wrappedHandler, options)\n }\n\n /**\n * Find all handlers matching the event using pattern matching.\n * Order: exact match -> model wildcard -> operation wildcard -> global wildcard\n */\n private findMatchingHandlers(event: string): RegisteredHandler[] {\n const handlers: RegisteredHandler[] = []\n\n const parts = event.split('.')\n\n if (parts.length === 3) {\n // Database event: \"phase.model.operation\"\n const [phase, model, operation] = parts\n\n // 1. Exact match: \"after.user.create\"\n handlers.push(...(this.handlers.get(event) ?? []))\n\n // 2. Model wildcard: \"after.user\"\n handlers.push(...(this.handlers.get(`${phase}.${model}`) ?? []))\n\n // 3. Operation wildcard: \"after.create\"\n handlers.push(...(this.handlers.get(`${phase}.${operation}`) ?? []))\n\n // 4. Global wildcard: \"after\"\n handlers.push(...(this.handlers.get(phase) ?? []))\n } else if (parts.length === 2) {\n // Could be wildcard like \"after.user\" or custom event like \"auth.verified\"\n handlers.push(...(this.handlers.get(event) ?? []))\n\n if (parts[0] === 'before' || parts[0] === 'after') {\n handlers.push(...(this.handlers.get(parts[0]) ?? []))\n }\n } else {\n handlers.push(...(this.handlers.get(event) ?? []))\n }\n\n return handlers\n }\n\n /**\n * Determine if we should use ctx.waitUntil (non-blocking) or await (blocking)\n */\n private shouldUseWaitUntil(\n event: string,\n handlers: RegisteredHandler[]\n ): boolean {\n const hasBlockingHandler = handlers.some((h) => h.blocking === true)\n if (hasBlockingHandler) return false\n\n const hasNonBlockingHandler = handlers.some((h) => h.blocking === false)\n if (hasNonBlockingHandler) return true\n\n const phase = event.split('.')[0]\n if (phase === 'before') return false\n if (phase === 'after') return true\n return false // Custom events block by default\n }\n\n /**\n * Execute a single handler with error isolation\n */\n private async executeHandler<E extends EventName>(\n handler: EventHandler,\n context: EventContext<E>,\n event: string\n ): Promise<void> {\n try {\n await handler(context as EventContext)\n } catch (error) {\n this.logger.error('Event handler error', {\n event,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n }\n }\n}\n","import { DI_TOKENS } from '../di/tokens'\nimport { Module } from '../module/module.decorator'\nimport { EventRegistry } from './event-registry'\n\n/**\n * Registers the event registry (`DI_TOKENS.EventRegistry`).\n *\n * Lazy: loaded on demand via `LazyModuleLoader` — by the framework's\n * `DatabaseModule` (which needs it to wire DB event emission) and by the\n * application's event-listener trigger paths. Kept out of cold start for apps\n * that neither emit events nor use the database.\n */\n@Module({\n providers: [\n { provide: DI_TOKENS.EventRegistry, useClass: EventRegistry },\n ],\n})\nexport class EventsModule { }\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as ContainerError, v as ROUTER_TOKENS } from "./di-
|
|
1
|
+
import { _ as ContainerError, v as ROUTER_TOKENS } from "./di-B0NXIdRF.mjs";
|
|
2
2
|
import { t as Macroable } from "./macroable-cvDTFZ_A.mjs";
|
|
3
3
|
import { deleteCookie, getCookie, setCookie } from "hono/cookie";
|
|
4
4
|
import { stream, streamSSE, streamText } from "hono/streaming";
|
|
@@ -426,4 +426,4 @@ function createCliExceptionContext(commandName) {
|
|
|
426
426
|
//#endregion
|
|
427
427
|
export { RouterContext as a, METHOD_STATUS_CODES as c, SECURITY_SCHEMES as d, VERSION_NEUTRAL as f, createQueueExceptionContext as i, ROUTER_CONTEXT_KEYS as l, createCronExceptionContext as n, DEFAULT_CONTENT_TYPE as o, createHttpExceptionContext as r, HTTP_METHODS as s, createCliExceptionContext as t, ROUTE_METADATA_KEYS as u };
|
|
428
428
|
|
|
429
|
-
//# sourceMappingURL=exception-context-
|
|
429
|
+
//# sourceMappingURL=exception-context-Bd5Hk2c_.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exception-context-kEoMFwze.mjs","names":["honoGetCookie","honoDeleteCookie","honoStream","honoStreamText","honoStreamSSE"],"sources":["../src/router/constants.ts","../src/router/router-context.ts","../src/errors/exception-context.ts"],"sourcesContent":["/**\n * Type-safe context keys for Hono router variables\n * Using symbols to avoid string collisions\n */\nexport const ROUTER_CONTEXT_KEYS = {\n REQUEST_CONTAINER: 'requestContainer',\n LOCALE: 'locale'\n} as const satisfies Record<string, string>\n\n/**\n * Metadata keys for storing route and controller configuration\n * Using symbols to avoid collisions with other decorators\n */\nexport const ROUTE_METADATA_KEYS = {\n CONTROLLER_ROUTE: Symbol.for('stratal:controller:route'),\n CONTROLLER_OPTIONS: Symbol.for('stratal:controller:options'),\n CONTROLLER_MIDDLEWARES: Symbol.for('stratal:controller:middlewares'),\n ROUTE_CONFIG: Symbol.for('stratal:route:config'),\n DECORATED_METHODS: Symbol.for('stratal:decorated:methods'),\n AUTH_GUARD: Symbol.for('stratal:auth:guard'),\n GATEWAY_MARKER: Symbol.for('stratal:gateway:marker'),\n WS_ON_MESSAGE: Symbol.for('stratal:ws:on-message'),\n WS_ON_CLOSE: Symbol.for('stratal:ws:on-close'),\n WS_ON_ERROR: Symbol.for('stratal:ws:on-error'),\n RATE_LIMIT: Symbol.for('stratal:route:rate-limit'),\n} as const\n\n/**\n * Security scheme identifiers for OpenAPI\n * These reference the security scheme definitions in security.schemas.ts\n */\nexport const SECURITY_SCHEMES = {\n BEARER_AUTH: 'bearerAuth',\n API_KEY: 'apiKey',\n SESSION_COOKIE: 'sessionCookie'\n} as const\n\n/**\n * HTTP method mapping for RESTful controller methods\n * Maps controller method names to HTTP verbs and path patterns\n */\nexport const HTTP_METHODS = {\n index: { method: 'get', path: '' } as const,\n show: { method: 'get', path: '/:id' } as const,\n create: { method: 'post', path: '' } as const,\n update: { method: 'put', path: '/:id' } as const,\n patch: { method: 'patch', path: '/:id' } as const,\n destroy: { method: 'delete', path: '/:id' } as const\n} as const\n\n/**\n * Default success status codes for RESTful controller methods\n * Used by @Route() decorator to auto-derive response status\n */\nexport const METHOD_STATUS_CODES = {\n index: 200,\n show: 200,\n create: 201,\n update: 200,\n patch: 200,\n destroy: 200\n} as const\n\n/**\n * Sentinel symbol to opt a controller out of versioning.\n * When used as the version, no prefix is applied even when defaultVersion is set.\n */\nexport const VERSION_NEUTRAL = Symbol.for('stratal:version:neutral')\n\n/**\n * Default content type for request bodies and responses\n */\nexport const DEFAULT_CONTENT_TYPE = 'application/json'\n","import type { Context } from 'hono'\nimport {\n deleteCookie as honoDeleteCookie,\n getCookie as honoGetCookie,\n setCookie as honoSetCookie,\n} from 'hono/cookie'\nimport type { SSEStreamingApi } from 'hono/streaming'\nimport { stream as honoStream, streamSSE as honoStreamSSE, streamText as honoStreamText } from 'hono/streaming'\nimport type { CookieOptions } from 'hono/utils/cookie'\nimport type { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status'\nimport type { StreamingApi } from 'hono/utils/stream'\nimport type { Container } from '../di/container'\nimport { ContainerError } from '../di/container.error'\nimport { Macroable } from '../macroable'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport type { RouteName, RouteParams } from './route-map'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { RouterEnv } from './types'\nimport type { SignedUriOptions, Uri, UriOptions } from './uri'\n\nexport type ContextQueryResult<R extends Record<string, unknown> | undefined, K extends string | undefined> = K extends string ? string : R extends undefined ? Record<string, unknown> : R\n\n/**\n * Router context wrapper with helper methods\n *\n * Provides convenient access to Hono's context and common request/response operations.\n * The native Hono context is available via the `c` property for advanced use cases.\n *\n * @example\n * ```typescript\n * async index(ctx: RouterContext): Promise<Response> {\n * // Use helper methods\n * const users = await this.service.findAll()\n * return ctx.json(users)\n * }\n *\n * async show(ctx: RouterContext): Promise<Response> {\n * // Access route params\n * const id = ctx.param('id')\n * const user = await this.service.findById(id)\n * return ctx.json(user)\n * }\n *\n * async create(ctx: RouterContext): Promise<Response> {\n * // Parse request body\n * const body = await ctx.body<CreateUserInput>()\n * const user = await this.service.create(body)\n * return ctx.json(user, 201)\n * }\n * ```\n */\nexport class RouterContext<T extends RouterEnv = RouterEnv> extends Macroable {\n /**\n * Native Hono context\n * Access for advanced use cases not covered by helper methods\n */\n constructor(\n public readonly c: Context<T>\n ) {\n super()\n }\n\n /**\n * Cloudflare-provided request properties (geo, TLS, bot management, etc.).\n * Always available on Cloudflare Workers requests via `c.req.raw.cf`.\n */\n get cf(): CfProperties {\n return this.c.req.raw.cf!\n }\n\n /**\n * Get request-scoped DI container\n * Contains request-specific services and context (AuthContext)\n *\n * @throws Error if container not initialized\n */\n getContainer(): Container {\n const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n if (!container) {\n throw new ContainerError('Request container has not been initialized')\n }\n return container as Container\n }\n\n /**\n * Set locale for the current request\n *\n * @param locale - Locale code (e.g., 'en', 'fr')\n */\n setLocale(locale: string): void {\n this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale)\n }\n\n /**\n * Get locale for the current request\n *\n * @returns Current locale code\n */\n getLocale(): string {\n const locale = this.c.get(ROUTER_CONTEXT_KEYS.LOCALE)\n return (locale as string) || 'en'\n }\n\n /**\n * Return JSON response\n *\n * When data is null, automatically returns 204 No Content (configurable via status param).\n *\n * @param data - Data to serialize as JSON, or null for 204\n * @param status - HTTP status code (default: 200, or 204 when data is null)\n */\n json(data: object | null, status?: ContentfulStatusCode): Response {\n if (data === null) {\n return this.c.body(null, status ?? 204)\n }\n return this.c.json(data, status)\n }\n\n /**\n * Get route parameter value(s).\n *\n * Reads the validated, Zod-coerced param record from `c.req.valid('param')`,\n * which is what `@hono/zod-openapi` populates for every route registered\n * via `app.openapi(...)`. Bare `c.req.param()` returns `undefined` for those\n * routes — always go through the validated record.\n *\n * - With a key → returns the single string value.\n * - With no args → returns the full `Record<string, string>` (or `{}` when\n * the matched route has no path params).\n *\n * @param key - Parameter name (e.g., 'id' for /users/:id)\n */\n param(): Record<string, string>\n param(key: string): string\n param(key?: string): string | Record<string, string> {\n const all = (this.c.req as unknown as { valid(target: 'param'): Record<string, string> | undefined }).valid('param') ?? {}\n return key === undefined ? all : all[key]\n }\n\n /**\n * Get query parameter value\n *\n * @param key - Query parameter name\n */\n query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n const validated = (this.c.req as unknown as { valid(target: 'query'): Record<string, unknown> }).valid('query')\n return key ? validated[key] as ContextQueryResult<R, K> : validated as ContextQueryResult<R, K>\n }\n\n /**\n * Get request header value\n *\n * @param name - Header name (case-insensitive)\n */\n header(name: string): string | undefined {\n return this.c.req.header(name)\n }\n\n /**\n * Read a cookie value from the current request.\n *\n * @param name - Cookie name\n * @returns The cookie value, or `undefined` if the cookie is not present\n *\n * @example\n * ```typescript\n * const redirectTo = ctx.getCookie('redirectTo')\n * ```\n */\n getCookie(name: string): string | undefined {\n return honoGetCookie(this.c, name)\n }\n\n /**\n * Set a cookie on the response.\n *\n * Cookie operations must run while the response is mutable — call this\n * before returning the final `Response` from the handler.\n *\n * @param name - Cookie name\n * @param value - Cookie value\n * @param options - Cookie attributes (httpOnly, secure, sameSite, path, etc.)\n *\n * @example\n * ```typescript\n * ctx.setCookie('redirectTo', '/app/', {\n * httpOnly: true,\n * secure: true,\n * sameSite: 'lax',\n * path: '/',\n * })\n * ```\n */\n setCookie(name: string, value: string, options?: CookieOptions): void {\n honoSetCookie(this.c, name, value, options)\n }\n\n /**\n * Delete a cookie from the response.\n *\n * Pass the same `path` and `domain` options that were used when the cookie\n * was set, otherwise the browser will not clear the matching cookie.\n *\n * @param name - Cookie name\n * @param options - Cookie attributes used at set time (path, domain, etc.)\n * @returns The deleted cookie's previous value, or `undefined`\n *\n * @example\n * ```typescript\n * ctx.deleteCookie('redirectTo', { path: '/' })\n * ```\n */\n deleteCookie(name: string, options?: CookieOptions): string | undefined {\n return honoDeleteCookie(this.c, name, options)\n }\n\n /**\n * Get validated request body from OpenAPI route\n * Returns pre-validated data that has passed schema validation\n *\n * @returns Validated JSON body\n */\n body<T>(): Promise<T> {\n // Type assertion needed because req.valid() is type-safe per route\n // but this is a generic helper method that works across all routes\n return (this.c.req as unknown as { valid(target: 'json'): Promise<T> }).valid('json')\n }\n\n /**\n * Return text response\n *\n * @param text - Text content\n * @param status - HTTP status code (default: 200)\n */\n text(text: string, status?: ContentfulStatusCode): Response {\n return this.c.text(text, status)\n }\n\n /**\n * Return HTML response\n *\n * @param html - HTML content\n * @param status - HTTP status code (default: 200)\n */\n html(html: string, status?: ContentfulStatusCode): Response {\n return this.c.html(html, status)\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params are consumed from the same object.\n * Extra keys become query string parameters.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options (e.g., `{ absolute: true }`)\n *\n * @example\n * ```typescript\n * ctx.route('users.show', { id: '1' }) // '/v1/users/1'\n * ctx.route('users.show', { id: '1', q: 'test' }) // '/v1/users/1?q=test'\n * ```\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n return this.resolveUri().route(name, params, options)\n }\n\n /**\n * Get a domain parameter value from the current request.\n * Domain params are set by the domain matching middleware.\n *\n * @param key - Domain parameter name (e.g., 'tenant' from '{tenant}.myapp.com')\n *\n * @example\n * ```typescript\n * const tenant = ctx.domain('tenant')\n * ```\n */\n domain(key: string): string {\n return this.c.get(`domain:${key}`) as string\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params (same as route())\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n */\n async signedUrl<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n return this.resolveUri().signedRoute(name, params, options)\n }\n\n /**\n * Check if the current request has a valid signature.\n *\n * @returns true if the URL signature is valid and not expired\n */\n async hasValidSignature(): Promise<boolean> {\n return this.resolveUri().hasValidSignature()\n }\n\n /**\n * Redirect to another URL\n *\n * @param url - Target URL\n * @param status - HTTP status code (default: 302)\n */\n redirect(url: string, status?: RedirectStatusCode): Response {\n return this.c.redirect(url, status)\n }\n\n /**\n * Return a streaming response (binary/generic)\n *\n * @param callback - Async function that writes to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n stream(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n return honoStream(this.c, callback, onError)\n }\n\n /**\n * Return a streaming text response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes text to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamText(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamText(this.c, callback, onError)\n }\n\n /**\n * Return a Server-Sent Events (SSE) streaming response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes SSE events to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamSSE(callback: (stream: SSEStreamingApi) => Promise<void>, onError?: (err: Error, stream: SSEStreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamSSE(this.c, callback, onError)\n }\n\n private resolveUri(): Uri {\n return this.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n }\n}\n","import type { Context } from 'hono'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\n\n/**\n * Exception context for errors occurring during HTTP request handling.\n *\n * Provides access to the full {@link RouterContext} for building responses\n * with `ctx.json()`, `ctx.text()`, `ctx.html()`, etc.\n */\nexport interface HttpExceptionContext {\n readonly type: 'http'\n /** Stratal RouterContext — use for building HTTP responses */\n readonly ctx: RouterContext\n}\n\n/**\n * Exception context for errors occurring during queue message processing.\n */\nexport interface QueueExceptionContext {\n readonly type: 'queue'\n /** Name of the queue being processed */\n readonly queueName: string\n}\n\n/**\n * Exception context for errors occurring during scheduled cron execution.\n */\nexport interface CronExceptionContext {\n readonly type: 'cron'\n}\n\n/**\n * Exception context for errors occurring during CLI command execution.\n */\nexport interface CliExceptionContext {\n readonly type: 'cli'\n /** Name of the command that threw */\n readonly commandName: string\n}\n\n/**\n * Discriminated union of all exception context types.\n *\n * Narrow via `ctx.type` to access context-specific properties:\n *\n * @example\n * ```typescript\n * handler.renderable(MyError, (error, ctx) => {\n * if (ctx.type === 'http') {\n * return ctx.ctx.json({ message: 'Something went wrong' }, 500)\n * }\n * // Non-HTTP contexts: return undefined to use default rendering\n * })\n * ```\n */\nexport type ExceptionContext =\n | HttpExceptionContext\n | QueueExceptionContext\n | CronExceptionContext\n | CliExceptionContext\n\n/**\n * Create an HTTP exception context from a Hono context.\n *\n * @param c - The raw Hono context from the request\n * @returns An {@link HttpExceptionContext} wrapping a RouterContext\n */\nexport function createHttpExceptionContext(c: Context<RouterEnv>): HttpExceptionContext {\n return { type: 'http', ctx: new RouterContext(c) }\n}\n\n/**\n * Create a queue exception context.\n *\n * @param queueName - The name of the queue being processed\n * @returns A {@link QueueExceptionContext}\n */\nexport function createQueueExceptionContext(queueName: string): QueueExceptionContext {\n return { type: 'queue', queueName }\n}\n\n/**\n * Create a cron exception context.\n *\n * @returns A {@link CronExceptionContext}\n */\nexport function createCronExceptionContext(): CronExceptionContext {\n return { type: 'cron' }\n}\n\n/**\n * Create a CLI command exception context.\n *\n * @param commandName - The name of the command that threw\n * @returns A {@link CliExceptionContext}\n */\nexport function createCliExceptionContext(commandName: string): CliExceptionContext {\n return { type: 'cli', commandName }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"exception-context-Bd5Hk2c_.mjs","names":["honoGetCookie","honoDeleteCookie","honoStream","honoStreamText","honoStreamSSE"],"sources":["../src/router/constants.ts","../src/router/router-context.ts","../src/errors/exception-context.ts"],"sourcesContent":["/**\n * Type-safe context keys for Hono router variables\n * Using symbols to avoid string collisions\n */\nexport const ROUTER_CONTEXT_KEYS = {\n REQUEST_CONTAINER: 'requestContainer',\n LOCALE: 'locale'\n} as const satisfies Record<string, string>\n\n/**\n * Metadata keys for storing route and controller configuration\n * Using symbols to avoid collisions with other decorators\n */\nexport const ROUTE_METADATA_KEYS = {\n CONTROLLER_ROUTE: Symbol.for('stratal:controller:route'),\n CONTROLLER_OPTIONS: Symbol.for('stratal:controller:options'),\n CONTROLLER_MIDDLEWARES: Symbol.for('stratal:controller:middlewares'),\n ROUTE_CONFIG: Symbol.for('stratal:route:config'),\n DECORATED_METHODS: Symbol.for('stratal:decorated:methods'),\n AUTH_GUARD: Symbol.for('stratal:auth:guard'),\n GATEWAY_MARKER: Symbol.for('stratal:gateway:marker'),\n WS_ON_MESSAGE: Symbol.for('stratal:ws:on-message'),\n WS_ON_CLOSE: Symbol.for('stratal:ws:on-close'),\n WS_ON_ERROR: Symbol.for('stratal:ws:on-error'),\n RATE_LIMIT: Symbol.for('stratal:route:rate-limit'),\n} as const\n\n/**\n * Security scheme identifiers for OpenAPI\n * These reference the security scheme definitions in security.schemas.ts\n */\nexport const SECURITY_SCHEMES = {\n BEARER_AUTH: 'bearerAuth',\n API_KEY: 'apiKey',\n SESSION_COOKIE: 'sessionCookie'\n} as const\n\n/**\n * HTTP method mapping for RESTful controller methods\n * Maps controller method names to HTTP verbs and path patterns\n */\nexport const HTTP_METHODS = {\n index: { method: 'get', path: '' } as const,\n show: { method: 'get', path: '/:id' } as const,\n create: { method: 'post', path: '' } as const,\n update: { method: 'put', path: '/:id' } as const,\n patch: { method: 'patch', path: '/:id' } as const,\n destroy: { method: 'delete', path: '/:id' } as const\n} as const\n\n/**\n * Default success status codes for RESTful controller methods\n * Used by @Route() decorator to auto-derive response status\n */\nexport const METHOD_STATUS_CODES = {\n index: 200,\n show: 200,\n create: 201,\n update: 200,\n patch: 200,\n destroy: 200\n} as const\n\n/**\n * Sentinel symbol to opt a controller out of versioning.\n * When used as the version, no prefix is applied even when defaultVersion is set.\n */\nexport const VERSION_NEUTRAL = Symbol.for('stratal:version:neutral')\n\n/**\n * Default content type for request bodies and responses\n */\nexport const DEFAULT_CONTENT_TYPE = 'application/json'\n","import type { Context } from 'hono'\nimport {\n deleteCookie as honoDeleteCookie,\n getCookie as honoGetCookie,\n setCookie as honoSetCookie,\n} from 'hono/cookie'\nimport type { SSEStreamingApi } from 'hono/streaming'\nimport { stream as honoStream, streamSSE as honoStreamSSE, streamText as honoStreamText } from 'hono/streaming'\nimport type { CookieOptions } from 'hono/utils/cookie'\nimport type { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status'\nimport type { StreamingApi } from 'hono/utils/stream'\nimport type { Container } from '../di/container'\nimport { ContainerError } from '../di/container.error'\nimport { Macroable } from '../macroable'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport type { RouteName, RouteParams } from './route-map'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { RouterEnv } from './types'\nimport type { SignedUriOptions, Uri, UriOptions } from './uri'\n\nexport type ContextQueryResult<R extends Record<string, unknown> | undefined, K extends string | undefined> = K extends string ? string : R extends undefined ? Record<string, unknown> : R\n\n/**\n * Router context wrapper with helper methods\n *\n * Provides convenient access to Hono's context and common request/response operations.\n * The native Hono context is available via the `c` property for advanced use cases.\n *\n * @example\n * ```typescript\n * async index(ctx: RouterContext): Promise<Response> {\n * // Use helper methods\n * const users = await this.service.findAll()\n * return ctx.json(users)\n * }\n *\n * async show(ctx: RouterContext): Promise<Response> {\n * // Access route params\n * const id = ctx.param('id')\n * const user = await this.service.findById(id)\n * return ctx.json(user)\n * }\n *\n * async create(ctx: RouterContext): Promise<Response> {\n * // Parse request body\n * const body = await ctx.body<CreateUserInput>()\n * const user = await this.service.create(body)\n * return ctx.json(user, 201)\n * }\n * ```\n */\nexport class RouterContext<T extends RouterEnv = RouterEnv> extends Macroable {\n /**\n * Native Hono context\n * Access for advanced use cases not covered by helper methods\n */\n constructor(\n public readonly c: Context<T>\n ) {\n super()\n }\n\n /**\n * Cloudflare-provided request properties (geo, TLS, bot management, etc.).\n * Always available on Cloudflare Workers requests via `c.req.raw.cf`.\n */\n get cf(): CfProperties {\n return this.c.req.raw.cf!\n }\n\n /**\n * Get request-scoped DI container\n * Contains request-specific services and context (AuthContext)\n *\n * @throws Error if container not initialized\n */\n getContainer(): Container {\n const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n if (!container) {\n throw new ContainerError('Request container has not been initialized')\n }\n return container as Container\n }\n\n /**\n * Set locale for the current request\n *\n * @param locale - Locale code (e.g., 'en', 'fr')\n */\n setLocale(locale: string): void {\n this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale)\n }\n\n /**\n * Get locale for the current request\n *\n * @returns Current locale code\n */\n getLocale(): string {\n const locale = this.c.get(ROUTER_CONTEXT_KEYS.LOCALE)\n return (locale as string) || 'en'\n }\n\n /**\n * Return JSON response\n *\n * When data is null, automatically returns 204 No Content (configurable via status param).\n *\n * @param data - Data to serialize as JSON, or null for 204\n * @param status - HTTP status code (default: 200, or 204 when data is null)\n */\n json(data: object | null, status?: ContentfulStatusCode): Response {\n if (data === null) {\n return this.c.body(null, status ?? 204)\n }\n return this.c.json(data, status)\n }\n\n /**\n * Get route parameter value(s).\n *\n * Reads the validated, Zod-coerced param record from `c.req.valid('param')`,\n * which is what `@hono/zod-openapi` populates for every route registered\n * via `app.openapi(...)`. Bare `c.req.param()` returns `undefined` for those\n * routes — always go through the validated record.\n *\n * - With a key → returns the single string value.\n * - With no args → returns the full `Record<string, string>` (or `{}` when\n * the matched route has no path params).\n *\n * @param key - Parameter name (e.g., 'id' for /users/:id)\n */\n param(): Record<string, string>\n param(key: string): string\n param(key?: string): string | Record<string, string> {\n const all = (this.c.req as unknown as { valid(target: 'param'): Record<string, string> | undefined }).valid('param') ?? {}\n return key === undefined ? all : all[key]\n }\n\n /**\n * Get query parameter value\n *\n * @param key - Query parameter name\n */\n query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n const validated = (this.c.req as unknown as { valid(target: 'query'): Record<string, unknown> }).valid('query')\n return key ? validated[key] as ContextQueryResult<R, K> : validated as ContextQueryResult<R, K>\n }\n\n /**\n * Get request header value\n *\n * @param name - Header name (case-insensitive)\n */\n header(name: string): string | undefined {\n return this.c.req.header(name)\n }\n\n /**\n * Read a cookie value from the current request.\n *\n * @param name - Cookie name\n * @returns The cookie value, or `undefined` if the cookie is not present\n *\n * @example\n * ```typescript\n * const redirectTo = ctx.getCookie('redirectTo')\n * ```\n */\n getCookie(name: string): string | undefined {\n return honoGetCookie(this.c, name)\n }\n\n /**\n * Set a cookie on the response.\n *\n * Cookie operations must run while the response is mutable — call this\n * before returning the final `Response` from the handler.\n *\n * @param name - Cookie name\n * @param value - Cookie value\n * @param options - Cookie attributes (httpOnly, secure, sameSite, path, etc.)\n *\n * @example\n * ```typescript\n * ctx.setCookie('redirectTo', '/app/', {\n * httpOnly: true,\n * secure: true,\n * sameSite: 'lax',\n * path: '/',\n * })\n * ```\n */\n setCookie(name: string, value: string, options?: CookieOptions): void {\n honoSetCookie(this.c, name, value, options)\n }\n\n /**\n * Delete a cookie from the response.\n *\n * Pass the same `path` and `domain` options that were used when the cookie\n * was set, otherwise the browser will not clear the matching cookie.\n *\n * @param name - Cookie name\n * @param options - Cookie attributes used at set time (path, domain, etc.)\n * @returns The deleted cookie's previous value, or `undefined`\n *\n * @example\n * ```typescript\n * ctx.deleteCookie('redirectTo', { path: '/' })\n * ```\n */\n deleteCookie(name: string, options?: CookieOptions): string | undefined {\n return honoDeleteCookie(this.c, name, options)\n }\n\n /**\n * Get validated request body from OpenAPI route\n * Returns pre-validated data that has passed schema validation\n *\n * @returns Validated JSON body\n */\n body<T>(): Promise<T> {\n // Type assertion needed because req.valid() is type-safe per route\n // but this is a generic helper method that works across all routes\n return (this.c.req as unknown as { valid(target: 'json'): Promise<T> }).valid('json')\n }\n\n /**\n * Return text response\n *\n * @param text - Text content\n * @param status - HTTP status code (default: 200)\n */\n text(text: string, status?: ContentfulStatusCode): Response {\n return this.c.text(text, status)\n }\n\n /**\n * Return HTML response\n *\n * @param html - HTML content\n * @param status - HTTP status code (default: 200)\n */\n html(html: string, status?: ContentfulStatusCode): Response {\n return this.c.html(html, status)\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params are consumed from the same object.\n * Extra keys become query string parameters.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options (e.g., `{ absolute: true }`)\n *\n * @example\n * ```typescript\n * ctx.route('users.show', { id: '1' }) // '/v1/users/1'\n * ctx.route('users.show', { id: '1', q: 'test' }) // '/v1/users/1?q=test'\n * ```\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n return this.resolveUri().route(name, params, options)\n }\n\n /**\n * Get a domain parameter value from the current request.\n * Domain params are set by the domain matching middleware.\n *\n * @param key - Domain parameter name (e.g., 'tenant' from '{tenant}.myapp.com')\n *\n * @example\n * ```typescript\n * const tenant = ctx.domain('tenant')\n * ```\n */\n domain(key: string): string {\n return this.c.get(`domain:${key}`) as string\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params (same as route())\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n */\n async signedUrl<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n return this.resolveUri().signedRoute(name, params, options)\n }\n\n /**\n * Check if the current request has a valid signature.\n *\n * @returns true if the URL signature is valid and not expired\n */\n async hasValidSignature(): Promise<boolean> {\n return this.resolveUri().hasValidSignature()\n }\n\n /**\n * Redirect to another URL\n *\n * @param url - Target URL\n * @param status - HTTP status code (default: 302)\n */\n redirect(url: string, status?: RedirectStatusCode): Response {\n return this.c.redirect(url, status)\n }\n\n /**\n * Return a streaming response (binary/generic)\n *\n * @param callback - Async function that writes to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n stream(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n return honoStream(this.c, callback, onError)\n }\n\n /**\n * Return a streaming text response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes text to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamText(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamText(this.c, callback, onError)\n }\n\n /**\n * Return a Server-Sent Events (SSE) streaming response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes SSE events to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamSSE(callback: (stream: SSEStreamingApi) => Promise<void>, onError?: (err: Error, stream: SSEStreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamSSE(this.c, callback, onError)\n }\n\n private resolveUri(): Uri {\n return this.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n }\n}\n","import type { Context } from 'hono'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\n\n/**\n * Exception context for errors occurring during HTTP request handling.\n *\n * Provides access to the full {@link RouterContext} for building responses\n * with `ctx.json()`, `ctx.text()`, `ctx.html()`, etc.\n */\nexport interface HttpExceptionContext {\n readonly type: 'http'\n /** Stratal RouterContext — use for building HTTP responses */\n readonly ctx: RouterContext\n}\n\n/**\n * Exception context for errors occurring during queue message processing.\n */\nexport interface QueueExceptionContext {\n readonly type: 'queue'\n /** Name of the queue being processed */\n readonly queueName: string\n}\n\n/**\n * Exception context for errors occurring during scheduled cron execution.\n */\nexport interface CronExceptionContext {\n readonly type: 'cron'\n}\n\n/**\n * Exception context for errors occurring during CLI command execution.\n */\nexport interface CliExceptionContext {\n readonly type: 'cli'\n /** Name of the command that threw */\n readonly commandName: string\n}\n\n/**\n * Discriminated union of all exception context types.\n *\n * Narrow via `ctx.type` to access context-specific properties:\n *\n * @example\n * ```typescript\n * handler.renderable(MyError, (error, ctx) => {\n * if (ctx.type === 'http') {\n * return ctx.ctx.json({ message: 'Something went wrong' }, 500)\n * }\n * // Non-HTTP contexts: return undefined to use default rendering\n * })\n * ```\n */\nexport type ExceptionContext =\n | HttpExceptionContext\n | QueueExceptionContext\n | CronExceptionContext\n | CliExceptionContext\n\n/**\n * Create an HTTP exception context from a Hono context.\n *\n * @param c - The raw Hono context from the request\n * @returns An {@link HttpExceptionContext} wrapping a RouterContext\n */\nexport function createHttpExceptionContext(c: Context<RouterEnv>): HttpExceptionContext {\n return { type: 'http', ctx: new RouterContext(c) }\n}\n\n/**\n * Create a queue exception context.\n *\n * @param queueName - The name of the queue being processed\n * @returns A {@link QueueExceptionContext}\n */\nexport function createQueueExceptionContext(queueName: string): QueueExceptionContext {\n return { type: 'queue', queueName }\n}\n\n/**\n * Create a cron exception context.\n *\n * @returns A {@link CronExceptionContext}\n */\nexport function createCronExceptionContext(): CronExceptionContext {\n return { type: 'cron' }\n}\n\n/**\n * Create a CLI command exception context.\n *\n * @param commandName - The name of the command that threw\n * @returns A {@link CliExceptionContext}\n */\nexport function createCliExceptionContext(commandName: string): CliExceptionContext {\n return { type: 'cli', commandName }\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as ApplicationError } from "./container-storage-BmOJ4_Na.mjs";
|
|
2
2
|
import { n as getMetadata, t as defineMetadata } from "./metadata-DzzprcID.mjs";
|
|
3
3
|
import { LOGGER_TOKENS } from "./logger/index.mjs";
|
|
4
|
-
import "./errors-
|
|
5
|
-
import { a as RouterContext, u as ROUTE_METADATA_KEYS } from "./exception-context-
|
|
6
|
-
import { t as Controller } from "./controller.decorator-
|
|
4
|
+
import "./errors-EUtwVfNm.mjs";
|
|
5
|
+
import { a as RouterContext, u as ROUTE_METADATA_KEYS } from "./exception-context-Bd5Hk2c_.mjs";
|
|
6
|
+
import { t as Controller } from "./controller.decorator-DKeZ71aP.mjs";
|
|
7
7
|
//#region src/websocket/decorators/gateway.decorator.ts
|
|
8
8
|
const GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER;
|
|
9
9
|
/**
|
|
@@ -222,4 +222,4 @@ var GatewayContext = class extends RouterContext {
|
|
|
222
222
|
//#endregion
|
|
223
223
|
export { getWsOnCloseMethod as a, WebSocketError as c, OnMessage as i, Gateway as l, OnClose as n, getWsOnErrorMethod as o, OnError as r, getWsOnMessageMethod as s, GatewayContext as t, isGateway as u };
|
|
224
224
|
|
|
225
|
-
//# sourceMappingURL=gateway-context-
|
|
225
|
+
//# sourceMappingURL=gateway-context-I0tKgGfh.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-context-TMu_AlJt.mjs","names":[],"sources":["../src/websocket/decorators/gateway.decorator.ts","../src/websocket/websocket.error.ts","../src/websocket/decorators/ws-event.decorator.ts","../src/websocket/gateway-context.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport { Controller } from '../../router/decorators/controller.decorator'\nimport { type Constructor } from '../../types'\nimport type { GatewayOptions } from '../../websocket/types'\n\nconst GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER\n\n/**\n * Gateway decorator for WebSocket route registration\n *\n * Marks a class as a WebSocket gateway and stores route metadata.\n * Reuses the same metadata key as @Controller for middleware compatibility —\n * `getControllerRoute()`, `forRoutes()`, and the entire middleware system work\n * with zero changes.\n *\n * @param route - WebSocket route path (e.g., '/ws/chat')\n *\n * @example\n * ```typescript\n * import { type GatewayContext, Gateway, OnMessage, OnClose } from 'stratal/websocket'\n *\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack')\n * }\n *\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function Gateway(route: string, options?: GatewayOptions) {\n return function <T extends Constructor>(target: T) {\n Controller(route, options)(target)\n defineMetadata(GATEWAY_MARKER_KEY, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is a WebSocket gateway\n *\n * @param target - Class constructor or instance\n * @returns true if the class is decorated with @Gateway\n */\nexport function isGateway(target: object): boolean {\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return getMetadata(GATEWAY_MARKER_KEY, metadataTarget) === true\n}\n","import { ApplicationError } from '../errors'\n\nexport class WebSocketError extends ApplicationError {}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport type { Constructor } from '../../types'\nimport { WebSocketError } from '../websocket.error'\n\nconst WS_ON_MESSAGE_KEY = ROUTE_METADATA_KEYS.WS_ON_MESSAGE\nconst WS_ON_CLOSE_KEY = ROUTE_METADATA_KEYS.WS_ON_CLOSE\nconst WS_ON_ERROR_KEY = ROUTE_METADATA_KEYS.WS_ON_ERROR\n\n/**\n * Define a single-handler metadata key on the prototype.\n * Throws if a different method already owns this key (prevents silent override).\n */\nfunction defineSingleHandlerMetadata(key: symbol, propertyKey: string | symbol, target: object, decoratorName: string): void {\n const existing = getMetadata<string | symbol>(key, target)\n if (existing !== undefined && existing !== propertyKey) {\n throw new WebSocketError(`Duplicate @${decoratorName} handler: method \"${String(existing)}\" is already registered`)\n }\n defineMetadata(key, propertyKey, target)\n}\n\n/**\n * Marks a method as the WebSocket message handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send(evt.data)\n * }\n * }\n * ```\n */\nexport function OnMessage(): MethodDecorator {\n // `_target` is the class prototype (method decorator convention).\n // The getter functions below read from `target.prototype` symmetrically.\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_MESSAGE_KEY, propertyKey, _target, 'OnMessage')\n }\n}\n\n/**\n * Marks a method as the WebSocket close handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function OnClose(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_CLOSE_KEY, propertyKey, _target, 'OnClose')\n }\n}\n\n/**\n * Marks a method as the WebSocket error handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnError()\n * handleError(evt: Event, ctx: GatewayContext) {\n * console.error('WebSocket error', evt)\n * }\n * }\n * ```\n */\nexport function OnError(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_ERROR_KEY, propertyKey, _target, 'OnError')\n }\n}\n\n/**\n * Get the method name decorated with @OnMessage\n */\nexport function getWsOnMessageMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_MESSAGE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnClose\n */\nexport function getWsOnCloseMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_CLOSE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnError\n */\nexport function getWsOnErrorMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_ERROR_KEY, target.prototype as object)\n}\n","import type { Context } from 'hono'\nimport type { WSContext, WSReadyState } from 'hono/ws'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport type { ContextQueryResult } from '../router/router-context'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\nimport { WebSocketError } from './websocket.error'\n\n/** WebSocket OPEN ready state (`WSReadyState` is a type-only union in hono/ws). */\nconst WS_OPEN = 1\n\n/**\n * WebSocket gateway context\n *\n * Extends RouterContext with WebSocket-specific methods.\n * Inherits `getContainer()`, `param()`, `query()`, `header()`, `getLocale()`\n * from RouterContext. HTTP response methods (`json()`, `redirect()`, etc.) are\n * inherited but harmless post-upgrade.\n *\n * @example\n * ```typescript\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack') // convenience method\n * ctx.header('Authorization') // upgrade request headers\n * }\n * ```\n */\nexport class GatewayContext extends RouterContext {\n constructor(c: Context<RouterEnv>, public readonly ws: WSContext) {\n super(c)\n }\n\n /** Send data through the WebSocket connection */\n send(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): void {\n this.ws.send(data)\n }\n\n /**\n * Send only if the socket is still open. Returns `false` (and logs a warning)\n * when the socket is closing/closed — e.g. inside `@OnError`, which fires on a\n * transport error after the socket is already dead, or after an `await` in\n * `@OnMessage` when the client disconnected mid-handler. Use this for\n * fire-and-forget acks/errors instead of `send()`, which throws on a closed\n * socket (\"Can't call WebSocket send() after close()\").\n */\n trySend(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): boolean {\n if (this.ws.readyState !== WS_OPEN) {\n this.getContainer()\n .resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n .warn('Skipped WebSocket send on non-open socket', { readyState: this.ws.readyState })\n return false\n }\n this.ws.send(data)\n return true\n }\n\n /** Close the WebSocket connection */\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason)\n }\n\n /** Current WebSocket ready state */\n get readyState(): WSReadyState {\n return this.ws.readyState\n }\n\n /**\n * Get route parameter value(s) from the raw request — WebSocket gateways are\n * not OpenAPI-registered, so reads come straight from Hono's matcher.\n *\n * - With a key → single string value.\n * - With no args → full `Record<string, string>` (or `{}` when none).\n *\n * @param key - Parameter name (e.g., 'id' for /ws/chat/:id)\n */\n override param(): Record<string, string>\n override param(key: string): string\n override param(key?: string): string | Record<string, string> {\n if (key === undefined) return this.c.req.param() ?? {}\n return this.c.req.param(key)!\n }\n\n /**\n * Get query parameter value from the raw request (no OpenAPI validation)\n *\n * @param key - Query parameter name\n */\n override query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n if (key) {\n return this.c.req.query(key) as ContextQueryResult<R, K>\n }\n return this.c.req.query() as ContextQueryResult<R, K>\n }\n\n /**\n * Request body is not available in WebSocket gateways\n *\n * @throws WebSocketError always — WebSocket upgrade requests do not have a body\n */\n override body<T>(): Promise<T> {\n throw new WebSocketError('Request body is not available in WebSocket gateways')\n }\n}\n"],"mappings":";;;;;;;AAMA,MAAM,qBAAqB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B/C,SAAgB,QAAQ,OAAe,SAA0B;CAC/D,OAAO,SAAiC,QAAW;EACjD,WAAW,OAAO,OAAO,EAAE,MAAM;EACjC,eAAe,oBAAoB,MAAM,MAAM;EAC/C,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,UAAU,QAAyB;CAEjD,OAAO,YAAY,oBADI,OAAO,WAAW,aAAa,SAAU,OAAmC,WAC9C,MAAM;AAC7D;;;ACnDA,IAAa,iBAAb,cAAoC,iBAAiB,CAAC;;;ACGtD,MAAM,oBAAoB,oBAAoB;AAC9C,MAAM,kBAAkB,oBAAoB;AAC5C,MAAM,kBAAkB,oBAAoB;;;;;AAM5C,SAAS,4BAA4B,KAAa,aAA8B,QAAgB,eAA6B;CAC3H,MAAM,WAAW,YAA6B,KAAK,MAAM;CACzD,IAAI,aAAa,KAAA,KAAa,aAAa,aACzC,MAAM,IAAI,eAAe,cAAc,cAAc,oBAAoB,OAAO,QAAQ,EAAE,wBAAwB;CAEpH,eAAe,KAAK,aAAa,MAAM;AACzC;;;;;;;;;;;;;;;AAgBA,SAAgB,YAA6B;CAG3C,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,mBAAmB,aAAa,SAAS,WAAW;CAClF;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;AAKA,SAAgB,qBAAqB,QAAyC;CAC5E,OAAO,YAAoB,mBAAmB,OAAO,SAAmB;AAC1E;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AC7FA,MAAM,UAAU;;;;;;;;;;;;;;;;;;AAmBhB,IAAa,iBAAb,cAAoC,cAAc;CACG;CAAnD,YAAY,GAAuB,IAA+B;EAChE,MAAM,CAAC;EAD0C,KAAA,KAAA;CAEnD;;CAGA,KAAK,MAA4D;EAC/D,KAAK,GAAG,KAAK,IAAI;CACnB;;;;;;;;;CAUA,QAAQ,MAA+D;EACrE,IAAI,KAAK,GAAG,eAAe,SAAS;GAClC,KAAK,aAAa,EACf,QAAuB,cAAc,aAAa,EAClD,KAAK,6CAA6C,EAAE,YAAY,KAAK,GAAG,WAAW,CAAC;GACvF,OAAO;EACT;EACA,KAAK,GAAG,KAAK,IAAI;EACjB,OAAO;CACT;;CAGA,MAAM,MAAe,QAAuB;EAC1C,KAAK,GAAG,MAAM,MAAM,MAAM;CAC5B;;CAGA,IAAI,aAA2B;EAC7B,OAAO,KAAK,GAAG;CACjB;CAaA,MAAe,KAA+C;EAC5D,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAK,EAAE,IAAI,MAAM,KAAK,CAAC;EACrD,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;CAC7B;;;;;;CAOA,MAAoH,KAAmC;EACrJ,IAAI,KACF,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;EAE7B,OAAO,KAAK,EAAE,IAAI,MAAM;CAC1B;;;;;;CAOA,OAA+B;EAC7B,MAAM,IAAI,eAAe,qDAAqD;CAChF;AACF"}
|
|
1
|
+
{"version":3,"file":"gateway-context-I0tKgGfh.mjs","names":[],"sources":["../src/websocket/decorators/gateway.decorator.ts","../src/websocket/websocket.error.ts","../src/websocket/decorators/ws-event.decorator.ts","../src/websocket/gateway-context.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport { Controller } from '../../router/decorators/controller.decorator'\nimport { type Constructor } from '../../types'\nimport type { GatewayOptions } from '../../websocket/types'\n\nconst GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER\n\n/**\n * Gateway decorator for WebSocket route registration\n *\n * Marks a class as a WebSocket gateway and stores route metadata.\n * Reuses the same metadata key as @Controller for middleware compatibility —\n * `getControllerRoute()`, `forRoutes()`, and the entire middleware system work\n * with zero changes.\n *\n * @param route - WebSocket route path (e.g., '/ws/chat')\n *\n * @example\n * ```typescript\n * import { type GatewayContext, Gateway, OnMessage, OnClose } from 'stratal/websocket'\n *\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack')\n * }\n *\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function Gateway(route: string, options?: GatewayOptions) {\n return function <T extends Constructor>(target: T) {\n Controller(route, options)(target)\n defineMetadata(GATEWAY_MARKER_KEY, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is a WebSocket gateway\n *\n * @param target - Class constructor or instance\n * @returns true if the class is decorated with @Gateway\n */\nexport function isGateway(target: object): boolean {\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return getMetadata(GATEWAY_MARKER_KEY, metadataTarget) === true\n}\n","import { ApplicationError } from '../errors'\n\nexport class WebSocketError extends ApplicationError {}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport type { Constructor } from '../../types'\nimport { WebSocketError } from '../websocket.error'\n\nconst WS_ON_MESSAGE_KEY = ROUTE_METADATA_KEYS.WS_ON_MESSAGE\nconst WS_ON_CLOSE_KEY = ROUTE_METADATA_KEYS.WS_ON_CLOSE\nconst WS_ON_ERROR_KEY = ROUTE_METADATA_KEYS.WS_ON_ERROR\n\n/**\n * Define a single-handler metadata key on the prototype.\n * Throws if a different method already owns this key (prevents silent override).\n */\nfunction defineSingleHandlerMetadata(key: symbol, propertyKey: string | symbol, target: object, decoratorName: string): void {\n const existing = getMetadata<string | symbol>(key, target)\n if (existing !== undefined && existing !== propertyKey) {\n throw new WebSocketError(`Duplicate @${decoratorName} handler: method \"${String(existing)}\" is already registered`)\n }\n defineMetadata(key, propertyKey, target)\n}\n\n/**\n * Marks a method as the WebSocket message handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send(evt.data)\n * }\n * }\n * ```\n */\nexport function OnMessage(): MethodDecorator {\n // `_target` is the class prototype (method decorator convention).\n // The getter functions below read from `target.prototype` symmetrically.\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_MESSAGE_KEY, propertyKey, _target, 'OnMessage')\n }\n}\n\n/**\n * Marks a method as the WebSocket close handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function OnClose(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_CLOSE_KEY, propertyKey, _target, 'OnClose')\n }\n}\n\n/**\n * Marks a method as the WebSocket error handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnError()\n * handleError(evt: Event, ctx: GatewayContext) {\n * console.error('WebSocket error', evt)\n * }\n * }\n * ```\n */\nexport function OnError(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_ERROR_KEY, propertyKey, _target, 'OnError')\n }\n}\n\n/**\n * Get the method name decorated with @OnMessage\n */\nexport function getWsOnMessageMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_MESSAGE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnClose\n */\nexport function getWsOnCloseMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_CLOSE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnError\n */\nexport function getWsOnErrorMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_ERROR_KEY, target.prototype as object)\n}\n","import type { Context } from 'hono'\nimport type { WSContext, WSReadyState } from 'hono/ws'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport type { ContextQueryResult } from '../router/router-context'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\nimport { WebSocketError } from './websocket.error'\n\n/** WebSocket OPEN ready state (`WSReadyState` is a type-only union in hono/ws). */\nconst WS_OPEN = 1\n\n/**\n * WebSocket gateway context\n *\n * Extends RouterContext with WebSocket-specific methods.\n * Inherits `getContainer()`, `param()`, `query()`, `header()`, `getLocale()`\n * from RouterContext. HTTP response methods (`json()`, `redirect()`, etc.) are\n * inherited but harmless post-upgrade.\n *\n * @example\n * ```typescript\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack') // convenience method\n * ctx.header('Authorization') // upgrade request headers\n * }\n * ```\n */\nexport class GatewayContext extends RouterContext {\n constructor(c: Context<RouterEnv>, public readonly ws: WSContext) {\n super(c)\n }\n\n /** Send data through the WebSocket connection */\n send(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): void {\n this.ws.send(data)\n }\n\n /**\n * Send only if the socket is still open. Returns `false` (and logs a warning)\n * when the socket is closing/closed — e.g. inside `@OnError`, which fires on a\n * transport error after the socket is already dead, or after an `await` in\n * `@OnMessage` when the client disconnected mid-handler. Use this for\n * fire-and-forget acks/errors instead of `send()`, which throws on a closed\n * socket (\"Can't call WebSocket send() after close()\").\n */\n trySend(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): boolean {\n if (this.ws.readyState !== WS_OPEN) {\n this.getContainer()\n .resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n .warn('Skipped WebSocket send on non-open socket', { readyState: this.ws.readyState })\n return false\n }\n this.ws.send(data)\n return true\n }\n\n /** Close the WebSocket connection */\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason)\n }\n\n /** Current WebSocket ready state */\n get readyState(): WSReadyState {\n return this.ws.readyState\n }\n\n /**\n * Get route parameter value(s) from the raw request — WebSocket gateways are\n * not OpenAPI-registered, so reads come straight from Hono's matcher.\n *\n * - With a key → single string value.\n * - With no args → full `Record<string, string>` (or `{}` when none).\n *\n * @param key - Parameter name (e.g., 'id' for /ws/chat/:id)\n */\n override param(): Record<string, string>\n override param(key: string): string\n override param(key?: string): string | Record<string, string> {\n if (key === undefined) return this.c.req.param() ?? {}\n return this.c.req.param(key)!\n }\n\n /**\n * Get query parameter value from the raw request (no OpenAPI validation)\n *\n * @param key - Query parameter name\n */\n override query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n if (key) {\n return this.c.req.query(key) as ContextQueryResult<R, K>\n }\n return this.c.req.query() as ContextQueryResult<R, K>\n }\n\n /**\n * Request body is not available in WebSocket gateways\n *\n * @throws WebSocketError always — WebSocket upgrade requests do not have a body\n */\n override body<T>(): Promise<T> {\n throw new WebSocketError('Request body is not available in WebSocket gateways')\n }\n}\n"],"mappings":";;;;;;;AAMA,MAAM,qBAAqB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B/C,SAAgB,QAAQ,OAAe,SAA0B;CAC/D,OAAO,SAAiC,QAAW;EACjD,WAAW,OAAO,OAAO,EAAE,MAAM;EACjC,eAAe,oBAAoB,MAAM,MAAM;EAC/C,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,UAAU,QAAyB;CAEjD,OAAO,YAAY,oBADI,OAAO,WAAW,aAAa,SAAU,OAAmC,WAC9C,MAAM;AAC7D;;;ACnDA,IAAa,iBAAb,cAAoC,iBAAiB,CAAC;;;ACGtD,MAAM,oBAAoB,oBAAoB;AAC9C,MAAM,kBAAkB,oBAAoB;AAC5C,MAAM,kBAAkB,oBAAoB;;;;;AAM5C,SAAS,4BAA4B,KAAa,aAA8B,QAAgB,eAA6B;CAC3H,MAAM,WAAW,YAA6B,KAAK,MAAM;CACzD,IAAI,aAAa,KAAA,KAAa,aAAa,aACzC,MAAM,IAAI,eAAe,cAAc,cAAc,oBAAoB,OAAO,QAAQ,EAAE,wBAAwB;CAEpH,eAAe,KAAK,aAAa,MAAM;AACzC;;;;;;;;;;;;;;;AAgBA,SAAgB,YAA6B;CAG3C,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,mBAAmB,aAAa,SAAS,WAAW;CAClF;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;AAKA,SAAgB,qBAAqB,QAAyC;CAC5E,OAAO,YAAoB,mBAAmB,OAAO,SAAmB;AAC1E;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AC7FA,MAAM,UAAU;;;;;;;;;;;;;;;;;;AAmBhB,IAAa,iBAAb,cAAoC,cAAc;CACG;CAAnD,YAAY,GAAuB,IAA+B;EAChE,MAAM,CAAC;EAD0C,KAAA,KAAA;CAEnD;;CAGA,KAAK,MAA4D;EAC/D,KAAK,GAAG,KAAK,IAAI;CACnB;;;;;;;;;CAUA,QAAQ,MAA+D;EACrE,IAAI,KAAK,GAAG,eAAe,SAAS;GAClC,KAAK,aAAa,EACf,QAAuB,cAAc,aAAa,EAClD,KAAK,6CAA6C,EAAE,YAAY,KAAK,GAAG,WAAW,CAAC;GACvF,OAAO;EACT;EACA,KAAK,GAAG,KAAK,IAAI;EACjB,OAAO;CACT;;CAGA,MAAM,MAAe,QAAuB;EAC1C,KAAK,GAAG,MAAM,MAAM,MAAM;CAC5B;;CAGA,IAAI,aAA2B;EAC7B,OAAO,KAAK,GAAG;CACjB;CAaA,MAAe,KAA+C;EAC5D,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAK,EAAE,IAAI,MAAM,KAAK,CAAC;EACrD,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;CAC7B;;;;;;CAOA,MAAoH,KAAmC;EACrJ,IAAI,KACF,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;EAE7B,OAAO,KAAK,EAAE,IAAI,MAAM;CAC1B;;;;;;CAOA,OAA+B;EAC7B,MAAM,IAAI,eAAe,qDAAqD;CAChF;AACF"}
|
package/dist/guards/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Y as Container, rt as RouterContext } from "../index-
|
|
1
|
+
import { Y as Container, rt as RouterContext } from "../index-C_t8VVQD.mjs";
|
|
2
2
|
import { r as LoggerService } from "../index-BUt92sAE.mjs";
|
|
3
3
|
import { t as Constructor } from "../types-CmV_9xBD.mjs";
|
|
4
4
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
|
|
2
|
-
import { d as inject, n as CONTAINER_TOKEN, r as DI_TOKENS, s as Singleton } from "./di-
|
|
2
|
+
import { d as inject, n as CONTAINER_TOKEN, r as DI_TOKENS, s as Singleton } from "./di-B0NXIdRF.mjs";
|
|
3
3
|
import { r as runWithContainer } from "./container-storage-BmOJ4_Na.mjs";
|
|
4
4
|
import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
|
|
5
5
|
import { LOGGER_TOKENS } from "./logger/index.mjs";
|
|
6
|
-
import { a as RouterContext, l as ROUTER_CONTEXT_KEYS, r as createHttpExceptionContext } from "./exception-context-
|
|
7
|
-
import { o as RouterError } from "./module-registry-
|
|
6
|
+
import { a as RouterContext, l as ROUTER_CONTEXT_KEYS, r as createHttpExceptionContext } from "./exception-context-Bd5Hk2c_.mjs";
|
|
7
|
+
import { o as RouterError } from "./module-registry-MfWmniZ7.mjs";
|
|
8
8
|
import { t as OpenAPIHono } from "./zod-eKqqhZ5_.mjs";
|
|
9
9
|
import { n as OPENAPI_TOKENS } from "./openapi-tools.service-BC5EC3R3.mjs";
|
|
10
|
-
import "./openapi-
|
|
11
|
-
import { p as createMiddlewareChain, t as RouteRegistrationService, v as SchemaValidationError, y as RouteNotFoundError } from "./route-registration.service-
|
|
10
|
+
import "./openapi-BKDwQKh-.mjs";
|
|
11
|
+
import { p as createMiddlewareChain, t as RouteRegistrationService, v as SchemaValidationError, y as RouteNotFoundError } from "./route-registration.service-HN8WgIis.mjs";
|
|
12
12
|
import { t as applyTrailingSlash } from "./trailing-slash-CFyw8nYu.mjs";
|
|
13
13
|
//#region src/router/middleware/logger.middleware.ts
|
|
14
14
|
/**
|
|
@@ -158,4 +158,4 @@ HonoApp = __decorate([
|
|
|
158
158
|
//#endregion
|
|
159
159
|
export { hono_app_exports as n, HonoApp as t };
|
|
160
160
|
|
|
161
|
-
//# sourceMappingURL=hono-app-
|
|
161
|
+
//# sourceMappingURL=hono-app-C7-1m9eK.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono-app-CvV3hOfT.mjs","names":[],"sources":["../src/router/middleware/logger.middleware.ts","../src/router/middleware/trailing-slash-redirect.ts","../src/router/hono-app.ts"],"sourcesContent":["import type { MiddlewareHandler } from 'hono'\nimport type { LoggerService } from '../../logger'\n\n/**\n * Create a Hono middleware that logs HTTP requests using our Logger service\n *\n * Logs request method, path, status code, and duration in milliseconds.\n * Format: [HTTP] METHOD /path -> STATUS (duration ms)\n *\n * @param logger - Logger service instance\n * @returns Hono middleware handler\n *\n * @example\n * ```typescript\n * const logger = container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n * app.use('*', createLoggerMiddleware(logger))\n * ```\n */\nexport function createLoggerMiddleware(logger: LoggerService): MiddlewareHandler {\n return async (c, next) => {\n const start = Date.now()\n const method = c.req.method\n const path = c.req.path\n\n await next()\n\n const duration = Date.now() - start\n const status = c.res.status\n\n logger.info(`[HTTP] ${method} ${path} -> ${status}`, {\n method,\n path,\n status,\n duration,\n })\n }\n}\n","import type { MiddlewareHandler } from 'hono'\nimport { applyTrailingSlash } from '../trailing-slash'\nimport type { RouterEnv, TrailingSlashMode } from '../types'\n\nconst REDIRECT_STATUS = 308\n\n/**\n * Create a Hono middleware that canonicalises trailing slashes via 308 redirects.\n *\n * - `'ignore'` — returns `null`; routes match both `/foo` and `/foo/` natively\n * (Hono handles this when constructed with `strict: false`).\n * - `'always'` — non-trailing requests redirect to the trailing-slash form.\n * Paths whose last segment contains `.` (e.g. `/api/openapi.json`) are skipped.\n * - `'never'` — trailing requests redirect to the non-trailing form.\n *\n * Root (`/`) is always passed through unchanged.\n *\n * 308 is used so that POST/PUT/PATCH bodies survive the redirect.\n *\n * Location headers are emitted as path-relative URIs so the user agent\n * resolves them against the effective request URI — sidestepping scheme\n * mismatches behind HTTPS-terminating proxies that proxy HTTPS pages to an\n * HTTP-speaking backend (which would otherwise produce a mixed-content block).\n */\nexport function createTrailingSlashRedirect(\n mode: TrailingSlashMode,\n): MiddlewareHandler<RouterEnv> | null {\n if (mode === 'ignore') return null\n\n return async (c, next) => {\n const url = new URL(c.req.url)\n const canonicalPath = applyTrailingSlash(url.pathname, mode)\n if (canonicalPath === url.pathname) return next()\n return c.redirect(`${canonicalPath}${url.search}`, REDIRECT_STATUS)\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { inject } from '../di'\nimport type { Application } from '../application'\nimport type { Container } from '../di/container'\nimport { runWithContainer } from '../di/container-storage'\nimport { Singleton } from '../di/decorators'\nimport { CONTAINER_TOKEN, DI_TOKENS } from '../di/tokens'\nimport { createHttpExceptionContext } from '../errors/exception-context'\nimport type { ExceptionHandler } from '../errors/exception-handler'\nimport { OpenAPIHono } from '../i18n/validation/zod'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport { OPENAPI_TOKENS, type OpenAPIService } from '../openapi'\nimport type { Constructor } from '../types'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport { RouteNotFoundError, SchemaValidationError } from './errors'\nimport { RouterError } from './router.error'\nimport { createLoggerMiddleware, createMiddlewareChain, createTrailingSlashRedirect } from './middleware'\nimport type { Middleware } from './middleware.interface'\nimport { RouterContext } from './router-context'\nimport { RouteRegistrationService } from './services/route-registration.service'\nimport type { RouterEnv, TrailingSlashMode } from './types'\n\nconst isMiddlewareClass = (arg: unknown): arg is Constructor<Middleware> =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n typeof arg === 'function' && arg.prototype && 'handle' in arg.prototype\n\n\n/**\n * HonoApp — extends OpenAPIHono with Stratal-specific setup\n *\n * - Request scope middleware (child container per request)\n * - Global middleware (CORS, logging, error handling)\n * - defaultHook for validation errors\n * - `use()` overload for Stratal middleware classes\n * - `configure()` for OpenAPI, routes, and 404\n */\n@Singleton()\nexport class HonoApp extends OpenAPIHono<RouterEnv> {\n private configured = false\n private readonly _container: Container\n private readonly _logger: LoggerService\n\n /**\n * Reference to the original Hono `use` implementation.\n * Captured in constructor after super() sets it as an instance property.\n * Used by private methods to register middleware without going through the override.\n */\n private nativeUse!: typeof this.use\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(LOGGER_TOKENS.LoggerService) logger: LoggerService,\n @inject(DI_TOKENS.Application) application: Application,\n ) {\n const trailingSlash: TrailingSlashMode = application.config.trailingSlash ?? 'ignore'\n\n super({\n // Always non-strict: a registered `/foo` route matches both `/foo` and `/foo/`.\n // For the redirect modes, the trailing-slash middleware runs first and\n // canonicalises via 308 before matching reaches the registered route.\n strict: false,\n defaultHook: (result) => {\n if (!result.success) {\n throw new SchemaValidationError(result.error)\n }\n },\n })\n\n this._container = container\n this._logger = logger\n\n // Capture Hono's original `use` (set by super() as an instance property)\n this.nativeUse = this.use\n\n // Override `use` to support Stratal middleware classes alongside Hono-native handlers\n this.use = ((...args: unknown[]) => {\n if (isMiddlewareClass(args[0])) {\n this.nativeUse('*', createMiddlewareChain(args as Constructor<Middleware>[]))\n return this\n }\n\n if (typeof args[0] === 'string' && args.length > 1 && isMiddlewareClass(args[1])) {\n this.nativeUse(args[0], createMiddlewareChain(args.slice(1) as Constructor<Middleware>[]))\n return this\n }\n\n return (this.nativeUse as (...a: unknown[]) => unknown)(...args)\n }) as typeof this.use\n\n // Trailing-slash redirect runs first so redirected requests skip request-scope\n // and logger overhead.\n const trailingSlashRedirect = createTrailingSlashRedirect(trailingSlash)\n if (trailingSlashRedirect) {\n this.nativeUse('*', trailingSlashRedirect)\n }\n\n // Internal setup — uses nativeUse to bypass the override\n this.setupRequestScope()\n this.applyGlobalMiddleware()\n }\n\n /**\n * Apply global middleware (logger + error handler).\n * Called by Application after locale middleware is applied by LocalePathService.\n */\n private applyGlobalMiddleware(): void {\n this.nativeUse('*', createLoggerMiddleware(this._logger) as MiddlewareHandler<RouterEnv>)\n this.onError((err, c) => this.handleException(c, err))\n }\n\n /**\n * Configure OpenAPI endpoints, controller routes, and 404 handler.\n * Called once by Application.initialize().\n */\n async configure(): Promise<void> {\n if (this.configured) throw new RouterError('HonoApp has already been configured')\n\n // OpenAPI endpoints\n const openAPIService = this._container.resolve<OpenAPIService>(OPENAPI_TOKENS.OpenAPIService)\n openAPIService.setupEndpoints(this, this._container)\n\n // Controller routes + global middleware\n const routeRegistrationService = this._container.resolve<RouteRegistrationService>(RouteRegistrationService)\n await routeRegistrationService.configure()\n\n // 404 handler (must be last)\n this.notFound((c) => { throw new RouteNotFoundError(c.req.path, c.req.method) })\n\n this.configured = true\n }\n\n private setupRequestScope(): void {\n this.nativeUse('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const routerContext = new RouterContext(c)\n const requestContainer = this._container.createRequestScope(routerContext)\n c.set(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER, requestContainer)\n\n await runWithContainer(requestContainer, next)\n })\n }\n\n private handleException(c: Context<RouterEnv>, err: unknown) {\n // Fallback to global container if request scope setup failed before storing REQUEST_CONTAINER\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard: REQUEST_CONTAINER may be unset if request scope middleware throws\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER) ?? this._container\n const handler = requestContainer.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n const ctx = createHttpExceptionContext(c)\n // Run the handler within the request container's async context so standalone\n // helpers like `route()` (which read the ambient container via getContainer)\n // resolve correctly. Errors thrown before the request-scope middleware's\n // `runWithContainer` body — e.g. route-param validation failures — otherwise\n // reach here outside any container scope, breaking redirect-back rendering.\n return runWithContainer(requestContainer, () => handler.handle(err, ctx))\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hono-app-C7-1m9eK.mjs","names":[],"sources":["../src/router/middleware/logger.middleware.ts","../src/router/middleware/trailing-slash-redirect.ts","../src/router/hono-app.ts"],"sourcesContent":["import type { MiddlewareHandler } from 'hono'\nimport type { LoggerService } from '../../logger'\n\n/**\n * Create a Hono middleware that logs HTTP requests using our Logger service\n *\n * Logs request method, path, status code, and duration in milliseconds.\n * Format: [HTTP] METHOD /path -> STATUS (duration ms)\n *\n * @param logger - Logger service instance\n * @returns Hono middleware handler\n *\n * @example\n * ```typescript\n * const logger = container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n * app.use('*', createLoggerMiddleware(logger))\n * ```\n */\nexport function createLoggerMiddleware(logger: LoggerService): MiddlewareHandler {\n return async (c, next) => {\n const start = Date.now()\n const method = c.req.method\n const path = c.req.path\n\n await next()\n\n const duration = Date.now() - start\n const status = c.res.status\n\n logger.info(`[HTTP] ${method} ${path} -> ${status}`, {\n method,\n path,\n status,\n duration,\n })\n }\n}\n","import type { MiddlewareHandler } from 'hono'\nimport { applyTrailingSlash } from '../trailing-slash'\nimport type { RouterEnv, TrailingSlashMode } from '../types'\n\nconst REDIRECT_STATUS = 308\n\n/**\n * Create a Hono middleware that canonicalises trailing slashes via 308 redirects.\n *\n * - `'ignore'` — returns `null`; routes match both `/foo` and `/foo/` natively\n * (Hono handles this when constructed with `strict: false`).\n * - `'always'` — non-trailing requests redirect to the trailing-slash form.\n * Paths whose last segment contains `.` (e.g. `/api/openapi.json`) are skipped.\n * - `'never'` — trailing requests redirect to the non-trailing form.\n *\n * Root (`/`) is always passed through unchanged.\n *\n * 308 is used so that POST/PUT/PATCH bodies survive the redirect.\n *\n * Location headers are emitted as path-relative URIs so the user agent\n * resolves them against the effective request URI — sidestepping scheme\n * mismatches behind HTTPS-terminating proxies that proxy HTTPS pages to an\n * HTTP-speaking backend (which would otherwise produce a mixed-content block).\n */\nexport function createTrailingSlashRedirect(\n mode: TrailingSlashMode,\n): MiddlewareHandler<RouterEnv> | null {\n if (mode === 'ignore') return null\n\n return async (c, next) => {\n const url = new URL(c.req.url)\n const canonicalPath = applyTrailingSlash(url.pathname, mode)\n if (canonicalPath === url.pathname) return next()\n return c.redirect(`${canonicalPath}${url.search}`, REDIRECT_STATUS)\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { inject } from '../di'\nimport type { Application } from '../application'\nimport type { Container } from '../di/container'\nimport { runWithContainer } from '../di/container-storage'\nimport { Singleton } from '../di/decorators'\nimport { CONTAINER_TOKEN, DI_TOKENS } from '../di/tokens'\nimport { createHttpExceptionContext } from '../errors/exception-context'\nimport type { ExceptionHandler } from '../errors/exception-handler'\nimport { OpenAPIHono } from '../i18n/validation/zod'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport { OPENAPI_TOKENS, type OpenAPIService } from '../openapi'\nimport type { Constructor } from '../types'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport { RouteNotFoundError, SchemaValidationError } from './errors'\nimport { RouterError } from './router.error'\nimport { createLoggerMiddleware, createMiddlewareChain, createTrailingSlashRedirect } from './middleware'\nimport type { Middleware } from './middleware.interface'\nimport { RouterContext } from './router-context'\nimport { RouteRegistrationService } from './services/route-registration.service'\nimport type { RouterEnv, TrailingSlashMode } from './types'\n\nconst isMiddlewareClass = (arg: unknown): arg is Constructor<Middleware> =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n typeof arg === 'function' && arg.prototype && 'handle' in arg.prototype\n\n\n/**\n * HonoApp — extends OpenAPIHono with Stratal-specific setup\n *\n * - Request scope middleware (child container per request)\n * - Global middleware (CORS, logging, error handling)\n * - defaultHook for validation errors\n * - `use()` overload for Stratal middleware classes\n * - `configure()` for OpenAPI, routes, and 404\n */\n@Singleton()\nexport class HonoApp extends OpenAPIHono<RouterEnv> {\n private configured = false\n private readonly _container: Container\n private readonly _logger: LoggerService\n\n /**\n * Reference to the original Hono `use` implementation.\n * Captured in constructor after super() sets it as an instance property.\n * Used by private methods to register middleware without going through the override.\n */\n private nativeUse!: typeof this.use\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(LOGGER_TOKENS.LoggerService) logger: LoggerService,\n @inject(DI_TOKENS.Application) application: Application,\n ) {\n const trailingSlash: TrailingSlashMode = application.config.trailingSlash ?? 'ignore'\n\n super({\n // Always non-strict: a registered `/foo` route matches both `/foo` and `/foo/`.\n // For the redirect modes, the trailing-slash middleware runs first and\n // canonicalises via 308 before matching reaches the registered route.\n strict: false,\n defaultHook: (result) => {\n if (!result.success) {\n throw new SchemaValidationError(result.error)\n }\n },\n })\n\n this._container = container\n this._logger = logger\n\n // Capture Hono's original `use` (set by super() as an instance property)\n this.nativeUse = this.use\n\n // Override `use` to support Stratal middleware classes alongside Hono-native handlers\n this.use = ((...args: unknown[]) => {\n if (isMiddlewareClass(args[0])) {\n this.nativeUse('*', createMiddlewareChain(args as Constructor<Middleware>[]))\n return this\n }\n\n if (typeof args[0] === 'string' && args.length > 1 && isMiddlewareClass(args[1])) {\n this.nativeUse(args[0], createMiddlewareChain(args.slice(1) as Constructor<Middleware>[]))\n return this\n }\n\n return (this.nativeUse as (...a: unknown[]) => unknown)(...args)\n }) as typeof this.use\n\n // Trailing-slash redirect runs first so redirected requests skip request-scope\n // and logger overhead.\n const trailingSlashRedirect = createTrailingSlashRedirect(trailingSlash)\n if (trailingSlashRedirect) {\n this.nativeUse('*', trailingSlashRedirect)\n }\n\n // Internal setup — uses nativeUse to bypass the override\n this.setupRequestScope()\n this.applyGlobalMiddleware()\n }\n\n /**\n * Apply global middleware (logger + error handler).\n * Called by Application after locale middleware is applied by LocalePathService.\n */\n private applyGlobalMiddleware(): void {\n this.nativeUse('*', createLoggerMiddleware(this._logger) as MiddlewareHandler<RouterEnv>)\n this.onError((err, c) => this.handleException(c, err))\n }\n\n /**\n * Configure OpenAPI endpoints, controller routes, and 404 handler.\n * Called once by Application.initialize().\n */\n async configure(): Promise<void> {\n if (this.configured) throw new RouterError('HonoApp has already been configured')\n\n // OpenAPI endpoints\n const openAPIService = this._container.resolve<OpenAPIService>(OPENAPI_TOKENS.OpenAPIService)\n openAPIService.setupEndpoints(this, this._container)\n\n // Controller routes + global middleware\n const routeRegistrationService = this._container.resolve<RouteRegistrationService>(RouteRegistrationService)\n await routeRegistrationService.configure()\n\n // 404 handler (must be last)\n this.notFound((c) => { throw new RouteNotFoundError(c.req.path, c.req.method) })\n\n this.configured = true\n }\n\n private setupRequestScope(): void {\n this.nativeUse('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const routerContext = new RouterContext(c)\n const requestContainer = this._container.createRequestScope(routerContext)\n c.set(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER, requestContainer)\n\n await runWithContainer(requestContainer, next)\n })\n }\n\n private handleException(c: Context<RouterEnv>, err: unknown) {\n // Fallback to global container if request scope setup failed before storing REQUEST_CONTAINER\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard: REQUEST_CONTAINER may be unset if request scope middleware throws\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER) ?? this._container\n const handler = requestContainer.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n const ctx = createHttpExceptionContext(c)\n // Run the handler within the request container's async context so standalone\n // helpers like `route()` (which read the ambient container via getContainer)\n // resolve correctly. Errors thrown before the request-scope middleware's\n // `runWithContainer` body — e.g. route-param validation failures — otherwise\n // reach here outside any container scope, breaking redirect-back rendering.\n return runWithContainer(requestContainer, () => handler.handle(err, ctx))\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as getMetadata, t as defineMetadata } from "./metadata-DzzprcID.mjs";
|
|
2
|
-
import { u as ROUTE_METADATA_KEYS } from "./exception-context-
|
|
2
|
+
import { u as ROUTE_METADATA_KEYS } from "./exception-context-Bd5Hk2c_.mjs";
|
|
3
3
|
import { r as z } from "./zod-eKqqhZ5_.mjs";
|
|
4
4
|
//#region src/router/decorators/http-method.decorator.ts
|
|
5
5
|
/**
|
|
@@ -94,4 +94,4 @@ const All = createHttpMethodDecorator("all");
|
|
|
94
94
|
//#endregion
|
|
95
95
|
export { Post as a, Patch as i, Delete as n, Put as o, Get as r, All as t };
|
|
96
96
|
|
|
97
|
-
//# sourceMappingURL=http-method.decorator-
|
|
97
|
+
//# sourceMappingURL=http-method.decorator-xCuGoZPC.mjs.map
|
package/dist/{http-method.decorator-ByWZb9DO.mjs.map → http-method.decorator-xCuGoZPC.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-method.decorator-
|
|
1
|
+
{"version":3,"file":"http-method.decorator-xCuGoZPC.mjs","names":[],"sources":["../src/router/decorators/http-method.decorator.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { z } from '../../i18n/validation/zod'\nimport { ROUTE_METADATA_KEYS } from '../constants'\nimport type { ExplicitRouteMetadata, HttpMethod, RouteConfig } from '../types'\n\n/**\n * Creates an HTTP method decorator factory for the given HTTP method.\n *\n * The returned decorator stores {@link ExplicitRouteMetadata} on the method and\n * tracks the method name under {@link ROUTE_METADATA_KEYS.DECORATED_METHODS}\n * on the controller prototype so they can be discovered at registration time.\n */\nfunction createHttpMethodDecorator(method: HttpMethod) {\n return function (path: string, config?: RouteConfig) {\n return function (\n target: object,\n propertyKey: string,\n descriptor: PropertyDescriptor\n ) {\n const metadata: ExplicitRouteMetadata = {\n type: 'explicit',\n method,\n path,\n config: config ?? { response: z.any() },\n }\n\n defineMetadata(\n ROUTE_METADATA_KEYS.ROUTE_CONFIG,\n metadata,\n target,\n propertyKey\n )\n\n // Track this method as decorated on the prototype\n const existing: string[] =\n getMetadata<string[]>(ROUTE_METADATA_KEYS.DECORATED_METHODS, target) ?? []\n existing.push(propertyKey)\n defineMetadata(ROUTE_METADATA_KEYS.DECORATED_METHODS, existing, target)\n\n return descriptor\n }\n }\n}\n\n/**\n * Registers a GET route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (response schema, body, params, etc.)\n *\n * @example\n * ```typescript\n * @Controller('/api/v1/users')\n * class UsersController {\n * @Get('/', { response: z.array(userSchema), summary: 'List users' })\n * async list(ctx: RouterContext) { ... }\n *\n * @Get('/:id', { params: z.object({ id: z.string().uuid() }), response: userSchema })\n * async getUser(ctx: RouterContext) { ... }\n * }\n * ```\n */\nexport const Get = createHttpMethodDecorator('get')\n\n/**\n * Registers a POST route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (response schema, body, params, etc.)\n *\n * @example\n * ```typescript\n * @Controller('/api/v1/users')\n * class UsersController {\n * @Post('/', { body: createUserSchema, response: userSchema, statusCode: 201 })\n * async createUser(ctx: RouterContext) { ... }\n * }\n * ```\n */\nexport const Post = createHttpMethodDecorator('post')\n\n/**\n * Registers a PUT route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const Put = createHttpMethodDecorator('put')\n\n/**\n * Registers a PATCH route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const Patch = createHttpMethodDecorator('patch')\n\n/**\n * Registers a DELETE route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const Delete = createHttpMethodDecorator('delete')\n\n/**\n * Registers an ALL (any HTTP method) route on the controller method.\n * Routes using @All are registered without OpenAPI validation\n * since OpenAPI does not support a catch-all HTTP method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const All = createHttpMethodDecorator('all')\n"],"mappings":";;;;;;;;;;;AAYA,SAAS,0BAA0B,QAAoB;CACrD,OAAO,SAAU,MAAc,QAAsB;EACnD,OAAO,SACL,QACA,aACA,YACA;GACA,MAAM,WAAkC;IACtC,MAAM;IACN;IACA;IACA,QAAQ,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE;GACxC;GAEA,eACE,oBAAoB,cACpB,UACA,QACA,WACF;GAGA,MAAM,WACJ,YAAsB,oBAAoB,mBAAmB,MAAM,KAAK,CAAC;GAC3E,SAAS,KAAK,WAAW;GACzB,eAAe,oBAAoB,mBAAmB,UAAU,MAAM;GAEtE,OAAO;EACT;CACF;AACF;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,MAAM,0BAA0B,KAAK;;;;;;;;;;;;;;;;AAiBlD,MAAa,OAAO,0BAA0B,MAAM;;;;;;;AAQpD,MAAa,MAAM,0BAA0B,KAAK;;;;;;;AAQlD,MAAa,QAAQ,0BAA0B,OAAO;;;;;;;AAQtD,MAAa,SAAS,0BAA0B,QAAQ;;;;;;;;;AAUxD,MAAa,MAAM,0BAA0B,KAAK"}
|
package/dist/i18n/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dr as ApplicationError, In as OnInitialize, Nn as ModuleContext, kn as DynamicModule } from "../index-
|
|
1
|
+
import { Dr as ApplicationError, In as OnInitialize, Nn as ModuleContext, kn as DynamicModule } from "../index-C_t8VVQD.mjs";
|
|
2
2
|
import { _ as MessageParams, d as AppMessages, f as DeepKeys, g as MessageKeys, h as MessageKeyPrefix, l as AppMessageKeys, m as II18nService, p as FilterByPrefix, u as AppMessageNamespaces, v as Prefixes, y as SystemMessageKeys } from "../zod-wecrEVAs.mjs";
|
|
3
3
|
import { t as index_d_exports } from "../index-HgOLNruQ.mjs";
|
|
4
4
|
import { DetectorOptions } from "hono/language";
|
package/dist/i18n/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as ApplicationError, n as getContainer } from "../container-storage-BmOJ4_Na.mjs";
|
|
2
|
-
import "../errors-
|
|
2
|
+
import "../errors-EUtwVfNm.mjs";
|
|
3
3
|
import { t as I18N_TOKENS } from "../i18n.tokens-CZ_v8oyS.mjs";
|
|
4
|
-
import { i as resolveI18nOptions, r as buildDetectorOptions } from "../locale-path.service-
|
|
5
|
-
import { a as getLocales, i as MessageLoaderService, o as getMessages, r as MessageRegistry, s as messages, t as I18nModule } from "../i18n.module-
|
|
4
|
+
import { i as resolveI18nOptions, r as buildDetectorOptions } from "../locale-path.service-DzA01Kvc.mjs";
|
|
5
|
+
import { a as getLocales, i as MessageLoaderService, o as getMessages, r as MessageRegistry, s as messages, t as I18nModule } from "../i18n.module-JOPUNpvi.mjs";
|
|
6
6
|
//#region src/i18n/i18n.error.ts
|
|
7
7
|
var I18nError = class extends ApplicationError {};
|
|
8
8
|
//#endregion
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
|
|
2
|
-
import { d as inject, o as Request, s as Singleton, v as ROUTER_TOKENS } from "./di-
|
|
2
|
+
import { d as inject, o as Request, s as Singleton, v as ROUTER_TOKENS } from "./di-B0NXIdRF.mjs";
|
|
3
3
|
import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
|
|
4
4
|
import { n as Module } from "./module.decorator-CYHY6pG5.mjs";
|
|
5
5
|
import "./module/index.mjs";
|
|
6
6
|
import { t as I18N_TOKENS } from "./i18n.tokens-CZ_v8oyS.mjs";
|
|
7
7
|
import { r as z } from "./zod-eKqqhZ5_.mjs";
|
|
8
8
|
import { t as zodErrorMap } from "./validation.context-CRvmrhq7.mjs";
|
|
9
|
-
import "./router-
|
|
9
|
+
import "./router-OCnf4VB6.mjs";
|
|
10
10
|
import { t as en_exports } from "./en-CDZBMcc1.mjs";
|
|
11
11
|
import { t as deepMerge } from "./deep-merge-ByiAOZ3r.mjs";
|
|
12
12
|
import IntlMessageFormat from "intl-messageformat";
|
|
@@ -219,4 +219,4 @@ I18nModule = _I18nModule = __decorate([Module({ providers: [
|
|
|
219
219
|
//#endregion
|
|
220
220
|
export { getLocales as a, MessageLoaderService as i, i18n_module_exports as n, getMessages as o, MessageRegistry as r, messages as s, I18nModule as t };
|
|
221
221
|
|
|
222
|
-
//# sourceMappingURL=i18n.module-
|
|
222
|
+
//# sourceMappingURL=i18n.module-JOPUNpvi.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.module-DRQAZoSZ.mjs","names":[],"sources":["../src/i18n/services/i18n.service.ts","../src/i18n/messages/index.ts","../src/i18n/services/message-loader.service.ts","../src/i18n/services/message-registry.ts","../src/i18n/i18n.module.ts"],"sourcesContent":["import { inject } from '../../di'\nimport { Request } from '../../di/decorators'\nimport { ROUTER_TOKENS, type RouterContext } from '../../router'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport type { II18nService, MessageKeys, MessageParams } from '../i18n.types'\nimport type { MessageLoaderService } from './message-loader.service'\n\n@Request(I18N_TOKENS.I18nService)\nexport class I18nService implements II18nService {\n constructor(\n @inject(I18N_TOKENS.MessageLoader) private readonly loader: MessageLoaderService,\n @inject(ROUTER_TOKENS.RouterContext, { isOptional: true }) private readonly routerContext?: RouterContext\n ) {\n }\n\n t(key: MessageKeys, params?: MessageParams): string {\n return this.loader.translate(this.getLocale(), key, params as Record<string, unknown>)\n }\n\n getLocale(): string {\n return this.routerContext?.getLocale() ?? 'en'\n }\n}\n","/**\n * Core Messages\n *\n * Messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nimport * as en from './en'\n\n/**\n * All locale messages\n * Explicitly import and export (no filesystem scanning - Cloudflare Workers compatible)\n */\nexport const messages = { en } as const\n\n/**\n * Type for all messages\n */\nexport type Messages = typeof messages\n\n/**\n * Get messages for all locales\n */\nexport function getMessages(): Record<string, Record<string, unknown>> {\n return messages\n}\n\n/**\n * Get available locales\n */\nexport function getLocales(): string[] {\n return Object.keys(messages)\n}\n","import IntlMessageFormat from 'intl-messageformat'\nimport { inject } from '../../di'\nimport { Singleton } from '../../di/decorators'\nimport type { I18nModuleOptions } from '../i18n.options'\nimport type { MessageKeyPrefix } from '../i18n.types'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport { getLocales, getMessages } from '../messages'\nimport { deepMerge } from '../utils/deep-merge'\nimport type { MessageRegistry } from './message-registry'\n\ntype CompiledMessages = Record<string, (params?: Record<string, unknown>) => string>\n\n@Singleton(I18N_TOKENS.MessageLoader)\nexport class MessageLoaderService {\n private readonly cache: Map<string, Record<string, unknown>>\n private readonly compiledCache: Map<string, CompiledMessages>\n private readonly locales: string[]\n private readonly defaultLocale: string\n\n constructor(\n @inject(I18N_TOKENS.MessageRegistry) private readonly registry: MessageRegistry,\n @inject(I18N_TOKENS.Options, { isOptional: true })\n private readonly options?: I18nModuleOptions\n ) {\n this.defaultLocale = this.options?.defaultLocale ?? 'en'\n this.cache = new Map()\n this.compiledCache = new Map()\n\n const coreMessages = getMessages()\n const coreLocales = getLocales()\n\n const registryMessages = this.registry.getMergedMessages()\n const registryLocales = Object.keys(registryMessages)\n\n const allLocales = [...new Set([...coreLocales, ...registryLocales])]\n this.locales = allLocales\n\n for (const locale of allLocales) {\n const coreLocaleMessages = coreMessages[locale] ?? {}\n const registryLocaleMessages = registryMessages[locale] ?? {}\n\n const merged = deepMerge(coreLocaleMessages, registryLocaleMessages)\n this.cache.set(locale, merged)\n }\n }\n\n translate(locale: string, key: string, params?: Record<string, unknown>): string {\n const compiled = this.getCompiledMessages(locale)\n const fn = compiled[key]\n if (!fn) return key\n return fn(params)\n }\n\n getMessages(locale: string): Record<string, unknown> {\n return this.cache.get(locale) ?? this.cache.get(this.defaultLocale) ?? {}\n }\n\n getAvailableLocales(): string[] {\n return this.locales\n }\n\n isLocaleSupported(locale: string): boolean {\n return this.cache.has(locale)\n }\n\n getDefaultLocale(): string {\n return this.defaultLocale\n }\n\n getFilteredMessages(\n locale: string,\n options?: { only?: MessageKeyPrefix[] }\n ): Record<string, string> {\n const messages = this.getMessages(locale)\n const flattened = this.flattenMessages(messages)\n\n if (!options?.only?.length) return flattened\n\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(flattened)) {\n if (options.only.some((prefix) => key === prefix || key.startsWith(`${prefix}.`))) {\n result[key] = value\n }\n }\n return result\n }\n\n private getCompiledMessages(locale: string): CompiledMessages {\n const effectiveLocale = this.cache.has(locale) ? locale : this.defaultLocale\n\n const cached = this.compiledCache.get(effectiveLocale)\n if (cached) return cached\n\n const messages = this.cache.get(effectiveLocale) ?? {}\n const flattened = this.flattenMessages(messages)\n\n const compiled: CompiledMessages = {}\n for (const [key, value] of Object.entries(flattened)) {\n const msg = new IntlMessageFormat(value, effectiveLocale)\n compiled[key] = (params) => String(msg.format(params as Record<string, string | number | boolean>))\n }\n\n this.compiledCache.set(effectiveLocale, compiled)\n return compiled\n }\n\n private flattenMessages(\n messages: Record<string, unknown>,\n prefix = ''\n ): Record<string, string> {\n const result: Record<string, string> = {}\n\n for (const key of Object.keys(messages)) {\n const value = messages[key]\n const newKey = prefix ? `${prefix}.${key}` : key\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n Object.assign(result, this.flattenMessages(value as Record<string, unknown>, newKey))\n } else {\n result[newKey] = String(value)\n }\n }\n\n return result\n }\n}\n","import { Singleton } from '../../di/decorators'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport { deepMerge } from '../utils/deep-merge'\n\n/**\n * Global key for the shared contributions array.\n *\n * When stratal is installed via portal/symlink (e.g., in monorepos), bundlers\n * like esbuild may inline multiple copies of this module. Each copy gets its\n * own static class fields, so messages registered by one copy are invisible\n * to another. Using a `Symbol.for()` key on `globalThis` ensures all copies\n * share the same contributions array.\n */\nconst CONTRIBUTIONS_KEY = Symbol.for('stratal:i18n:message-registry:contributions')\n\ntype Contributions = Record<string, Record<string, unknown>>[]\n\nfunction getContributions(): Contributions {\n const g = globalThis as Record<symbol, unknown>\n g[CONTRIBUTIONS_KEY] ??= [];\n return g[CONTRIBUTIONS_KEY] as Contributions\n}\n\n/**\n * Message Registry\n *\n * Accumulates i18n messages from multiple `I18nModule.registerMessages()` calls.\n * Messages are collected statically (at module import time) and deep-merged\n * when `getMergedMessages()` is called by `MessageLoaderService`.\n *\n * Later registrations override earlier ones at leaf level.\n */\n@Singleton(I18N_TOKENS.MessageRegistry)\nexport class MessageRegistry {\n /**\n * Add messages (called statically by I18nModule.registerMessages)\n */\n static addMessages(messages: Record<string, Record<string, unknown>>): void {\n if (Boolean(messages) && typeof messages === 'object' && Object.keys(messages).length > 0) {\n getContributions().push(messages)\n }\n }\n\n /**\n * Get all messages deep-merged in registration order\n */\n getMergedMessages(): Record<string, Record<string, unknown>> {\n const merged: Record<string, Record<string, unknown>> = {}\n\n for (const contribution of getContributions()) {\n for (const locale of Object.keys(contribution)) {\n merged[locale] = deepMerge(\n (merged[locale] ?? {}),\n contribution[locale],\n )\n }\n }\n\n return merged\n }\n\n /**\n * Reset registry (for testing)\n * @internal\n */\n static reset(): void {\n (globalThis as Record<symbol, unknown>)[CONTRIBUTIONS_KEY] = []\n }\n}\n","import { Module } from '../module'\nimport type { DynamicModule, ModuleContext, OnInitialize } from '../module/types'\nimport type { I18nModuleOptions } from './i18n.options'\nimport { I18N_TOKENS } from './i18n.tokens'\nimport { I18nService } from './services/i18n.service'\nimport { MessageLoaderService } from './services/message-loader.service'\nimport { MessageRegistry } from './services/message-registry'\nimport { zodErrorMap } from './validation/validation.context'\nimport { z } from './validation/zod'\n\n@Module({\n providers: [\n { provide: I18N_TOKENS.MessageRegistry, useClass: MessageRegistry },\n { provide: I18N_TOKENS.MessageLoader, useClass: MessageLoaderService },\n { provide: I18N_TOKENS.I18nService, useClass: I18nService },\n ],\n})\nexport class I18nModule implements OnInitialize {\n onInitialize(_context: ModuleContext): void {\n z.config({ customError: zodErrorMap })\n }\n\n static forRoot(options: I18nModuleOptions = {}): DynamicModule {\n return {\n module: I18nModule,\n providers: [\n { provide: I18N_TOKENS.Options, useValue: options },\n ],\n }\n }\n\n static registerMessages(messages: Record<string, Record<string, unknown>>): DynamicModule {\n MessageRegistry.addMessages(messages)\n return {\n module: I18nModule,\n providers: [],\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAQO,IAAA,cAAA,MAAM,YAAoC;CAEO;CACwB;CAF9E,YACE,QACA,eACA;EAFoD,KAAA,SAAA;EACwB,KAAA,gBAAA;CAE9E;CAEA,EAAE,KAAkB,QAAgC;EAClD,OAAO,KAAK,OAAO,UAAU,KAAK,UAAU,GAAG,KAAK,MAAiC;CACvF;CAEA,YAAoB;EAClB,OAAO,KAAK,eAAe,UAAU,KAAK;CAC5C;AACF;;CAfC,QAAQ,YAAY,WAAW;oBAG3B,OAAO,YAAY,aAAa,CAAA;oBAChC,OAAO,cAAc,eAAe,EAAE,YAAY,KAAK,CAAC,CAAA;;;;;;;;;;;;;;ACE7D,MAAa,WAAW,EAAE,IAAA,WAAG;;;;AAU7B,SAAgB,cAAuD;CACrE,OAAO;AACT;;;;AAKA,SAAgB,aAAuB;CACrC,OAAO,OAAO,KAAK,QAAQ;AAC7B;;;ACnBO,IAAA,uBAAA,MAAM,qBAAqB;CAOwB;CAErC;CARnB;CACA;CACA;CACA;CAEA,YACE,UACA,SAEA;EAHsD,KAAA,WAAA;EAErC,KAAA,UAAA;EAEjB,KAAK,gBAAgB,KAAK,SAAS,iBAAiB;EACpD,KAAK,wBAAQ,IAAI,IAAI;EACrB,KAAK,gCAAgB,IAAI,IAAI;EAE7B,MAAM,eAAe,YAAY;EACjC,MAAM,cAAc,WAAW;EAE/B,MAAM,mBAAmB,KAAK,SAAS,kBAAkB;EACzD,MAAM,kBAAkB,OAAO,KAAK,gBAAgB;EAEpD,MAAM,aAAa,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,aAAa,GAAG,eAAe,CAAC,CAAC;EACpE,KAAK,UAAU;EAEf,KAAK,MAAM,UAAU,YAAY;GAI/B,MAAM,SAAS,UAHY,aAAa,WAAW,CAAC,GACrB,iBAAiB,WAAW,CAAC,CAEO;GACnE,KAAK,MAAM,IAAI,QAAQ,MAAM;EAC/B;CACF;CAEA,UAAU,QAAgB,KAAa,QAA0C;EAE/E,MAAM,KADW,KAAK,oBAAoB,MACxB,EAAE;EACpB,IAAI,CAAC,IAAI,OAAO;EAChB,OAAO,GAAG,MAAM;CAClB;CAEA,YAAY,QAAyC;EACnD,OAAO,KAAK,MAAM,IAAI,MAAM,KAAK,KAAK,MAAM,IAAI,KAAK,aAAa,KAAK,CAAC;CAC1E;CAEA,sBAAgC;EAC9B,OAAO,KAAK;CACd;CAEA,kBAAkB,QAAyB;EACzC,OAAO,KAAK,MAAM,IAAI,MAAM;CAC9B;CAEA,mBAA2B;EACzB,OAAO,KAAK;CACd;CAEA,oBACE,QACA,SACwB;EACxB,MAAM,WAAW,KAAK,YAAY,MAAM;EACxC,MAAM,YAAY,KAAK,gBAAgB,QAAQ;EAE/C,IAAI,CAAC,SAAS,MAAM,QAAQ,OAAO;EAEnC,MAAM,SAAiC,CAAC;EACxC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,GACjD,IAAI,QAAQ,KAAK,MAAM,WAAW,QAAQ,UAAU,IAAI,WAAW,GAAG,OAAO,EAAE,CAAC,GAC9E,OAAO,OAAO;EAGlB,OAAO;CACT;CAEA,oBAA4B,QAAkC;EAC5D,MAAM,kBAAkB,KAAK,MAAM,IAAI,MAAM,IAAI,SAAS,KAAK;EAE/D,MAAM,SAAS,KAAK,cAAc,IAAI,eAAe;EACrD,IAAI,QAAQ,OAAO;EAEnB,MAAM,WAAW,KAAK,MAAM,IAAI,eAAe,KAAK,CAAC;EACrD,MAAM,YAAY,KAAK,gBAAgB,QAAQ;EAE/C,MAAM,WAA6B,CAAC;EACpC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,GAAG;GACpD,MAAM,MAAM,IAAI,kBAAkB,OAAO,eAAe;GACxD,SAAS,QAAQ,WAAW,OAAO,IAAI,OAAO,MAAmD,CAAC;EACpG;EAEA,KAAK,cAAc,IAAI,iBAAiB,QAAQ;EAChD,OAAO;CACT;CAEA,gBACE,UACA,SAAS,IACe;EACxB,MAAM,SAAiC,CAAC;EAExC,KAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,GAAG;GACvC,MAAM,QAAQ,SAAS;GACvB,MAAM,SAAS,SAAS,GAAG,OAAO,GAAG,QAAQ;GAE7C,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,GACrE,OAAO,OAAO,QAAQ,KAAK,gBAAgB,OAAkC,MAAM,CAAC;QAEpF,OAAO,UAAU,OAAO,KAAK;EAEjC;EAEA,OAAO;CACT;AACF;;CAjHC,UAAU,YAAY,aAAa;oBAQ/B,OAAO,YAAY,eAAe,CAAA;oBAClC,OAAO,YAAY,SAAS,EAAE,YAAY,KAAK,CAAC,CAAA;;;;;;;;;;;;;ACRrD,MAAM,oBAAoB,OAAO,IAAI,6CAA6C;AAIlF,SAAS,mBAAkC;CACzC,MAAM,IAAI;CACV,EAAE,uBAAuB,CAAC;CAC1B,OAAO,EAAE;AACX;AAYO,IAAA,kBAAA,MAAM,gBAAgB;;;;CAI3B,OAAO,YAAY,UAAyD;EAC1E,IAAI,QAAQ,QAAQ,KAAK,OAAO,aAAa,YAAY,OAAO,KAAK,QAAQ,EAAE,SAAS,GACtF,iBAAiB,EAAE,KAAK,QAAQ;CAEpC;;;;CAKA,oBAA6D;EAC3D,MAAM,SAAkD,CAAC;EAEzD,KAAK,MAAM,gBAAgB,iBAAiB,GAC1C,KAAK,MAAM,UAAU,OAAO,KAAK,YAAY,GAC3C,OAAO,UAAU,UACd,OAAO,WAAW,CAAC,GACpB,aAAa,OACf;EAIJ,OAAO;CACT;;;;;CAMA,OAAO,QAAc;EACnB,WAAwC,qBAAqB,CAAC;CAChE;AACF;8BApCC,UAAU,YAAY,eAAe,CAAA,GAAA,eAAA;;;;;ACf/B,IAAA,aAAA,cAAA,MAAM,WAAmC;CAC9C,aAAa,UAA+B;EAC1C,EAAE,OAAO,EAAE,aAAa,YAAY,CAAC;CACvC;CAEA,OAAO,QAAQ,UAA6B,CAAC,GAAkB;EAC7D,OAAO;GACL,QAAA;GACA,WAAW,CACT;IAAE,SAAS,YAAY;IAAS,UAAU;GAAQ,CACpD;EACF;CACF;CAEA,OAAO,iBAAiB,UAAkE;EACxF,gBAAgB,YAAY,QAAQ;EACpC,OAAO;GACL,QAAA;GACA,WAAW,CAAC;EACd;CACF;AACF;uCA5BC,OAAO,EACN,WAAW;CACT;EAAE,SAAS,YAAY;EAAiB,UAAU;CAAgB;CAClE;EAAE,SAAS,YAAY;EAAe,UAAU;CAAqB;CACrE;EAAE,SAAS,YAAY;EAAa,UAAU;CAAY;AAC5D,EACF,CAAC,CAAA,GAAA,UAAA"}
|
|
1
|
+
{"version":3,"file":"i18n.module-JOPUNpvi.mjs","names":[],"sources":["../src/i18n/services/i18n.service.ts","../src/i18n/messages/index.ts","../src/i18n/services/message-loader.service.ts","../src/i18n/services/message-registry.ts","../src/i18n/i18n.module.ts"],"sourcesContent":["import { inject } from '../../di'\nimport { Request } from '../../di/decorators'\nimport { ROUTER_TOKENS, type RouterContext } from '../../router'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport type { II18nService, MessageKeys, MessageParams } from '../i18n.types'\nimport type { MessageLoaderService } from './message-loader.service'\n\n@Request(I18N_TOKENS.I18nService)\nexport class I18nService implements II18nService {\n constructor(\n @inject(I18N_TOKENS.MessageLoader) private readonly loader: MessageLoaderService,\n @inject(ROUTER_TOKENS.RouterContext, { isOptional: true }) private readonly routerContext?: RouterContext\n ) {\n }\n\n t(key: MessageKeys, params?: MessageParams): string {\n return this.loader.translate(this.getLocale(), key, params as Record<string, unknown>)\n }\n\n getLocale(): string {\n return this.routerContext?.getLocale() ?? 'en'\n }\n}\n","/**\n * Core Messages\n *\n * Messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nimport * as en from './en'\n\n/**\n * All locale messages\n * Explicitly import and export (no filesystem scanning - Cloudflare Workers compatible)\n */\nexport const messages = { en } as const\n\n/**\n * Type for all messages\n */\nexport type Messages = typeof messages\n\n/**\n * Get messages for all locales\n */\nexport function getMessages(): Record<string, Record<string, unknown>> {\n return messages\n}\n\n/**\n * Get available locales\n */\nexport function getLocales(): string[] {\n return Object.keys(messages)\n}\n","import IntlMessageFormat from 'intl-messageformat'\nimport { inject } from '../../di'\nimport { Singleton } from '../../di/decorators'\nimport type { I18nModuleOptions } from '../i18n.options'\nimport type { MessageKeyPrefix } from '../i18n.types'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport { getLocales, getMessages } from '../messages'\nimport { deepMerge } from '../utils/deep-merge'\nimport type { MessageRegistry } from './message-registry'\n\ntype CompiledMessages = Record<string, (params?: Record<string, unknown>) => string>\n\n@Singleton(I18N_TOKENS.MessageLoader)\nexport class MessageLoaderService {\n private readonly cache: Map<string, Record<string, unknown>>\n private readonly compiledCache: Map<string, CompiledMessages>\n private readonly locales: string[]\n private readonly defaultLocale: string\n\n constructor(\n @inject(I18N_TOKENS.MessageRegistry) private readonly registry: MessageRegistry,\n @inject(I18N_TOKENS.Options, { isOptional: true })\n private readonly options?: I18nModuleOptions\n ) {\n this.defaultLocale = this.options?.defaultLocale ?? 'en'\n this.cache = new Map()\n this.compiledCache = new Map()\n\n const coreMessages = getMessages()\n const coreLocales = getLocales()\n\n const registryMessages = this.registry.getMergedMessages()\n const registryLocales = Object.keys(registryMessages)\n\n const allLocales = [...new Set([...coreLocales, ...registryLocales])]\n this.locales = allLocales\n\n for (const locale of allLocales) {\n const coreLocaleMessages = coreMessages[locale] ?? {}\n const registryLocaleMessages = registryMessages[locale] ?? {}\n\n const merged = deepMerge(coreLocaleMessages, registryLocaleMessages)\n this.cache.set(locale, merged)\n }\n }\n\n translate(locale: string, key: string, params?: Record<string, unknown>): string {\n const compiled = this.getCompiledMessages(locale)\n const fn = compiled[key]\n if (!fn) return key\n return fn(params)\n }\n\n getMessages(locale: string): Record<string, unknown> {\n return this.cache.get(locale) ?? this.cache.get(this.defaultLocale) ?? {}\n }\n\n getAvailableLocales(): string[] {\n return this.locales\n }\n\n isLocaleSupported(locale: string): boolean {\n return this.cache.has(locale)\n }\n\n getDefaultLocale(): string {\n return this.defaultLocale\n }\n\n getFilteredMessages(\n locale: string,\n options?: { only?: MessageKeyPrefix[] }\n ): Record<string, string> {\n const messages = this.getMessages(locale)\n const flattened = this.flattenMessages(messages)\n\n if (!options?.only?.length) return flattened\n\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(flattened)) {\n if (options.only.some((prefix) => key === prefix || key.startsWith(`${prefix}.`))) {\n result[key] = value\n }\n }\n return result\n }\n\n private getCompiledMessages(locale: string): CompiledMessages {\n const effectiveLocale = this.cache.has(locale) ? locale : this.defaultLocale\n\n const cached = this.compiledCache.get(effectiveLocale)\n if (cached) return cached\n\n const messages = this.cache.get(effectiveLocale) ?? {}\n const flattened = this.flattenMessages(messages)\n\n const compiled: CompiledMessages = {}\n for (const [key, value] of Object.entries(flattened)) {\n const msg = new IntlMessageFormat(value, effectiveLocale)\n compiled[key] = (params) => String(msg.format(params as Record<string, string | number | boolean>))\n }\n\n this.compiledCache.set(effectiveLocale, compiled)\n return compiled\n }\n\n private flattenMessages(\n messages: Record<string, unknown>,\n prefix = ''\n ): Record<string, string> {\n const result: Record<string, string> = {}\n\n for (const key of Object.keys(messages)) {\n const value = messages[key]\n const newKey = prefix ? `${prefix}.${key}` : key\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n Object.assign(result, this.flattenMessages(value as Record<string, unknown>, newKey))\n } else {\n result[newKey] = String(value)\n }\n }\n\n return result\n }\n}\n","import { Singleton } from '../../di/decorators'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport { deepMerge } from '../utils/deep-merge'\n\n/**\n * Global key for the shared contributions array.\n *\n * When stratal is installed via portal/symlink (e.g., in monorepos), bundlers\n * like esbuild may inline multiple copies of this module. Each copy gets its\n * own static class fields, so messages registered by one copy are invisible\n * to another. Using a `Symbol.for()` key on `globalThis` ensures all copies\n * share the same contributions array.\n */\nconst CONTRIBUTIONS_KEY = Symbol.for('stratal:i18n:message-registry:contributions')\n\ntype Contributions = Record<string, Record<string, unknown>>[]\n\nfunction getContributions(): Contributions {\n const g = globalThis as Record<symbol, unknown>\n g[CONTRIBUTIONS_KEY] ??= [];\n return g[CONTRIBUTIONS_KEY] as Contributions\n}\n\n/**\n * Message Registry\n *\n * Accumulates i18n messages from multiple `I18nModule.registerMessages()` calls.\n * Messages are collected statically (at module import time) and deep-merged\n * when `getMergedMessages()` is called by `MessageLoaderService`.\n *\n * Later registrations override earlier ones at leaf level.\n */\n@Singleton(I18N_TOKENS.MessageRegistry)\nexport class MessageRegistry {\n /**\n * Add messages (called statically by I18nModule.registerMessages)\n */\n static addMessages(messages: Record<string, Record<string, unknown>>): void {\n if (Boolean(messages) && typeof messages === 'object' && Object.keys(messages).length > 0) {\n getContributions().push(messages)\n }\n }\n\n /**\n * Get all messages deep-merged in registration order\n */\n getMergedMessages(): Record<string, Record<string, unknown>> {\n const merged: Record<string, Record<string, unknown>> = {}\n\n for (const contribution of getContributions()) {\n for (const locale of Object.keys(contribution)) {\n merged[locale] = deepMerge(\n (merged[locale] ?? {}),\n contribution[locale],\n )\n }\n }\n\n return merged\n }\n\n /**\n * Reset registry (for testing)\n * @internal\n */\n static reset(): void {\n (globalThis as Record<symbol, unknown>)[CONTRIBUTIONS_KEY] = []\n }\n}\n","import { Module } from '../module'\nimport type { DynamicModule, ModuleContext, OnInitialize } from '../module/types'\nimport type { I18nModuleOptions } from './i18n.options'\nimport { I18N_TOKENS } from './i18n.tokens'\nimport { I18nService } from './services/i18n.service'\nimport { MessageLoaderService } from './services/message-loader.service'\nimport { MessageRegistry } from './services/message-registry'\nimport { zodErrorMap } from './validation/validation.context'\nimport { z } from './validation/zod'\n\n@Module({\n providers: [\n { provide: I18N_TOKENS.MessageRegistry, useClass: MessageRegistry },\n { provide: I18N_TOKENS.MessageLoader, useClass: MessageLoaderService },\n { provide: I18N_TOKENS.I18nService, useClass: I18nService },\n ],\n})\nexport class I18nModule implements OnInitialize {\n onInitialize(_context: ModuleContext): void {\n z.config({ customError: zodErrorMap })\n }\n\n static forRoot(options: I18nModuleOptions = {}): DynamicModule {\n return {\n module: I18nModule,\n providers: [\n { provide: I18N_TOKENS.Options, useValue: options },\n ],\n }\n }\n\n static registerMessages(messages: Record<string, Record<string, unknown>>): DynamicModule {\n MessageRegistry.addMessages(messages)\n return {\n module: I18nModule,\n providers: [],\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dn as AsyncModuleOptions, Dr as ApplicationError, In as OnInitialize, Nn as ModuleContext, Y as Container, kn as DynamicModule } from "./index-
|
|
1
|
+
import { Dn as AsyncModuleOptions, Dr as ApplicationError, In as OnInitialize, Nn as ModuleContext, Y as Container, kn as DynamicModule } from "./index-C_t8VVQD.mjs";
|
|
2
2
|
import { t as StratalEnv } from "./env-ug22bJj7.mjs";
|
|
3
3
|
import { m as II18nService } from "./zod-wecrEVAs.mjs";
|
|
4
4
|
import { r as LoggerService } from "./index-BUt92sAE.mjs";
|
|
@@ -541,4 +541,4 @@ type QueueToken = (typeof QUEUE_TOKENS)[keyof typeof QUEUE_TOKENS];
|
|
|
541
541
|
declare class QueueError extends ApplicationError {}
|
|
542
542
|
//#endregion
|
|
543
543
|
export { QueueStore as _, FailedJobCleanupJob as a, QueueModule as b, QueueProviderFactory as c, CloudflareQueueProvider as d, IQueueProvider as f, DEFAULT_STORE_BINDING as g, QueueManager as h, InjectQueue as i, QueueSender as l, IQueueSender as m, QUEUE_TOKENS as n, failedJobCleanupJob as o, DispatchMessage as p, QueueToken as r, QueueRegistry as s, QueueError as t, SyncQueueProvider as u, FailedJob as v, QueueModuleOptions as x, FailedJobMetadata as y };
|
|
544
|
-
//# sourceMappingURL=index-
|
|
544
|
+
//# sourceMappingURL=index-BPJSBHhq.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-BPJSBHhq.d.mts","names":[],"sources":["../src/queue/queue.module.ts","../src/queue/failed-job.ts","../src/queue/queue-store.ts","../src/queue/queue-manager.ts","../src/queue/queue-sender.interface.ts","../src/queue/providers/queue-provider.interface.ts","../src/queue/providers/cloudflare-queue.provider.ts","../src/queue/providers/sync-queue.provider.ts","../src/queue/queue-sender.ts","../src/queue/services/queue-provider-factory.ts","../src/queue/queue-registry.ts","../src/queue/jobs/failed-job-cleanup.job.ts","../src/queue/decorators/inject-queue.decorator.ts","../src/queue/queue.tokens.ts","../src/queue/queue.error.ts"],"mappings":"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"}
|
|
@@ -491,6 +491,11 @@ interface WhenOptions {
|
|
|
491
491
|
type ExtensionDecorator<T> = (service: T, container: ContainerLike) => T;
|
|
492
492
|
interface ContainerLike {
|
|
493
493
|
resolve<T>(token: InjectionToken<T>): T;
|
|
494
|
+
/**
|
|
495
|
+
* Resolves an optional dependency: `undefined` when nothing is registered,
|
|
496
|
+
* or when a request-scoped provider is requested outside a request scope.
|
|
497
|
+
*/
|
|
498
|
+
tryResolve<T>(token: InjectionToken<T>): T | undefined;
|
|
494
499
|
}
|
|
495
500
|
//#endregion
|
|
496
501
|
//#region src/module/types.d.ts
|
|
@@ -2599,6 +2604,12 @@ declare class Container {
|
|
|
2599
2604
|
private collectDependencyTokens;
|
|
2600
2605
|
/** The implementing class for a token, following class/alias registrations. */
|
|
2601
2606
|
private classForToken;
|
|
2607
|
+
/**
|
|
2608
|
+
* The effective scope a token would resolve with, following alias
|
|
2609
|
+
* registrations. Bare constructor tokens fall back to their decorator
|
|
2610
|
+
* metadata — the same scope {@link resolve} uses when auto-registering.
|
|
2611
|
+
*/
|
|
2612
|
+
private scopeForToken;
|
|
2602
2613
|
/**
|
|
2603
2614
|
* Evict a token from the request cache along with every cached request-scoped
|
|
2604
2615
|
* instance that transitively depends on it. Re-registering a value must
|
|
@@ -2949,4 +2960,4 @@ declare class AuthError extends ApplicationError {
|
|
|
2949
2960
|
}
|
|
2950
2961
|
//#endregion
|
|
2951
2962
|
export { ConditionalBindingGive as $, LocaleUrlConfig as $n, applyLocalePrefix as $t, ErrorResponse as A, ExistingProvider as An, uuidParamSchema as At, Transient as B, ContainerLike as Bn, Put as Bt, HttpExceptionContext as C, ParsedArgument as Cn, StratalRouteMap as Cr, createDomainMiddleware as Ct, createHttpExceptionContext as D, AsyncModuleOptions as Dn, ApplicationError as Dr, paginatedResponseSchema as Dt, createCronExceptionContext as E, Quarry as En, DI_TOKENS as Er, errorResponseSchema as Et, defineMetadata as F, OnException as Fn, All as Ft, InjectParam as G, LazyToken as Gn, createMiddlewareChain as Gt, getInjectionTokens as H, InjectionToken as Hn, getControllerOptions as Ht, getMetadata as I, OnInitialize as In, Delete as It, ContainerError as J, StratalExecutionContext as Jn, generateConventionRouteName as Jt, ParamInjection as K, isLazyToken as Kn, extractDomainParamNames as Kt, hasMetadata as L, OnShutdown as Ln, Get as Lt, containerStorage as M, ModuleClass as Mn, Route as Mt, getContainer as N, ModuleContext as Nn, getRouteDecoratedMethods as Nt, createQueueExceptionContext as O, ClassProvider as On, paginationQuerySchema as Ot, runWithContainer as P, ModuleOptions as Pn, getRouteMetadata as Pt, ConditionalBindingBuilderImpl as Q, LocalePathConfig as Qn, applyTrailingSlash as Qt, Request as R, Provider as Rn, Patch as Rt, ExceptionContext as S, CommandResult as Sn, SerializedRoutes as Sr, VerifySignatureMiddleware as St, createCliExceptionContext as T, ParsedSignature as Tn, DIToken as Tr, commonErrorSchemas as Tt, inject as U, Scope as Un, getControllerRoute as Ut, getClassMetadata as V, ExtensionDecorator as Vn, Controller as Vt, INJECT_PARAM_METADATA_KEY as W, WhenOptions as Wn, getControllerVersion as Wt, ContainerOptions as X, ConventionRouteMetadata as Xn, sortRoutesBySpecificity as Xt, Container as Y, ControllerOptions as Yn, getPathSpecificityScore as Yt, ConditionalBindingBuilder as Z, ExplicitRouteMetadata as Zn, toOpenAPIPath as Zt, Reportable as _, Middleware as _n, RouteMatcher as _r, RouteNotFoundError as _t, isApplicationError as a, RegisteredRoute as an, RouteResponseObject as ar, Uri as at, CliExceptionContext as b, CommandInput as bn, RoutePrefixes as br, signUrl as bt, HttpException as c, VersioningService as cn, SecurityScheme as cr, Application as ct, ExceptionHandler as d, Router as dn, HTTP_METHODS as dr, SSEMessage as dt, shouldPrefixLocale as en, RouteBody as er, ConditionalBindingUse as et, ApplicationErrorConstructor as f, RouterGroupConfig as fn, ROUTER_CONTEXT_KEYS as fr, SSEStreamingApi$1 as ft, RenderableCallback as g, HonoApp as gn, CurrentRoute as gr, SchemaValidationError as gt, LogSeverity as h, ResolvedPath as hn, VERSION_NEUTRAL as hr, ResponseValidationError as ht, ContainerNotInitializedError as i, RouteRegistrationService as in, RouteResponse as ir, SignedUriOptions as it, isErrorResponse as j, FactoryProvider as jn, validationErrorResponseSchema as jt, Environment as k, DynamicModule as kn, successMessageSchema as kt, abort as l, ModuleRegistry as ln, TrailingSlashMode as lr, ApplicationConfig as lt, ErrorPageCallback as m, LocalePathService as mn, SECURITY_SCHEMES as mr, InvalidSignatureError as mt, DatabaseError as n, route as nn, RouteConfig as nr, ContextQueryResult as nt, InternalError as o, RouteRegistrationInput as on, RouterEnv as or, UriOptions as ot, ContextCallback as p, LocaleUrlService as pn, ROUTE_METADATA_KEYS as pr, StreamingApi$1 as pt, getMethodInjections as q, lazy as qn, extractParamNames as qt, StratalNotInitializedError as r, ROUTER_TOKENS as rn, RouteMetadata as rr, RouterContext as rt, HTTP_STATUS_MESSAGES as s, RouteRegistry as sn, RouterVariables as sr, buildRouteUrl as st, AuthError as t, stripLocalePrefix as tn, RouteBodyObject as tr, PredicateContainer as tt, DefaultExceptionHandler as u, RouteConfigurable as un, VersioningOptions as ur, ApplicationOptions as ut, ReportableCallback as v, Next$1 as vn, RouteName as vr, RouterError as vt, QueueExceptionContext as w, ParsedOption as wn, CONTAINER_TOKEN as wr, parseDomainPattern as wt, CronExceptionContext as x, CommandInternals as xn, SerializedRoute as xr, verifySignedUrl as xt, RespondCallback as y, IController as yn, RouteParams as yr, SignedUrlOptions as yt, Singleton as z, ValueProvider as zn, Post as zt };
|
|
2952
|
-
//# sourceMappingURL=index-
|
|
2963
|
+
//# sourceMappingURL=index-C_t8VVQD.d.mts.map
|