@theokit/http 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  TheoApp
3
- } from "./chunk-GQ2UH554.js";
4
- import "./chunk-QGB5YC4T.js";
3
+ } from "./chunk-GXTGOPRU.js";
4
+ import "./chunk-JQMJK47T.js";
5
5
  import "./chunk-HLW7YKZE.js";
6
- import "./chunk-3PGQVQWG.js";
6
+ import "./chunk-KPC7AIVC.js";
7
7
  import "./chunk-7QVYU63E.js";
8
8
  export {
9
9
  TheoApp
@@ -2,7 +2,7 @@ import {
2
2
  CATCH_EXCEPTIONS,
3
3
  HttpException,
4
4
  getMeta
5
- } from "./chunk-3PGQVQWG.js";
5
+ } from "./chunk-KPC7AIVC.js";
6
6
  import {
7
7
  resolveOrNew
8
8
  } from "./chunk-MQAJWR3K.js";
@@ -68,4 +68,4 @@ __name(globalFallback, "globalFallback");
68
68
  export {
69
69
  runExceptionFilters
70
70
  };
71
- //# sourceMappingURL=chunk-6W4T4DPJ.js.map
71
+ //# sourceMappingURL=chunk-CMPP4ULU.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createExecutionContext,
3
3
  walkControllerMetadata
4
- } from "./chunk-QGB5YC4T.js";
4
+ } from "./chunk-JQMJK47T.js";
5
5
  import {
6
6
  createNodeAdapter
7
7
  } from "./chunk-HLW7YKZE.js";
8
8
  import {
9
9
  ForbiddenException,
10
10
  HttpException
11
- } from "./chunk-3PGQVQWG.js";
11
+ } from "./chunk-KPC7AIVC.js";
12
12
  import {
13
13
  __name
14
14
  } from "./chunk-7QVYU63E.js";
@@ -678,7 +678,7 @@ var TheoApp = class _TheoApp {
678
678
  return buildResponse(result, entry.walk, method);
679
679
  } catch (err) {
680
680
  if (entry.walk.filters.length > 0) {
681
- const { runExceptionFilters } = await import("./exception-filter-chain-O45FXGEB.js");
681
+ const { runExceptionFilters } = await import("./exception-filter-chain-V2MFO4WV.js");
682
682
  return runExceptionFilters(err, entry.walk.filters, request);
683
683
  }
684
684
  if (err instanceof HttpException) {
@@ -787,4 +787,4 @@ export {
787
787
  streamToResponse,
788
788
  TheoApp
789
789
  };
790
- //# sourceMappingURL=chunk-GQ2UH554.js.map
790
+ //# sourceMappingURL=chunk-GXTGOPRU.js.map
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  CONTROLLER_PREFIX,
3
+ EXPOSE_AGENT,
3
4
  ROUTE_HEADERS,
4
5
  ROUTE_METHODS,
5
6
  ROUTE_PARAMS,
@@ -9,7 +10,7 @@ import {
9
10
  USE_GUARDS,
10
11
  USE_INTERCEPTORS,
11
12
  getMeta
12
- } from "./chunk-3PGQVQWG.js";
13
+ } from "./chunk-KPC7AIVC.js";
13
14
  import {
14
15
  __name
15
16
  } from "./chunk-7QVYU63E.js";
@@ -110,8 +111,34 @@ function walkControllerMetadata(ControllerClass) {
110
111
  filters: getMeta(USE_FILTERS, ControllerClass, m.propertyKey) ?? classFilters
111
112
  };
112
113
  });
113
- walkCache.set(ControllerClass, result);
114
- return result;
114
+ const exposeEntries = getMeta(EXPOSE_AGENT, ControllerClass) ?? [];
115
+ const agentResults = exposeEntries.map((e) => {
116
+ const memberGuards = getMeta(USE_GUARDS, ControllerClass, e.propertyKey) ?? [];
117
+ const verb = "POST";
118
+ return {
119
+ verb,
120
+ fullPath: joinPath(prefix, String(e.propertyKey)),
121
+ propertyKey: e.propertyKey,
122
+ paramEntries: [],
123
+ headers: [],
124
+ guards: [
125
+ ...classGuards,
126
+ ...memberGuards
127
+ ],
128
+ interceptors: [],
129
+ filters: classFilters,
130
+ agent: {
131
+ module: e.agent,
132
+ opts: e.opts
133
+ }
134
+ };
135
+ });
136
+ const all = [
137
+ ...result,
138
+ ...agentResults
139
+ ];
140
+ walkCache.set(ControllerClass, all);
141
+ return all;
115
142
  }
116
143
  __name(walkControllerMetadata, "walkControllerMetadata");
117
144
 
@@ -122,4 +149,4 @@ export {
122
149
  joinPath,
123
150
  walkControllerMetadata
124
151
  };
125
- //# sourceMappingURL=chunk-QGB5YC4T.js.map
152
+ //# sourceMappingURL=chunk-JQMJK47T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridge/execution-context.ts","../src/bridge/dto-zod.ts","../src/bridge/errors.ts","../src/bridge/walk-metadata.ts"],"sourcesContent":["/**\n * ExecutionContext — Web Standard Request-based context passed to guards.\n *\n * Per ADR D460: the pipeline operates on Web Standard Request/Response.\n * node:http types live ONLY in the runtime adapter (runtime/node.ts).\n *\n * Guards access request headers via request.headers.get('x-role'),\n * NOT via req.headers['x-role'].\n */\n\n/**\n * Execution context available in guards during request processing.\n * Uses Web Standard Request (works on Node, Bun, Deno, CF Workers).\n */\nexport interface ExecutionContext {\n /** The Web Standard Request object. */\n getRequest(): Request\n /** Parsed URL (convenience — avoids re-parsing). */\n getUrl(): URL\n /** The controller class constructor. */\n getClass(): Function\n /** The handler method name (property key on the controller). */\n getMethodName(): string | symbol\n}\n\n/**\n * Interface for guard classes (bound via @UseGuards).\n *\n * @example\n * ```ts\n * class RolesGuard implements CanActivate {\n * canActivate(context: ExecutionContext): boolean {\n * const request = context.getRequest()\n * const role = request.headers.get('x-role')\n * return role === 'admin'\n * }\n * }\n * ```\n */\nexport interface CanActivate {\n canActivate(context: ExecutionContext): boolean | Promise<boolean>\n}\n\n/** Create an ExecutionContext from a Web Standard Request. */\nexport function createExecutionContext(\n request: Request,\n controllerClass: Function,\n methodName: string | symbol,\n): ExecutionContext {\n const url = new URL(request.url)\n return {\n getRequest: () => request,\n getUrl: () => url,\n getClass: () => controllerClass,\n getMethodName: () => methodName,\n }\n}\n","import type { z } from 'zod'\n\n/**\n * Resolves a Zod schema from a DTO class via the `static schema` convention (Pattern D2).\n * Returns undefined when the class doesn't carry a compatible schema.\n */\nexport function resolveDtoSchema(dtoClass: unknown): z.ZodType | undefined {\n if (typeof dtoClass !== 'function') return undefined\n const maybe = (dtoClass as unknown as Record<string, unknown>).schema\n if (\n maybe !== null &&\n maybe !== undefined &&\n typeof (maybe as Record<string, unknown>).safeParse === 'function'\n ) {\n return maybe as z.ZodType\n }\n return undefined\n}\n","/**\n * Configuration error thrown by the bridge when decorator setup is incomplete.\n * Carries actionable messages pointing consumers to the migration guide.\n */\nexport class HttpDecoratorsConfigError extends Error {\n override readonly name = 'HttpDecoratorsConfigError'\n\n constructor(message: string) {\n super(message)\n }\n}\n","import 'reflect-metadata'\nimport type { z } from 'zod'\n\nimport type { ControllerMeta } from '../decorators/controller.js'\nimport type { ExposeEntry, ExposeOptions } from '../decorators/expose.js'\nimport type { RouteMethodEntry, HttpVerb } from '../decorators/methods.js'\nimport type { ParamEntry } from '../decorators/params.js'\nimport type { RedirectMeta } from '../decorators/response.js'\nimport {\n getMeta,\n CONTROLLER_PREFIX,\n EXPOSE_AGENT,\n ROUTE_METHODS,\n ROUTE_PARAMS,\n ROUTE_STATUS,\n ROUTE_HEADERS,\n ROUTE_REDIRECT,\n USE_GUARDS,\n USE_INTERCEPTORS,\n USE_FILTERS,\n} from '../metadata/index.js'\n\nimport { resolveDtoSchema } from './dto-zod.js'\nimport { HttpDecoratorsConfigError } from './errors.js'\n\nexport interface WalkResult {\n verb: HttpVerb\n fullPath: string\n propertyKey: string | symbol\n bodySchema?: z.ZodType\n querySchema?: z.ZodType\n paramsSchema?: z.ZodType\n paramEntries: ParamEntry[]\n status?: number\n headers: [string, string][]\n redirect?: RedirectMeta\n guards: Function[]\n interceptors: Function[]\n filters: Function[]\n /**\n * M47 — set when the member is bound via `@Expose(agent, opts)`. The dispatcher delegates such routes to\n * the agent runtime (`mountAgent`) instead of invoking a JSON handler. `undefined` for normal verb routes.\n */\n agent?: { module: unknown; opts: ExposeOptions }\n}\n\n/**\n * Normalize a joined path: strip doubles, trim trailing, ensure leading.\n * (EC-3)\n */\nexport function joinPath(prefix: string, path: string): string {\n return ('/' + prefix + '/' + path).replace(/\\/+/g, '/').replace(/\\/$/, '') || '/'\n}\n\n/**\n * Resolve the Zod body schema for a method's @Body() param entry.\n *\n * Priority: explicit @Body(zodSchema) > design:paramtypes + DTO static schema.\n * EC-4 relaxed: warns (not throws) when paramtypes missing — @Body(zodSchema) is the fix.\n */\nfunction resolveBodySchema(\n paramEntries: ParamEntry[],\n ControllerClass: Function,\n propertyKey: string | symbol,\n): z.ZodType | undefined {\n const bodyParam = paramEntries.find((p) => p.source === 'body' && !p.key)\n if (!bodyParam) return undefined\n\n // Priority 1: explicit Zod schema from @Body(zodSchema)\n if (bodyParam.schema) return bodyParam.schema\n\n // Priority 2: design:paramtypes + DTO static schema (requires emitDecoratorMetadata)\n const paramTypes: Function[] =\n Reflect.getMetadata('design:paramtypes', ControllerClass.prototype, propertyKey) ?? []\n if (paramTypes.length > 0) {\n return resolveDtoSchema(paramTypes[bodyParam.index])\n }\n\n // EC-4 relaxed: warn when @Body() has no schema and no paramtypes\n console.warn(\n `[@theokit/http] method ${String(propertyKey)} on ` +\n `${ControllerClass.name}: @Body() without explicit schema and ` +\n `emitDecoratorMetadata is not active. Body will be passed raw (no validation). ` +\n `Fix: use @Body(zodSchema) for validation without metadata emission.`,\n )\n return undefined\n}\n\n/** WeakMap cache — metadata is immutable; walk once, reuse forever. */\nconst walkCache = new WeakMap<Function, WalkResult[]>()\n\n/**\n * Walk all decorator metadata on a controller class and produce\n * a structured list of route descriptors. Memoized per class via WeakMap.\n */\nexport function walkControllerMetadata(ControllerClass: Function): WalkResult[] {\n const cached = walkCache.get(ControllerClass)\n if (cached) return cached\n // EC-2: throw when @Controller decorator is missing\n const controllerMeta = getMeta<ControllerMeta>(CONTROLLER_PREFIX, ControllerClass)\n if (!controllerMeta) {\n throw new HttpDecoratorsConfigError(\n `Controller class ${ControllerClass.name} is missing @Controller() decorator. ` +\n `Add @Controller('prefix') to the class declaration.`,\n )\n }\n const { prefix, host } = controllerMeta\n\n // Q4: host captured but enforcement deferred to v0.2.0\n if (host) {\n console.warn(\n `[@theokit/http] @Controller host '${host}' captured but enforcement deferred to v0.2.0`,\n )\n }\n\n const methods = getMeta<RouteMethodEntry[]>(ROUTE_METHODS, ControllerClass) ?? []\n const paramsMap =\n getMeta<Map<string | symbol, ParamEntry[]>>(ROUTE_PARAMS, ControllerClass) ?? new Map()\n\n // Class-level guards/interceptors\n const classGuards = getMeta<Function[]>(USE_GUARDS, ControllerClass) ?? []\n const classInterceptors = getMeta<Function[]>(USE_INTERCEPTORS, ControllerClass) ?? []\n const classFilters = getMeta<Function[]>(USE_FILTERS, ControllerClass) ?? []\n\n const result = methods.map((m) => {\n const paramEntries = paramsMap.get(m.propertyKey) ?? []\n const bodySchema = resolveBodySchema(paramEntries, ControllerClass, m.propertyKey)\n\n // Method-level guards/interceptors (composed: class FIRST per NestJS convention — EC-9)\n const methodGuards = getMeta<Function[]>(USE_GUARDS, ControllerClass, m.propertyKey) ?? []\n const methodInterceptors =\n getMeta<Function[]>(USE_INTERCEPTORS, ControllerClass, m.propertyKey) ?? []\n\n return {\n verb: m.verb,\n fullPath: joinPath(prefix, m.path),\n propertyKey: m.propertyKey,\n bodySchema,\n paramEntries: [...paramEntries].sort((a, b) => a.index - b.index),\n status: getMeta<number>(ROUTE_STATUS, ControllerClass, m.propertyKey),\n headers: getMeta<[string, string][]>(ROUTE_HEADERS, ControllerClass, m.propertyKey) ?? [],\n redirect: getMeta<RedirectMeta>(ROUTE_REDIRECT, ControllerClass, m.propertyKey),\n guards: [...classGuards, ...methodGuards],\n interceptors: [...classInterceptors, ...methodInterceptors],\n filters: getMeta<Function[]>(USE_FILTERS, ControllerClass, m.propertyKey) ?? classFilters,\n }\n })\n\n // M47 — @Expose-bound members have no verb decorator, so they are absent from `methods`. Produce an\n // agent-serving WalkResult per binding: verb POST (agents are POST), path = prefix + member name (this\n // MUST be the agent's convention route so the generated handle's path matches — see ExposeOptions), the\n // agent module carried for the dispatcher, guards composed class-first (G5 shared guards). Interceptors\n // do NOT run for agent routes — the dispatcher delegates straight to `mountAgent` before the interceptor\n // chain — so they are intentionally not collected here (documented on `@Expose`).\n const exposeEntries = getMeta<ExposeEntry[]>(EXPOSE_AGENT, ControllerClass) ?? []\n const agentResults: WalkResult[] = exposeEntries.map((e) => {\n const memberGuards = getMeta<Function[]>(USE_GUARDS, ControllerClass, e.propertyKey) ?? []\n const verb: HttpVerb = 'POST'\n return {\n verb,\n fullPath: joinPath(prefix, String(e.propertyKey)),\n propertyKey: e.propertyKey,\n paramEntries: [],\n headers: [],\n guards: [...classGuards, ...memberGuards],\n interceptors: [],\n filters: classFilters,\n agent: { module: e.agent, opts: e.opts },\n }\n })\n\n const all = [...result, ...agentResults]\n walkCache.set(ControllerClass, all)\n return all\n}\n"],"mappings":"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","names":["createExecutionContext","request","controllerClass","methodName","url","URL","getRequest","getUrl","getClass","getMethodName","resolveDtoSchema","dtoClass","undefined","maybe","schema","safeParse","HttpDecoratorsConfigError","Error","name","message","joinPath","prefix","path","replace","resolveBodySchema","paramEntries","ControllerClass","propertyKey","bodyParam","find","p","source","key","undefined","schema","paramTypes","Reflect","getMetadata","prototype","length","resolveDtoSchema","index","console","warn","String","name","walkCache","WeakMap","walkControllerMetadata","cached","get","controllerMeta","getMeta","CONTROLLER_PREFIX","HttpDecoratorsConfigError","host","methods","ROUTE_METHODS","paramsMap","ROUTE_PARAMS","Map","classGuards","USE_GUARDS","classInterceptors","USE_INTERCEPTORS","classFilters","USE_FILTERS","result","map","m","bodySchema","methodGuards","methodInterceptors","verb","fullPath","sort","a","b","status","ROUTE_STATUS","headers","ROUTE_HEADERS","redirect","ROUTE_REDIRECT","guards","interceptors","filters","exposeEntries","EXPOSE_AGENT","agentResults","e","memberGuards","agent","module","opts","all","set"]}
@@ -13,6 +13,7 @@ var USE_GUARDS = /* @__PURE__ */ Symbol.for("theokit:http-decorators:use-guards"
13
13
  var USE_INTERCEPTORS = /* @__PURE__ */ Symbol.for("theokit:http-decorators:use-interceptors");
14
14
  var USE_FILTERS = /* @__PURE__ */ Symbol.for("theokit:http-decorators:use-filters");
15
15
  var CATCH_EXCEPTIONS = /* @__PURE__ */ Symbol.for("theokit:http-decorators:catch-exceptions");
16
+ var EXPOSE_AGENT = /* @__PURE__ */ Symbol.for("theokit:http-decorators:expose-agent");
16
17
 
17
18
  // src/metadata/storage.ts
18
19
  import "reflect-metadata";
@@ -247,6 +248,7 @@ export {
247
248
  USE_INTERCEPTORS,
248
249
  USE_FILTERS,
249
250
  CATCH_EXCEPTIONS,
251
+ EXPOSE_AGENT,
250
252
  setMeta,
251
253
  getMeta,
252
254
  HttpException,
@@ -273,4 +275,4 @@ export {
273
275
  TooManyRequestsException,
274
276
  HttpStatus
275
277
  };
276
- //# sourceMappingURL=chunk-3PGQVQWG.js.map
278
+ //# sourceMappingURL=chunk-KPC7AIVC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/metadata/keys.ts","../src/metadata/storage.ts","../src/exceptions/http-exception.ts"],"sourcesContent":["/**\n * Global Symbol-keyed metadata namespace constants for @theokit/http.\n *\n * Uses Symbol.for() (global Symbol registry) instead of Symbol() (local) because\n * the SWC loader imports controller files as separate module instances. With local\n * Symbols, the decorator-set metadata keys would be different Symbol instances from\n * the keys used by walkControllerMetadata — making metadata lookup silently fail.\n *\n * Symbol.for() ensures the SAME Symbol instance across module boundaries, which is\n * exactly how reflect-metadata keys should work in a multi-module decorator system.\n */\n\nexport const CONTROLLER_PREFIX = Symbol.for('theokit:http-decorators:controller-prefix')\nexport const ROUTE_METHODS = Symbol.for('theokit:http-decorators:route-methods')\nexport const ROUTE_PARAMS = Symbol.for('theokit:http-decorators:route-params')\nexport const ROUTE_STATUS = Symbol.for('theokit:http-decorators:route-status')\nexport const ROUTE_HEADERS = Symbol.for('theokit:http-decorators:route-headers')\nexport const ROUTE_REDIRECT = Symbol.for('theokit:http-decorators:route-redirect')\nexport const USE_GUARDS = Symbol.for('theokit:http-decorators:use-guards')\nexport const USE_INTERCEPTORS = Symbol.for('theokit:http-decorators:use-interceptors')\nexport const USE_FILTERS = Symbol.for('theokit:http-decorators:use-filters')\nexport const CATCH_EXCEPTIONS = Symbol.for('theokit:http-decorators:catch-exceptions')\nexport const EXPOSE_AGENT = Symbol.for('theokit:http-decorators:expose-agent')\n","import 'reflect-metadata'\n\n/**\n * Typed facade over Reflect.defineMetadata / Reflect.getMetadata.\n * Centralizes all reflect-metadata calls so decorators + bridge\n * never call Reflect.* directly (single import point for the polyfill).\n */\n\nexport function setMeta<T>(\n key: symbol,\n target: object,\n value: T,\n propertyKey?: string | symbol,\n): void {\n if (propertyKey !== undefined) {\n Reflect.defineMetadata(key, value, target, propertyKey)\n } else {\n Reflect.defineMetadata(key, value, target)\n }\n}\n\nexport function getMeta<T>(\n key: symbol,\n target: object,\n propertyKey?: string | symbol,\n): T | undefined {\n if (propertyKey !== undefined) {\n return Reflect.getMetadata(key, target, propertyKey) as T | undefined\n }\n return Reflect.getMetadata(key, target) as T | undefined\n}\n","/**\n * HttpException hierarchy for @theokit/http.\n *\n * Per ADR D2: response shape {error: {code, message, statusCode}} matches\n * existing guard (401) and validation (422) format.\n */\n\nconst STATUS_CODES: Record<number, string> = {\n 400: 'BAD_REQUEST',\n 401: 'UNAUTHORIZED',\n 403: 'FORBIDDEN',\n 404: 'NOT_FOUND',\n 405: 'METHOD_NOT_ALLOWED',\n 406: 'NOT_ACCEPTABLE',\n 408: 'REQUEST_TIMEOUT',\n 409: 'CONFLICT',\n 410: 'GONE',\n 412: 'PRECONDITION_FAILED',\n 413: 'PAYLOAD_TOO_LARGE',\n 415: 'UNSUPPORTED_MEDIA_TYPE',\n 418: 'IM_A_TEAPOT',\n 422: 'UNPROCESSABLE_ENTITY',\n 429: 'TOO_MANY_REQUESTS',\n 500: 'INTERNAL_SERVER_ERROR',\n 501: 'NOT_IMPLEMENTED',\n 502: 'BAD_GATEWAY',\n 503: 'SERVICE_UNAVAILABLE',\n 504: 'GATEWAY_TIMEOUT',\n 505: 'HTTP_VERSION_NOT_SUPPORTED',\n}\n\nexport interface HttpExceptionOptions {\n cause?: Error\n description?: string\n}\n\nexport class HttpException extends Error {\n public readonly statusCode: number\n public readonly code: string\n public readonly description?: string\n\n constructor(message: string, statusCode: number, options?: HttpExceptionOptions) {\n super(message, options?.cause ? { cause: options.cause } : undefined)\n this.name = this.constructor.name\n this.statusCode = statusCode\n this.code = STATUS_CODES[statusCode] ?? 'INTERNAL_SERVER_ERROR'\n this.description = options?.description\n }\n\n toJSON() {\n return {\n error: {\n code: this.code,\n message: this.message,\n statusCode: this.statusCode,\n ...(this.description ? { description: this.description } : {}),\n },\n }\n }\n}\n\nfunction factory(status: number, defaultMsg: string) {\n return class extends HttpException {\n constructor(message = defaultMsg, options?: HttpExceptionOptions) {\n super(message, status, options)\n this.name = this.constructor.name\n }\n }\n}\n\nexport class BadRequestException extends factory(400, 'Bad Request') {}\nexport class UnauthorizedException extends factory(401, 'Unauthorized') {}\nexport class ForbiddenException extends factory(403, 'Forbidden') {}\nexport class NotFoundException extends factory(404, 'Not Found') {}\nexport class MethodNotAllowedException extends factory(405, 'Method Not Allowed') {}\nexport class NotAcceptableException extends factory(406, 'Not Acceptable') {}\nexport class RequestTimeoutException extends factory(408, 'Request Timeout') {}\nexport class ConflictException extends factory(409, 'Conflict') {}\nexport class GoneException extends factory(410, 'Gone') {}\nexport class PreconditionFailedException extends factory(412, 'Precondition Failed') {}\nexport class PayloadTooLargeException extends factory(413, 'Payload Too Large') {}\nexport class UnsupportedMediaTypeException extends factory(415, 'Unsupported Media Type') {}\nexport class ImATeapotException extends factory(418, \"I'm a Teapot\") {}\nexport class UnprocessableEntityException extends factory(422, 'Unprocessable Entity') {}\nexport class InternalServerErrorException extends factory(500, 'Internal Server Error') {}\nexport class NotImplementedException extends factory(501, 'Not Implemented') {}\nexport class BadGatewayException extends factory(502, 'Bad Gateway') {}\nexport class ServiceUnavailableException extends factory(503, 'Service Unavailable') {}\nexport class GatewayTimeoutException extends factory(504, 'Gateway Timeout') {}\nexport class HttpVersionNotSupportedException extends factory(505, 'HTTP Version Not Supported') {}\nexport class TooManyRequestsException extends factory(429, 'Too Many Requests') {}\n\n/**\n * HttpStatus enum — all standard HTTP status codes as named constants.\n *\n * @example\n * ```ts\n * import { HttpStatus } from '@theokit/http'\n *\n * @HttpCode(HttpStatus.CREATED)\n * @Post()\n * create() { ... }\n *\n * if (res.status === HttpStatus.NOT_FOUND) { ... }\n * ```\n */\nexport const HttpStatus = {\n // 2xx Success\n OK: 200,\n CREATED: 201,\n ACCEPTED: 202,\n NO_CONTENT: 204,\n\n // 3xx Redirection\n MOVED_PERMANENTLY: 301,\n FOUND: 302,\n NOT_MODIFIED: 304,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n\n // 4xx Client Error\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n NOT_ACCEPTABLE: 406,\n REQUEST_TIMEOUT: 408,\n CONFLICT: 409,\n GONE: 410,\n PRECONDITION_FAILED: 412,\n PAYLOAD_TOO_LARGE: 413,\n UNSUPPORTED_MEDIA_TYPE: 415,\n IM_A_TEAPOT: 418,\n UNPROCESSABLE_ENTITY: 422,\n TOO_MANY_REQUESTS: 429,\n\n // 5xx Server Error\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n BAD_GATEWAY: 502,\n SERVICE_UNAVAILABLE: 503,\n GATEWAY_TIMEOUT: 504,\n} as const\n\nexport type HttpStatusCode = (typeof HttpStatus)[keyof typeof HttpStatus]\n"],"mappings":"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","names":["CONTROLLER_PREFIX","Symbol","for","ROUTE_METHODS","ROUTE_PARAMS","ROUTE_STATUS","ROUTE_HEADERS","ROUTE_REDIRECT","USE_GUARDS","USE_INTERCEPTORS","USE_FILTERS","CATCH_EXCEPTIONS","EXPOSE_AGENT","setMeta","key","target","value","propertyKey","undefined","Reflect","defineMetadata","getMeta","getMetadata","STATUS_CODES","HttpException","Error","statusCode","code","description","message","options","cause","undefined","name","toJSON","error","factory","status","defaultMsg","BadRequestException","UnauthorizedException","ForbiddenException","NotFoundException","MethodNotAllowedException","NotAcceptableException","RequestTimeoutException","ConflictException","GoneException","PreconditionFailedException","PayloadTooLargeException","UnsupportedMediaTypeException","ImATeapotException","UnprocessableEntityException","InternalServerErrorException","NotImplementedException","BadGatewayException","ServiceUnavailableException","GatewayTimeoutException","HttpVersionNotSupportedException","TooManyRequestsException","HttpStatus","OK","CREATED","ACCEPTED","NO_CONTENT","MOVED_PERMANENTLY","FOUND","NOT_MODIFIED","TEMPORARY_REDIRECT","PERMANENT_REDIRECT","BAD_REQUEST","UNAUTHORIZED","PAYMENT_REQUIRED","FORBIDDEN","NOT_FOUND","METHOD_NOT_ALLOWED","NOT_ACCEPTABLE","REQUEST_TIMEOUT","CONFLICT","GONE","PRECONDITION_FAILED","PAYLOAD_TOO_LARGE","UNSUPPORTED_MEDIA_TYPE","IM_A_TEAPOT","UNPROCESSABLE_ENTITY","TOO_MANY_REQUESTS","INTERNAL_SERVER_ERROR","NOT_IMPLEMENTED","BAD_GATEWAY","SERVICE_UNAVAILABLE","GATEWAY_TIMEOUT"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HttpDecoratorsConfigError
3
- } from "./chunk-QGB5YC4T.js";
3
+ } from "./chunk-JQMJK47T.js";
4
4
  import {
5
5
  resolveOrNew
6
6
  } from "./chunk-MQAJWR3K.js";
