@theokit/http 0.6.0 → 1.0.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.d.ts +33 -4
- package/dist/app.js +3 -3
- package/dist/{chunk-6W4T4DPJ.js → chunk-CMPP4ULU.js} +2 -2
- package/dist/{chunk-GQ2UH554.js → chunk-DRCRGDA3.js} +26 -41
- package/dist/chunk-DRCRGDA3.js.map +1 -0
- package/dist/{chunk-QGB5YC4T.js → chunk-JQMJK47T.js} +31 -4
- package/dist/chunk-JQMJK47T.js.map +1 -0
- package/dist/{chunk-3PGQVQWG.js → chunk-KPC7AIVC.js} +3 -1
- package/dist/chunk-KPC7AIVC.js.map +1 -0
- package/dist/{chunk-RC4V75DI.js → chunk-OBHHOS6E.js} +2 -2
- package/dist/{exception-filter-chain-O45FXGEB.js → exception-filter-chain-V2MFO4WV.js} +3 -3
- package/dist/index.d.ts +64 -4
- package/dist/index.js +38 -9
- package/dist/index.js.map +1 -1
- package/dist/theokit-plugin.js +4 -4
- package/package.json +8 -3
- package/dist/chunk-3PGQVQWG.js.map +0 -1
- package/dist/chunk-GQ2UH554.js.map +0 -1
- package/dist/chunk-QGB5YC4T.js.map +0 -1
- /package/dist/{chunk-6W4T4DPJ.js.map → chunk-CMPP4ULU.js.map} +0 -0
- /package/dist/{chunk-RC4V75DI.js.map → chunk-OBHHOS6E.js.map} +0 -0
- /package/dist/{exception-filter-chain-O45FXGEB.js.map → exception-filter-chain-V2MFO4WV.js.map} +0 -0
package/dist/theokit-plugin.js
CHANGED
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
MiddlewareConsumerImpl,
|
|
3
3
|
loadControllersFromGlob,
|
|
4
4
|
runMiddleware
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OBHHOS6E.js";
|
|
6
6
|
import {
|
|
7
7
|
createExecutionContext,
|
|
8
8
|
walkControllerMetadata
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
19
|
+
} from "./chunk-CMPP4ULU.js";
|
|
20
20
|
import {
|
|
21
21
|
ForbiddenException
|
|
22
|
-
} from "./chunk-
|
|
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.
|
|
3
|
+
"version": "1.0.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,
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"react": ">=18.0.0",
|
|
35
35
|
"react-dom": ">=18.0.0",
|
|
36
36
|
"reflect-metadata": "^0.2.2",
|
|
37
|
-
"zod": "^4.0.0"
|
|
37
|
+
"zod": "^4.0.0",
|
|
38
|
+
"@theokit/agents": ">=0.47.0"
|
|
38
39
|
},
|
|
39
40
|
"peerDependenciesMeta": {
|
|
40
41
|
"@swc/core": {
|
|
@@ -45,6 +46,9 @@
|
|
|
45
46
|
},
|
|
46
47
|
"react-dom": {
|
|
47
48
|
"optional": true
|
|
49
|
+
},
|
|
50
|
+
"@theokit/agents": {
|
|
51
|
+
"optional": true
|
|
48
52
|
}
|
|
49
53
|
},
|
|
50
54
|
"devDependencies": {
|
|
@@ -53,7 +57,8 @@
|
|
|
53
57
|
"tsup": "^8.5.1",
|
|
54
58
|
"typescript": "^5.9.3",
|
|
55
59
|
"vitest": "^3.2.6",
|
|
56
|
-
"zod": "^4.4.3"
|
|
60
|
+
"zod": "^4.4.3",
|
|
61
|
+
"@theokit/agents": "1.0.0"
|
|
57
62
|
},
|
|
58
63
|
"license": "MIT",
|
|
59
64
|
"engines": {
|
|
@@ -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/app.ts","../src/request-context.ts","../src/static.ts","../src/stream-renderer.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-regexp, complexity, sonarjs/cognitive-complexity, max-depth, sonarjs/no-collapsible-if, max-lines, max-lines-per-function */\nimport 'reflect-metadata'\n\nimport { createExecutionContext, type CanActivate } from './bridge/execution-context.js'\nimport { createNodeAdapter } from './bridge/runtime/node.js'\nimport type { ServerHandle } from './bridge/runtime/types.js'\nimport { walkControllerMetadata, type WalkResult } from './bridge/walk-metadata.js'\nimport type { ParamEntry } from './decorators/params.js'\nimport { ForbiddenException, HttpException } from './exceptions/http-exception.js'\nimport { runWithRequestContext, type TheoRequestContext } from './request-context.js'\nimport { createStaticHandler } from './static.js'\nimport { renderToStream, streamToResponse } from './stream-renderer.js'\n\n/**\n * TheoApp — NestJS/Spring Boot-style application bootstrap.\n *\n * Internally uses Web Standard Request/Response pipeline.\n * Node adapter converts at the HTTP server boundary.\n */\n\n/** Readiness check — async function returning health status. */\nexport type ReadinessCheck = () => Promise<{ name: string; healthy: boolean; message?: string }>\n\nexport interface TheoAppOptions {\n /** Controller classes decorated with @Controller. */\n controllers: Function[]\n /** Agent classes decorated with @Agent — auto-wired with routes + SSE + tools. */\n agents?: Function[]\n /** @Module class for structured DI. */\n module?: Function\n /** Provider/toolbox classes — instantiated and injected into controllers + agents. */\n providers?: Function[]\n /** LLM API key for agent execution (reads OPENROUTER_API_KEY env if not set). */\n llmApiKey?: string\n /** LLM model override (default: from @Agent({ model }) metadata). */\n llmModel?: string\n /** Agent stream factory override (for testing or custom SDK wiring). */\n agentStreamFactory?: (\n walk: unknown,\n tools: unknown[],\n apiKey: string,\n model?: string,\n ) => (message: string, sessionId: string) => AsyncIterable<unknown>\n /** HTML string to serve at GET / (inline frontend). */\n html?: string\n /** React root element — framework renders SSR internally (preferred over html). */\n root?: unknown\n /** Directory for static file serving (default: 'public', false to disable). */\n staticDir?: string | false\n /** Readiness checks for GET /__theo/ready (K8s readiness probe). */\n readinessChecks?: ReadinessCheck[]\n /** Custom health endpoint path (default: '/__theo/health'). */\n healthPath?: string\n /** Custom readiness endpoint path (default: '/__theo/ready'). */\n readyPath?: string\n /**\n * Enable streaming SSR via `renderToReadableStream` (default: false).\n *\n * When `true` AND `root` is provided, the app serves GET / with a streamed\n * HTML response instead of a static `renderToString` result. This enables\n * progressive rendering with React Suspense boundaries.\n *\n * **EC-7 — Error handling difference:** In streaming mode, errors inside\n * Suspense boundaries are caught by React's streaming error handler and\n * activate client-side error boundaries (the shell is already sent). In\n * string mode, errors throw synchronously before any bytes are sent,\n * allowing a full 500 error page.\n */\n streaming?: boolean\n}\n\ninterface RouteEntry {\n walk: WalkResult\n instance: object\n /** Pre-compiled regex + param names (Elysia-inspired: compile once at create, not per-request). */\n compiledPattern?: RegExp\n compiledParamNames?: string[]\n /** Whether handler needs body parsing (skip for GET/DELETE without @Body). */\n needsBody?: boolean\n}\n\nexport class TheoApp {\n private serverHandle: ServerHandle\n private readonly routes: RouteEntry[] = []\n private frontendHtml?: string\n private streamingRoot?: unknown\n private staticHandler?: (request: Request) => Promise<Response | null>\n private readonly startTime = Date.now()\n private readonly healthPath: string\n private readonly readyPath: string\n private readonly readinessChecks: ReadinessCheck[]\n\n private constructor(opts?: Pick<TheoAppOptions, 'readinessChecks' | 'healthPath' | 'readyPath'>) {\n const hp = opts?.healthPath ?? '/__theo/health'\n const rp = opts?.readyPath ?? '/__theo/ready'\n // Security: prevent health paths from colliding with user API routes\n if (hp.startsWith('/api/'))\n throw new Error(\n `[TheoApp] healthPath \"${hp}\" must not start with /api/ — would collide with user routes`,\n )\n if (rp.startsWith('/api/'))\n throw new Error(\n `[TheoApp] readyPath \"${rp}\" must not start with /api/ — would collide with user routes`,\n )\n this.healthPath = hp\n this.readyPath = rp\n this.readinessChecks = opts?.readinessChecks ?? []\n const adapter = createNodeAdapter()\n this.serverHandle = adapter.createServer((request) => this.handleRequest(request))\n }\n\n /**\n * Create a TheoKit application with Spring Boot-style DI.\n *\n * EC-7: async because Container may resolve async factories (Agent.create).\n * EC-2: Registration order guaranteed: providers → controllers → agents.\n */\n static async create(opts: TheoAppOptions): Promise<TheoApp> {\n const app = new TheoApp(opts)\n\n // ── DI Container (replaces manual Map<Function, object>) ──\n // Uses @theokit/di Container for: scopes, lifecycle, async, typed errors.\n // Fallback to manual resolution when @theokit/di is not available.\n const registry = new Map<Function, object>()\n\n // 1. Module resolution (@Module metadata)\n if (opts.module) {\n const moduleMeta = Reflect.getMetadata('usetheo:di:module', opts.module)\n if (moduleMeta) {\n const allModules = [opts.module, ...(moduleMeta.imports ?? [])]\n for (const Mod of allModules) {\n const meta = Reflect.getMetadata('usetheo:di:module', Mod)\n if (!meta) continue\n for (const Prov of (meta.providers ?? []) as Function[]) {\n if (!registry.has(Prov)) {\n registry.set(Prov, new (Prov as new () => object)())\n }\n }\n }\n }\n }\n\n // 2. Inline providers (EC-2: BEFORE controllers and agents)\n if (opts.providers) {\n for (const Prov of opts.providers) {\n if (!registry.has(Prov)) {\n registry.set(Prov, new (Prov as new () => object)())\n }\n }\n }\n\n // 3. Controllers with DI\n for (const Controller of opts.controllers) {\n const paramTypes: Function[] = Reflect.getMetadata('design:paramtypes', Controller) ?? []\n const args = paramTypes.map((pt: Function) => {\n const dep = registry.get(pt)\n if (!dep) {\n throw new Error(\n `[TheoApp] Cannot resolve ${pt.name} for ${Controller.name}. ` +\n `Add ${pt.name} to providers (or to @Module({ providers: [...] })).`,\n )\n }\n return dep\n })\n const instance = new (Controller as new (...a: unknown[]) => object)(...args)\n\n // Lifecycle: call @PostConstruct if present\n const postConstruct = Reflect.getMetadata('usetheo:di:post-construct', Controller)\n if (\n postConstruct &&\n typeof (instance as Record<string, Function>)[postConstruct] === 'function'\n ) {\n const result = (instance as Record<string, Function>)[postConstruct]()\n if (result instanceof Promise) await result // EC-1: await async PostConstruct\n }\n\n const walks = walkControllerMetadata(Controller)\n for (const w of walks) {\n app.routes.push({ walk: w, instance })\n }\n }\n\n // Sort: static before parameterized\n app.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 // Pre-compile route patterns (Elysia-inspired: regex built once, not per-request)\n for (const entry of app.routes) {\n const paramNames: string[] = []\n const regexStr = entry.walk.fullPath.replace(/:(\\w+)/g, (_m, name: string) => {\n paramNames.push(name)\n return '([^/]+)'\n })\n entry.compiledPattern = new RegExp(`^${regexStr}$`)\n entry.compiledParamNames = paramNames\n // Determine if handler needs body parsing (skip if no @Body decorator)\n entry.needsBody = entry.walk.paramEntries.some((p) => p.source === 'body')\n }\n\n // Frontend HTML — from root (React SSR) or html string\n if (opts.root && opts.streaming) {\n // Streaming mode: store the root element; render per-request via renderToStream\n app.streamingRoot = opts.root\n } else if (opts.root) {\n const { renderToString } = await import('react-dom/server')\n app.frontendHtml = '<!DOCTYPE html>' + renderToString(opts.root as React.ReactElement)\n } else if (opts.html) {\n app.frontendHtml = opts.html\n }\n\n // Static file serving from public/ (default: enabled)\n if (opts.staticDir !== false) {\n app.staticHandler = createStaticHandler({ root: opts.staticDir ?? 'public' })\n }\n\n // 4. Auto-wire agents (EC-2: AFTER providers and controllers)\n // The framework handles EVERYTHING — walk, compile, mount, stream.\n // Consumer writes: agents: [MyAgent] — and that's it.\n if (opts.agents?.length) {\n await app.autoWireAgents(opts.agents, registry, opts)\n }\n\n return app\n }\n\n async listen(port: number): Promise<void> {\n return new Promise((resolve) => {\n this.serverHandle.listen(port, () => {\n console.log(`TheoKit app listening on http://localhost:${port}`)\n resolve()\n })\n })\n }\n\n getServerHandle(): ServerHandle {\n return this.serverHandle\n }\n\n async close(): Promise<void> {\n return new Promise((resolve) => {\n this.serverHandle.close(() => {\n resolve()\n })\n })\n }\n\n // ── Auto-wire agents (the \"SpringApplication.run()\" moment) ──\n\n private agentRoutes: {\n method: string\n pattern: RegExp\n paramNames: string[]\n handler: (request: Request) => Promise<Response>\n guards: Function[]\n agentClass: Function\n methodName: string | symbol\n }[] = []\n\n private async autoWireAgents(\n agentClasses: Function[],\n registry: Map<Function, object>,\n opts: TheoAppOptions,\n ) {\n // Dynamic import — @theokit/agents is optional peer dependency\n // SECURITY: new Function used for dynamic import of optional peer dep.\n // Argument is HARDCODED ('@theokit/agents'), never user input. Safe.\n // eslint-disable-next-line @typescript-eslint/no-implied-eval -- dynamic import avoids compile-time dependency on optional peer\n const importFn = new Function('specifier', 'return import(specifier)') as (\n s: string,\n ) => Promise<Record<string, Function>>\n let walkAgentMetadata: Function,\n compileAgent: Function,\n generateAgentRoutes: Function,\n getMixins: Function,\n createSdkAgentStreamFn: Function\n try {\n const mod = await importFn('@theokit/agents')\n walkAgentMetadata = mod.walkAgentMetadata\n compileAgent = mod.compileAgent\n generateAgentRoutes = mod.generateAgentRoutes\n getMixins = mod.getMixins\n createSdkAgentStreamFn = mod.createSdkAgentStream\n } catch {\n throw new Error(\n '[TheoApp] @theokit/agents is required when agents[] is provided. Install: npm install @theokit/agents',\n )\n }\n\n const apiKey = opts.llmApiKey ?? process.env.OPENROUTER_API_KEY ?? ''\n\n for (const AgentClass of agentClasses) {\n // 1. Walk metadata (decorators → structured data)\n const mixins = getMixins(AgentClass)\n const allToolboxes = [...mixins]\n\n // Also check providers for @Toolbox classes\n for (const [Cls] of registry) {\n if (Reflect.getMetadata(Symbol.for('theokit:agents:toolbox'), Cls)) {\n if (!allToolboxes.includes(Cls)) allToolboxes.push(Cls)\n }\n }\n\n const walk = walkAgentMetadata(AgentClass, allToolboxes)\n\n // 2. Resolve toolbox instances from registry (DI)\n const toolboxInstances = new Map<Function, object>()\n for (const tb of walk.toolboxes) {\n let instance = registry.get(tb.class)\n if (!instance) {\n instance = new (tb.class as new () => object)()\n registry.set(tb.class, instance)\n }\n toolboxInstances.set(tb.class, instance)\n }\n\n // 3. Compile tools (decorator metadata → defineTool-compatible)\n const compiled = compileAgent(walk, toolboxInstances)\n\n // 4. Create SDK agent stream factory\n let createRun: (message: string, sessionId: string) => AsyncIterable<unknown>\n\n if (opts.agentStreamFactory) {\n createRun = opts.agentStreamFactory(walk, compiled.tools, apiKey, opts.llmModel)\n } else if (apiKey) {\n // SDK adapter: bridges @theokit/agents decorators → @theokit/sdk runtime\n createRun = createSdkAgentStreamFn(walk, compiled.tools, apiKey, opts.llmModel) as (\n m: string,\n s: string,\n ) => AsyncIterable<unknown>\n } else {\n createRun = this.createFallbackStream(walk.agentConfig.name, apiKey)\n }\n\n // 5. Generate routes (POST /chat, GET /runs/:id)\n const routes = generateAgentRoutes({\n walkResult: walk,\n compiledOptions: compiled,\n createRun: createRun as (\n message: string,\n sessionId: string,\n ) => AsyncIterable<{ type: string; [k: string]: unknown }>,\n })\n\n // 6. Mount routes\n for (const route of routes) {\n const paramNames: string[] = []\n const regexStr = route.path.replace(/:(\\w+)/g, (_m: string, name: string) => {\n paramNames.push(name)\n return '([^/]+)'\n })\n this.agentRoutes.push({\n method: route.method,\n pattern: new RegExp(`^${regexStr}$`),\n paramNames,\n handler: route.handler,\n guards: walk.guards ?? [],\n agentClass: AgentClass,\n methodName: walk.mainLoop?.propertyKey ?? 'run',\n })\n }\n\n console.log(\n ` 🤖 Agent \"${walk.agentConfig.name}\" mounted at ${walk.route}/chat (${compiled.tools.length} tools)`,\n )\n }\n }\n\n private async handleReadinessCheck(): Promise<Response> {\n if (this.readinessChecks.length === 0) {\n return jsonResponse(200, { status: 'ready', checks: [] })\n }\n const results = await Promise.all(\n this.readinessChecks.map(async (check) => {\n try {\n return await Promise.race([\n check(),\n new Promise<{ name: string; healthy: boolean; message?: string }>((resolve) =>\n setTimeout(\n () =>\n resolve({\n name: 'unknown',\n healthy: false,\n message: 'Readiness check timed out (5s)',\n }),\n 5000,\n ),\n ),\n ])\n } catch (err) {\n return {\n name: 'unknown',\n healthy: false,\n message: err instanceof Error ? err.message : 'Check failed',\n }\n }\n }),\n )\n const allHealthy = results.every((r) => r.healthy)\n return jsonResponse(allHealthy ? 200 : 503, {\n status: allHealthy ? 'ready' : 'not_ready',\n checks: results,\n })\n }\n\n private createFallbackStream(agentName: string, apiKey: string) {\n const msg = !apiKey\n ? 'Set OPENROUTER_API_KEY environment variable or pass llmApiKey to TheoApp.create()'\n : 'Pass agentStreamFactory to TheoApp.create() to connect your LLM provider'\n return (_message: string, _sessionId: string) => {\n const events = [\n { type: 'run_started', runId: `run-${Date.now()}`, agentName },\n { type: 'error', code: 'AGENT_NOT_WIRED', message: msg, retryable: false },\n ]\n return {\n [Symbol.asyncIterator]: () => {\n let i = 0\n return {\n next: () =>\n Promise.resolve(\n i < events.length\n ? { value: events[i++], done: false as const }\n : { value: undefined, done: true as const },\n ),\n }\n },\n }\n }\n }\n\n // ── Web Standard request handler ──────────────────\n\n private async handleRequest(request: Request): Promise<Response> {\n const pathname = new URL(request.url).pathname\n\n // Wrap entire request in AsyncLocalStorage context\n const reqCtx: TheoRequestContext = {\n request,\n pathname,\n method: request.method,\n params: {},\n startedAt: Date.now(),\n }\n return runWithRequestContext(reqCtx, () =>\n this.handleRequestInContext(request, pathname, reqCtx),\n )\n }\n\n private async handleRequestInContext(\n request: Request,\n pathname: string,\n _reqCtx: TheoRequestContext,\n ): Promise<Response> {\n // ── Health & Readiness probes (bypass guards/interceptors) ──\n if (request.method === 'GET') {\n if (pathname === this.healthPath) {\n return jsonResponse(200, {\n status: 'ok',\n uptime: (Date.now() - this.startTime) / 1000,\n timestamp: Date.now(),\n })\n }\n if (pathname === this.readyPath) {\n return this.handleReadinessCheck()\n }\n }\n\n // Bug #8: Serve frontend HTML at GET /\n if (request.method === 'GET') {\n if ((pathname === '/' || pathname === '/index.html') && this.streamingRoot) {\n const result = await renderToStream({\n root: this.streamingRoot as React.ReactElement,\n })\n return streamToResponse(result)\n }\n if ((pathname === '/' || pathname === '/index.html') && this.frontendHtml) {\n return new Response(this.frontendHtml, {\n status: 200,\n headers: { 'content-type': 'text/html; charset=utf-8' },\n })\n }\n }\n\n // Static files from public/ (runtime-agnostic — Node/Bun/Deno)\n if (this.staticHandler && (request.method === 'GET' || request.method === 'HEAD')) {\n const staticResponse = await this.staticHandler(request)\n if (staticResponse) return staticResponse\n }\n\n // Agent routes (auto-wired — checked first, with guard enforcement per Bug #4)\n for (const route of this.agentRoutes) {\n if (request.method.toUpperCase() === route.method && route.pattern.test(pathname)) {\n // Bug #4 fix: enforce @UseGuards on agent routes (same pipeline as controllers)\n if (route.guards.length > 0) {\n const ctx = createExecutionContext(request, route.agentClass, route.methodName)\n for (const GuardCtor of route.guards) {\n const guard = new (GuardCtor as new () => CanActivate)()\n if (!(await guard.canActivate(ctx))) {\n const ex = new ForbiddenException('Forbidden resource')\n return jsonResponse(ex.statusCode, ex.toJSON())\n }\n }\n }\n return route.handler(request)\n }\n }\n\n const url = new URL(request.url)\n const method = request.method.toUpperCase()\n\n const match = this.findRoute(method, url.pathname)\n if (!match) {\n return jsonResponse(404, {\n error: { code: 'NOT_FOUND', message: `No route for ${method} ${url.pathname}` },\n })\n }\n\n const { entry, params } = match\n\n try {\n // Guards\n const ctx = createExecutionContext(\n request,\n entry.instance.constructor,\n entry.walk.propertyKey,\n )\n for (const GuardCtor of entry.walk.guards) {\n const guard = new (GuardCtor as new () => CanActivate)()\n if (!(await guard.canActivate(ctx))) {\n const ex = new ForbiddenException('Forbidden resource')\n return jsonResponse(ex.statusCode, ex.toJSON())\n }\n }\n\n // Body — skip parsing entirely if handler has no @Body decorator (Elysia-inspired lazy parsing)\n let body: unknown\n if (entry.needsBody && ['POST', 'PUT', 'PATCH'].includes(method)) {\n try {\n const text = await request.text()\n body = text ? JSON.parse(text) : undefined\n } catch {\n body = undefined\n }\n\n if (entry.walk.bodySchema && body !== undefined) {\n const result = entry.walk.bodySchema.safeParse(body)\n if (!result.success) {\n return jsonResponse(422, {\n error: { code: 'VALIDATION_ERROR', issues: result.error.issues },\n })\n }\n body = result.data\n }\n }\n\n // Args\n const args = this.buildArgs(\n entry.walk.paramEntries,\n request,\n body,\n params,\n Object.fromEntries(url.searchParams),\n )\n\n // Redirect\n if (entry.walk.redirect) {\n return new Response(null, {\n status: entry.walk.redirect.status,\n headers: { location: entry.walk.redirect.url },\n })\n }\n\n // Handler — wrapped by interceptor chain (Bug #2 fix)\n const handlerFn = (entry.instance as Record<string | symbol, Function>)[\n entry.walk.propertyKey\n ]\n\n let result: unknown\n if (entry.walk.interceptors.length > 0) {\n // Import runInterceptors dynamically to avoid circular dep\n const { runInterceptors } = await import('./bridge/interceptor-chain.js')\n result = await runInterceptors(\n entry.walk.interceptors,\n () => handlerFn.apply(entry.instance, args) as Promise<unknown>,\n request,\n )\n } else {\n result = await handlerFn.apply(entry.instance, args)\n }\n\n return buildResponse(result, entry.walk, method)\n } catch (err) {\n // Exception filters (Bug #2 fix — filters also wired)\n if (entry.walk.filters.length > 0) {\n const { runExceptionFilters } = await import('./bridge/exception-filter-chain.js')\n return runExceptionFilters(err, entry.walk.filters, request)\n }\n // Fallback: HttpException subclasses (Bug #3 fix)\n if (err instanceof HttpException) {\n return jsonResponse(err.statusCode, err.toJSON())\n }\n // Security: never leak raw error messages to clients\n console.error('[theokit] Internal error:', err instanceof Error ? err.message : err)\n return jsonResponse(500, {\n error: { code: 'INTERNAL_SERVER_ERROR', message: 'Internal Server Error' },\n })\n }\n }\n\n private findRoute(method: string, pathname: string) {\n for (const entry of this.routes) {\n if (entry.walk.verb !== 'ALL' && entry.walk.verb !== method) continue\n // Use pre-compiled regex (built once at create time, not per-request)\n const match = entry.compiledPattern!.exec(pathname)\n if (!match) continue\n const params: Record<string, string> = {}\n entry.compiledParamNames!.forEach((name, i) => {\n params[name] = match[i + 1]\n })\n return { entry, params }\n }\n return null\n }\n\n private buildArgs(\n entries: ParamEntry[],\n request: Request,\n body: unknown,\n params: Record<string, string>,\n query: Record<string, string>,\n ): unknown[] {\n if (entries.length === 0) return []\n const max = Math.max(...entries.map((p) => p.index))\n const args: unknown[] = Array.from({ length: max + 1 }, () => undefined)\n for (const p of entries) {\n switch (p.source) {\n case 'req':\n args[p.index] = request\n break\n case 'body':\n args[p.index] = p.key ? (body as Record<string, unknown>)[p.key] : body\n break\n case 'param':\n args[p.index] = p.key ? params[p.key] : params\n break\n case 'query':\n args[p.index] = p.key ? query[p.key] : query\n break\n case 'headers':\n args[p.index] = p.key\n ? request.headers.get(p.key.toLowerCase())\n : Object.fromEntries(request.headers.entries())\n break\n case 'ip':\n args[p.index] = request.headers.get('x-forwarded-for') ?? '127.0.0.1'\n break\n default:\n args[p.index] = undefined\n }\n }\n return args\n }\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\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 [n, v] of walk.headers) headers[n.toLowerCase()] = v\n\n if (result === undefined || result === null) {\n return new Response(null, { status: status === 200 ? 204 : status, headers })\n }\n if (typeof result === 'string') {\n headers['content-type'] = 'text/plain'\n return new Response(result, { status, headers })\n }\n return new Response(JSON.stringify(result), { status, headers })\n}\n","/**\n * Request Context — per-request state via AsyncLocalStorage.\n *\n * Inspired by Next.js workAsyncStorage pattern (app-render.tsx:3325).\n * Eliminates prop drilling — any code in the request path can access\n * the current request without receiving it as a parameter.\n *\n * Usage:\n * import { getRequestContext } from '@theokit/http'\n * const { request, pathname, method, params } = getRequestContext()\n *\n * The context is populated by TheoApp.handleRequest() and available\n * to guards, interceptors, filters, controllers, agents, and tools.\n */\nimport { AsyncLocalStorage } from 'node:async_hooks'\n\nexport interface TheoRequestContext {\n /** The raw Web Standard Request object. */\n request: Request\n /** URL pathname (e.g., '/api/tasks'). */\n pathname: string\n /** HTTP method (e.g., 'GET', 'POST'). */\n method: string\n /** Route params extracted from URL (e.g., { id: '42' }). */\n params: Record<string, string>\n /** Matched controller or agent class name (if resolved). */\n handler?: string\n /** Request start time (ms). */\n startedAt: number\n}\n\nconst storage = new AsyncLocalStorage<TheoRequestContext>()\n\n/**\n * Get the current request context.\n *\n * @throws Error if called outside a request (e.g., at module load time).\n *\n * @example\n * ```typescript\n * import { getRequestContext } from '@theokit/http'\n *\n * class AuthGuard {\n * canActivate() {\n * const { request } = getRequestContext()\n * return request.headers.get('authorization') !== null\n * }\n * }\n * ```\n */\nexport function getRequestContext(): TheoRequestContext {\n const ctx = storage.getStore()\n if (!ctx) {\n throw new Error(\n 'getRequestContext() called outside a request. ' +\n 'This function is only available inside TheoApp request handlers ' +\n '(controllers, guards, interceptors, filters, agents).',\n )\n }\n return ctx\n}\n\n/**\n * Try to get the current request context, or null if not in a request.\n * Useful for code that may run both inside and outside requests.\n */\nexport function tryGetRequestContext(): TheoRequestContext | null {\n return storage.getStore() ?? null\n}\n\n/**\n * Run a function within a request context.\n * Used internally by TheoApp — not part of public API.\n * @internal\n */\nexport async function runWithRequestContext<T>(\n ctx: TheoRequestContext,\n fn: () => T | Promise<T>,\n): Promise<T> {\n return storage.run(ctx, fn)\n}\n","/**\n * Static file handler — runtime-agnostic (Node/Bun/Deno).\n *\n * Serves files from a root directory (default: `public/`).\n * Derived from Hono's serve-static middleware pattern:\n * - MIME type detection from extension\n * - Path traversal prevention via regex guard\n * - Runtime-agnostic file reading (Bun.file / Deno.readFile / node:fs)\n */\n\n// ── MIME type map (50+ types) ──────────────────────────\n\nconst MIME_TYPES: Record<string, string> = {\n // Text\n '.html': 'text/html; charset=utf-8',\n '.htm': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'text/javascript; charset=utf-8',\n '.mjs': 'text/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.xml': 'application/xml; charset=utf-8',\n '.txt': 'text/plain; charset=utf-8',\n '.csv': 'text/csv; charset=utf-8',\n '.md': 'text/markdown; charset=utf-8',\n '.yaml': 'text/yaml; charset=utf-8',\n '.yml': 'text/yaml; charset=utf-8',\n '.ts': 'text/typescript; charset=utf-8',\n '.tsx': 'text/tsx; charset=utf-8',\n '.jsx': 'text/jsx; charset=utf-8',\n\n // Images\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.tiff': 'image/tiff',\n '.tif': 'image/tiff',\n\n // Fonts\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.otf': 'font/otf',\n '.eot': 'application/vnd.ms-fontobject',\n\n // Media\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.avi': 'video/x-msvideo',\n\n // Documents\n '.pdf': 'application/pdf',\n '.zip': 'application/zip',\n '.gz': 'application/gzip',\n '.tar': 'application/x-tar',\n '.wasm': 'application/wasm',\n\n // Misc\n '.map': 'application/json; charset=utf-8',\n '.jsonld': 'application/ld+json; charset=utf-8',\n '.manifest': 'application/manifest+json; charset=utf-8',\n '.webmanifest': 'application/manifest+json; charset=utf-8',\n}\n\n// ── Path traversal guard (Hono-derived regex) ──────────\n\n/**\n * Regex that catches path traversal attacks:\n * - `..` segments (beginning, middle, or end of path)\n * - Double slashes `//`\n * - Backslash sequences `\\\\`\n */\nconst UNSAFE_PATH_RE = /(?:^|[/\\\\])\\.{1,2}(?:$|[/\\\\])|[/\\\\]{2,}/\n\n// ── Public API ─────────────────────────────────────────\n\nexport interface StaticOptions {\n /** Root directory to serve from (default: 'public'). */\n root?: string\n /** Cache-Control max-age in seconds (default: 0 — no caching). */\n maxAge?: number\n}\n\n/**\n * Returns the MIME type for a given file path based on its extension.\n * Falls back to 'application/octet-stream' for unknown extensions.\n */\nexport function getMimeType(filePath: string): string {\n const dot = filePath.lastIndexOf('.')\n if (dot === -1) return 'application/octet-stream'\n const ext = filePath.slice(dot).toLowerCase()\n return MIME_TYPES[ext] ?? 'application/octet-stream'\n}\n\n/**\n * Returns true when the path is safe (no traversal, no double slashes).\n */\nexport function isSafePath(pathname: string): boolean {\n return !UNSAFE_PATH_RE.test(pathname)\n}\n\n// ── Runtime-agnostic file reader ───────────────────────\n\ninterface FileResult {\n content: Uint8Array\n size: number\n}\n\nasync function readFileBun(fullPath: string): Promise<FileResult | null> {\n const g = globalThis as Record<string, unknown>\n const BunRT = g.Bun as {\n file: (path: string) => {\n exists: () => Promise<boolean>\n arrayBuffer: () => Promise<ArrayBuffer>\n size: number\n }\n }\n const file = BunRT.file(fullPath)\n if (!(await file.exists())) return null\n const buf = await file.arrayBuffer()\n return { content: new Uint8Array(buf), size: file.size }\n}\n\nasync function readFileDeno(fullPath: string): Promise<FileResult | null> {\n const g = globalThis as Record<string, unknown>\n const DenoRT = g.Deno as {\n readFile: (path: string) => Promise<Uint8Array>\n stat: (path: string) => Promise<{ isDirectory: boolean }>\n }\n try {\n const stat = await DenoRT.stat(fullPath)\n if (stat.isDirectory) return null\n const content = await DenoRT.readFile(fullPath)\n return { content, size: content.byteLength }\n } catch {\n return null\n }\n}\n\nasync function readFileNode(fullPath: string): Promise<FileResult | null> {\n try {\n const fs = await import('node:fs/promises')\n const stat = await fs.stat(fullPath)\n if (stat.isDirectory()) return null\n const content = await fs.readFile(fullPath)\n return { content: new Uint8Array(content), size: stat.size }\n } catch {\n return null\n }\n}\n\nasync function readFile(fullPath: string): Promise<FileResult | null> {\n const g = globalThis as Record<string, unknown>\n if (g.Bun) return readFileBun(fullPath)\n if (g.Deno) return readFileDeno(fullPath)\n return readFileNode(fullPath)\n}\n\n// ── Resolve root to absolute path ──────────────────────\n\nasync function resolveRoot(root: string): Promise<string> {\n const g = globalThis as Record<string, unknown>\n if (g.Deno) {\n const DenoRT = g.Deno as { cwd: () => string }\n const { join } = await import('node:path')\n return join(DenoRT.cwd(), root)\n }\n const { resolve } = await import('node:path')\n return resolve(root)\n}\n\n// ── Factory ────────────────────────────────────────────\n\n/**\n * Creates a static file handler that serves files from `root` directory.\n *\n * Returns `null` when the request does not match a static file (allowing\n * the caller to fall through to the next handler).\n */\nexport function createStaticHandler(\n options?: StaticOptions,\n): (request: Request) => Promise<Response | null> {\n const root = options?.root ?? 'public'\n const maxAge = options?.maxAge ?? 0\n\n let resolvedRoot: string | undefined\n\n return async (request: Request): Promise<Response | null> => {\n // Only serve GET and HEAD\n const method = request.method.toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') return null\n\n // Extract pathname, strip query params\n const url = new URL(request.url)\n let pathname: string\n try {\n pathname = decodeURIComponent(url.pathname)\n } catch {\n return null // Malformed URL encoding\n }\n\n // Skip framework-reserved paths\n if (pathname.startsWith('/api/') || pathname.startsWith('/@theo/')) return null\n\n // Path traversal guard\n if (!isSafePath(pathname)) return null\n\n // Lazy-resolve root to absolute path (once per handler lifetime)\n resolvedRoot ??= await resolveRoot(root)\n\n // Build full file path\n const { join } = await import('node:path')\n let fullPath = join(resolvedRoot, pathname)\n\n // Directory → try index.html\n let result = await readFile(fullPath)\n if (!result && (pathname.endsWith('/') || !pathname.includes('.'))) {\n fullPath = join(fullPath, 'index.html')\n result = await readFile(fullPath)\n }\n\n if (!result) return null\n\n // Build response headers\n const contentType = getMimeType(fullPath)\n const headers: Record<string, string> = {\n 'content-type': contentType,\n 'content-length': String(result.size),\n }\n if (maxAge > 0) {\n headers['cache-control'] = `public, max-age=${String(maxAge)}`\n }\n\n // HEAD: headers only, no body\n if (method === 'HEAD') {\n return new Response(null, { status: 200, headers })\n }\n\n return new Response(result.content as unknown as BodyInit, { status: 200, headers })\n }\n}\n","/**\n * Streaming SSR — renders a React element tree to a `ReadableStream<Uint8Array>`.\n *\n * Inspired by Next.js `stream-ops.ts`. Uses Web Standard `renderToReadableStream`\n * (works on Node 18+, Bun, Deno). Falls back to `renderToString` wrapped in a\n * ReadableStream when `renderToReadableStream` is not available (React 17 — EC-4).\n *\n * React is loaded via dynamic `import('react-dom/server')` because react-dom\n * is an optional peerDep of @theokit/http (ADR D2).\n */\n\nimport type * as ReactTypes from 'react'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface StreamRenderOptions {\n /** React element to render */\n root: ReactTypes.ReactElement\n /** Whether to wait for all Suspense to resolve (default: false — stream immediately) */\n waitForAll?: boolean\n}\n\nexport interface StreamRenderResult {\n /** The HTML stream */\n stream: ReadableStream<Uint8Array>\n /** Promise that resolves when all content has been flushed */\n allReady: Promise<void>\n}\n\n// ---------------------------------------------------------------------------\n// Doctype prefix\n// ---------------------------------------------------------------------------\n\nconst DOCTYPE = '<!DOCTYPE html>'\nconst encoder = new TextEncoder()\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\n/**\n * Renders a React element to a `ReadableStream<Uint8Array>` (Web Standard).\n *\n * 1. Tries `renderToReadableStream` first (React 18+ — Web Standard API).\n * 2. Falls back to `renderToString` wrapped in a ReadableStream when\n * `renderToReadableStream` is not available (React 17 compat — EC-4).\n * 3. Prepends `<!DOCTYPE html>` to the stream.\n *\n * **EC-7 — Streaming error handling:** In streaming mode, errors thrown inside\n * Suspense boundaries are caught by React's streaming error handler and result\n * in a client-side error boundary activation (the shell is already sent). In\n * string mode (`renderToString`), errors throw synchronously before any bytes\n * are sent, allowing a full 500 error page. Choose streaming when you want\n * progressive rendering; choose string mode when you want atomic error handling.\n */\nexport async function renderToStream(options: StreamRenderOptions): Promise<StreamRenderResult> {\n const { root, waitForAll = false } = options\n\n // Dynamic import — react-dom is optional peerDep\n const reactDomServer = await import('react-dom/server')\n\n // Prefer renderToReadableStream (Web Standard — React 18+)\n if (typeof reactDomServer.renderToReadableStream === 'function') {\n return renderWithReadableStream(reactDomServer.renderToReadableStream, root, waitForAll)\n }\n\n // EC-4: Fallback to renderToString wrapped in ReadableStream (React 17)\n if (typeof reactDomServer.renderToString === 'function') {\n console.warn(\n '[theokit] renderToReadableStream not available — falling back to renderToString. ' +\n 'Upgrade to React 18+ for streaming SSR support.',\n )\n return renderWithString(reactDomServer.renderToString, root)\n }\n\n throw new Error(\n '[theokit] react-dom/server does not export renderToReadableStream or renderToString. ' +\n 'Ensure react-dom >= 17 is installed.',\n )\n}\n\n// ---------------------------------------------------------------------------\n// Strategy: Web Standard renderToReadableStream\n// ---------------------------------------------------------------------------\n\nasync function renderWithReadableStream(\n renderFn: (\n element: ReactTypes.ReactElement,\n ) => Promise<ReadableStream & { allReady: Promise<void> }>,\n root: ReactTypes.ReactElement,\n waitForAll: boolean,\n): Promise<StreamRenderResult> {\n const reactStream = await renderFn(root)\n\n // If waitForAll, wait for all Suspense boundaries to resolve before emitting\n if (waitForAll) {\n await reactStream.allReady\n }\n\n // Prepend DOCTYPE\n const doctypeStream = prependDoctype(reactStream)\n\n return {\n stream: doctypeStream,\n allReady: reactStream.allReady,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Strategy: Fallback renderToString (EC-4)\n// ---------------------------------------------------------------------------\n\nfunction renderWithString(\n renderFn: (element: ReactTypes.ReactElement) => string,\n root: ReactTypes.ReactElement,\n): StreamRenderResult {\n const html = DOCTYPE + renderFn(root)\n const bytes = encoder.encode(html)\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes)\n controller.close()\n },\n })\n\n return {\n stream,\n allReady: Promise.resolve(),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Prepends `<!DOCTYPE html>` bytes to a ReadableStream.\n */\nfunction prependDoctype(source: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {\n const reader = source.getReader()\n let doctypeSent = false\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n if (!doctypeSent) {\n controller.enqueue(encoder.encode(DOCTYPE))\n doctypeSent = true\n }\n const { value, done } = await reader.read()\n if (done) {\n controller.close()\n return\n }\n controller.enqueue(value)\n },\n cancel() {\n void reader.cancel()\n },\n })\n}\n\n// ---------------------------------------------------------------------------\n// Response helper\n// ---------------------------------------------------------------------------\n\n/**\n * Converts a {@link StreamRenderResult} into a Web Standard `Response`.\n *\n * Convenience wrapper for use in request handlers:\n * ```ts\n * const result = await renderToStream({ root: <App /> })\n * return streamToResponse(result)\n * ```\n */\nexport function streamToResponse(result: StreamRenderResult): Response {\n return new Response(result.stream, {\n status: 200,\n headers: { 'content-type': 'text/html; charset=utf-8' },\n })\n}\n"],"mappings":"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","names":["AsyncLocalStorage","storage","AsyncLocalStorage","getRequestContext","ctx","getStore","Error","tryGetRequestContext","runWithRequestContext","fn","run","MIME_TYPES","UNSAFE_PATH_RE","getMimeType","filePath","dot","lastIndexOf","ext","slice","toLowerCase","isSafePath","pathname","test","readFileBun","fullPath","g","globalThis","BunRT","Bun","file","exists","buf","arrayBuffer","content","Uint8Array","size","readFileDeno","DenoRT","Deno","stat","isDirectory","readFile","byteLength","readFileNode","fs","resolveRoot","root","join","cwd","resolve","createStaticHandler","options","maxAge","resolvedRoot","request","method","toUpperCase","url","URL","decodeURIComponent","startsWith","result","endsWith","includes","contentType","headers","String","Response","status","DOCTYPE","encoder","TextEncoder","renderToStream","options","root","waitForAll","reactDomServer","renderToReadableStream","renderWithReadableStream","renderToString","console","warn","renderWithString","Error","renderFn","reactStream","allReady","doctypeStream","prependDoctype","stream","html","bytes","encode","ReadableStream","start","controller","enqueue","close","Promise","resolve","source","reader","getReader","doctypeSent","pull","value","done","read","cancel","streamToResponse","result","Response","status","headers","TheoApp","serverHandle","routes","frontendHtml","streamingRoot","staticHandler","startTime","Date","now","healthPath","readyPath","readinessChecks","opts","hp","rp","startsWith","Error","adapter","createNodeAdapter","createServer","request","handleRequest","create","app","registry","Map","module","moduleMeta","Reflect","getMetadata","allModules","imports","Mod","meta","Prov","providers","has","set","Controller","controllers","paramTypes","args","map","pt","dep","get","name","instance","postConstruct","result","Promise","walks","walkControllerMetadata","w","push","walk","sort","a","b","aP","fullPath","includes","bP","entry","paramNames","regexStr","replace","_m","compiledPattern","RegExp","compiledParamNames","needsBody","paramEntries","some","p","source","root","streaming","renderToString","html","staticDir","createStaticHandler","agents","length","autoWireAgents","listen","port","resolve","console","log","getServerHandle","close","agentRoutes","agentClasses","importFn","Function","walkAgentMetadata","compileAgent","generateAgentRoutes","getMixins","createSdkAgentStreamFn","mod","createSdkAgentStream","apiKey","llmApiKey","process","env","OPENROUTER_API_KEY","AgentClass","mixins","allToolboxes","Cls","Symbol","for","toolboxInstances","tb","toolboxes","class","compiled","createRun","agentStreamFactory","tools","llmModel","createFallbackStream","agentConfig","walkResult","compiledOptions","route","path","method","pattern","handler","guards","agentClass","methodName","mainLoop","propertyKey","handleReadinessCheck","jsonResponse","status","checks","results","all","check","race","setTimeout","healthy","message","err","allHealthy","every","r","agentName","msg","_message","_sessionId","events","type","runId","code","retryable","asyncIterator","i","next","value","done","undefined","pathname","URL","url","reqCtx","params","startedAt","runWithRequestContext","handleRequestInContext","_reqCtx","uptime","timestamp","renderToStream","streamToResponse","Response","headers","staticResponse","toUpperCase","test","ctx","createExecutionContext","GuardCtor","guard","canActivate","ex","ForbiddenException","statusCode","toJSON","match","findRoute","error","body","text","JSON","parse","bodySchema","safeParse","success","issues","data","buildArgs","Object","fromEntries","searchParams","redirect","location","handlerFn","interceptors","runInterceptors","apply","buildResponse","filters","runExceptionFilters","HttpException","verb","exec","forEach","entries","query","max","Math","index","Array","from","key","toLowerCase","stringify","n","v"]}
|
|
@@ -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":"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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","set"]}
|
|
File without changes
|
|
File without changes
|
/package/dist/{exception-filter-chain-O45FXGEB.js.map → exception-filter-chain-V2MFO4WV.js.map}
RENAMED
|
File without changes
|