@@ -254,4 +254,4 @@ export {
254
254
  loadControllersFromGlob,
255
255
  isControllerClass
256
256
  };
257
- //# sourceMappingURL=chunk-RC4V75DI.js.map
257
+ //# sourceMappingURL=chunk-OBHHOS6E.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  runExceptionFilters
3
- } from "./chunk-6W4T4DPJ.js";
4
- import "./chunk-3PGQVQWG.js";
3
+ } from "./chunk-CMPP4ULU.js";
4
+ import "./chunk-KPC7AIVC.js";
5
5
  import "./chunk-MQAJWR3K.js";
6
6
  import "./chunk-7QVYU63E.js";
7
7
  export {
8
8
  runExceptionFilters
9
9
  };
10
- //# sourceMappingURL=exception-filter-chain-O45FXGEB.js.map
10
+ //# sourceMappingURL=exception-filter-chain-V2MFO4WV.js.map
package/dist/index.d.ts CHANGED
@@ -70,6 +70,50 @@ declare function Res(opts?: {
70
70
  passthrough?: boolean;
71
71
  }): ParameterDecorator;
72
72
 
73
+ /**
74
+ * M47 (ADR-M47-1) — `@Expose(agent, opts?)` binds a SEPARATELY-BUILT agent (a pure `agent()…build()` from
75
+ * `agents/<name>.ts`) to a controller PROPERTY, making the exposure (route, auth via `@UseGuards`, streaming)
76
+ * visible in one code review. It mirrors the #122 verb decorators (`@Post`) — storing metadata via the same
77
+ * `Symbol.for()` seam — but records the agent instead of an HTTP verb, so the controller walker turns the
78
+ * property into an agent-serving route (`POST <prefix>/<property>`) delegated to the ONE runtime
79
+ * (`mountAgent`), never a JSON handler. It is a new AUTHORING surface over the existing runtime, not a
80
+ * parallel runtime (G2). CSRF is enforced once at the controller-dispatch boundary. Interceptors do NOT run
81
+ * for agent routes (the dispatcher delegates straight to `mountAgent`); guards DO (G5). The served path is
82
+ * the controller prefix + property name — keep it equal to the agent's convention route (`/api/agents/<name>`
83
+ * for a property named `<name>` under `@Controller('api/agents')`) so the generated `useAgent(handle)` path
84
+ * lines up.
85
+ */
86
+ /**
87
+ * Per-binding options for an exposed agent. Reserved for forward-compat — no options are wired yet.
88
+ *
89
+ * Two candidate fields were removed before shipping (M47 review): `path` (a route override) would let the
90
+ * served URL diverge from the generated handle's path — the codegen derives the handle from the agent's
91
+ * convention route (`/api/agents/<name>`), so an overridden route would make `useAgent(handle)` hit the
92
+ * wrong URL. And `csrf` was a no-op — CSRF is enforced exactly once at the controller-dispatch boundary
93
+ * regardless. Both return only when they can be wired end-to-end (codegen reads `@Expose` metadata / a
94
+ * per-route CSRF opt-out threads through the dispatcher). Until then, `@Expose(agent)` is the shape, and the
95
+ * exposure's path MUST be the convention route — put `@Expose` on a property named after the agent under
96
+ * `@Controller('api/agents')` (e.g. `chat` for `agents/chat.ts` → `/api/agents/chat`).
97
+ */
98
+ type ExposeOptions = Record<string, never>;
99
+ /** Metadata recorded per `@Expose`-decorated controller member. */
100
+ interface ExposeEntry {
101
+ /** The separately-built agent module bound to this member. */
102
+ agent: unknown;
103
+ /** The per-binding options (defaulted to `{}`). */
104
+ opts: ExposeOptions;
105
+ /** The controller member the binding is attached to. */
106
+ propertyKey: string | symbol;
107
+ }
108
+ /**
109
+ * Bind an agent to a controller PROPERTY. Accumulates one {@link ExposeEntry} per member under the
110
+ * `EXPOSE_AGENT` metadata key on the controller constructor — the same accumulation shape `@Post` uses for
111
+ * `ROUTE_METHODS`, so `walkControllerMetadata` reads both alongside each other. Typed as `PropertyDecorator`
112
+ * (the exposure is declared as a property, e.g. `@Expose(chatAgent) chat!: typeof chatAgent`); the agent's
113
+ * behavior lives in its own `agents/<name>.ts`, never in a controller method body.
114
+ */
115
+ declare function Expose(agent: unknown, opts?: ExposeOptions): PropertyDecorator;
116
+
73
117
  declare function HttpCode(status: number): MethodDecorator;
74
118
  declare function Header(name: string, value: string): MethodDecorator;
75
119
  interface RedirectMeta {
@@ -78,7 +122,7 @@ interface RedirectMeta {
78
122
  }
79
123
  declare function Redirect(url: string, status?: number): MethodDecorator;
80
124
 
81
- declare function UseGuards(...guards: Function[]): ClassDecorator & MethodDecorator;
125
+ declare function UseGuards(...guards: Function[]): ClassDecorator & MethodDecorator & PropertyDecorator;
82
126
  declare function UseInterceptors(...interceptors: Function[]): ClassDecorator & MethodDecorator;
83
127
  declare function UseFilters(...filters: Function[]): ClassDecorator & MethodDecorator;
84
128
  /** @Catch(ExceptionType, ...) — marks which exception types an ExceptionFilter handles.
@@ -223,6 +267,7 @@ declare const USE_GUARDS: unique symbol;
223
267
  declare const USE_INTERCEPTORS: unique symbol;
224
268
  declare const USE_FILTERS: unique symbol;
225
269
  declare const CATCH_EXCEPTIONS: unique symbol;
270
+ declare const EXPOSE_AGENT: unique symbol;
226
271
 
227
272
  /**
228
273
  * Typed facade over Reflect.defineMetadata / Reflect.getMetadata.
@@ -343,6 +388,14 @@ interface WalkResult {
343
388
  guards: Function[];
344
389
  interceptors: Function[];
345
390
  filters: Function[];
391
+ /**
392
+ * M47 — set when the member is bound via `@Expose(agent, opts)`. The dispatcher delegates such routes to
393
+ * the agent runtime (`mountAgent`) instead of invoking a JSON handler. `undefined` for normal verb routes.
394
+ */
395
+ agent?: {
396
+ module: unknown;
397
+ opts: ExposeOptions;
398
+ };
346
399
  }
347
400
  /**
348
401
  * Normalize a joined path: strip doubles, trim trailing, ensure leading.
@@ -427,13 +480,16 @@ interface RouteRegistration {
427
480
  declare function registerControllers(controllers: Function[]): RouteRegistration[];
428
481
 
429
482
  /**
430
- * Creates a real HTTP server from decorated controller classes.
431
- * Uses Web Standard Request/Response internally; Node adapter at the boundary.
483
+ * M47 serves an `@Expose`-bound agent route. http is agent-runtime agnostic (G1/G2): it invokes this
484
+ * injected callback (theo supplies a `mountAgent`-backed impl) instead of calling a controller method.
432
485
  */
486
+ type ServeAgent = (agent: unknown, request: Request, opts: ExposeOptions) => Promise<Response>;
433
487
  interface CreateDecoratorServerOptions {
434
488
  controllers: Function[];
435
489
  container?: DiContainer;
436
490
  configure?: (consumer: MiddlewareConsumerImpl) => void;
491
+ /** M47 — required when any controller `@Expose`-binds an agent; serves the agent route. */
492
+ serveAgent?: ServeAgent;
437
493
  }
438
494
  /**
439
495
  * A pure Web-Standard controller handler: callable as `(request) => Response | null`
@@ -454,6 +510,10 @@ interface DecoratorHandler {
454
510
  * controller dispatch (#122) so it never re-implements match/bind/validate.
455
511
  */
456
512
  declare function createDecoratorHandler(controllersOrOpts: Function[] | CreateDecoratorServerOptions): DecoratorHandler;
513
+ /**
514
+ * Creates a real HTTP server from decorated controller classes.
515
+ * Uses Web Standard Request/Response internally; Node adapter at the boundary.
516
+ */
457
517
  declare function createDecoratorServer(controllersOrOpts: Function[] | CreateDecoratorServerOptions): ServerHandle;
458
518
 
459
519
  /**
@@ -1366,4 +1426,4 @@ declare function revalidatePath(path: string): void;
1366
1426
  */
1367
1427
  declare function getRevalidationSignals(): RevalidationSignal[];
1368
1428
 
1369
- export { All, type ArgumentsHost, BadGatewayException, BadRequestException, Body, CATCH_EXCEPTIONS, CONTROLLER_PREFIX, type CanActivate, Catch, ConflictException, Controller, type ControllerMeta, type ControllerOptions, type DecoratorHandler, Delete, DiContainer, type DigestedError, type ErrorContext, type ExceptionFilter, type ExecutionContext, ForbiddenException, GatewayTimeoutException, Get, GoneException, Head, Header, Headers, HostParam, HttpCode, HttpDecoratorsConfigError, HttpException, type HttpExceptionOptions, HttpStatus, type HttpStatusCode, type HttpVerb, HttpVersionNotSupportedException, ImATeapotException, type Interceptor, InternalServerErrorException, Ip, type MetadataKey, MethodNotAllowedException, MiddlewareConsumerImpl, NotAcceptableException, NotFoundException, NotImplementedException, Options, Param, type ParamEntry, type ParamSource, Patch, PayloadTooLargeException, Post, PreconditionFailedException, Put, Query, ROUTE_HEADERS, ROUTE_METHODS, ROUTE_PARAMS, ROUTE_REDIRECT, ROUTE_STATUS, Redirect, type RedirectMeta, Reflector, Req, RequestTimeoutException, Res, type RevalidationSignal, type RouteDefinition, type RouteMap, type RouteMethodEntry, type RouteRegistration, type RouteTree, ServiceUnavailableException, Session, SetMetadata, SkipThrottle, type StaticOptions, type StreamRenderOptions, type StreamRenderResult, type SwcCore, type TheoRequestContext, Throttle, type ThrottleOptions, TooManyRequestsException, type TypedClient, TypedClientError, USE_FILTERS, USE_GUARDS, USE_INTERCEPTORS, UnauthorizedException, UnprocessableEntityException, UnsupportedMediaTypeException, UseFilters, UseGuards, UseInterceptors, type WalkResult, composeComponentTree, contract, createDecorator, createDecoratorHandler, createDecoratorServer, createExecutionContext, createStaticHandler, createTypedClient, digestError, getMeta, getMimeType, getRequestContext, getRevalidationSignals, getThrottleOptions, isControllerClass, isSafePath, isThrottleSkipped, joinPath, loadControllerWithSwc, loadControllersFromGlob, registerControllers, renderToStream, resolveDtoSchema, revalidatePath, revalidateTag, runExceptionFilters, runInterceptors, setMeta, streamToResponse, transformControllerSource, tryGetRequestContext, walkControllerMetadata };
1429
+ export { All, type ArgumentsHost, BadGatewayException, BadRequestException, Body, CATCH_EXCEPTIONS, CONTROLLER_PREFIX, type CanActivate, Catch, ConflictException, Controller, type ControllerMeta, type ControllerOptions, type CreateDecoratorServerOptions, type DecoratorHandler, Delete, DiContainer, type DigestedError, EXPOSE_AGENT, type ErrorContext, type ExceptionFilter, type ExecutionContext, Expose, type ExposeEntry, type ExposeOptions, ForbiddenException, GatewayTimeoutException, Get, GoneException, Head, Header, Headers, HostParam, HttpCode, HttpDecoratorsConfigError, HttpException, type HttpExceptionOptions, HttpStatus, type HttpStatusCode, type HttpVerb, HttpVersionNotSupportedException, ImATeapotException, type Interceptor, InternalServerErrorException, Ip, type MetadataKey, MethodNotAllowedException, MiddlewareConsumerImpl, NotAcceptableException, NotFoundException, NotImplementedException, Options, Param, type ParamEntry, type ParamSource, Patch, PayloadTooLargeException, Post, PreconditionFailedException, Put, Query, ROUTE_HEADERS, ROUTE_METHODS, ROUTE_PARAMS, ROUTE_REDIRECT, ROUTE_STATUS, Redirect, type RedirectMeta, Reflector, Req, RequestTimeoutException, Res, type RevalidationSignal, type RouteDefinition, type RouteMap, type RouteMethodEntry, type RouteRegistration, type RouteTree, type ServeAgent, ServiceUnavailableException, Session, SetMetadata, SkipThrottle, type StaticOptions, type StreamRenderOptions, type StreamRenderResult, type SwcCore, type TheoRequestContext, Throttle, type ThrottleOptions, TooManyRequestsException, type TypedClient, TypedClientError, USE_FILTERS, USE_GUARDS, USE_INTERCEPTORS, UnauthorizedException, UnprocessableEntityException, UnsupportedMediaTypeException, UseFilters, UseGuards, UseInterceptors, type WalkResult, composeComponentTree, contract, createDecorator, createDecoratorHandler, createDecoratorServer, createExecutionContext, createStaticHandler, createTypedClient, digestError, getMeta, getMimeType, getRequestContext, getRevalidationSignals, getThrottleOptions, isControllerClass, isSafePath, isThrottleSkipped, joinPath, loadControllerWithSwc, loadControllersFromGlob, registerControllers, renderToStream, resolveDtoSchema, revalidatePath, revalidateTag, runExceptionFilters, runInterceptors, setMeta, streamToResponse, transformControllerSource, tryGetRequestContext, walkControllerMetadata };
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  renderToStream,
8
8
  streamToResponse,
9
9
  tryGetRequestContext
10
- } from "./chunk-GQ2UH554.js";
10
+ } from "./chunk-GXTGOPRU.js";
11
11
  import {
12
12
  MiddlewareConsumerImpl,
13
13
  isControllerClass,
@@ -16,14 +16,14 @@ import {
16
16
  middlewareMatchesPath,
17
17
  runMiddleware,
18
18
  transformControllerSource
19
- } from "./chunk-RC4V75DI.js";
19
+ } from "./chunk-OBHHOS6E.js";
20
20
  import {
21
21
  HttpDecoratorsConfigError,
22
22
  createExecutionContext,
23
23
  joinPath,
24
24
  resolveDtoSchema,
25
25
  walkControllerMetadata
26
- } from "./chunk-QGB5YC4T.js";
26
+ } from "./chunk-JQMJK47T.js";
27
27
  import {
28
28
  createNodeAdapter
29
29
  } from "./chunk-HLW7YKZE.js";
@@ -32,13 +32,14 @@ import {
32
32
  } from "./chunk-ELCXHPAD.js";
33
33
  import {
34
34
  runExceptionFilters
35
- } from "./chunk-6W4T4DPJ.js";
35
+ } from "./chunk-CMPP4ULU.js";
36
36
  import {
37
37
  BadGatewayException,
38
38
  BadRequestException,
39
39
  CATCH_EXCEPTIONS,
40
40
  CONTROLLER_PREFIX,
41
41
  ConflictException,
42
+ EXPOSE_AGENT,
42
43
  ForbiddenException,
43
44
  GatewayTimeoutException,
44
45
  GoneException,
@@ -69,7 +70,7 @@ import {
69
70
  UnsupportedMediaTypeException,
70
71
  getMeta,
71
72
  setMeta
72
- } from "./chunk-3PGQVQWG.js";
73
+ } from "./chunk-KPC7AIVC.js";
73
74
  import {
74
75
  resolveOrNew
75
76
  } from "./chunk-MQAJWR3K.js";
@@ -178,6 +179,20 @@ function Res(opts) {
178
179
  }
179
180
  __name(Res, "Res");
180
181
 
182
+ // src/decorators/expose.ts
183
+ function Expose(agent, opts = {}) {
184
+ return (target, propertyKey) => {
185
+ const existing = getMeta(EXPOSE_AGENT, target.constructor) ?? [];
186
+ existing.push({
187
+ agent,
188
+ opts,
189
+ propertyKey
190
+ });
191
+ setMeta(EXPOSE_AGENT, target.constructor, existing);
192
+ };
193
+ }
194
+ __name(Expose, "Expose");
195
+
181
196
  // src/decorators/response.ts
182
197
  function HttpCode(status) {
183
198
  return (target, propertyKey) => {
@@ -424,10 +439,11 @@ __name(registerControllers, "registerControllers");
424
439
  // src/bridge/create-server.ts
425
440
  import "reflect-metadata";
426
441
  function createDecoratorHandler(controllersOrOpts) {
427
- const { controllers, container, configure } = Array.isArray(controllersOrOpts) ? {
442
+ const { controllers, container, configure, serveAgent } = Array.isArray(controllersOrOpts) ? {
428
443
  controllers: controllersOrOpts,
429
444
  container: void 0,
430
- configure: void 0
445
+ configure: void 0,
446
+ serveAgent: void 0
431
447
  } : controllersOrOpts;
432
448
  const middlewareConsumer = new MiddlewareConsumerImpl(container);
433
449
  if (configure) configure(middlewareConsumer);
@@ -456,7 +472,7 @@ function createDecoratorHandler(controllersOrOpts) {
456
472
  if (aP !== bP) return aP ? 1 : -1;
457
473
  return 0;
458
474
  });
459
- const handler = /* @__PURE__ */ __name((request) => handleRequest(routes, request, container, middlewareEntries), "handler");
475
+ const handler = /* @__PURE__ */ __name((request) => handleRequest(routes, request, container, middlewareEntries, serveAgent), "handler");
460
476
  handler.matches = (method, pathname) => findRoute(routes, method.toUpperCase(), pathname) !== null;
461
477
  return handler;
462
478
  }
@@ -477,7 +493,7 @@ function createDecoratorServer(controllersOrOpts) {
477
493
  });
478
494
  }
479
495
  __name(createDecoratorServer, "createDecoratorServer");
480
- async function handleRequest(routes, request, container, middlewareEntries = []) {
496
+ async function handleRequest(routes, request, container, middlewareEntries = [], serveAgent) {
481
497
  const url = new URL(request.url);
482
498
  const method = request.method.toUpperCase();
483
499
  const pathname = url.pathname;
@@ -490,6 +506,17 @@ async function handleRequest(routes, request, container, middlewareEntries = [])
490
506
  const ctx = createExecutionContext(request, instance.constructor, walk.propertyKey);
491
507
  const guardResponse = await runGuards(walk.guards, ctx, container);
492
508
  if (guardResponse) return guardResponse;
509
+ if (walk.agent) {
510
+ if (!serveAgent) {
511
+ return jsonResponse(500, {
512
+ error: {
513
+ code: "AGENT_SERVER_NOT_WIRED",
514
+ message: `Controller route ${String(walk.propertyKey)} is @Expose-bound but no serveAgent was provided to createDecoratorHandler. The framework must wire serveAgent (mountAgent).`
515
+ }
516
+ });
517
+ }
518
+ return await serveAgent(walk.agent.module, request, walk.agent.opts);
519
+ }
493
520
  const body = await resolveBody(method, request, walk);
494
521
  if (body instanceof Response) return body;
495
522
  const args = buildArgs(walk.paramEntries, {
@@ -865,6 +892,8 @@ export {
865
892
  ConflictException,
866
893
  Controller,
867
894
  Delete,
895
+ EXPOSE_AGENT,
896
+ Expose,
868
897
  ForbiddenException,
869
898
  GatewayTimeoutException,
870
899
  Get,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/decorators/controller.ts","../src/decorators/methods.ts","../src/decorators/params.ts","../src/decorators/response.ts","../src/decorators/middleware.ts","../src/decorators/set-metadata.ts","../src/decorators/throttle.ts","../src/bridge/register-controllers.ts","../src/bridge/create-server.ts","../src/typed-client.ts","../src/contract.ts","../src/error-digest.ts","../src/component-tree.ts","../src/cache-signal.ts"],"sourcesContent":["import { setMeta, CONTROLLER_PREFIX } from '../metadata/index.js'\n\nexport interface ControllerOptions {\n host?: string\n}\n\nexport interface ControllerMeta {\n prefix: string\n host?: string\n}\n\n/**\n * Infer route prefix from class name (Rails-style convention naming).\n *\n * UsersController → api/users\n * TasksController → api/tasks\n * AuthController → api/auth\n * HealthCheckController → api/health-check\n *\n * Strips \"Controller\" suffix, converts PascalCase to kebab-case,\n * prepends \"api/\".\n */\nfunction inferPrefix(className: string): string {\n const stripped = className.replace(/Controller$/, '')\n const kebab = stripped\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n return `api/${kebab}`\n}\n\n/**\n * Class decorator that declares a route-prefix scope.\n *\n * Convention over configuration:\n * @Controller() → prefix inferred from class name\n * @Controller('api/users') → explicit prefix\n *\n * @example\n * ```ts\n * // Convention: UsersController → /api/users (zero config)\n * @Controller()\n * class UsersController { ... }\n *\n * // Explicit: override when convention doesn't fit\n * @Controller('api/v2/users')\n * class UsersController { ... }\n * ```\n */\nexport function Controller(prefix?: string, opts?: ControllerOptions): ClassDecorator\nexport function Controller(opts?: ControllerOptions): ClassDecorator\nexport function Controller(\n prefixOrOpts?: string | ControllerOptions,\n maybeOpts?: ControllerOptions,\n): ClassDecorator {\n return (target) => {\n let prefix: string\n let opts: ControllerOptions\n\n if (typeof prefixOrOpts === 'string') {\n prefix = prefixOrOpts\n opts = maybeOpts ?? {}\n } else {\n // Convention naming: infer from class name\n prefix = inferPrefix(target.name)\n opts = prefixOrOpts ?? {}\n }\n\n setMeta<ControllerMeta>(CONTROLLER_PREFIX, target, {\n prefix,\n host: opts.host,\n })\n }\n}\n","import { setMeta, getMeta, ROUTE_METHODS } from '../metadata/index.js'\n\nexport type HttpVerb = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'ALL'\n\nexport interface RouteMethodEntry {\n verb: HttpVerb\n path: string\n propertyKey: string | symbol\n}\n\nfunction makeVerbDecorator(verb: HttpVerb) {\n return function (path = ''): MethodDecorator {\n return (target, propertyKey) => {\n const existing = getMeta<RouteMethodEntry[]>(ROUTE_METHODS, target.constructor) ?? []\n existing.push({ verb, path, propertyKey })\n setMeta(ROUTE_METHODS, target.constructor, existing)\n }\n }\n}\n\nexport const Get = makeVerbDecorator('GET')\nexport const Post = makeVerbDecorator('POST')\nexport const Put = makeVerbDecorator('PUT')\nexport const Patch = makeVerbDecorator('PATCH')\nexport const Delete = makeVerbDecorator('DELETE')\nexport const Options = makeVerbDecorator('OPTIONS')\nexport const Head = makeVerbDecorator('HEAD')\nexport const All = makeVerbDecorator('ALL')\n","import type { z } from 'zod'\n\nimport { setMeta, getMeta, ROUTE_PARAMS } from '../metadata/index.js'\n\nexport type ParamSource =\n | 'req'\n | 'res'\n | 'body'\n | 'param'\n | 'query'\n | 'headers'\n | 'session'\n | 'ip'\n | 'host'\n\nexport interface ParamEntry {\n source: ParamSource\n key?: string\n index: number\n passthrough?: boolean\n /** Explicit Zod schema — when set, bypasses design:paramtypes + DTO resolution.\n * Preferred path: `@Body(zMySchema)` works without emitDecoratorMetadata. */\n schema?: z.ZodType\n}\n\n/** Detect whether a value is a Zod schema (has `.safeParse()` method). */\nfunction isZodSchema(v: unknown): v is z.ZodType {\n return (\n v !== null &&\n v !== undefined &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>).safeParse === 'function'\n )\n}\n\nfunction makeParamDecorator(source: ParamSource) {\n /**\n * Overloaded parameter decorator:\n * - `@Body()` / `@Param()` / `@Query()` — whole-object extraction\n * - `@Body('key')` / `@Param('key')` — named-field extraction\n * - `@Body(zodSchema)` — whole-object with explicit Zod validation\n * (works WITHOUT emitDecoratorMetadata — TheoKit \"Zod is SSoT\" alignment)\n */\n return function (keyOrSchema?: string | z.ZodType): ParameterDecorator {\n return (target, propertyKey, parameterIndex) => {\n if (propertyKey === undefined) return\n const map =\n getMeta<Map<string | symbol, ParamEntry[]>>(ROUTE_PARAMS, target.constructor) ?? new Map()\n const entries = map.get(propertyKey) ?? []\n\n const entry: ParamEntry = { source, index: parameterIndex }\n if (typeof keyOrSchema === 'string') {\n entry.key = keyOrSchema\n } else if (isZodSchema(keyOrSchema)) {\n entry.schema = keyOrSchema\n }\n\n entries.push(entry)\n map.set(propertyKey, entries)\n setMeta(ROUTE_PARAMS, target.constructor, map)\n }\n }\n}\n\nexport const Req = makeParamDecorator('req')\nexport const Body = makeParamDecorator('body')\nexport const Param = makeParamDecorator('param')\nexport const Query = makeParamDecorator('query')\nexport const Headers = makeParamDecorator('headers')\nexport const Session = makeParamDecorator('session')\nexport const Ip = makeParamDecorator('ip')\nexport const HostParam = makeParamDecorator('host')\n\nexport function Res(opts?: { passthrough?: boolean }): ParameterDecorator {\n return (target, propertyKey, parameterIndex) => {\n if (propertyKey === undefined) return\n const map =\n getMeta<Map<string | symbol, ParamEntry[]>>(ROUTE_PARAMS, target.constructor) ?? new Map()\n const entries = map.get(propertyKey) ?? []\n entries.push({\n source: 'res',\n index: parameterIndex,\n passthrough: opts?.passthrough,\n })\n map.set(propertyKey, entries)\n setMeta(ROUTE_PARAMS, target.constructor, map)\n }\n}\n","import { setMeta, getMeta, ROUTE_STATUS, ROUTE_HEADERS, ROUTE_REDIRECT } from '../metadata/index.js'\n\nexport function HttpCode(status: number): MethodDecorator {\n return (target, propertyKey) => {\n setMeta(ROUTE_STATUS, target.constructor, status, propertyKey as string)\n }\n}\n\nexport function Header(name: string, value: string): MethodDecorator {\n return (target, propertyKey) => {\n const existing =\n getMeta<[string, string][]>(ROUTE_HEADERS, target.constructor, propertyKey) ?? []\n existing.push([name, value])\n setMeta(ROUTE_HEADERS, target.constructor, existing, propertyKey as string)\n }\n}\n\nexport interface RedirectMeta {\n url: string\n status: number\n}\n\nexport function Redirect(url: string, status = 302): MethodDecorator {\n return (target, propertyKey) => {\n setMeta<RedirectMeta>(ROUTE_REDIRECT, target.constructor, { url, status }, propertyKey)\n }\n}\n","import {\n setMeta,\n getMeta,\n USE_GUARDS,\n USE_INTERCEPTORS,\n USE_FILTERS,\n CATCH_EXCEPTIONS,\n} from '../metadata/index.js'\n\nexport function UseGuards(...guards: Function[]): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey ? target.constructor : target\n const existing = getMeta<Function[]>(USE_GUARDS, actualTarget, propertyKey) ?? []\n setMeta(USE_GUARDS, actualTarget, [...existing, ...guards], propertyKey)\n }\n}\n\nexport function UseInterceptors(...interceptors: Function[]): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey ? target.constructor : target\n const existing = getMeta<Function[]>(USE_INTERCEPTORS, actualTarget, propertyKey) ?? []\n setMeta(USE_INTERCEPTORS, actualTarget, [...existing, ...interceptors], propertyKey)\n }\n}\n\nexport function UseFilters(...filters: Function[]): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey ? target.constructor : target\n const existing = getMeta<Function[]>(USE_FILTERS, actualTarget, propertyKey) ?? []\n setMeta(USE_FILTERS, actualTarget, [...existing, ...filters], propertyKey)\n }\n}\n\n/** @Catch(ExceptionType, ...) — marks which exception types an ExceptionFilter handles.\n * Empty args = catch-all filter. */\nexport function Catch(...exceptions: Function[]): ClassDecorator {\n return (target: object) => {\n setMeta(CATCH_EXCEPTIONS, target, exceptions)\n }\n}\n","/**\n * @SetMetadata + Reflector — NestJS-style custom metadata for guards.\n *\n * Enables role-based auth pattern:\n * const Roles = createDecorator<string[]>()\n * @Roles(['admin']) → guard reads via reflector.get(Roles, handler)\n */\nimport 'reflect-metadata'\n\n/** Unique key type for type-safe metadata decorators. */\nexport type MetadataKey<T> = symbol & { __type?: T }\n\n/**\n * Create a typed decorator that attaches metadata to a handler or class.\n * NestJS equivalent: `Reflector.createDecorator<T>()`.\n *\n * @example\n * ```ts\n * const Roles = createDecorator<string[]>()\n *\n * @Controller('cats')\n * class CatsController {\n * @Post()\n * @Roles(['admin'])\n * create() { ... }\n * }\n * ```\n */\n/** Monotonic counter for unique decorator keys — deterministic, no randomness. */\nlet decoratorKeyCounter = 0\n\nexport function createDecorator<T>(): (value: T) => MethodDecorator & ClassDecorator {\n const key = Symbol.for(`theokit:custom:${++decoratorKeyCounter}`) as MetadataKey<T>\n\n const decorator = (value: T): MethodDecorator & ClassDecorator => {\n return (target: object, propertyKey?: string | symbol) => {\n const metaTarget = propertyKey !== undefined ? target.constructor : target\n Reflect.defineMetadata(key, value, metaTarget, propertyKey as string)\n }\n }\n\n // Attach the key so Reflector can read it\n ;(decorator as unknown as { key: MetadataKey<T> }).key = key\n return decorator\n}\n\n/**\n * Low-level @SetMetadata decorator — attaches arbitrary metadata.\n * NestJS equivalent: `@SetMetadata(key, value)`.\n *\n * Prefer `createDecorator<T>()` for type-safe metadata.\n */\nexport function SetMetadata<T>(\n metaKey: string | symbol,\n value: T,\n): MethodDecorator & ClassDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const metaTarget = propertyKey !== undefined ? target.constructor : target\n Reflect.defineMetadata(metaKey, value, metaTarget, propertyKey as string)\n }\n}\n\n/**\n * Reflector — reads metadata set by createDecorator or @SetMetadata.\n * NestJS-compatible Reflector with getAllAndOverride/getAllAndMerge.\n * HTTP-only per ADR D1.\n */\nexport class Reflector {\n /**\n * Read metadata set by a typed decorator created via createDecorator<T>().\n *\n * @example\n * ```ts\n * const Roles = createDecorator<string[]>()\n * const reflector = new Reflector()\n * const roles = reflector.get(Roles, handlerFn) // string[] | undefined\n * ```\n */\n get<T>(\n decorator: (value: T) => MethodDecorator & ClassDecorator,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n const key = (decorator as { key?: MetadataKey<T> }).key\n if (!key) return undefined\n if (propertyKey !== undefined) {\n return Reflect.getMetadata(key, target, propertyKey) as T | undefined\n }\n return Reflect.getMetadata(key, target) as T | undefined\n }\n\n /**\n * Read metadata set by @SetMetadata(key, value).\n */\n getByKey<T>(\n key: string | symbol,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n if (propertyKey !== undefined) {\n return Reflect.getMetadata(key, target, propertyKey) as T | undefined\n }\n return Reflect.getMetadata(key, target) as T | undefined\n }\n\n /**\n * Read metadata checking method-level first, then class-level.\n * Returns the first non-undefined value found.\n *\n * NestJS equivalent: `reflector.getAllAndOverride(ROLES_KEY, [context.getHandler(), context.getClass()])`\n *\n * @example\n * ```ts\n * const Roles = createDecorator<string[]>()\n * // In a guard:\n * const roles = reflector.getAllAndOverride(Roles, context.getClass(), context.getMethodName())\n * // Checks method-level @Roles first, falls back to class-level @Roles\n * ```\n */\n getAllAndOverride<T>(\n decorator: (value: T) => MethodDecorator & ClassDecorator,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n if (propertyKey !== undefined) {\n const methodLevel = this.get(decorator, target, propertyKey)\n if (methodLevel !== undefined) return methodLevel\n }\n return this.get(decorator, target)\n }\n\n /**\n * Read metadata checking method-level first, then class-level, by raw key.\n * Returns the first non-undefined value found.\n */\n getAllAndOverrideByKey<T>(\n key: string | symbol,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n if (propertyKey !== undefined) {\n const methodLevel = this.getByKey<T>(key, target, propertyKey)\n if (methodLevel !== undefined) return methodLevel\n }\n return this.getByKey<T>(key, target)\n }\n\n /**\n * Read metadata from both method-level and class-level, merging arrays.\n * Returns all found values as a flat array.\n *\n * NestJS equivalent: `reflector.getAllAndMerge(ROLES_KEY, [context.getHandler(), context.getClass()])`\n *\n * @example\n * ```ts\n * const Tags = createDecorator<string[]>()\n *\n * @Tags(['api'])\n * @Controller('cats')\n * class CatsCtrl {\n * @Tags(['read'])\n * @Get()\n * findAll() {}\n * }\n *\n * reflector.getAllAndMerge(Tags, CatsCtrl, 'findAll')\n * // → ['read', 'api'] (method + class merged)\n * ```\n */\n getAllAndMerge<T>(\n decorator: (value: T) => MethodDecorator & ClassDecorator,\n target: Function,\n propertyKey?: string | symbol,\n ): T extends (infer U)[] ? U[] : T[] {\n const result: unknown[] = []\n if (propertyKey !== undefined) {\n const methodLevel = this.get(decorator, target, propertyKey)\n if (methodLevel !== undefined) {\n if (Array.isArray(methodLevel)) result.push(...methodLevel)\n else result.push(methodLevel)\n }\n }\n const classLevel = this.get(decorator, target)\n if (classLevel !== undefined) {\n if (Array.isArray(classLevel)) result.push(...classLevel)\n else result.push(classLevel)\n }\n return result as T extends (infer U)[] ? U[] : T[]\n }\n}\n","/**\n * @Throttle() + @SkipThrottle() — NestJS-style rate limiting decorators.\n *\n * Thin bridge over @theokit/plugin-rate-limit. These decorators store\n * metadata that the rate-limit plugin reads at request time to override\n * or skip the global throttle config per route/controller.\n *\n * Usage:\n * ```ts\n * @Controller('api/tasks')\n * @Throttle({ limit: 100, ttl: 60_000 }) // 100 req/min for all routes\n * class TasksController {\n * @Get()\n * @SkipThrottle() // no rate limit on this route\n * health() { return { ok: true } }\n *\n * @Post()\n * @Throttle({ limit: 5, ttl: 60_000 }) // stricter: 5 req/min\n * create(@Body(schema) body) { ... }\n * }\n * ```\n */\nimport { setMeta, getMeta } from '../metadata/index.js'\n\nconst THROTTLE_KEY = Symbol.for('theokit:http-decorators:throttle')\nconst SKIP_THROTTLE_KEY = Symbol.for('theokit:http-decorators:skip-throttle')\n\nexport interface ThrottleOptions {\n /** Maximum requests within the TTL window. */\n limit: number\n /** Time-to-live in milliseconds. */\n ttl: number\n /** Optional throttle set name (for multiple throttler definitions). */\n name?: string\n}\n\n/**\n * Override the global rate limit for a controller or specific route.\n * NestJS equivalent: `@Throttle({ default: { limit, ttl } })`.\n */\nexport function Throttle(options: ThrottleOptions): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey !== undefined ? target.constructor : target\n setMeta(THROTTLE_KEY, actualTarget, options, propertyKey)\n }\n}\n\n/**\n * Skip rate limiting for a controller or specific route.\n * NestJS equivalent: `@SkipThrottle()`.\n *\n * @param skip — defaults to `true`. Pass `false` to re-enable on a\n * specific route inside a skipped controller.\n */\nexport function SkipThrottle(skip = true): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey !== undefined ? target.constructor : target\n setMeta(SKIP_THROTTLE_KEY, actualTarget, skip, propertyKey)\n }\n}\n\n/**\n * Read throttle metadata for a given class or method.\n * Used by the rate-limit plugin to resolve per-route overrides.\n */\nexport function getThrottleOptions(\n target: Function,\n propertyKey?: string | symbol,\n): ThrottleOptions | undefined {\n return getMeta<ThrottleOptions>(THROTTLE_KEY, target, propertyKey)\n}\n\n/**\n * Check if throttling is skipped for a given class or method.\n */\nexport function isThrottleSkipped(target: Function, propertyKey?: string | symbol): boolean {\n return getMeta<boolean>(SKIP_THROTTLE_KEY, target, propertyKey) ?? false\n}\n","import type { HttpVerb } from '../decorators/methods.js'\n\nimport { walkControllerMetadata, type WalkResult } from './walk-metadata.js'\n\nexport interface RouteRegistration {\n verb: HttpVerb\n fullPath: string\n walkResult: WalkResult\n}\n\n/**\n * Low-level API: walks decorator metadata per controller class and returns\n * structured route descriptors. Used internally by the Vite plugin (ADR D7)\n * and available to advanced consumers who don't use Vite.\n *\n * EC-5: deduplicates by class reference; warns on duplicates.\n */\nexport function registerControllers(controllers: Function[]): RouteRegistration[] {\n const seen = new Set<Function>()\n const unique: Function[] = []\n for (const Ctor of controllers) {\n if (seen.has(Ctor)) {\n console.warn(\n `[@theokit/http] Controller ${Ctor.name} registered multiple times — dropping duplicate`,\n )\n continue\n }\n seen.add(Ctor)\n unique.push(Ctor)\n }\n return unique.flatMap((Ctor) => {\n const walks = walkControllerMetadata(Ctor)\n return walks.map((w) => ({\n verb: w.verb,\n fullPath: w.fullPath,\n walkResult: w,\n }))\n })\n}\n","/* eslint-disable security/detect-non-literal-regexp --\n * Route patterns like /cats/:id are converted to regex at startup —\n * NOT from user HTTP input. The patterns come from decorator metadata\n * authored by the developer. No injection vector.\n */\nimport 'reflect-metadata'\n\nimport type { ParamEntry } from '../decorators/params.js'\nimport { ForbiddenException } from '../exceptions/http-exception.js'\n\nimport { resolveOrNew, type DiContainer } from './di-resolve.js'\nexport type { DiContainer } from './di-resolve.js'\nimport { runExceptionFilters } from './exception-filter-chain.js'\nimport {\n createExecutionContext,\n type CanActivate,\n type ExecutionContext,\n} from './execution-context.js'\nimport { runInterceptors } from './interceptor-chain.js'\nimport {\n MiddlewareConsumerImpl,\n runMiddleware,\n type ResolvedMiddleware,\n} from './middleware-consumer.js'\nimport { createNodeAdapter } from './runtime/node.js'\nimport { walkControllerMetadata, type WalkResult } from './walk-metadata.js'\n\n/**\n * Creates a real HTTP server from decorated controller classes.\n * Uses Web Standard Request/Response internally; Node adapter at the boundary.\n */\nexport interface CreateDecoratorServerOptions {\n controllers: Function[]\n container?: DiContainer\n configure?: (consumer: MiddlewareConsumerImpl) => void\n}\n\n/**\n * A pure Web-Standard controller handler: callable as `(request) => Response | null`\n * plus a non-executing `matches(method, pathname)` route probe (so a host can gate\n * — e.g. CSRF — before dispatch runs a handler).\n */\nexport interface DecoratorHandler {\n (request: Request): Promise<Response | null>\n /** True when a controller route owns `method` + `pathname` (no handler executed). */\n matches(method: string, pathname: string): boolean\n}\n\n/**\n * Build a pure Web-Standard request handler from decorated controller classes,\n * WITHOUT binding a network listener. Returns a {@link DecoratorHandler} whose\n * call returns `null` when no controller route matched — the caller decides the\n * miss (a standalone server answers 404; a host middleware falls through to its\n * own routing). This is the reusable dispatch seam consumed by the framework's\n * controller dispatch (#122) so it never re-implements match/bind/validate.\n */\nexport function createDecoratorHandler(\n controllersOrOpts: Function[] | CreateDecoratorServerOptions,\n): DecoratorHandler {\n const { controllers, container, configure } = Array.isArray(controllersOrOpts)\n ? { controllers: controllersOrOpts, container: undefined, configure: undefined }\n : controllersOrOpts\n\n // Collect middleware\n const middlewareConsumer = new MiddlewareConsumerImpl(container)\n if (configure) configure(middlewareConsumer)\n const middlewareEntries = middlewareConsumer.getEntries()\n\n // Dedupe controllers (EC-5)\n const seen = new Set<Function>()\n const unique: Function[] = []\n for (const Ctor of controllers) {\n if (seen.has(Ctor)) continue\n seen.add(Ctor)\n unique.push(Ctor)\n }\n\n // Walk metadata\n const routes: { walk: WalkResult; instance: object }[] = []\n for (const Ctor of unique) {\n const instance = resolveOrNew(Ctor, container)\n const walks = walkControllerMetadata(Ctor)\n for (const w of walks) {\n routes.push({ walk: w, instance })\n }\n }\n\n // Sort: static routes first\n routes.sort((a, b) => {\n const aP = a.walk.fullPath.includes(':')\n const bP = b.walk.fullPath.includes(':')\n if (aP !== bP) return aP ? 1 : -1\n return 0\n })\n\n const handler = ((request: Request) =>\n handleRequest(routes, request, container, middlewareEntries)) as DecoratorHandler\n handler.matches = (method: string, pathname: string): boolean =>\n findRoute(routes, method.toUpperCase(), pathname) !== null\n return handler\n}\n\nexport function createDecoratorServer(\n controllersOrOpts: Function[] | CreateDecoratorServerOptions,\n) {\n const handle = createDecoratorHandler(controllersOrOpts)\n // Standalone server: a no-match (handler returns null) becomes a 404.\n const adapter = createNodeAdapter()\n return adapter.createServer(async (request: Request) => {\n const res = await handle(request)\n if (res) return res\n const { pathname } = new URL(request.url)\n return jsonResponse(404, {\n error: {\n code: 'NOT_FOUND',\n message: `No route for ${request.method.toUpperCase()} ${pathname}`,\n },\n })\n })\n}\n\n// ─── Web Standard request handler ────────────────────────────\n\nasync function handleRequest(\n routes: { walk: WalkResult; instance: object }[],\n request: Request,\n container?: DiContainer,\n middlewareEntries: ResolvedMiddleware[] = [],\n): Promise<Response | null> {\n const url = new URL(request.url)\n const method = request.method.toUpperCase()\n const pathname = url.pathname\n\n const match = findRoute(routes, method, pathname)\n // null = no controller route matched; the caller owns the miss (404 or fall-through).\n if (!match) return null\n\n const { walk, instance, params } = match\n\n try {\n // Middleware\n const mwResponse = await runMiddleware(middlewareEntries, request, pathname)\n if (mwResponse) return mwResponse\n\n // Guards\n const ctx = createExecutionContext(request, instance.constructor, walk.propertyKey)\n const guardResponse = await runGuards(walk.guards, ctx, container)\n if (guardResponse) return guardResponse\n\n // Body\n const body = await resolveBody(method, request, walk)\n if (body instanceof Response) return body // validation error response\n\n // Build args\n const args = buildArgs(walk.paramEntries, {\n request,\n body,\n params,\n query: Object.fromEntries(url.searchParams),\n })\n\n // Redirect\n if (walk.redirect) {\n return new Response(null, {\n status: walk.redirect.status,\n headers: { location: walk.redirect.url },\n })\n }\n\n const handlerFn = (instance as Record<string | symbol, Function>)[walk.propertyKey]\n\n // Interceptors wrap handler\n const result = await runInterceptors(\n walk.interceptors,\n () => handlerFn.apply(instance, args) as Promise<unknown>,\n request,\n container,\n )\n\n // A handler may return a Web `Response` directly (Set-Cookie, custom status /\n // headers) — parity with file-based `route()`. Pass it through untouched\n // instead of JSON-stringifying it into `{}`.\n if (result instanceof Response) return result\n\n return buildResponse(result, walk, method)\n } catch (err) {\n return runExceptionFilters(err, walk.filters, request, container)\n }\n}\n\n// ─── Guards (return Response on rejection, null on pass) ─────\n\nasync function runGuards(\n guards: Function[],\n context: ExecutionContext,\n container?: DiContainer,\n): Promise<Response | null> {\n for (const GuardCtor of guards) {\n const guard = resolveOrNew(GuardCtor, container) as CanActivate\n const allowed = await guard.canActivate(context)\n if (!allowed) {\n const ex = new ForbiddenException('Forbidden resource')\n return jsonResponse(ex.statusCode, ex.toJSON())\n }\n }\n return null\n}\n\n// ─── Body resolution ─────────────────────────────────────────\n\nasync function resolveBody(method: string, request: Request, walk: WalkResult): Promise<unknown> {\n if (!['POST', 'PUT', 'PATCH'].includes(method)) return undefined\n\n let body: unknown\n try {\n const text = await request.text()\n body = text ? JSON.parse(text) : undefined\n } catch {\n body = undefined\n }\n\n if (walk.bodySchema && body !== undefined) {\n const result = walk.bodySchema.safeParse(body)\n if (!result.success) {\n return jsonResponse(422, { error: { code: 'VALIDATION_ERROR', issues: result.error.issues } })\n }\n body = result.data\n }\n return body\n}\n\n// ─── Response builder ────────────────────────────────────────\n\nfunction buildResponse(result: unknown, walk: WalkResult, method: string): Response {\n const status = walk.status ?? (method === 'POST' ? 201 : 200)\n const headers: Record<string, string> = { 'content-type': 'application/json' }\n for (const [name, value] of walk.headers) {\n headers[name.toLowerCase()] = value\n }\n\n if (result === undefined || result === null) {\n return new Response(null, { status: status === 200 ? 204 : status, headers })\n }\n\n if (typeof result === 'string') {\n headers['content-type'] = 'text/plain'\n return new Response(result, { status, headers })\n }\n\n return new Response(JSON.stringify(result), { status, headers })\n}\n\nfunction jsonResponse(status: number, body: unknown): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\n// ─── Route matching ──────────────────────────────────────────\n\ninterface RouteMatch {\n walk: WalkResult\n instance: object\n params: Record<string, string>\n}\n\nfunction findRoute(\n routes: { walk: WalkResult; instance: object }[],\n method: string,\n pathname: string,\n): RouteMatch | null {\n for (const { walk, instance } of routes) {\n if (walk.verb !== 'ALL' && walk.verb !== method) continue\n const params = matchPath(walk.fullPath, pathname)\n if (params !== null) return { walk, instance, params }\n }\n return null\n}\n\nfunction matchPath(pattern: string, pathname: string): Record<string, string> | null {\n const paramNames: string[] = []\n const regexStr = pattern.replace(/:(\\w+)/g, (_m, name: string) => {\n paramNames.push(name)\n return '([^/]+)'\n })\n const match = new RegExp(`^${regexStr}$`).exec(pathname)\n if (!match) return null\n const params: Record<string, string> = {}\n paramNames.forEach((name, i) => {\n params[name] = match[i + 1]\n })\n return params\n}\n\n// ─── Argument builder ────────────────────────────────────────\n\ninterface ArgContext {\n request: Request\n body: unknown\n params: Record<string, string>\n query: Record<string, string>\n}\n\nfunction buildArgs(paramEntries: ParamEntry[], ctx: ArgContext): unknown[] {\n if (paramEntries.length === 0) return []\n const maxIndex = Math.max(...paramEntries.map((p) => p.index))\n const args: unknown[] = Array.from({ length: maxIndex + 1 }, () => undefined)\n for (const p of paramEntries) {\n switch (p.source) {\n case 'req':\n args[p.index] = ctx.request\n break\n case 'body':\n args[p.index] = p.key ? (ctx.body as Record<string, unknown>)[p.key] : ctx.body\n break\n case 'param':\n args[p.index] = p.key ? ctx.params[p.key] : ctx.params\n break\n case 'query':\n args[p.index] = p.key ? ctx.query[p.key] : ctx.query\n break\n case 'headers':\n args[p.index] = p.key\n ? ctx.request.headers.get(p.key.toLowerCase())\n : Object.fromEntries(ctx.request.headers.entries())\n break\n case 'ip':\n args[p.index] = ctx.request.headers.get('x-forwarded-for') ?? '127.0.0.1'\n break\n case 'session':\n args[p.index] = undefined\n break\n default:\n args[p.index] = undefined\n }\n }\n return args\n}\n","/**\n * Typed Client — end-to-end type inference from route contracts.\n *\n * Zero codegen, zero runtime overhead on types. The developer defines\n * a route map using `contract()`, and `createTypedClient<T>()` infers\n * request body + response types automatically.\n */\nimport type { z } from 'zod'\n\n// ── Route Map types ──\n\nexport interface RouteDefinition {\n body?: z.ZodType\n params?: Record<string, 'string' | 'number'>\n query?: Record<string, 'string' | 'number' | 'boolean'>\n response: unknown\n}\n\nexport type RouteMap = Record<string, RouteDefinition>\n\n// ── Type extraction ──\n\ntype InferBody<D> = D extends { body: z.ZodType } ? z.infer<D['body']> : never\ntype InferResponse<D> = D extends { response: infer R } ? R : unknown\n\n// ── Client interface (simplified — works with strict DTS) ──\n\nexport interface TypedClient<M extends RouteMap> {\n get<P extends string>(\n path: P,\n opts?: { query?: Record<string, string>; headers?: Record<string, string> },\n ): Promise<InferResponse<M[`GET ${P}`]>>\n\n post<P extends string>(\n path: P,\n body?: InferBody<M[`POST ${P}`]>,\n opts?: { headers?: Record<string, string> },\n ): Promise<InferResponse<M[`POST ${P}`]>>\n\n put<P extends string>(\n path: P,\n body?: InferBody<M[`PUT ${P}`]>,\n opts?: { headers?: Record<string, string> },\n ): Promise<InferResponse<M[`PUT ${P}`]>>\n\n delete<P extends string>(\n path: P,\n opts?: { headers?: Record<string, string> },\n ): Promise<InferResponse<M[`DELETE ${P}`]>>\n}\n\n// ── Client factory ──\n\nexport function createTypedClient<M extends RouteMap>(\n baseUrl: string,\n defaultHeaders?: Record<string, string>,\n): TypedClient<M> {\n async function request(\n method: string,\n path: string,\n body?: unknown,\n opts?: { headers?: Record<string, string>; query?: Record<string, string> },\n ) {\n const url = new URL(path, baseUrl)\n if (opts?.query) {\n for (const [k, v] of Object.entries(opts.query)) url.searchParams.set(k, v)\n }\n const headers: Record<string, string> = { ...defaultHeaders, ...opts?.headers }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await fetch(url.toString(), {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ message: res.statusText }))\n throw new TypedClientError(res.status, error as Record<string, unknown>)\n }\n\n if (res.status === 204) return undefined\n return res.json()\n }\n\n return {\n get: (path: string, opts?: Record<string, unknown>) => request('GET', path, undefined, opts),\n post: (path: string, body?: unknown, opts?: Record<string, unknown>) =>\n request('POST', path, body, opts),\n put: (path: string, body?: unknown, opts?: Record<string, unknown>) =>\n request('PUT', path, body, opts),\n delete: (path: string, opts?: Record<string, unknown>) =>\n request('DELETE', path, undefined, opts),\n } as TypedClient<M>\n}\n\nexport class TypedClientError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: Record<string, unknown>,\n ) {\n super(`HTTP ${status}: ${JSON.stringify(body)}`)\n this.name = 'TypedClientError'\n }\n}\n","/**\n * Route Contract — type-level bridge between @Controller and TypedClient.\n *\n * The developer defines a contract object mapping routes to their types.\n * This object is the single source of truth for both server validation\n * and client type inference.\n *\n * @example\n * ```ts\n * // server/contracts.ts — shared between server and client\n * import { z } from 'zod'\n * import { contract } from '@theokit/http'\n *\n * export const zCreateTask = z.object({\n * title: z.string().min(3),\n * priority: z.enum(['low', 'medium', 'high']).default('medium'),\n * })\n *\n * export interface Task { id: number; title: string; priority: string; done: boolean }\n *\n * export const routes = contract({\n * 'GET /api/tasks': { response: [] as Task[] },\n * 'GET /api/tasks/:id': { response: {} as Task },\n * 'POST /api/tasks': { body: zCreateTask, response: {} as Task },\n * 'PUT /api/tasks/:id': { body: z.object({ done: z.boolean() }), response: {} as Task },\n * 'DELETE /api/tasks/:id': { response: undefined as void },\n * })\n * export type AppRoutes = typeof routes\n * ```\n *\n * The `contract()` function is identity at runtime (zero overhead) but\n * enforces the RouteMap type at the type level, enabling full inference.\n */\nimport type { RouteMap } from './typed-client.js'\n\n/**\n * Identity function that enforces RouteMap type constraint.\n * Zero runtime overhead — exists only for type inference.\n */\nexport function contract<T extends RouteMap>(routes: T): T {\n return routes\n}\n","/**\n * Error digestion — converts any thrown value into a stable hash + context.\n *\n * Inspired by Next.js `create-error-handler.tsx`. Produces a deterministic\n * digest ID suitable for logging and client-safe error references without\n * leaking stack traces in production.\n *\n * Uses djb2 hash (sync, no crypto dependency) per ADR D3.\n */\n\nimport { HttpException } from './exceptions/http-exception.js'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ErrorContext {\n route?: string\n phase?: 'guard' | 'interceptor' | 'handler' | 'filter' | 'agent'\n source?: string\n}\n\nexport interface DigestedError {\n digest: string\n message: string\n status: number\n context: ErrorContext\n stack?: string\n}\n\n// ---------------------------------------------------------------------------\n// djb2 hash — deterministic, sync, no crypto dependency\n// ---------------------------------------------------------------------------\n\nfunction djb2(input: string): string {\n let hash = 5381\n for (let i = 0; i < input.length; i++) {\n // hash * 33 + charCode — classic djb2\n hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0\n }\n // Convert to unsigned 32-bit hex\n return (hash >>> 0).toString(16)\n}\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\n/**\n * Converts any thrown value into a structured {@link DigestedError}.\n *\n * - Sync (never async) — safe to call inside catch blocks.\n * - Stack trace stripped when `process.env.NODE_ENV === 'production'`.\n * - Preserves {@link HttpException} status codes.\n * - Handles non-Error throws (string, number, object).\n */\nexport function digestError(err: unknown, context: ErrorContext = {}): DigestedError {\n const message = extractMessage(err)\n const status = extractStatus(err)\n const rawStack = extractStack(err)\n\n const digest = djb2(message)\n\n const isProduction = process.env.NODE_ENV === 'production'\n\n return {\n digest,\n message,\n status,\n context,\n ...(rawStack && !isProduction ? { stack: rawStack } : {}),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction extractMessage(err: unknown): string {\n if (err instanceof Error) {\n return err.message\n }\n if (typeof err === 'string') {\n return err\n }\n if (typeof err === 'number') {\n return String(err)\n }\n // object / null / undefined / symbol / bigint\n try {\n return JSON.stringify(err)\n } catch {\n return 'Unknown error'\n }\n}\n\nfunction extractStatus(err: unknown): number {\n if (err instanceof HttpException) {\n return err.statusCode\n }\n return 500\n}\n\nfunction extractStack(err: unknown): string | undefined {\n if (err instanceof Error) {\n return err.stack\n }\n return undefined\n}\n","/**\n * Component tree composition — recursive wrapping of file-convention\n * components (layout, page, loading, error, not-found) into a React\n * element tree with Suspense and error boundaries.\n *\n * Inspired by Next.js `create-component-tree.tsx`.\n *\n * React is loaded via dynamic `import('react')` because it is an\n * optional peerDep of @theokit/http (EC-2).\n */\n\nimport type * as ReactTypes from 'react'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface RouteTree {\n layout?: ReactTypes.ComponentType<{ children: ReactTypes.ReactNode }>\n page?: ReactTypes.ComponentType\n loading?: ReactTypes.ComponentType\n error?: ReactTypes.ComponentType\n notFound?: ReactTypes.ComponentType\n children?: Record<string, RouteTree>\n}\n\n// ---------------------------------------------------------------------------\n// Error boundary — minimal class component wrapping error.tsx\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an ErrorBoundary class component using the provided React module.\n * Must be a class component — React has no hook-based error boundary API.\n */\nfunction createErrorBoundary(\n React: typeof ReactTypes,\n FallbackComponent: ReactTypes.ComponentType,\n): ReactTypes.ComponentType<{ children: ReactTypes.ReactNode }> {\n return class ErrorBoundary extends React.Component<\n { children: ReactTypes.ReactNode },\n { hasError: boolean }\n > {\n constructor(props: { children: ReactTypes.ReactNode }) {\n super(props)\n this.state = { hasError: false }\n }\n\n static getDerivedStateFromError(): { hasError: boolean } {\n return { hasError: true }\n }\n\n render(): ReactTypes.ReactElement | null {\n if (this.state.hasError) {\n return React.createElement(FallbackComponent)\n }\n return React.createElement(React.Fragment, null, this.props.children)\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\n/**\n * Composes a {@link RouteTree} into a nested React element tree.\n *\n * Wrapping order (outermost → innermost):\n * layout → ErrorBoundary(error) → Suspense(loading) → page\n *\n * Returns `null` when no `page` component is found in the tree.\n *\n * @param tree - The route tree describing file conventions found.\n * @returns A React element or `null`.\n */\nexport async function composeComponentTree(\n tree: RouteTree,\n): Promise<ReactTypes.ReactElement | null> {\n // Dynamic import — React is optional peerDep\n const React = await import('react')\n\n return composeNode(React, tree)\n}\n\nfunction composeNode(React: typeof ReactTypes, node: RouteTree): ReactTypes.ReactElement | null {\n const { layout: Layout, page: Page, loading: Loading, error: ErrorFallback } = node\n\n // No page → nothing to render\n if (!Page) {\n return null\n }\n\n // Start with the page element\n let element: ReactTypes.ReactElement = React.createElement(Page)\n\n // Wrap with Suspense if loading component exists\n if (Loading) {\n element = React.createElement(\n React.Suspense,\n { fallback: React.createElement(Loading) },\n element,\n )\n }\n\n // Wrap with error boundary if error component exists\n if (ErrorFallback) {\n const Boundary = createErrorBoundary(React, ErrorFallback)\n element = React.createElement(Boundary, null, element)\n }\n\n // Wrap with layout if it exists\n if (Layout) {\n element = React.createElement(Layout, null, element)\n }\n\n return element\n}\n","/**\n * Cache revalidation signals — runtime-agnostic intent layer.\n *\n * Controllers/agents call `revalidateTag('tasks')` or `revalidatePath('/api/tasks')`\n * to signal that cached data is stale. The signals are collected in the request\n * context and consumed by the cache engine (when present).\n *\n * In standalone @theokit/http (no full theokit framework), signals are stored\n * but not executed — no cache engine is wired. When theokit is present, the\n * cache engine reads signals from the request context after the handler completes.\n *\n * Inspired by Next.js cache-signal.ts + revalidateTag/revalidatePath API.\n */\nimport { tryGetRequestContext } from './request-context.js'\n\nexport interface RevalidationSignal {\n kind: 'tag' | 'path'\n value: string\n timestamp: number\n}\n\n/**\n * Signal that a cache tag should be revalidated.\n *\n * Safe to call from any request handler (controller, agent, action).\n * Signals are accumulated per-request and consumed by the cache engine.\n *\n * @example\n * ```typescript\n * import { revalidateTag } from '@theokit/http'\n *\n * @Post()\n * async createTask(@Body(schema) body) {\n * const task = await db.tasks.create(body)\n * revalidateTag('tasks') // invalidate cached task lists\n * return task\n * }\n * ```\n */\nexport function revalidateTag(tag: string): void {\n collectSignal({ kind: 'tag', value: tag, timestamp: Date.now() })\n}\n\n/**\n * Signal that a cached path should be revalidated.\n *\n * @example\n * ```typescript\n * import { revalidatePath } from '@theokit/http'\n *\n * @Delete(':id')\n * async removeTask(@Param('id') id: string) {\n * await db.tasks.delete(id)\n * revalidatePath('/api/tasks')\n * }\n * ```\n */\nexport function revalidatePath(path: string): void {\n collectSignal({ kind: 'path', value: path, timestamp: Date.now() })\n}\n\n/**\n * Get all revalidation signals collected during the current request.\n * Called by the cache engine after the handler completes.\n */\nexport function getRevalidationSignals(): RevalidationSignal[] {\n const ctx = tryGetRequestContext()\n if (!ctx) return []\n return (\n (ctx as unknown as { _revalidationSignals?: RevalidationSignal[] })._revalidationSignals ?? []\n )\n}\n\n// ── Internal ──\n\nfunction collectSignal(signal: RevalidationSignal): void {\n const ctx = tryGetRequestContext()\n if (!ctx) {\n console.warn(\n '[theokit] revalidateTag/revalidatePath called outside a request context. Signal ignored.',\n )\n return\n }\n const extended = ctx as unknown as { _revalidationSignals?: RevalidationSignal[] }\n extended._revalidationSignals ??= []\n extended._revalidationSignals.push(signal)\n}\n"],"mappings":"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","names":["inferPrefix","className","stripped","replace","kebab","toLowerCase","Controller","prefixOrOpts","maybeOpts","target","prefix","opts","name","setMeta","CONTROLLER_PREFIX","host","makeVerbDecorator","verb","path","target","propertyKey","existing","getMeta","ROUTE_METHODS","push","setMeta","Get","Post","Put","Patch","Delete","Options","Head","All","isZodSchema","v","undefined","safeParse","makeParamDecorator","source","keyOrSchema","target","propertyKey","parameterIndex","map","getMeta","ROUTE_PARAMS","Map","entries","get","entry","index","key","schema","push","set","setMeta","Req","Body","Param","Query","Headers","Session","Ip","HostParam","Res","opts","passthrough","HttpCode","status","target","propertyKey","setMeta","ROUTE_STATUS","Header","name","value","existing","getMeta","ROUTE_HEADERS","push","Redirect","url","ROUTE_REDIRECT","UseGuards","guards","target","propertyKey","actualTarget","existing","getMeta","USE_GUARDS","setMeta","UseInterceptors","interceptors","USE_INTERCEPTORS","UseFilters","filters","USE_FILTERS","Catch","exceptions","CATCH_EXCEPTIONS","decoratorKeyCounter","createDecorator","key","Symbol","for","decorator","value","target","propertyKey","metaTarget","undefined","Reflect","defineMetadata","SetMetadata","metaKey","Reflector","get","getMetadata","getByKey","getAllAndOverride","methodLevel","getAllAndOverrideByKey","getAllAndMerge","result","Array","isArray","push","classLevel","THROTTLE_KEY","Symbol","for","SKIP_THROTTLE_KEY","Throttle","options","target","propertyKey","actualTarget","undefined","setMeta","SkipThrottle","skip","getThrottleOptions","getMeta","isThrottleSkipped","registerControllers","controllers","seen","Set","unique","Ctor","has","console","warn","name","add","push","flatMap","walks","walkControllerMetadata","map","w","verb","fullPath","walkResult","createDecoratorHandler","controllersOrOpts","controllers","container","configure","Array","isArray","undefined","middlewareConsumer","MiddlewareConsumerImpl","middlewareEntries","getEntries","seen","Set","unique","Ctor","has","add","push","routes","instance","resolveOrNew","walks","walkControllerMetadata","w","walk","sort","a","b","aP","fullPath","includes","bP","handler","request","handleRequest","matches","method","pathname","findRoute","toUpperCase","createDecoratorServer","handle","adapter","createNodeAdapter","createServer","res","URL","url","jsonResponse","error","code","message","match","params","mwResponse","runMiddleware","ctx","createExecutionContext","propertyKey","guardResponse","runGuards","guards","body","resolveBody","Response","args","buildArgs","paramEntries","query","Object","fromEntries","searchParams","redirect","status","headers","location","handlerFn","result","runInterceptors","interceptors","apply","buildResponse","err","runExceptionFilters","filters","context","GuardCtor","guard","allowed","canActivate","ex","ForbiddenException","statusCode","toJSON","text","JSON","parse","bodySchema","safeParse","success","issues","data","name","value","toLowerCase","stringify","verb","matchPath","pattern","paramNames","regexStr","replace","_m","RegExp","exec","forEach","i","length","maxIndex","Math","max","map","p","index","from","source","key","get","entries","createTypedClient","baseUrl","defaultHeaders","request","method","path","body","opts","url","URL","query","k","v","Object","entries","searchParams","set","headers","undefined","res","fetch","toString","JSON","stringify","ok","error","json","catch","message","statusText","TypedClientError","status","get","post","put","delete","Error","name","contract","routes","djb2","input","hash","i","length","charCodeAt","toString","digestError","err","context","message","extractMessage","status","extractStatus","rawStack","extractStack","digest","isProduction","process","env","NODE_ENV","stack","Error","String","JSON","stringify","HttpException","statusCode","undefined","createErrorBoundary","React","FallbackComponent","ErrorBoundary","Component","props","state","hasError","getDerivedStateFromError","render","createElement","Fragment","children","composeComponentTree","tree","composeNode","node","layout","Layout","page","Page","loading","Loading","error","ErrorFallback","element","Suspense","fallback","Boundary","revalidateTag","tag","collectSignal","kind","value","timestamp","Date","now","revalidatePath","path","getRevalidationSignals","ctx","tryGetRequestContext","_revalidationSignals","signal","console","warn","extended","push"]}
1
+ {"version":3,"sources":["../src/decorators/controller.ts","../src/decorators/methods.ts","../src/decorators/params.ts","../src/decorators/expose.ts","../src/decorators/response.ts","../src/decorators/middleware.ts","../src/decorators/set-metadata.ts","../src/decorators/throttle.ts","../src/bridge/register-controllers.ts","../src/bridge/create-server.ts","../src/typed-client.ts","../src/contract.ts","../src/error-digest.ts","../src/component-tree.ts","../src/cache-signal.ts"],"sourcesContent":["import { setMeta, CONTROLLER_PREFIX } from '../metadata/index.js'\n\nexport interface ControllerOptions {\n host?: string\n}\n\nexport interface ControllerMeta {\n prefix: string\n host?: string\n}\n\n/**\n * Infer route prefix from class name (Rails-style convention naming).\n *\n * UsersController → api/users\n * TasksController → api/tasks\n * AuthController → api/auth\n * HealthCheckController → api/health-check\n *\n * Strips \"Controller\" suffix, converts PascalCase to kebab-case,\n * prepends \"api/\".\n */\nfunction inferPrefix(className: string): string {\n const stripped = className.replace(/Controller$/, '')\n const kebab = stripped\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n return `api/${kebab}`\n}\n\n/**\n * Class decorator that declares a route-prefix scope.\n *\n * Convention over configuration:\n * @Controller() → prefix inferred from class name\n * @Controller('api/users') → explicit prefix\n *\n * @example\n * ```ts\n * // Convention: UsersController → /api/users (zero config)\n * @Controller()\n * class UsersController { ... }\n *\n * // Explicit: override when convention doesn't fit\n * @Controller('api/v2/users')\n * class UsersController { ... }\n * ```\n */\nexport function Controller(prefix?: string, opts?: ControllerOptions): ClassDecorator\nexport function Controller(opts?: ControllerOptions): ClassDecorator\nexport function Controller(\n prefixOrOpts?: string | ControllerOptions,\n maybeOpts?: ControllerOptions,\n): ClassDecorator {\n return (target) => {\n let prefix: string\n let opts: ControllerOptions\n\n if (typeof prefixOrOpts === 'string') {\n prefix = prefixOrOpts\n opts = maybeOpts ?? {}\n } else {\n // Convention naming: infer from class name\n prefix = inferPrefix(target.name)\n opts = prefixOrOpts ?? {}\n }\n\n setMeta<ControllerMeta>(CONTROLLER_PREFIX, target, {\n prefix,\n host: opts.host,\n })\n }\n}\n","import { setMeta, getMeta, ROUTE_METHODS } from '../metadata/index.js'\n\nexport type HttpVerb = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'ALL'\n\nexport interface RouteMethodEntry {\n verb: HttpVerb\n path: string\n propertyKey: string | symbol\n}\n\nfunction makeVerbDecorator(verb: HttpVerb) {\n return function (path = ''): MethodDecorator {\n return (target, propertyKey) => {\n const existing = getMeta<RouteMethodEntry[]>(ROUTE_METHODS, target.constructor) ?? []\n existing.push({ verb, path, propertyKey })\n setMeta(ROUTE_METHODS, target.constructor, existing)\n }\n }\n}\n\nexport const Get = makeVerbDecorator('GET')\nexport const Post = makeVerbDecorator('POST')\nexport const Put = makeVerbDecorator('PUT')\nexport const Patch = makeVerbDecorator('PATCH')\nexport const Delete = makeVerbDecorator('DELETE')\nexport const Options = makeVerbDecorator('OPTIONS')\nexport const Head = makeVerbDecorator('HEAD')\nexport const All = makeVerbDecorator('ALL')\n","import type { z } from 'zod'\n\nimport { setMeta, getMeta, ROUTE_PARAMS } from '../metadata/index.js'\n\nexport type ParamSource =\n | 'req'\n | 'res'\n | 'body'\n | 'param'\n | 'query'\n | 'headers'\n | 'session'\n | 'ip'\n | 'host'\n\nexport interface ParamEntry {\n source: ParamSource\n key?: string\n index: number\n passthrough?: boolean\n /** Explicit Zod schema — when set, bypasses design:paramtypes + DTO resolution.\n * Preferred path: `@Body(zMySchema)` works without emitDecoratorMetadata. */\n schema?: z.ZodType\n}\n\n/** Detect whether a value is a Zod schema (has `.safeParse()` method). */\nfunction isZodSchema(v: unknown): v is z.ZodType {\n return (\n v !== null &&\n v !== undefined &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>).safeParse === 'function'\n )\n}\n\nfunction makeParamDecorator(source: ParamSource) {\n /**\n * Overloaded parameter decorator:\n * - `@Body()` / `@Param()` / `@Query()` — whole-object extraction\n * - `@Body('key')` / `@Param('key')` — named-field extraction\n * - `@Body(zodSchema)` — whole-object with explicit Zod validation\n * (works WITHOUT emitDecoratorMetadata — TheoKit \"Zod is SSoT\" alignment)\n */\n return function (keyOrSchema?: string | z.ZodType): ParameterDecorator {\n return (target, propertyKey, parameterIndex) => {\n if (propertyKey === undefined) return\n const map =\n getMeta<Map<string | symbol, ParamEntry[]>>(ROUTE_PARAMS, target.constructor) ?? new Map()\n const entries = map.get(propertyKey) ?? []\n\n const entry: ParamEntry = { source, index: parameterIndex }\n if (typeof keyOrSchema === 'string') {\n entry.key = keyOrSchema\n } else if (isZodSchema(keyOrSchema)) {\n entry.schema = keyOrSchema\n }\n\n entries.push(entry)\n map.set(propertyKey, entries)\n setMeta(ROUTE_PARAMS, target.constructor, map)\n }\n }\n}\n\nexport const Req = makeParamDecorator('req')\nexport const Body = makeParamDecorator('body')\nexport const Param = makeParamDecorator('param')\nexport const Query = makeParamDecorator('query')\nexport const Headers = makeParamDecorator('headers')\nexport const Session = makeParamDecorator('session')\nexport const Ip = makeParamDecorator('ip')\nexport const HostParam = makeParamDecorator('host')\n\nexport function Res(opts?: { passthrough?: boolean }): ParameterDecorator {\n return (target, propertyKey, parameterIndex) => {\n if (propertyKey === undefined) return\n const map =\n getMeta<Map<string | symbol, ParamEntry[]>>(ROUTE_PARAMS, target.constructor) ?? new Map()\n const entries = map.get(propertyKey) ?? []\n entries.push({\n source: 'res',\n index: parameterIndex,\n passthrough: opts?.passthrough,\n })\n map.set(propertyKey, entries)\n setMeta(ROUTE_PARAMS, target.constructor, map)\n }\n}\n","import { setMeta, getMeta, EXPOSE_AGENT } from '../metadata/index.js'\n\n/**\n * M47 (ADR-M47-1) — `@Expose(agent, opts?)` binds a SEPARATELY-BUILT agent (a pure `agent()…build()` from\n * `agents/<name>.ts`) to a controller PROPERTY, making the exposure (route, auth via `@UseGuards`, streaming)\n * visible in one code review. It mirrors the #122 verb decorators (`@Post`) — storing metadata via the same\n * `Symbol.for()` seam — but records the agent instead of an HTTP verb, so the controller walker turns the\n * property into an agent-serving route (`POST <prefix>/<property>`) delegated to the ONE runtime\n * (`mountAgent`), never a JSON handler. It is a new AUTHORING surface over the existing runtime, not a\n * parallel runtime (G2). CSRF is enforced once at the controller-dispatch boundary. Interceptors do NOT run\n * for agent routes (the dispatcher delegates straight to `mountAgent`); guards DO (G5). The served path is\n * the controller prefix + property name — keep it equal to the agent's convention route (`/api/agents/<name>`\n * for a property named `<name>` under `@Controller('api/agents')`) so the generated `useAgent(handle)` path\n * lines up.\n */\n\n/**\n * Per-binding options for an exposed agent. Reserved for forward-compat — no options are wired yet.\n *\n * Two candidate fields were removed before shipping (M47 review): `path` (a route override) would let the\n * served URL diverge from the generated handle's path — the codegen derives the handle from the agent's\n * convention route (`/api/agents/<name>`), so an overridden route would make `useAgent(handle)` hit the\n * wrong URL. And `csrf` was a no-op — CSRF is enforced exactly once at the controller-dispatch boundary\n * regardless. Both return only when they can be wired end-to-end (codegen reads `@Expose` metadata / a\n * per-route CSRF opt-out threads through the dispatcher). Until then, `@Expose(agent)` is the shape, and the\n * exposure's path MUST be the convention route — put `@Expose` on a property named after the agent under\n * `@Controller('api/agents')` (e.g. `chat` for `agents/chat.ts` → `/api/agents/chat`).\n */\nexport type ExposeOptions = Record<string, never>\n\n/** Metadata recorded per `@Expose`-decorated controller member. */\nexport interface ExposeEntry {\n /** The separately-built agent module bound to this member. */\n agent: unknown\n /** The per-binding options (defaulted to `{}`). */\n opts: ExposeOptions\n /** The controller member the binding is attached to. */\n propertyKey: string | symbol\n}\n\n/**\n * Bind an agent to a controller PROPERTY. Accumulates one {@link ExposeEntry} per member under the\n * `EXPOSE_AGENT` metadata key on the controller constructor — the same accumulation shape `@Post` uses for\n * `ROUTE_METHODS`, so `walkControllerMetadata` reads both alongside each other. Typed as `PropertyDecorator`\n * (the exposure is declared as a property, e.g. `@Expose(chatAgent) chat!: typeof chatAgent`); the agent's\n * behavior lives in its own `agents/<name>.ts`, never in a controller method body.\n */\nexport function Expose(agent: unknown, opts: ExposeOptions = {}): PropertyDecorator {\n return (target: object, propertyKey: string | symbol) => {\n const existing = getMeta<ExposeEntry[]>(EXPOSE_AGENT, target.constructor) ?? []\n existing.push({ agent, opts, propertyKey })\n setMeta(EXPOSE_AGENT, target.constructor, existing)\n }\n}\n","import { setMeta, getMeta, ROUTE_STATUS, ROUTE_HEADERS, ROUTE_REDIRECT } from '../metadata/index.js'\n\nexport function HttpCode(status: number): MethodDecorator {\n return (target, propertyKey) => {\n setMeta(ROUTE_STATUS, target.constructor, status, propertyKey as string)\n }\n}\n\nexport function Header(name: string, value: string): MethodDecorator {\n return (target, propertyKey) => {\n const existing =\n getMeta<[string, string][]>(ROUTE_HEADERS, target.constructor, propertyKey) ?? []\n existing.push([name, value])\n setMeta(ROUTE_HEADERS, target.constructor, existing, propertyKey as string)\n }\n}\n\nexport interface RedirectMeta {\n url: string\n status: number\n}\n\nexport function Redirect(url: string, status = 302): MethodDecorator {\n return (target, propertyKey) => {\n setMeta<RedirectMeta>(ROUTE_REDIRECT, target.constructor, { url, status }, propertyKey)\n }\n}\n","import {\n setMeta,\n getMeta,\n USE_GUARDS,\n USE_INTERCEPTORS,\n USE_FILTERS,\n CATCH_EXCEPTIONS,\n} from '../metadata/index.js'\n\nexport function UseGuards(\n ...guards: Function[]\n): ClassDecorator & MethodDecorator & PropertyDecorator {\n // M47 — also a PropertyDecorator so per-agent guards attach to an `@Expose` property (visible auth). The\n // runtime already keys guards by propertyKey; only the type is widened (back-compat — strictly permissive).\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey ? target.constructor : target\n const existing = getMeta<Function[]>(USE_GUARDS, actualTarget, propertyKey) ?? []\n setMeta(USE_GUARDS, actualTarget, [...existing, ...guards], propertyKey)\n }\n}\n\nexport function UseInterceptors(...interceptors: Function[]): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey ? target.constructor : target\n const existing = getMeta<Function[]>(USE_INTERCEPTORS, actualTarget, propertyKey) ?? []\n setMeta(USE_INTERCEPTORS, actualTarget, [...existing, ...interceptors], propertyKey)\n }\n}\n\nexport function UseFilters(...filters: Function[]): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey ? target.constructor : target\n const existing = getMeta<Function[]>(USE_FILTERS, actualTarget, propertyKey) ?? []\n setMeta(USE_FILTERS, actualTarget, [...existing, ...filters], propertyKey)\n }\n}\n\n/** @Catch(ExceptionType, ...) — marks which exception types an ExceptionFilter handles.\n * Empty args = catch-all filter. */\nexport function Catch(...exceptions: Function[]): ClassDecorator {\n return (target: object) => {\n setMeta(CATCH_EXCEPTIONS, target, exceptions)\n }\n}\n","/**\n * @SetMetadata + Reflector — NestJS-style custom metadata for guards.\n *\n * Enables role-based auth pattern:\n * const Roles = createDecorator<string[]>()\n * @Roles(['admin']) → guard reads via reflector.get(Roles, handler)\n */\nimport 'reflect-metadata'\n\n/** Unique key type for type-safe metadata decorators. */\nexport type MetadataKey<T> = symbol & { __type?: T }\n\n/**\n * Create a typed decorator that attaches metadata to a handler or class.\n * NestJS equivalent: `Reflector.createDecorator<T>()`.\n *\n * @example\n * ```ts\n * const Roles = createDecorator<string[]>()\n *\n * @Controller('cats')\n * class CatsController {\n * @Post()\n * @Roles(['admin'])\n * create() { ... }\n * }\n * ```\n */\n/** Monotonic counter for unique decorator keys — deterministic, no randomness. */\nlet decoratorKeyCounter = 0\n\nexport function createDecorator<T>(): (value: T) => MethodDecorator & ClassDecorator {\n const key = Symbol.for(`theokit:custom:${++decoratorKeyCounter}`) as MetadataKey<T>\n\n const decorator = (value: T): MethodDecorator & ClassDecorator => {\n return (target: object, propertyKey?: string | symbol) => {\n const metaTarget = propertyKey !== undefined ? target.constructor : target\n Reflect.defineMetadata(key, value, metaTarget, propertyKey as string)\n }\n }\n\n // Attach the key so Reflector can read it\n ;(decorator as unknown as { key: MetadataKey<T> }).key = key\n return decorator\n}\n\n/**\n * Low-level @SetMetadata decorator — attaches arbitrary metadata.\n * NestJS equivalent: `@SetMetadata(key, value)`.\n *\n * Prefer `createDecorator<T>()` for type-safe metadata.\n */\nexport function SetMetadata<T>(\n metaKey: string | symbol,\n value: T,\n): MethodDecorator & ClassDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const metaTarget = propertyKey !== undefined ? target.constructor : target\n Reflect.defineMetadata(metaKey, value, metaTarget, propertyKey as string)\n }\n}\n\n/**\n * Reflector — reads metadata set by createDecorator or @SetMetadata.\n * NestJS-compatible Reflector with getAllAndOverride/getAllAndMerge.\n * HTTP-only per ADR D1.\n */\nexport class Reflector {\n /**\n * Read metadata set by a typed decorator created via createDecorator<T>().\n *\n * @example\n * ```ts\n * const Roles = createDecorator<string[]>()\n * const reflector = new Reflector()\n * const roles = reflector.get(Roles, handlerFn) // string[] | undefined\n * ```\n */\n get<T>(\n decorator: (value: T) => MethodDecorator & ClassDecorator,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n const key = (decorator as { key?: MetadataKey<T> }).key\n if (!key) return undefined\n if (propertyKey !== undefined) {\n return Reflect.getMetadata(key, target, propertyKey) as T | undefined\n }\n return Reflect.getMetadata(key, target) as T | undefined\n }\n\n /**\n * Read metadata set by @SetMetadata(key, value).\n */\n getByKey<T>(\n key: string | symbol,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n if (propertyKey !== undefined) {\n return Reflect.getMetadata(key, target, propertyKey) as T | undefined\n }\n return Reflect.getMetadata(key, target) as T | undefined\n }\n\n /**\n * Read metadata checking method-level first, then class-level.\n * Returns the first non-undefined value found.\n *\n * NestJS equivalent: `reflector.getAllAndOverride(ROLES_KEY, [context.getHandler(), context.getClass()])`\n *\n * @example\n * ```ts\n * const Roles = createDecorator<string[]>()\n * // In a guard:\n * const roles = reflector.getAllAndOverride(Roles, context.getClass(), context.getMethodName())\n * // Checks method-level @Roles first, falls back to class-level @Roles\n * ```\n */\n getAllAndOverride<T>(\n decorator: (value: T) => MethodDecorator & ClassDecorator,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n if (propertyKey !== undefined) {\n const methodLevel = this.get(decorator, target, propertyKey)\n if (methodLevel !== undefined) return methodLevel\n }\n return this.get(decorator, target)\n }\n\n /**\n * Read metadata checking method-level first, then class-level, by raw key.\n * Returns the first non-undefined value found.\n */\n getAllAndOverrideByKey<T>(\n key: string | symbol,\n target: Function,\n propertyKey?: string | symbol,\n ): T | undefined {\n if (propertyKey !== undefined) {\n const methodLevel = this.getByKey<T>(key, target, propertyKey)\n if (methodLevel !== undefined) return methodLevel\n }\n return this.getByKey<T>(key, target)\n }\n\n /**\n * Read metadata from both method-level and class-level, merging arrays.\n * Returns all found values as a flat array.\n *\n * NestJS equivalent: `reflector.getAllAndMerge(ROLES_KEY, [context.getHandler(), context.getClass()])`\n *\n * @example\n * ```ts\n * const Tags = createDecorator<string[]>()\n *\n * @Tags(['api'])\n * @Controller('cats')\n * class CatsCtrl {\n * @Tags(['read'])\n * @Get()\n * findAll() {}\n * }\n *\n * reflector.getAllAndMerge(Tags, CatsCtrl, 'findAll')\n * // → ['read', 'api'] (method + class merged)\n * ```\n */\n getAllAndMerge<T>(\n decorator: (value: T) => MethodDecorator & ClassDecorator,\n target: Function,\n propertyKey?: string | symbol,\n ): T extends (infer U)[] ? U[] : T[] {\n const result: unknown[] = []\n if (propertyKey !== undefined) {\n const methodLevel = this.get(decorator, target, propertyKey)\n if (methodLevel !== undefined) {\n if (Array.isArray(methodLevel)) result.push(...methodLevel)\n else result.push(methodLevel)\n }\n }\n const classLevel = this.get(decorator, target)\n if (classLevel !== undefined) {\n if (Array.isArray(classLevel)) result.push(...classLevel)\n else result.push(classLevel)\n }\n return result as T extends (infer U)[] ? U[] : T[]\n }\n}\n","/**\n * @Throttle() + @SkipThrottle() — NestJS-style rate limiting decorators.\n *\n * Thin bridge over @theokit/plugin-rate-limit. These decorators store\n * metadata that the rate-limit plugin reads at request time to override\n * or skip the global throttle config per route/controller.\n *\n * Usage:\n * ```ts\n * @Controller('api/tasks')\n * @Throttle({ limit: 100, ttl: 60_000 }) // 100 req/min for all routes\n * class TasksController {\n * @Get()\n * @SkipThrottle() // no rate limit on this route\n * health() { return { ok: true } }\n *\n * @Post()\n * @Throttle({ limit: 5, ttl: 60_000 }) // stricter: 5 req/min\n * create(@Body(schema) body) { ... }\n * }\n * ```\n */\nimport { setMeta, getMeta } from '../metadata/index.js'\n\nconst THROTTLE_KEY = Symbol.for('theokit:http-decorators:throttle')\nconst SKIP_THROTTLE_KEY = Symbol.for('theokit:http-decorators:skip-throttle')\n\nexport interface ThrottleOptions {\n /** Maximum requests within the TTL window. */\n limit: number\n /** Time-to-live in milliseconds. */\n ttl: number\n /** Optional throttle set name (for multiple throttler definitions). */\n name?: string\n}\n\n/**\n * Override the global rate limit for a controller or specific route.\n * NestJS equivalent: `@Throttle({ default: { limit, ttl } })`.\n */\nexport function Throttle(options: ThrottleOptions): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey !== undefined ? target.constructor : target\n setMeta(THROTTLE_KEY, actualTarget, options, propertyKey)\n }\n}\n\n/**\n * Skip rate limiting for a controller or specific route.\n * NestJS equivalent: `@SkipThrottle()`.\n *\n * @param skip — defaults to `true`. Pass `false` to re-enable on a\n * specific route inside a skipped controller.\n */\nexport function SkipThrottle(skip = true): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const actualTarget = propertyKey !== undefined ? target.constructor : target\n setMeta(SKIP_THROTTLE_KEY, actualTarget, skip, propertyKey)\n }\n}\n\n/**\n * Read throttle metadata for a given class or method.\n * Used by the rate-limit plugin to resolve per-route overrides.\n */\nexport function getThrottleOptions(\n target: Function,\n propertyKey?: string | symbol,\n): ThrottleOptions | undefined {\n return getMeta<ThrottleOptions>(THROTTLE_KEY, target, propertyKey)\n}\n\n/**\n * Check if throttling is skipped for a given class or method.\n */\nexport function isThrottleSkipped(target: Function, propertyKey?: string | symbol): boolean {\n return getMeta<boolean>(SKIP_THROTTLE_KEY, target, propertyKey) ?? false\n}\n","import type { HttpVerb } from '../decorators/methods.js'\n\nimport { walkControllerMetadata, type WalkResult } from './walk-metadata.js'\n\nexport interface RouteRegistration {\n verb: HttpVerb\n fullPath: string\n walkResult: WalkResult\n}\n\n/**\n * Low-level API: walks decorator metadata per controller class and returns\n * structured route descriptors. Used internally by the Vite plugin (ADR D7)\n * and available to advanced consumers who don't use Vite.\n *\n * EC-5: deduplicates by class reference; warns on duplicates.\n */\nexport function registerControllers(controllers: Function[]): RouteRegistration[] {\n const seen = new Set<Function>()\n const unique: Function[] = []\n for (const Ctor of controllers) {\n if (seen.has(Ctor)) {\n console.warn(\n `[@theokit/http] Controller ${Ctor.name} registered multiple times — dropping duplicate`,\n )\n continue\n }\n seen.add(Ctor)\n unique.push(Ctor)\n }\n return unique.flatMap((Ctor) => {\n const walks = walkControllerMetadata(Ctor)\n return walks.map((w) => ({\n verb: w.verb,\n fullPath: w.fullPath,\n walkResult: w,\n }))\n })\n}\n","/* eslint-disable security/detect-non-literal-regexp --\n * Route patterns like /cats/:id are converted to regex at startup —\n * NOT from user HTTP input. The patterns come from decorator metadata\n * authored by the developer. No injection vector.\n */\nimport 'reflect-metadata'\n\nimport type { ExposeOptions } from '../decorators/expose.js'\nimport type { ParamEntry } from '../decorators/params.js'\nimport { ForbiddenException } from '../exceptions/http-exception.js'\n\nimport { resolveOrNew, type DiContainer } from './di-resolve.js'\nexport type { DiContainer } from './di-resolve.js'\nimport { runExceptionFilters } from './exception-filter-chain.js'\nimport {\n createExecutionContext,\n type CanActivate,\n type ExecutionContext,\n} from './execution-context.js'\nimport { runInterceptors } from './interceptor-chain.js'\nimport {\n MiddlewareConsumerImpl,\n runMiddleware,\n type ResolvedMiddleware,\n} from './middleware-consumer.js'\nimport { createNodeAdapter } from './runtime/node.js'\nimport { walkControllerMetadata, type WalkResult } from './walk-metadata.js'\n\n/**\n * M47 — serves an `@Expose`-bound agent route. http is agent-runtime agnostic (G1/G2): it invokes this\n * injected callback (theo supplies a `mountAgent`-backed impl) instead of calling a controller method.\n */\nexport type ServeAgent = (\n agent: unknown,\n request: Request,\n opts: ExposeOptions,\n) => Promise<Response>\n\nexport interface CreateDecoratorServerOptions {\n controllers: Function[]\n container?: DiContainer\n configure?: (consumer: MiddlewareConsumerImpl) => void\n /** M47 — required when any controller `@Expose`-binds an agent; serves the agent route. */\n serveAgent?: ServeAgent\n}\n\n/**\n * A pure Web-Standard controller handler: callable as `(request) => Response | null`\n * plus a non-executing `matches(method, pathname)` route probe (so a host can gate\n * — e.g. CSRF — before dispatch runs a handler).\n */\nexport interface DecoratorHandler {\n (request: Request): Promise<Response | null>\n /** True when a controller route owns `method` + `pathname` (no handler executed). */\n matches(method: string, pathname: string): boolean\n}\n\n/**\n * Build a pure Web-Standard request handler from decorated controller classes,\n * WITHOUT binding a network listener. Returns a {@link DecoratorHandler} whose\n * call returns `null` when no controller route matched — the caller decides the\n * miss (a standalone server answers 404; a host middleware falls through to its\n * own routing). This is the reusable dispatch seam consumed by the framework's\n * controller dispatch (#122) so it never re-implements match/bind/validate.\n */\nexport function createDecoratorHandler(\n controllersOrOpts: Function[] | CreateDecoratorServerOptions,\n): DecoratorHandler {\n const { controllers, container, configure, serveAgent } = Array.isArray(controllersOrOpts)\n ? {\n controllers: controllersOrOpts,\n container: undefined,\n configure: undefined,\n serveAgent: undefined,\n }\n : controllersOrOpts\n\n // Collect middleware\n const middlewareConsumer = new MiddlewareConsumerImpl(container)\n if (configure) configure(middlewareConsumer)\n const middlewareEntries = middlewareConsumer.getEntries()\n\n // Dedupe controllers (EC-5)\n const seen = new Set<Function>()\n const unique: Function[] = []\n for (const Ctor of controllers) {\n if (seen.has(Ctor)) continue\n seen.add(Ctor)\n unique.push(Ctor)\n }\n\n // Walk metadata\n const routes: { walk: WalkResult; instance: object }[] = []\n for (const Ctor of unique) {\n const instance = resolveOrNew(Ctor, container)\n const walks = walkControllerMetadata(Ctor)\n for (const w of walks) {\n routes.push({ walk: w, instance })\n }\n }\n\n // Sort: static routes first\n routes.sort((a, b) => {\n const aP = a.walk.fullPath.includes(':')\n const bP = b.walk.fullPath.includes(':')\n if (aP !== bP) return aP ? 1 : -1\n return 0\n })\n\n const handler = ((request: Request) =>\n handleRequest(routes, request, container, middlewareEntries, serveAgent)) as DecoratorHandler\n handler.matches = (method: string, pathname: string): boolean =>\n findRoute(routes, method.toUpperCase(), pathname) !== null\n return handler\n}\n\n/**\n * Creates a real HTTP server from decorated controller classes.\n * Uses Web Standard Request/Response internally; Node adapter at the boundary.\n */\nexport function createDecoratorServer(\n controllersOrOpts: Function[] | CreateDecoratorServerOptions,\n) {\n const handle = createDecoratorHandler(controllersOrOpts)\n // Standalone server: a no-match (handler returns null) becomes a 404.\n const adapter = createNodeAdapter()\n return adapter.createServer(async (request: Request) => {\n const res = await handle(request)\n if (res) return res\n const { pathname } = new URL(request.url)\n return jsonResponse(404, {\n error: {\n code: 'NOT_FOUND',\n message: `No route for ${request.method.toUpperCase()} ${pathname}`,\n },\n })\n })\n}\n\n// ─── Web Standard request handler ────────────────────────────\n\nasync function handleRequest(\n routes: { walk: WalkResult; instance: object }[],\n request: Request,\n container?: DiContainer,\n middlewareEntries: ResolvedMiddleware[] = [],\n serveAgent?: ServeAgent,\n): Promise<Response | null> {\n const url = new URL(request.url)\n const method = request.method.toUpperCase()\n const pathname = url.pathname\n\n const match = findRoute(routes, method, pathname)\n // null = no controller route matched; the caller owns the miss (404 or fall-through).\n if (!match) return null\n\n const { walk, instance, params } = match\n\n try {\n // Middleware\n const mwResponse = await runMiddleware(middlewareEntries, request, pathname)\n if (mwResponse) return mwResponse\n\n // Guards\n const ctx = createExecutionContext(request, instance.constructor, walk.propertyKey)\n const guardResponse = await runGuards(walk.guards, ctx, container)\n if (guardResponse) return guardResponse\n\n // M47 — an @Expose-bound route is served by the injected agent runtime (mountAgent, via theo), AFTER\n // guards (auth applies to agents — G5) and NEVER as a JSON controller method. http stays agnostic.\n if (walk.agent) {\n if (!serveAgent) {\n return jsonResponse(500, {\n error: {\n code: 'AGENT_SERVER_NOT_WIRED',\n message:\n `Controller route ${String(walk.propertyKey)} is @Expose-bound but no serveAgent was ` +\n `provided to createDecoratorHandler. The framework must wire serveAgent (mountAgent).`,\n },\n })\n }\n return await serveAgent(walk.agent.module, request, walk.agent.opts)\n }\n\n // Body\n const body = await resolveBody(method, request, walk)\n if (body instanceof Response) return body // validation error response\n\n // Build args\n const args = buildArgs(walk.paramEntries, {\n request,\n body,\n params,\n query: Object.fromEntries(url.searchParams),\n })\n\n // Redirect\n if (walk.redirect) {\n return new Response(null, {\n status: walk.redirect.status,\n headers: { location: walk.redirect.url },\n })\n }\n\n const handlerFn = (instance as Record<string | symbol, Function>)[walk.propertyKey]\n\n // Interceptors wrap handler\n const result = await runInterceptors(\n walk.interceptors,\n () => handlerFn.apply(instance, args) as Promise<unknown>,\n request,\n container,\n )\n\n // A handler may return a Web `Response` directly (Set-Cookie, custom status /\n // headers) — parity with file-based `route()`. Pass it through untouched\n // instead of JSON-stringifying it into `{}`.\n if (result instanceof Response) return result\n\n return buildResponse(result, walk, method)\n } catch (err) {\n return runExceptionFilters(err, walk.filters, request, container)\n }\n}\n\n// ─── Guards (return Response on rejection, null on pass) ─────\n\nasync function runGuards(\n guards: Function[],\n context: ExecutionContext,\n container?: DiContainer,\n): Promise<Response | null> {\n for (const GuardCtor of guards) {\n const guard = resolveOrNew(GuardCtor, container) as CanActivate\n const allowed = await guard.canActivate(context)\n if (!allowed) {\n const ex = new ForbiddenException('Forbidden resource')\n return jsonResponse(ex.statusCode, ex.toJSON())\n }\n }\n return null\n}\n\n// ─── Body resolution ─────────────────────────────────────────\n\nasync function resolveBody(method: string, request: Request, walk: WalkResult): Promise<unknown> {\n if (!['POST', 'PUT', 'PATCH'].includes(method)) return undefined\n\n let body: unknown\n try {\n const text = await request.text()\n body = text ? JSON.parse(text) : undefined\n } catch {\n body = undefined\n }\n\n if (walk.bodySchema && body !== undefined) {\n const result = walk.bodySchema.safeParse(body)\n if (!result.success) {\n return jsonResponse(422, { error: { code: 'VALIDATION_ERROR', issues: result.error.issues } })\n }\n body = result.data\n }\n return body\n}\n\n// ─── Response builder ────────────────────────────────────────\n\nfunction buildResponse(result: unknown, walk: WalkResult, method: string): Response {\n const status = walk.status ?? (method === 'POST' ? 201 : 200)\n const headers: Record<string, string> = { 'content-type': 'application/json' }\n for (const [name, value] of walk.headers) {\n headers[name.toLowerCase()] = value\n }\n\n if (result === undefined || result === null) {\n return new Response(null, { status: status === 200 ? 204 : status, headers })\n }\n\n if (typeof result === 'string') {\n headers['content-type'] = 'text/plain'\n return new Response(result, { status, headers })\n }\n\n return new Response(JSON.stringify(result), { status, headers })\n}\n\nfunction jsonResponse(status: number, body: unknown): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\n// ─── Route matching ──────────────────────────────────────────\n\ninterface RouteMatch {\n walk: WalkResult\n instance: object\n params: Record<string, string>\n}\n\nfunction findRoute(\n routes: { walk: WalkResult; instance: object }[],\n method: string,\n pathname: string,\n): RouteMatch | null {\n for (const { walk, instance } of routes) {\n if (walk.verb !== 'ALL' && walk.verb !== method) continue\n const params = matchPath(walk.fullPath, pathname)\n if (params !== null) return { walk, instance, params }\n }\n return null\n}\n\nfunction matchPath(pattern: string, pathname: string): Record<string, string> | null {\n const paramNames: string[] = []\n const regexStr = pattern.replace(/:(\\w+)/g, (_m, name: string) => {\n paramNames.push(name)\n return '([^/]+)'\n })\n const match = new RegExp(`^${regexStr}$`).exec(pathname)\n if (!match) return null\n const params: Record<string, string> = {}\n paramNames.forEach((name, i) => {\n params[name] = match[i + 1]\n })\n return params\n}\n\n// ─── Argument builder ────────────────────────────────────────\n\ninterface ArgContext {\n request: Request\n body: unknown\n params: Record<string, string>\n query: Record<string, string>\n}\n\nfunction buildArgs(paramEntries: ParamEntry[], ctx: ArgContext): unknown[] {\n if (paramEntries.length === 0) return []\n const maxIndex = Math.max(...paramEntries.map((p) => p.index))\n const args: unknown[] = Array.from({ length: maxIndex + 1 }, () => undefined)\n for (const p of paramEntries) {\n switch (p.source) {\n case 'req':\n args[p.index] = ctx.request\n break\n case 'body':\n args[p.index] = p.key ? (ctx.body as Record<string, unknown>)[p.key] : ctx.body\n break\n case 'param':\n args[p.index] = p.key ? ctx.params[p.key] : ctx.params\n break\n case 'query':\n args[p.index] = p.key ? ctx.query[p.key] : ctx.query\n break\n case 'headers':\n args[p.index] = p.key\n ? ctx.request.headers.get(p.key.toLowerCase())\n : Object.fromEntries(ctx.request.headers.entries())\n break\n case 'ip':\n args[p.index] = ctx.request.headers.get('x-forwarded-for') ?? '127.0.0.1'\n break\n case 'session':\n args[p.index] = undefined\n break\n default:\n args[p.index] = undefined\n }\n }\n return args\n}\n","/**\n * Typed Client — end-to-end type inference from route contracts.\n *\n * Zero codegen, zero runtime overhead on types. The developer defines\n * a route map using `contract()`, and `createTypedClient<T>()` infers\n * request body + response types automatically.\n */\nimport type { z } from 'zod'\n\n// ── Route Map types ──\n\nexport interface RouteDefinition {\n body?: z.ZodType\n params?: Record<string, 'string' | 'number'>\n query?: Record<string, 'string' | 'number' | 'boolean'>\n response: unknown\n}\n\nexport type RouteMap = Record<string, RouteDefinition>\n\n// ── Type extraction ──\n\ntype InferBody<D> = D extends { body: z.ZodType } ? z.infer<D['body']> : never\ntype InferResponse<D> = D extends { response: infer R } ? R : unknown\n\n// ── Client interface (simplified — works with strict DTS) ──\n\nexport interface TypedClient<M extends RouteMap> {\n get<P extends string>(\n path: P,\n opts?: { query?: Record<string, string>; headers?: Record<string, string> },\n ): Promise<InferResponse<M[`GET ${P}`]>>\n\n post<P extends string>(\n path: P,\n body?: InferBody<M[`POST ${P}`]>,\n opts?: { headers?: Record<string, string> },\n ): Promise<InferResponse<M[`POST ${P}`]>>\n\n put<P extends string>(\n path: P,\n body?: InferBody<M[`PUT ${P}`]>,\n opts?: { headers?: Record<string, string> },\n ): Promise<InferResponse<M[`PUT ${P}`]>>\n\n delete<P extends string>(\n path: P,\n opts?: { headers?: Record<string, string> },\n ): Promise<InferResponse<M[`DELETE ${P}`]>>\n}\n\n// ── Client factory ──\n\nexport function createTypedClient<M extends RouteMap>(\n baseUrl: string,\n defaultHeaders?: Record<string, string>,\n): TypedClient<M> {\n async function request(\n method: string,\n path: string,\n body?: unknown,\n opts?: { headers?: Record<string, string>; query?: Record<string, string> },\n ) {\n const url = new URL(path, baseUrl)\n if (opts?.query) {\n for (const [k, v] of Object.entries(opts.query)) url.searchParams.set(k, v)\n }\n const headers: Record<string, string> = { ...defaultHeaders, ...opts?.headers }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await fetch(url.toString(), {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ message: res.statusText }))\n throw new TypedClientError(res.status, error as Record<string, unknown>)\n }\n\n if (res.status === 204) return undefined\n return res.json()\n }\n\n return {\n get: (path: string, opts?: Record<string, unknown>) => request('GET', path, undefined, opts),\n post: (path: string, body?: unknown, opts?: Record<string, unknown>) =>\n request('POST', path, body, opts),\n put: (path: string, body?: unknown, opts?: Record<string, unknown>) =>\n request('PUT', path, body, opts),\n delete: (path: string, opts?: Record<string, unknown>) =>\n request('DELETE', path, undefined, opts),\n } as TypedClient<M>\n}\n\nexport class TypedClientError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: Record<string, unknown>,\n ) {\n super(`HTTP ${status}: ${JSON.stringify(body)}`)\n this.name = 'TypedClientError'\n }\n}\n","/**\n * Route Contract — type-level bridge between @Controller and TypedClient.\n *\n * The developer defines a contract object mapping routes to their types.\n * This object is the single source of truth for both server validation\n * and client type inference.\n *\n * @example\n * ```ts\n * // server/contracts.ts — shared between server and client\n * import { z } from 'zod'\n * import { contract } from '@theokit/http'\n *\n * export const zCreateTask = z.object({\n * title: z.string().min(3),\n * priority: z.enum(['low', 'medium', 'high']).default('medium'),\n * })\n *\n * export interface Task { id: number; title: string; priority: string; done: boolean }\n *\n * export const routes = contract({\n * 'GET /api/tasks': { response: [] as Task[] },\n * 'GET /api/tasks/:id': { response: {} as Task },\n * 'POST /api/tasks': { body: zCreateTask, response: {} as Task },\n * 'PUT /api/tasks/:id': { body: z.object({ done: z.boolean() }), response: {} as Task },\n * 'DELETE /api/tasks/:id': { response: undefined as void },\n * })\n * export type AppRoutes = typeof routes\n * ```\n *\n * The `contract()` function is identity at runtime (zero overhead) but\n * enforces the RouteMap type at the type level, enabling full inference.\n */\nimport type { RouteMap } from './typed-client.js'\n\n/**\n * Identity function that enforces RouteMap type constraint.\n * Zero runtime overhead — exists only for type inference.\n */\nexport function contract<T extends RouteMap>(routes: T): T {\n return routes\n}\n","/**\n * Error digestion — converts any thrown value into a stable hash + context.\n *\n * Inspired by Next.js `create-error-handler.tsx`. Produces a deterministic\n * digest ID suitable for logging and client-safe error references without\n * leaking stack traces in production.\n *\n * Uses djb2 hash (sync, no crypto dependency) per ADR D3.\n */\n\nimport { HttpException } from './exceptions/http-exception.js'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ErrorContext {\n route?: string\n phase?: 'guard' | 'interceptor' | 'handler' | 'filter' | 'agent'\n source?: string\n}\n\nexport interface DigestedError {\n digest: string\n message: string\n status: number\n context: ErrorContext\n stack?: string\n}\n\n// ---------------------------------------------------------------------------\n// djb2 hash — deterministic, sync, no crypto dependency\n// ---------------------------------------------------------------------------\n\nfunction djb2(input: string): string {\n let hash = 5381\n for (let i = 0; i < input.length; i++) {\n // hash * 33 + charCode — classic djb2\n hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0\n }\n // Convert to unsigned 32-bit hex\n return (hash >>> 0).toString(16)\n}\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\n/**\n * Converts any thrown value into a structured {@link DigestedError}.\n *\n * - Sync (never async) — safe to call inside catch blocks.\n * - Stack trace stripped when `process.env.NODE_ENV === 'production'`.\n * - Preserves {@link HttpException} status codes.\n * - Handles non-Error throws (string, number, object).\n */\nexport function digestError(err: unknown, context: ErrorContext = {}): DigestedError {\n const message = extractMessage(err)\n const status = extractStatus(err)\n const rawStack = extractStack(err)\n\n const digest = djb2(message)\n\n const isProduction = process.env.NODE_ENV === 'production'\n\n return {\n digest,\n message,\n status,\n context,\n ...(rawStack && !isProduction ? { stack: rawStack } : {}),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction extractMessage(err: unknown): string {\n if (err instanceof Error) {\n return err.message\n }\n if (typeof err === 'string') {\n return err\n }\n if (typeof err === 'number') {\n return String(err)\n }\n // object / null / undefined / symbol / bigint\n try {\n return JSON.stringify(err)\n } catch {\n return 'Unknown error'\n }\n}\n\nfunction extractStatus(err: unknown): number {\n if (err instanceof HttpException) {\n return err.statusCode\n }\n return 500\n}\n\nfunction extractStack(err: unknown): string | undefined {\n if (err instanceof Error) {\n return err.stack\n }\n return undefined\n}\n","/**\n * Component tree composition — recursive wrapping of file-convention\n * components (layout, page, loading, error, not-found) into a React\n * element tree with Suspense and error boundaries.\n *\n * Inspired by Next.js `create-component-tree.tsx`.\n *\n * React is loaded via dynamic `import('react')` because it is an\n * optional peerDep of @theokit/http (EC-2).\n */\n\nimport type * as ReactTypes from 'react'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface RouteTree {\n layout?: ReactTypes.ComponentType<{ children: ReactTypes.ReactNode }>\n page?: ReactTypes.ComponentType\n loading?: ReactTypes.ComponentType\n error?: ReactTypes.ComponentType\n notFound?: ReactTypes.ComponentType\n children?: Record<string, RouteTree>\n}\n\n// ---------------------------------------------------------------------------\n// Error boundary — minimal class component wrapping error.tsx\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an ErrorBoundary class component using the provided React module.\n * Must be a class component — React has no hook-based error boundary API.\n */\nfunction createErrorBoundary(\n React: typeof ReactTypes,\n FallbackComponent: ReactTypes.ComponentType,\n): ReactTypes.ComponentType<{ children: ReactTypes.ReactNode }> {\n return class ErrorBoundary extends React.Component<\n { children: ReactTypes.ReactNode },\n { hasError: boolean }\n > {\n constructor(props: { children: ReactTypes.ReactNode }) {\n super(props)\n this.state = { hasError: false }\n }\n\n static getDerivedStateFromError(): { hasError: boolean } {\n return { hasError: true }\n }\n\n render(): ReactTypes.ReactElement | null {\n if (this.state.hasError) {\n return React.createElement(FallbackComponent)\n }\n return React.createElement(React.Fragment, null, this.props.children)\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\n/**\n * Composes a {@link RouteTree} into a nested React element tree.\n *\n * Wrapping order (outermost → innermost):\n * layout → ErrorBoundary(error) → Suspense(loading) → page\n *\n * Returns `null` when no `page` component is found in the tree.\n *\n * @param tree - The route tree describing file conventions found.\n * @returns A React element or `null`.\n */\nexport async function composeComponentTree(\n tree: RouteTree,\n): Promise<ReactTypes.ReactElement | null> {\n // Dynamic import — React is optional peerDep\n const React = await import('react')\n\n return composeNode(React, tree)\n}\n\nfunction composeNode(React: typeof ReactTypes, node: RouteTree): ReactTypes.ReactElement | null {\n const { layout: Layout, page: Page, loading: Loading, error: ErrorFallback } = node\n\n // No page → nothing to render\n if (!Page) {\n return null\n }\n\n // Start with the page element\n let element: ReactTypes.ReactElement = React.createElement(Page)\n\n // Wrap with Suspense if loading component exists\n if (Loading) {\n element = React.createElement(\n React.Suspense,\n { fallback: React.createElement(Loading) },\n element,\n )\n }\n\n // Wrap with error boundary if error component exists\n if (ErrorFallback) {\n const Boundary = createErrorBoundary(React, ErrorFallback)\n element = React.createElement(Boundary, null, element)\n }\n\n // Wrap with layout if it exists\n if (Layout) {\n element = React.createElement(Layout, null, element)\n }\n\n return element\n}\n","/**\n * Cache revalidation signals — runtime-agnostic intent layer.\n *\n * Controllers/agents call `revalidateTag('tasks')` or `revalidatePath('/api/tasks')`\n * to signal that cached data is stale. The signals are collected in the request\n * context and consumed by the cache engine (when present).\n *\n * In standalone @theokit/http (no full theokit framework), signals are stored\n * but not executed — no cache engine is wired. When theokit is present, the\n * cache engine reads signals from the request context after the handler completes.\n *\n * Inspired by Next.js cache-signal.ts + revalidateTag/revalidatePath API.\n */\nimport { tryGetRequestContext } from './request-context.js'\n\nexport interface RevalidationSignal {\n kind: 'tag' | 'path'\n value: string\n timestamp: number\n}\n\n/**\n * Signal that a cache tag should be revalidated.\n *\n * Safe to call from any request handler (controller, agent, action).\n * Signals are accumulated per-request and consumed by the cache engine.\n *\n * @example\n * ```typescript\n * import { revalidateTag } from '@theokit/http'\n *\n * @Post()\n * async createTask(@Body(schema) body) {\n * const task = await db.tasks.create(body)\n * revalidateTag('tasks') // invalidate cached task lists\n * return task\n * }\n * ```\n */\nexport function revalidateTag(tag: string): void {\n collectSignal({ kind: 'tag', value: tag, timestamp: Date.now() })\n}\n\n/**\n * Signal that a cached path should be revalidated.\n *\n * @example\n * ```typescript\n * import { revalidatePath } from '@theokit/http'\n *\n * @Delete(':id')\n * async removeTask(@Param('id') id: string) {\n * await db.tasks.delete(id)\n * revalidatePath('/api/tasks')\n * }\n * ```\n */\nexport function revalidatePath(path: string): void {\n collectSignal({ kind: 'path', value: path, timestamp: Date.now() })\n}\n\n/**\n * Get all revalidation signals collected during the current request.\n * Called by the cache engine after the handler completes.\n */\nexport function getRevalidationSignals(): RevalidationSignal[] {\n const ctx = tryGetRequestContext()\n if (!ctx) return []\n return (\n (ctx as unknown as { _revalidationSignals?: RevalidationSignal[] })._revalidationSignals ?? []\n )\n}\n\n// ── Internal ──\n\nfunction collectSignal(signal: RevalidationSignal): void {\n const ctx = tryGetRequestContext()\n if (!ctx) {\n console.warn(\n '[theokit] revalidateTag/revalidatePath called outside a request context. Signal ignored.',\n )\n return\n }\n const extended = ctx as unknown as { _revalidationSignals?: RevalidationSignal[] }\n extended._revalidationSignals ??= []\n extended._revalidationSignals.push(signal)\n}\n"],"mappings":"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","names":["inferPrefix","className","stripped","replace","kebab","toLowerCase","Controller","prefixOrOpts","maybeOpts","target","prefix","opts","name","setMeta","CONTROLLER_PREFIX","host","makeVerbDecorator","verb","path","target","propertyKey","existing","getMeta","ROUTE_METHODS","push","setMeta","Get","Post","Put","Patch","Delete","Options","Head","All","isZodSchema","v","undefined","safeParse","makeParamDecorator","source","keyOrSchema","target","propertyKey","parameterIndex","map","getMeta","ROUTE_PARAMS","Map","entries","get","entry","index","key","schema","push","set","setMeta","Req","Body","Param","Query","Headers","Session","Ip","HostParam","Res","opts","passthrough","Expose","agent","opts","target","propertyKey","existing","getMeta","EXPOSE_AGENT","push","setMeta","HttpCode","status","target","propertyKey","setMeta","ROUTE_STATUS","Header","name","value","existing","getMeta","ROUTE_HEADERS","push","Redirect","url","ROUTE_REDIRECT","UseGuards","guards","target","propertyKey","actualTarget","existing","getMeta","USE_GUARDS","setMeta","UseInterceptors","interceptors","USE_INTERCEPTORS","UseFilters","filters","USE_FILTERS","Catch","exceptions","CATCH_EXCEPTIONS","decoratorKeyCounter","createDecorator","key","Symbol","for","decorator","value","target","propertyKey","metaTarget","undefined","Reflect","defineMetadata","SetMetadata","metaKey","Reflector","get","getMetadata","getByKey","getAllAndOverride","methodLevel","getAllAndOverrideByKey","getAllAndMerge","result","Array","isArray","push","classLevel","THROTTLE_KEY","Symbol","for","SKIP_THROTTLE_KEY","Throttle","options","target","propertyKey","actualTarget","undefined","setMeta","SkipThrottle","skip","getThrottleOptions","getMeta","isThrottleSkipped","registerControllers","controllers","seen","Set","unique","Ctor","has","console","warn","name","add","push","flatMap","walks","walkControllerMetadata","map","w","verb","fullPath","walkResult","createDecoratorHandler","controllersOrOpts","controllers","container","configure","serveAgent","Array","isArray","undefined","middlewareConsumer","MiddlewareConsumerImpl","middlewareEntries","getEntries","seen","Set","unique","Ctor","has","add","push","routes","instance","resolveOrNew","walks","walkControllerMetadata","w","walk","sort","a","b","aP","fullPath","includes","bP","handler","request","handleRequest","matches","method","pathname","findRoute","toUpperCase","createDecoratorServer","handle","adapter","createNodeAdapter","createServer","res","URL","url","jsonResponse","error","code","message","match","params","mwResponse","runMiddleware","ctx","createExecutionContext","propertyKey","guardResponse","runGuards","guards","agent","String","module","opts","body","resolveBody","Response","args","buildArgs","paramEntries","query","Object","fromEntries","searchParams","redirect","status","headers","location","handlerFn","result","runInterceptors","interceptors","apply","buildResponse","err","runExceptionFilters","filters","context","GuardCtor","guard","allowed","canActivate","ex","ForbiddenException","statusCode","toJSON","text","JSON","parse","bodySchema","safeParse","success","issues","data","name","value","toLowerCase","stringify","verb","matchPath","pattern","paramNames","regexStr","replace","_m","RegExp","exec","forEach","i","length","maxIndex","Math","max","map","p","index","from","source","key","get","entries","createTypedClient","baseUrl","defaultHeaders","request","method","path","body","opts","url","URL","query","k","v","Object","entries","searchParams","set","headers","undefined","res","fetch","toString","JSON","stringify","ok","error","json","catch","message","statusText","TypedClientError","status","get","post","put","delete","Error","name","contract","routes","djb2","input","hash","i","length","charCodeAt","toString","digestError","err","context","message","extractMessage","status","extractStatus","rawStack","extractStack","digest","isProduction","process","env","NODE_ENV","stack","Error","String","JSON","stringify","HttpException","statusCode","undefined","createErrorBoundary","React","FallbackComponent","ErrorBoundary","Component","props","state","hasError","getDerivedStateFromError","render","createElement","Fragment","children","composeComponentTree","tree","composeNode","node","layout","Layout","page","Page","loading","Loading","error","ErrorFallback","element","Suspense","fallback","Boundary","revalidateTag","tag","collectSignal","kind","value","timestamp","Date","now","revalidatePath","path","getRevalidationSignals","ctx","tryGetRequestContext","_revalidationSignals","signal","console","warn","extended","push"]}
@@ -2,11 +2,11 @@ import {
2
2
  MiddlewareConsumerImpl,
3
3
  loadControllersFromGlob,
4
4
  runMiddleware
5
- } from "./chunk-RC4V75DI.js";
5
+ } from "./chunk-OBHHOS6E.js";
6
6
  import {
7
7
  createExecutionContext,
8
8
  walkControllerMetadata
9
- } from "./chunk-QGB5YC4T.js";
9
+ } from "./chunk-JQMJK47T.js";
10
10
  import {
11
11
  nodeIncomingToRequest,
12
12
  writeResponseToNode
@@ -16,10 +16,10 @@ import {
16
16
  } from "./chunk-ELCXHPAD.js";
17
17
  import {
18
18
  runExceptionFilters
19
- } from "./chunk-6W4T4DPJ.js";
19
+ } from "./chunk-CMPP4ULU.js";
20
20
  import {
21
21
  ForbiddenException
22
- } from "./chunk-3PGQVQWG.js";
22
+ } from "./chunk-KPC7AIVC.js";
23
23
  import {
24
24
  resolveOrNew
25
25
  } from "./chunk-MQAJWR3K.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theokit/http",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "NestJS-style decorators (@Controller, @Get, @Post, @Body, @UseGuards) bridging to TheoKit's defineRoute + defineMiddleware",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/metadata/keys.ts","../src/metadata/storage.ts","../src/exceptions/http-exception.ts"],"sourcesContent":["/**\n * Global Symbol-keyed metadata namespace constants for @theokit/http.\n *\n * Uses Symbol.for() (global Symbol registry) instead of Symbol() (local) because\n * the SWC loader imports controller files as separate module instances. With local\n * Symbols, the decorator-set metadata keys would be different Symbol instances from\n * the keys used by walkControllerMetadata — making metadata lookup silently fail.\n *\n * Symbol.for() ensures the SAME Symbol instance across module boundaries, which is\n * exactly how reflect-metadata keys should work in a multi-module decorator system.\n */\n\nexport const CONTROLLER_PREFIX = Symbol.for('theokit:http-decorators:controller-prefix')\nexport const ROUTE_METHODS = Symbol.for('theokit:http-decorators:route-methods')\nexport const ROUTE_PARAMS = Symbol.for('theokit:http-decorators:route-params')\nexport const ROUTE_STATUS = Symbol.for('theokit:http-decorators:route-status')\nexport const ROUTE_HEADERS = Symbol.for('theokit:http-decorators:route-headers')\nexport const ROUTE_REDIRECT = Symbol.for('theokit:http-decorators:route-redirect')\nexport const USE_GUARDS = Symbol.for('theokit:http-decorators:use-guards')\nexport const USE_INTERCEPTORS = Symbol.for('theokit:http-decorators:use-interceptors')\nexport const USE_FILTERS = Symbol.for('theokit:http-decorators:use-filters')\nexport const CATCH_EXCEPTIONS = Symbol.for('theokit:http-decorators:catch-exceptions')\n","import 'reflect-metadata'\n\n/**\n * Typed facade over Reflect.defineMetadata / Reflect.getMetadata.\n * Centralizes all reflect-metadata calls so decorators + bridge\n * never call Reflect.* directly (single import point for the polyfill).\n */\n\nexport function setMeta<T>(\n key: symbol,\n target: object,\n value: T,\n propertyKey?: string | symbol,\n): void {\n if (propertyKey !== undefined) {\n Reflect.defineMetadata(key, value, target, propertyKey)\n } else {\n Reflect.defineMetadata(key, value, target)\n }\n}\n\nexport function getMeta<T>(\n key: symbol,\n target: object,\n propertyKey?: string | symbol,\n): T | undefined {\n if (propertyKey !== undefined) {\n return Reflect.getMetadata(key, target, propertyKey) as T | undefined\n }\n return Reflect.getMetadata(key, target) as T | undefined\n}\n","/**\n * HttpException hierarchy for @theokit/http.\n *\n * Per ADR D2: response shape {error: {code, message, statusCode}} matches\n * existing guard (401) and validation (422) format.\n */\n\nconst STATUS_CODES: Record<number, string> = {\n 400: 'BAD_REQUEST',\n 401: 'UNAUTHORIZED',\n 403: 'FORBIDDEN',\n 404: 'NOT_FOUND',\n 405: 'METHOD_NOT_ALLOWED',\n 406: 'NOT_ACCEPTABLE',\n 408: 'REQUEST_TIMEOUT',\n 409: 'CONFLICT',\n 410: 'GONE',\n 412: 'PRECONDITION_FAILED',\n 413: 'PAYLOAD_TOO_LARGE',\n 415: 'UNSUPPORTED_MEDIA_TYPE',\n 418: 'IM_A_TEAPOT',\n 422: 'UNPROCESSABLE_ENTITY',\n 429: 'TOO_MANY_REQUESTS',\n 500: 'INTERNAL_SERVER_ERROR',\n 501: 'NOT_IMPLEMENTED',\n 502: 'BAD_GATEWAY',\n 503: 'SERVICE_UNAVAILABLE',\n 504: 'GATEWAY_TIMEOUT',\n 505: 'HTTP_VERSION_NOT_SUPPORTED',\n}\n\nexport interface HttpExceptionOptions {\n cause?: Error\n description?: string\n}\n\nexport class HttpException extends Error {\n public readonly statusCode: number\n public readonly code: string\n public readonly description?: string\n\n constructor(message: string, statusCode: number, options?: HttpExceptionOptions) {\n super(message, options?.cause ? { cause: options.cause } : undefined)\n this.name = this.constructor.name\n this.statusCode = statusCode\n this.code = STATUS_CODES[statusCode] ?? 'INTERNAL_SERVER_ERROR'\n this.description = options?.description\n }\n\n toJSON() {\n return {\n error: {\n code: this.code,\n message: this.message,\n statusCode: this.statusCode,\n ...(this.description ? { description: this.description } : {}),\n },\n }\n }\n}\n\nfunction factory(status: number, defaultMsg: string) {\n return class extends HttpException {\n constructor(message = defaultMsg, options?: HttpExceptionOptions) {\n super(message, status, options)\n this.name = this.constructor.name\n }\n }\n}\n\nexport class BadRequestException extends factory(400, 'Bad Request') {}\nexport class UnauthorizedException extends factory(401, 'Unauthorized') {}\nexport class ForbiddenException extends factory(403, 'Forbidden') {}\nexport class NotFoundException extends factory(404, 'Not Found') {}\nexport class MethodNotAllowedException extends factory(405, 'Method Not Allowed') {}\nexport class NotAcceptableException extends factory(406, 'Not Acceptable') {}\nexport class RequestTimeoutException extends factory(408, 'Request Timeout') {}\nexport class ConflictException extends factory(409, 'Conflict') {}\nexport class GoneException extends factory(410, 'Gone') {}\nexport class PreconditionFailedException extends factory(412, 'Precondition Failed') {}\nexport class PayloadTooLargeException extends factory(413, 'Payload Too Large') {}\nexport class UnsupportedMediaTypeException extends factory(415, 'Unsupported Media Type') {}\nexport class ImATeapotException extends factory(418, \"I'm a Teapot\") {}\nexport class UnprocessableEntityException extends factory(422, 'Unprocessable Entity') {}\nexport class InternalServerErrorException extends factory(500, 'Internal Server Error') {}\nexport class NotImplementedException extends factory(501, 'Not Implemented') {}\nexport class BadGatewayException extends factory(502, 'Bad Gateway') {}\nexport class ServiceUnavailableException extends factory(503, 'Service Unavailable') {}\nexport class GatewayTimeoutException extends factory(504, 'Gateway Timeout') {}\nexport class HttpVersionNotSupportedException extends factory(505, 'HTTP Version Not Supported') {}\nexport class TooManyRequestsException extends factory(429, 'Too Many Requests') {}\n\n/**\n * HttpStatus enum — all standard HTTP status codes as named constants.\n *\n * @example\n * ```ts\n * import { HttpStatus } from '@theokit/http'\n *\n * @HttpCode(HttpStatus.CREATED)\n * @Post()\n * create() { ... }\n *\n * if (res.status === HttpStatus.NOT_FOUND) { ... }\n * ```\n */\nexport const HttpStatus = {\n // 2xx Success\n OK: 200,\n CREATED: 201,\n ACCEPTED: 202,\n NO_CONTENT: 204,\n\n // 3xx Redirection\n MOVED_PERMANENTLY: 301,\n FOUND: 302,\n NOT_MODIFIED: 304,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n\n // 4xx Client Error\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n NOT_ACCEPTABLE: 406,\n REQUEST_TIMEOUT: 408,\n CONFLICT: 409,\n GONE: 410,\n PRECONDITION_FAILED: 412,\n PAYLOAD_TOO_LARGE: 413,\n UNSUPPORTED_MEDIA_TYPE: 415,\n IM_A_TEAPOT: 418,\n UNPROCESSABLE_ENTITY: 422,\n TOO_MANY_REQUESTS: 429,\n\n // 5xx Server Error\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n BAD_GATEWAY: 502,\n SERVICE_UNAVAILABLE: 503,\n GATEWAY_TIMEOUT: 504,\n} as const\n\nexport type HttpStatusCode = (typeof HttpStatus)[keyof typeof HttpStatus]\n"],"mappings":"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","names":["CONTROLLER_PREFIX","Symbol","for","ROUTE_METHODS","ROUTE_PARAMS","ROUTE_STATUS","ROUTE_HEADERS","ROUTE_REDIRECT","USE_GUARDS","USE_INTERCEPTORS","USE_FILTERS","CATCH_EXCEPTIONS","setMeta","key","target","value","propertyKey","undefined","Reflect","defineMetadata","getMeta","getMetadata","STATUS_CODES","HttpException","Error","statusCode","code","description","message","options","cause","undefined","name","toJSON","error","factory","status","defaultMsg","BadRequestException","UnauthorizedException","ForbiddenException","NotFoundException","MethodNotAllowedException","NotAcceptableException","RequestTimeoutException","ConflictException","GoneException","PreconditionFailedException","PayloadTooLargeException","UnsupportedMediaTypeException","ImATeapotException","UnprocessableEntityException","InternalServerErrorException","NotImplementedException","BadGatewayException","ServiceUnavailableException","GatewayTimeoutException","HttpVersionNotSupportedException","TooManyRequestsException","HttpStatus","OK","CREATED","ACCEPTED","NO_CONTENT","MOVED_PERMANENTLY","FOUND","NOT_MODIFIED","TEMPORARY_REDIRECT","PERMANENT_REDIRECT","BAD_REQUEST","UNAUTHORIZED","PAYMENT_REQUIRED","FORBIDDEN","NOT_FOUND","METHOD_NOT_ALLOWED","NOT_ACCEPTABLE","REQUEST_TIMEOUT","CONFLICT","GONE","PRECONDITION_FAILED","PAYLOAD_TOO_LARGE","UNSUPPORTED_MEDIA_TYPE","IM_A_TEAPOT","UNPROCESSABLE_ENTITY","TOO_MANY_REQUESTS","INTERNAL_SERVER_ERROR","NOT_IMPLEMENTED","BAD_GATEWAY","SERVICE_UNAVAILABLE","GATEWAY_TIMEOUT"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridge/execution-context.ts","../src/bridge/dto-zod.ts","../src/bridge/errors.ts","../src/bridge/walk-metadata.ts"],"sourcesContent":["/**\n * ExecutionContext — Web Standard Request-based context passed to guards.\n *\n * Per ADR D460: the pipeline operates on Web Standard Request/Response.\n * node:http types live ONLY in the runtime adapter (runtime/node.ts).\n *\n * Guards access request headers via request.headers.get('x-role'),\n * NOT via req.headers['x-role'].\n */\n\n/**\n * Execution context available in guards during request processing.\n * Uses Web Standard Request (works on Node, Bun, Deno, CF Workers).\n */\nexport interface ExecutionContext {\n /** The Web Standard Request object. */\n getRequest(): Request\n /** Parsed URL (convenience — avoids re-parsing). */\n getUrl(): URL\n /** The controller class constructor. */\n getClass(): Function\n /** The handler method name (property key on the controller). */\n getMethodName(): string | symbol\n}\n\n/**\n * Interface for guard classes (bound via @UseGuards).\n *\n * @example\n * ```ts\n * class RolesGuard implements CanActivate {\n * canActivate(context: ExecutionContext): boolean {\n * const request = context.getRequest()\n * const role = request.headers.get('x-role')\n * return role === 'admin'\n * }\n * }\n * ```\n */\nexport interface CanActivate {\n canActivate(context: ExecutionContext): boolean | Promise<boolean>\n}\n\n/** Create an ExecutionContext from a Web Standard Request. */\nexport function createExecutionContext(\n request: Request,\n controllerClass: Function,\n methodName: string | symbol,\n): ExecutionContext {\n const url = new URL(request.url)\n return {\n getRequest: () => request,\n getUrl: () => url,\n getClass: () => controllerClass,\n getMethodName: () => methodName,\n }\n}\n","import type { z } from 'zod'\n\n/**\n * Resolves a Zod schema from a DTO class via the `static schema` convention (Pattern D2).\n * Returns undefined when the class doesn't carry a compatible schema.\n */\nexport function resolveDtoSchema(dtoClass: unknown): z.ZodType | undefined {\n if (typeof dtoClass !== 'function') return undefined\n const maybe = (dtoClass as unknown as Record<string, unknown>).schema\n if (\n maybe !== null &&\n maybe !== undefined &&\n typeof (maybe as Record<string, unknown>).safeParse === 'function'\n ) {\n return maybe as z.ZodType\n }\n return undefined\n}\n","/**\n * Configuration error thrown by the bridge when decorator setup is incomplete.\n * Carries actionable messages pointing consumers to the migration guide.\n */\nexport class HttpDecoratorsConfigError extends Error {\n override readonly name = 'HttpDecoratorsConfigError'\n\n constructor(message: string) {\n super(message)\n }\n}\n","import 'reflect-metadata'\nimport type { z } from 'zod'\n\nimport type { ControllerMeta } from '../decorators/controller.js'\nimport type { RouteMethodEntry, HttpVerb } from '../decorators/methods.js'\nimport type { ParamEntry } from '../decorators/params.js'\nimport type { RedirectMeta } from '../decorators/response.js'\nimport {\n getMeta,\n CONTROLLER_PREFIX,\n ROUTE_METHODS,\n ROUTE_PARAMS,\n ROUTE_STATUS,\n ROUTE_HEADERS,\n ROUTE_REDIRECT,\n USE_GUARDS,\n USE_INTERCEPTORS,\n USE_FILTERS,\n} from '../metadata/index.js'\n\nimport { resolveDtoSchema } from './dto-zod.js'\nimport { HttpDecoratorsConfigError } from './errors.js'\n\nexport interface WalkResult {\n verb: HttpVerb\n fullPath: string\n propertyKey: string | symbol\n bodySchema?: z.ZodType\n querySchema?: z.ZodType\n paramsSchema?: z.ZodType\n paramEntries: ParamEntry[]\n status?: number\n headers: [string, string][]\n redirect?: RedirectMeta\n guards: Function[]\n interceptors: Function[]\n filters: Function[]\n}\n\n/**\n * Normalize a joined path: strip doubles, trim trailing, ensure leading.\n * (EC-3)\n */\nexport function joinPath(prefix: string, path: string): string {\n return ('/' + prefix + '/' + path).replace(/\\/+/g, '/').replace(/\\/$/, '') || '/'\n}\n\n/**\n * Resolve the Zod body schema for a method's @Body() param entry.\n *\n * Priority: explicit @Body(zodSchema) > design:paramtypes + DTO static schema.\n * EC-4 relaxed: warns (not throws) when paramtypes missing — @Body(zodSchema) is the fix.\n */\nfunction resolveBodySchema(\n paramEntries: ParamEntry[],\n ControllerClass: Function,\n propertyKey: string | symbol,\n): z.ZodType | undefined {\n const bodyParam = paramEntries.find((p) => p.source === 'body' && !p.key)\n if (!bodyParam) return undefined\n\n // Priority 1: explicit Zod schema from @Body(zodSchema)\n if (bodyParam.schema) return bodyParam.schema\n\n // Priority 2: design:paramtypes + DTO static schema (requires emitDecoratorMetadata)\n const paramTypes: Function[] =\n Reflect.getMetadata('design:paramtypes', ControllerClass.prototype, propertyKey) ?? []\n if (paramTypes.length > 0) {\n return resolveDtoSchema(paramTypes[bodyParam.index])\n }\n\n // EC-4 relaxed: warn when @Body() has no schema and no paramtypes\n console.warn(\n `[@theokit/http] method ${String(propertyKey)} on ` +\n `${ControllerClass.name}: @Body() without explicit schema and ` +\n `emitDecoratorMetadata is not active. Body will be passed raw (no validation). ` +\n `Fix: use @Body(zodSchema) for validation without metadata emission.`,\n )\n return undefined\n}\n\n/** WeakMap cache — metadata is immutable; walk once, reuse forever. */\nconst walkCache = new WeakMap<Function, WalkResult[]>()\n\n/**\n * Walk all decorator metadata on a controller class and produce\n * a structured list of route descriptors. Memoized per class via WeakMap.\n */\nexport function walkControllerMetadata(ControllerClass: Function): WalkResult[] {\n const cached = walkCache.get(ControllerClass)\n if (cached) return cached\n // EC-2: throw when @Controller decorator is missing\n const controllerMeta = getMeta<ControllerMeta>(CONTROLLER_PREFIX, ControllerClass)\n if (!controllerMeta) {\n throw new HttpDecoratorsConfigError(\n `Controller class ${ControllerClass.name} is missing @Controller() decorator. ` +\n `Add @Controller('prefix') to the class declaration.`,\n )\n }\n const { prefix, host } = controllerMeta\n\n // Q4: host captured but enforcement deferred to v0.2.0\n if (host) {\n console.warn(\n `[@theokit/http] @Controller host '${host}' captured but enforcement deferred to v0.2.0`,\n )\n }\n\n const methods = getMeta<RouteMethodEntry[]>(ROUTE_METHODS, ControllerClass) ?? []\n const paramsMap =\n getMeta<Map<string | symbol, ParamEntry[]>>(ROUTE_PARAMS, ControllerClass) ?? new Map()\n\n // Class-level guards/interceptors\n const classGuards = getMeta<Function[]>(USE_GUARDS, ControllerClass) ?? []\n const classInterceptors = getMeta<Function[]>(USE_INTERCEPTORS, ControllerClass) ?? []\n const classFilters = getMeta<Function[]>(USE_FILTERS, ControllerClass) ?? []\n\n const result = methods.map((m) => {\n const paramEntries = paramsMap.get(m.propertyKey) ?? []\n const bodySchema = resolveBodySchema(paramEntries, ControllerClass, m.propertyKey)\n\n // Method-level guards/interceptors (composed: class FIRST per NestJS convention — EC-9)\n const methodGuards = getMeta<Function[]>(USE_GUARDS, ControllerClass, m.propertyKey) ?? []\n const methodInterceptors =\n getMeta<Function[]>(USE_INTERCEPTORS, ControllerClass, m.propertyKey) ?? []\n\n return {\n verb: m.verb,\n fullPath: joinPath(prefix, m.path),\n propertyKey: m.propertyKey,\n bodySchema,\n paramEntries: [...paramEntries].sort((a, b) => a.index - b.index),\n status: getMeta<number>(ROUTE_STATUS, ControllerClass, m.propertyKey),\n headers: getMeta<[string, string][]>(ROUTE_HEADERS, ControllerClass, m.propertyKey) ?? [],\n redirect: getMeta<RedirectMeta>(ROUTE_REDIRECT, ControllerClass, m.propertyKey),\n guards: [...classGuards, ...methodGuards],\n interceptors: [...classInterceptors, ...methodInterceptors],\n filters: getMeta<Function[]>(USE_FILTERS, ControllerClass, m.propertyKey) ?? classFilters,\n }\n })\n\n walkCache.set(ControllerClass, result)\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA4CO,SAASA,uBACdC,SACAC,iBACAC,YAA2B;AAE3B,QAAMC,MAAM,IAAIC,IAAIJ,QAAQG,GAAG;AAC/B,SAAO;IACLE,YAAY,6BAAML,SAAN;IACZM,QAAQ,6BAAMH,KAAN;IACRI,UAAU,6BAAMN,iBAAN;IACVO,eAAe,6BAAMN,YAAN;EACjB;AACF;AAZgBH;;;ACtCT,SAASU,iBAAiBC,UAAiB;AAChD,MAAI,OAAOA,aAAa,WAAY,QAAOC;AAC3C,QAAMC,QAASF,SAAgDG;AAC/D,MACED,UAAU,QACVA,UAAUD,UACV,OAAQC,MAAkCE,cAAc,YACxD;AACA,WAAOF;EACT;AACA,SAAOD;AACT;AAXgBF;;;ACFT,IAAMM,4BAAN,cAAwCC,MAAAA;EAJ/C,OAI+CA;;;EAC3BC,OAAO;EAEzB,YAAYC,SAAiB;AAC3B,UAAMA,OAAAA;EACR;AACF;;;ACVA,OAAO;AA2CA,SAASC,SAASC,QAAgBC,MAAY;AACnD,UAAQ,MAAMD,SAAS,MAAMC,MAAMC,QAAQ,QAAQ,GAAA,EAAKA,QAAQ,OAAO,EAAA,KAAO;AAChF;AAFgBH;AAUhB,SAASI,kBACPC,cACAC,iBACAC,aAA4B;AAE5B,QAAMC,YAAYH,aAAaI,KAAK,CAACC,MAAMA,EAAEC,WAAW,UAAU,CAACD,EAAEE,GAAG;AACxE,MAAI,CAACJ,UAAW,QAAOK;AAGvB,MAAIL,UAAUM,OAAQ,QAAON,UAAUM;AAGvC,QAAMC,aACJC,QAAQC,YAAY,qBAAqBX,gBAAgBY,WAAWX,WAAAA,KAAgB,CAAA;AACtF,MAAIQ,WAAWI,SAAS,GAAG;AACzB,WAAOC,iBAAiBL,WAAWP,UAAUa,KAAK,CAAC;EACrD;AAGAC,UAAQC,KACN,0BAA0BC,OAAOjB,WAAAA,CAAAA,OAC5BD,gBAAgBmB,IAAI,yLAE8C;AAEzE,SAAOZ;AACT;AA1BST;AA6BT,IAAMsB,YAAY,oBAAIC,QAAAA;AAMf,SAASC,uBAAuBtB,iBAAyB;AAC9D,QAAMuB,SAASH,UAAUI,IAAIxB,eAAAA;AAC7B,MAAIuB,OAAQ,QAAOA;AAEnB,QAAME,iBAAiBC,QAAwBC,mBAAmB3B,eAAAA;AAClE,MAAI,CAACyB,gBAAgB;AACnB,UAAM,IAAIG,0BACR,oBAAoB5B,gBAAgBmB,IAAI,0FACe;EAE3D;AACA,QAAM,EAAExB,QAAQkC,KAAI,IAAKJ;AAGzB,MAAII,MAAM;AACRb,YAAQC,KACN,qCAAqCY,IAAAA,+CAAmD;EAE5F;AAEA,QAAMC,UAAUJ,QAA4BK,eAAe/B,eAAAA,KAAoB,CAAA;AAC/E,QAAMgC,YACJN,QAA4CO,cAAcjC,eAAAA,KAAoB,oBAAIkC,IAAAA;AAGpF,QAAMC,cAAcT,QAAoBU,YAAYpC,eAAAA,KAAoB,CAAA;AACxE,QAAMqC,oBAAoBX,QAAoBY,kBAAkBtC,eAAAA,KAAoB,CAAA;AACpF,QAAMuC,eAAeb,QAAoBc,aAAaxC,eAAAA,KAAoB,CAAA;AAE1E,QAAMyC,SAASX,QAAQY,IAAI,CAACC,MAAAA;AAC1B,UAAM5C,eAAeiC,UAAUR,IAAImB,EAAE1C,WAAW,KAAK,CAAA;AACrD,UAAM2C,aAAa9C,kBAAkBC,cAAcC,iBAAiB2C,EAAE1C,WAAW;AAGjF,UAAM4C,eAAenB,QAAoBU,YAAYpC,iBAAiB2C,EAAE1C,WAAW,KAAK,CAAA;AACxF,UAAM6C,qBACJpB,QAAoBY,kBAAkBtC,iBAAiB2C,EAAE1C,WAAW,KAAK,CAAA;AAE3E,WAAO;MACL8C,MAAMJ,EAAEI;MACRC,UAAUtD,SAASC,QAAQgD,EAAE/C,IAAI;MACjCK,aAAa0C,EAAE1C;MACf2C;MACA7C,cAAc;WAAIA;QAAckD,KAAK,CAACC,GAAGC,MAAMD,EAAEnC,QAAQoC,EAAEpC,KAAK;MAChEqC,QAAQ1B,QAAgB2B,cAAcrD,iBAAiB2C,EAAE1C,WAAW;MACpEqD,SAAS5B,QAA4B6B,eAAevD,iBAAiB2C,EAAE1C,WAAW,KAAK,CAAA;MACvFuD,UAAU9B,QAAsB+B,gBAAgBzD,iBAAiB2C,EAAE1C,WAAW;MAC9EyD,QAAQ;WAAIvB;WAAgBU;;MAC5Bc,cAAc;WAAItB;WAAsBS;;MACxCc,SAASlC,QAAoBc,aAAaxC,iBAAiB2C,EAAE1C,WAAW,KAAKsC;IAC/E;EACF,CAAA;AAEAnB,YAAUyC,IAAI7D,iBAAiByC,MAAAA;AAC/B,SAAOA;AACT;AAvDgBnB;","names":["createExecutionContext","request","controllerClass","methodName","url","URL","getRequest","getUrl","getClass","getMethodName","resolveDtoSchema","dtoClass","undefined","maybe","schema","safeParse","HttpDecoratorsConfigError","Error","name","message","joinPath","prefix","path","replace","resolveBodySchema","paramEntries","ControllerClass","propertyKey","bodyParam","find","p","source","key","undefined","schema","paramTypes","Reflect","getMetadata","prototype","length","resolveDtoSchema","index","console","warn","String","name","walkCache","WeakMap","walkControllerMetadata","cached","get","controllerMeta","getMeta","CONTROLLER_PREFIX","HttpDecoratorsConfigError","host","methods","ROUTE_METHODS","paramsMap","ROUTE_PARAMS","Map","classGuards","USE_GUARDS","classInterceptors","USE_INTERCEPTORS","classFilters","USE_FILTERS","result","map","m","bodySchema","methodGuards","methodInterceptors","verb","fullPath","sort","a","b","status","ROUTE_STATUS","headers","ROUTE_HEADERS","redirect","ROUTE_REDIRECT","guards","interceptors","filters","set"]}