@theokit/http 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -2
- package/README.md +132 -86
- package/dist/action-encryption.d.ts +32 -0
- package/dist/action-encryption.js +69 -0
- package/dist/action-encryption.js.map +1 -0
- package/dist/app.d.ts +69 -2
- package/dist/app.js +5 -5
- package/dist/app.js.map +1 -1
- package/dist/{chunk-KPC7AIVC.js → chunk-AJOJXZRY.js} +2 -2
- package/dist/chunk-AJOJXZRY.js.map +1 -0
- package/dist/{chunk-HLW7YKZE.js → chunk-BSS3KPGY.js} +2 -2
- package/dist/chunk-BSS3KPGY.js.map +1 -0
- package/dist/{chunk-OBHHOS6E.js → chunk-DI7KNIMB.js} +4 -4
- package/dist/chunk-DI7KNIMB.js.map +1 -0
- package/dist/{chunk-CMPP4ULU.js → chunk-HC47QXZV.js} +4 -4
- package/dist/chunk-HC47QXZV.js.map +1 -0
- package/dist/{chunk-MQAJWR3K.js → chunk-JP4J23TV.js} +2 -2
- package/dist/chunk-JP4J23TV.js.map +1 -0
- package/dist/{chunk-ELCXHPAD.js → chunk-PBV6ZO2V.js} +3 -3
- package/dist/chunk-PBV6ZO2V.js.map +1 -0
- package/dist/{chunk-JQMJK47T.js → chunk-X7Q5HPLK.js} +15 -15
- package/dist/chunk-X7Q5HPLK.js.map +1 -0
- package/dist/{chunk-7QVYU63E.js → chunk-Z4QWC7IK.js} +1 -1
- package/dist/chunk-Z4QWC7IK.js.map +1 -0
- package/dist/{chunk-DRCRGDA3.js → chunk-ZMMIH3I2.js} +60 -33
- package/dist/chunk-ZMMIH3I2.js.map +1 -0
- package/dist/css-resource.d.ts +31 -0
- package/dist/css-resource.js +29 -0
- package/dist/css-resource.js.map +1 -0
- package/dist/exception-filter-chain-AS6BB5PF.js +10 -0
- package/dist/exception-filter-chain-AS6BB5PF.js.map +1 -0
- package/dist/index.js +15 -15
- package/dist/index.js.map +1 -1
- package/dist/interceptor-chain-KMBBSUB5.js +9 -0
- package/dist/interceptor-chain-KMBBSUB5.js.map +1 -0
- package/dist/runtime-node.js +2 -2
- package/dist/runtime-node.js.map +1 -1
- package/dist/server-inserted-html.d.ts +35 -0
- package/dist/server-inserted-html.js +37 -0
- package/dist/server-inserted-html.js.map +1 -0
- package/dist/theokit-plugin.js +12 -12
- package/dist/theokit-plugin.js.map +1 -1
- package/package.json +39 -19
- package/dist/chunk-7QVYU63E.js.map +0 -1
- package/dist/chunk-CMPP4ULU.js.map +0 -1
- package/dist/chunk-DRCRGDA3.js.map +0 -1
- package/dist/chunk-ELCXHPAD.js.map +0 -1
- package/dist/chunk-HLW7YKZE.js.map +0 -1
- package/dist/chunk-JQMJK47T.js.map +0 -1
- package/dist/chunk-KPC7AIVC.js.map +0 -1
- package/dist/chunk-MQAJWR3K.js.map +0 -1
- package/dist/chunk-OBHHOS6E.js.map +0 -1
- package/dist/exception-filter-chain-V2MFO4WV.js +0 -10
- package/dist/exception-filter-chain-V2MFO4WV.js.map +0 -1
- package/dist/interceptor-chain-ELSL6KZT.js +0 -9
- package/dist/interceptor-chain-ELSL6KZT.js.map +0 -1
|
@@ -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, 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\n/**\n * One mounted agent. Replaces the decorated-class form: the app receives what it actually needs —\n * a name, a mount route, and already-compiled agent options — instead of walking metadata off a class.\n */\nexport interface AgentAppEntry {\n /** Display name (logs + fallback stream). */\n readonly name: string\n /** Mount point; routes are generated under it (`<route>/chat`, `<route>/runs/:id`). */\n readonly route: string\n /** `CompiledAgentOptions` from `@theokit/agents` (typed `unknown` — optional peer dependency). */\n readonly compiled: unknown\n /** Guards to run before the agent routes (same shape the controller pipeline uses). */\n readonly guards?: Function[]\n /** Method name reported for this agent's route (default `'run'`). */\n readonly methodName?: string\n /** Optional owning class, kept only for guard resolution parity with controllers. */\n readonly agentClass?: Function\n}\n\nexport interface TheoAppOptions {\n /** Controller classes decorated with @Controller. */\n controllers: Function[]\n /**\n * Agents to auto-wire (routes + SSE + tools). M53 — these are prepared ENTRIES, not decorated\n * classes: the app no longer reads agent metadata, so authoring is free to be capability-based\n * (`applyCapabilities([...])` produces the `compiled` options). The `@theokit/http` CONTROLLER\n * decorators are untouched.\n */\n agents?: AgentAppEntry[]\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 /** The COMPILED agent options — not the metadata walk (which carries no `model`). */\n compiled: unknown,\n tools: unknown[],\n apiKey: string,\n /** Per-run overrides, mirroring `createSdkAgentStream`'s 4th argument (never a bare string). */\n overrides?: { 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 entries: AgentAppEntry[],\n _registry: Map<Function, object>,\n opts: TheoAppOptions,\n ) {\n // `@theokit/agents` is an OPTIONAL peer, so it is imported dynamically. A plain `import()` is\n // enough — the package is already marked external in tsup.config.ts, so nothing is bundled — and\n // unlike the previous `new Function('return import(…)')` trick it is resolvable by the test\n // runner. That trick is exactly why this whole branch had no test and shipped a real bug.\n let generateAgentRoutes: Function, createSdkAgentStreamFn: Function\n try {\n const mod = (await import('@theokit/agents')) as unknown as Record<string, Function>\n generateAgentRoutes = mod.generateAgentRoutes\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 entry of entries) {\n const compiled = entry.compiled as { tools: unknown[] }\n let createRun: (message: string, sessionId: string) => AsyncIterable<unknown>\n if (opts.agentStreamFactory) {\n createRun = opts.agentStreamFactory(entry.compiled, compiled.tools, apiKey, {\n model: opts.llmModel,\n })\n } else if (apiKey) {\n createRun = createSdkAgentStreamFn(entry.compiled, compiled.tools, apiKey, {\n model: opts.llmModel,\n }) as (m: string, s: string) => AsyncIterable<unknown>\n } else {\n createRun = this.createFallbackStream(entry.name, apiKey)\n }\n\n // Guards receive `ctx.getClass()`, and a capability-authored agent has no class — so ONE\n // stable identity token per agent stands in (hoisted here, not per route, so the identity is\n // the agent's). It is never invoked; it exists to be named and compared.\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- identity token, never called\n const agentIdentity = entry.agentClass ?? function agent() {}\n\n const routes = generateAgentRoutes({\n walkResult: { route: entry.route },\n compiledOptions: entry.compiled,\n createRun: createRun as (\n message: string,\n sessionId: string,\n ) => AsyncIterable<{ type: string; [k: string]: unknown }>,\n })\n\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: entry.guards ?? [],\n agentClass: agentIdentity,\n methodName: entry.methodName ?? 'run',\n })\n }\n\n console.log(\n ` 🤖 Agent \"${entry.name}\" mounted at ${entry.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","entries","_registry","generateAgentRoutes","createSdkAgentStreamFn","mod","createSdkAgentStream","apiKey","llmApiKey","process","env","OPENROUTER_API_KEY","compiled","createRun","agentStreamFactory","tools","model","llmModel","createFallbackStream","agentIdentity","agentClass","agent","walkResult","route","compiledOptions","path","method","pattern","handler","guards","methodName","handleReadinessCheck","jsonResponse","status","checks","results","all","check","race","setTimeout","healthy","message","err","allHealthy","every","r","agentName","msg","_message","_sessionId","events","type","runId","code","retryable","Symbol","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","propertyKey","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","query","max","Math","index","Array","from","key","toLowerCase","stringify","n","v"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bridge/interceptor-chain.ts"],"sourcesContent":["/**\n * Interceptor execution engine — onion-model chain runner.\n *\n * Per Pattern D3: \"@UseInterceptors both translate to defineMiddleware wraps\".\n * Interceptors wrap the handler call (NOT body parsing — EC-1) and can\n * transform the response or short-circuit by not calling next().\n *\n * Execution order follows NestJS convention:\n * middleware → guards → interceptors → handler\n * Interceptor composition: class-level FIRST, then method-level (EC-9).\n */\nimport { resolveOrNew, type DiContainer } from './di-resolve.js'\n\n/**\n * Interceptor interface — Web Standard Request.\n * `next()` wraps ONLY the handler call — body parsing happens before.\n */\nexport interface Interceptor {\n intercept(\n request: Request,\n next: () => Promise<unknown>,\n ): Promise<unknown>\n}\n\n/**\n * Run the interceptor chain using the onion model.\n * Outermost interceptor (first in array) wraps all inner ones.\n */\nexport async function runInterceptors(\n interceptors: Function[],\n handler: () => Promise<unknown>,\n request: Request,\n container?: DiContainer,\n): Promise<unknown> {\n if (interceptors.length === 0) return handler()\n\n let chain = handler\n for (const Ctor of [...interceptors].reverse()) {\n const instance = resolveOrNew(Ctor, container) as Interceptor\n const nextFn = chain\n let called = false\n let cachedResult: unknown\n const memoizedNext = async () => {\n if (called) return cachedResult\n called = true\n cachedResult = await nextFn()\n return cachedResult\n }\n chain = () => instance.intercept(request, memoizedNext)\n }\n return chain()\n}\n"],"mappings":";;;;;;;;AA4BA,eAAsBA,gBACpBC,cACAC,SACAC,SACAC,WAAuB;AAEvB,MAAIH,aAAaI,WAAW,EAAG,QAAOH,QAAAA;AAEtC,MAAII,QAAQJ;AACZ,aAAWK,QAAQ;OAAIN;IAAcO,QAAO,GAAI;AAC9C,UAAMC,WAAWC,aAAaH,MAAMH,SAAAA;AACpC,UAAMO,SAASL;AACf,QAAIM,SAAS;AACb,QAAIC;AACJ,UAAMC,eAAe,mCAAA;AACnB,UAAIF,OAAQ,QAAOC;AACnBD,eAAS;AACTC,qBAAe,MAAMF,OAAAA;AACrB,aAAOE;IACT,GALqB;AAMrBP,YAAQ,6BAAMG,SAASM,UAAUZ,SAASW,YAAAA,GAAlC;EACV;AACA,SAAOR,MAAAA;AACT;AAvBsBN;","names":["runInterceptors","interceptors","handler","request","container","length","chain","Ctor","reverse","instance","resolveOrNew","nextFn","called","cachedResult","memoizedNext","intercept"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bridge/runtime/node.ts"],"sourcesContent":["/**\n * Node.js runtime adapter — converts IncomingMessage/ServerResponse ↔ Request/Response.\n *\n * Per ADR D460: node:http types live ONLY in this adapter file.\n * The rest of the pipeline operates on Web Standard Request/Response.\n *\n * EC-1: Body converted via Readable.toWeb() for streaming (no full buffering).\n */\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http'\nimport { Readable } from 'node:stream'\n\nimport type { RuntimeAdapter } from './types.js'\n\n/** Convert Node.js IncomingMessage to Web Standard Request. */\nexport function nodeIncomingToRequest(nodeReq: IncomingMessage): Request {\n const proto = nodeReq.headers['x-forwarded-proto'] ?? 'http'\n const host = nodeReq.headers.host ?? 'localhost'\n const url = `${proto}://${host}${nodeReq.url ?? \"/\"}` // eslint-disable-line @typescript-eslint/restrict-template-expressions -- proto/host are string|string[]\n const method = nodeReq.method ?? 'GET'\n\n const headers = new Headers()\n for (const [key, value] of Object.entries(nodeReq.headers)) {\n if (value !== undefined) {\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v)\n } else {\n headers.set(key, value)\n }\n }\n }\n\n // EC-1: Streaming body via Readable.toWeb() — no full buffering\n const hasBody = method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS'\n const body = hasBody ? Readable.toWeb(nodeReq) as ReadableStream : undefined\n\n return new Request(url, {\n method,\n headers,\n body,\n // @ts-expect-error — duplex is required for streaming bodies in Node 18+\n duplex: hasBody ? 'half' : undefined,\n })\n}\n\n/** Write Web Standard Response to Node.js ServerResponse. */\nexport async function writeResponseToNode(response: Response, nodeRes: ServerResponse): Promise<void> {\n nodeRes.writeHead(response.status, Object.fromEntries(response.headers.entries()))\n\n if (!response.body) {\n nodeRes.end()\n return\n }\n\n const reader = response.body.getReader()\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop with break\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n if (nodeRes.destroyed) break\n nodeRes.write(value)\n }\n } finally {\n reader.releaseLock()\n if (!nodeRes.destroyed) nodeRes.end()\n }\n}\n\n/** Create a Node.js HTTP server that delegates to a Web Standard handler. */\nexport function createNodeAdapter(): RuntimeAdapter {\n return {\n createServer(handler) {\n const server = createServer((nodeReq, nodeRes) => {\n void (async () => {\n try {\n const request = nodeIncomingToRequest(nodeReq)\n const response = await handler(request)\n await writeResponseToNode(response, nodeRes)\n } catch (err) {\n if (!nodeRes.destroyed) {\n nodeRes.writeHead(500, { 'content-type': 'application/json' })\n nodeRes.end(JSON.stringify({\n error: { code: 'INTERNAL_SERVER_ERROR', message: err instanceof Error ? err.message : 'Unknown error' },\n }))\n }\n }\n })()\n })\n\n return {\n listen: (port: number, cb?: () => void) => server.listen(port, cb),\n close: (cb?: () => void) => server.close(cb),\n address: () => {\n const addr = server.address()\n if (typeof addr === 'string' || addr === null) return null\n return { port: addr.port }\n },\n }\n },\n }\n}\n"],"mappings":";;;;;AAQA,SAASA,oBAA+D;AACxE,SAASC,gBAAgB;AAKlB,SAASC,sBAAsBC,SAAwB;AAC5D,QAAMC,QAAQD,QAAQE,QAAQ,mBAAA,KAAwB;AACtD,QAAMC,OAAOH,QAAQE,QAAQC,QAAQ;AACrC,QAAMC,MAAM,GAAGH,KAAAA,MAAWE,IAAAA,GAAOH,QAAQI,OAAO,GAAA;AAChD,QAAMC,SAASL,QAAQK,UAAU;AAEjC,QAAMH,UAAU,IAAII,QAAAA;AACpB,aAAW,CAACC,KAAKC,KAAAA,KAAUC,OAAOC,QAAQV,QAAQE,OAAO,GAAG;AAC1D,QAAIM,UAAUG,QAAW;AACvB,UAAIC,MAAMC,QAAQL,KAAAA,GAAQ;AACxB,mBAAWM,KAAKN,MAAON,SAAQa,OAAOR,KAAKO,CAAAA;MAC7C,OAAO;AACLZ,gBAAQc,IAAIT,KAAKC,KAAAA;MACnB;IACF;EACF;AAGA,QAAMS,UAAUZ,WAAW,SAASA,WAAW,UAAUA,WAAW;AACpE,QAAMa,OAAOD,UAAUE,SAASC,MAAMpB,OAAAA,IAA6BW;AAEnE,SAAO,IAAIU,QAAQjB,KAAK;IACtBC;IACAH;IACAgB;;IAEAI,QAAQL,UAAU,SAASN;EAC7B,CAAA;AACF;AA5BgBZ;AA+BhB,eAAsBwB,oBAAoBC,UAAoBC,SAAuB;AACnFA,UAAQC,UAAUF,SAASG,QAAQlB,OAAOmB,YAAYJ,SAAStB,QAAQQ,QAAO,CAAA,CAAA;AAE9E,MAAI,CAACc,SAASN,MAAM;AAClBO,YAAQI,IAAG;AACX;EACF;AAEA,QAAMC,SAASN,SAASN,KAAKa,UAAS;AACtC,MAAI;AAEF,WAAO,MAAM;AACX,YAAM,EAAEC,MAAMxB,MAAK,IAAK,MAAMsB,OAAOG,KAAI;AACzC,UAAID,KAAM;AACV,UAAIP,QAAQS,UAAW;AACvBT,cAAQU,MAAM3B,KAAAA;IAChB;EACF,UAAA;AACEsB,WAAOM,YAAW;AAClB,QAAI,CAACX,QAAQS,UAAWT,SAAQI,IAAG;EACrC;AACF;AArBsBN;AAwBf,SAASc,oBAAAA;AACd,SAAO;IACLC,aAAaC,SAAO;AAClB,YAAMC,SAASF,aAAa,CAACtC,SAASyB,YAAAA;AACpC,cAAM,YAAA;AACN,cAAI;AACF,kBAAMgB,UAAU1C,sBAAsBC,OAAAA;AACtC,kBAAMwB,WAAW,MAAMe,QAAQE,OAAAA;AAC/B,kBAAMlB,oBAAoBC,UAAUC,OAAAA;UACtC,SAASiB,KAAK;AACZ,gBAAI,CAACjB,QAAQS,WAAW;AACtBT,sBAAQC,UAAU,KAAK;gBAAE,gBAAgB;cAAmB,CAAA;AAC5DD,sBAAQI,IAAIc,KAAKC,UAAU;gBACzBC,OAAO;kBAAEC,MAAM;kBAAyBC,SAASL,eAAeM,QAAQN,IAAIK,UAAU;gBAAgB;cACxG,CAAA,CAAA;YACF;UACF;QACA,GAAA;MACF,CAAA;AAEA,aAAO;QACLE,QAAQ,wBAACC,MAAcC,OAAoBX,OAAOS,OAAOC,MAAMC,EAAAA,GAAvD;QACRC,OAAO,wBAACD,OAAoBX,OAAOY,MAAMD,EAAAA,GAAlC;QACPE,SAAS,6BAAA;AACP,gBAAMC,OAAOd,OAAOa,QAAO;AAC3B,cAAI,OAAOC,SAAS,YAAYA,SAAS,KAAM,QAAO;AACtD,iBAAO;YAAEJ,MAAMI,KAAKJ;UAAK;QAC3B,GAJS;MAKX;IACF;EACF;AACF;AA/BgBb;","names":["createServer","Readable","nodeIncomingToRequest","nodeReq","proto","headers","host","url","method","Headers","key","value","Object","entries","undefined","Array","isArray","v","append","set","hasBody","body","Readable","toWeb","Request","duplex","writeResponseToNode","response","nodeRes","writeHead","status","fromEntries","end","reader","getReader","done","read","destroyed","write","releaseLock","createNodeAdapter","createServer","handler","server","request","err","JSON","stringify","error","code","message","Error","listen","port","cb","close","address","addr"]}
|
|
@@ -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 { 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"]}
|
|
@@ -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')\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 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bridge/di-resolve.ts"],"sourcesContent":["/**\n * Shared DI resolution helper for guards, interceptors, and middleware.\n * Extracted to avoid DRY violation (EC-3) — was duplicated in create-server.ts\n * and theokit-plugin.ts.\n */\n\n/** DI container interface — structural match for @theokit/di Container. */\nexport interface DiContainer {\n resolve(token: Function): unknown\n}\n\n/**\n * Resolve a class via DI container if provided; otherwise fall back to bare `new`.\n * Guards, interceptors, and middleware classes all use this pattern.\n */\nexport function resolveOrNew(Ctor: Function, container?: DiContainer): object {\n if (container) {\n try {\n return container.resolve(Ctor) as object\n } catch {\n // MissingInjectableError or similar — fall back to bare new\n }\n }\n return new (Ctor as new () => object)()\n}\n"],"mappings":";;;;;AAeO,SAASA,aAAaC,MAAgBC,WAAuB;AAClE,MAAIA,WAAW;AACb,QAAI;AACF,aAAOA,UAAUC,QAAQF,IAAAA;IAC3B,QAAQ;IAER;EACF;AACA,SAAO,IAAKA,KAAAA;AACd;AATgBD;","names":["resolveOrNew","Ctor","container","resolve"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bridge/middleware-consumer.ts","../src/bridge/swc-loader.ts"],"sourcesContent":["/**\n * NestJS-style Middleware support — Web Standard Request/Response.\n *\n * Middleware runs BEFORE guards: middleware → guards → interceptors → handler\n *\n * Supports class middleware (NestMiddleware) and functional middleware.\n * Returns a Response to short-circuit, or null to continue.\n */\nimport { resolveOrNew, type DiContainer } from './di-resolve.js'\n\n/** NestJS-compatible middleware interface — Web Standard. */\nexport interface NestMiddleware {\n use(\n request: Request,\n next: () => Promise<Response | null>,\n ): Response | null | Promise<Response | null>\n}\n\n/** Functional middleware. */\nexport type MiddlewareFn = (\n request: Request,\n next: () => Promise<Response | null>,\n) => Response | null | Promise<Response | null>\n\nexport interface ResolvedMiddleware {\n handler: MiddlewareFn\n routePatterns: string[]\n excludePatterns: string[]\n}\n\nexport type RouteInfo = string | { path: string; method?: string }\n\nexport interface MiddlewareConfigProxy {\n forRoutes(...routes: RouteInfo[]): MiddlewareConsumerImpl\n exclude(...routes: RouteInfo[]): MiddlewareConfigProxy\n}\n\nexport class MiddlewareConsumerImpl {\n private entries: ResolvedMiddleware[] = []\n private container?: DiContainer\n\n constructor(container?: DiContainer) {\n this.container = container\n }\n\n apply(...middleware: (Function | MiddlewareFn)[]): MiddlewareConfigProxy {\n const resolved = middleware.map((m) => this.resolveMiddleware(m))\n const excludePatterns: string[] = []\n\n const proxy: MiddlewareConfigProxy = {\n exclude: (...routes: RouteInfo[]) => {\n for (const r of routes) excludePatterns.push(typeof r === 'string' ? r : r.path)\n return proxy\n },\n forRoutes: (...routes: RouteInfo[]) => {\n const routePatterns = routes.map((r) => (typeof r === 'string' ? r : r.path))\n for (const handler of resolved) {\n this.entries.push({ handler, routePatterns: [...routePatterns], excludePatterns: [...excludePatterns] })\n }\n return this\n },\n }\n return proxy\n }\n\n getEntries(): ResolvedMiddleware[] {\n return this.entries\n }\n\n private resolveMiddleware(m: Function | MiddlewareFn): MiddlewareFn {\n if (typeof m === 'function' && !m.prototype?.use) {\n return m as MiddlewareFn\n }\n const instance = resolveOrNew(m, this.container) as NestMiddleware\n return (request, next) => instance.use(request, next)\n }\n}\n\nexport function middlewareMatchesPath(entry: ResolvedMiddleware, requestPath: string): boolean {\n for (const pattern of entry.excludePatterns) {\n if (pathMatches(requestPath, pattern)) return false\n }\n for (const pattern of entry.routePatterns) {\n if (pathMatches(requestPath, pattern)) return true\n }\n return false\n}\n\nfunction pathMatches(requestPath: string, pattern: string): boolean {\n if (pattern === '*') return true\n const normPath = ('/' + requestPath).replace(/\\/+/g, '/').replace(/\\/$/, '')\n const normPattern = ('/' + pattern).replace(/\\/+/g, '/').replace(/\\/$/, '')\n return normPath === normPattern || normPath.startsWith(normPattern + '/')\n}\n\n/**\n * Run all matching middleware. Returns a Response if any short-circuited, null otherwise.\n */\nexport async function runMiddleware(\n entries: ResolvedMiddleware[],\n request: Request,\n requestPath: string,\n): Promise<Response | null> {\n for (const entry of entries) {\n if (!middlewareMatchesPath(entry, requestPath)) continue\n const response = await entry.handler(request, () => Promise.resolve(null))\n if (response) return response // short-circuit\n }\n return null\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * The SWC loader reads/writes controller files by absolute path derived\n * from developer-authored glob patterns in theo.config.ts, not from HTTP\n * input. The file paths come from scanControllerFiles() which walks the\n * project's own source tree. No injection vector.\n */\n/**\n * SWC-powered module loader for controller files with parameter decorators.\n *\n * esbuild (used by tsx/Vite SSR) fundamentally cannot parse TypeScript\n * parameter decorators (`@Body()`, `@Param()`, `@Query()`). This loader\n * uses @swc/core to transform controller files with full decorator support\n * (legacyDecorator + decoratorMetadata), then imports them via a temp .mjs\n * file written in the SAME directory (preserving relative import resolution).\n *\n * Pattern: follows Next.js's approach (read tsconfig → configure SWC)\n * but scoped to the http-decorators package, not the framework core.\n *\n * @see references/next.js/packages/next/src/build/swc/options.ts\n */\nimport 'reflect-metadata'\nimport { readFileSync, writeFileSync, unlinkSync, readdirSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { resolve, dirname, join, relative } from 'node:path'\nimport { pathToFileURL, fileURLToPath } from 'node:url'\n\nimport { HttpDecoratorsConfigError } from './errors.js'\n\n/** Extract jsc.target from parsed .swcrc or fall back to es2022. */\nfunction getSwcrcTarget(swcrc: Record<string, unknown> | null): string {\n if (!swcrc) return 'es2022'\n const jsc = swcrc.jsc\n if (typeof jsc !== 'object' || jsc === null) return 'es2022'\n const target = (jsc as Record<string, unknown>).target\n return typeof target === 'string' ? target : 'es2022'\n}\n\n/** Cached consumer .swcrc — read once per process. */\nlet consumerSwcrcCache: Record<string, unknown> | null | undefined\n\n/**\n * Walk up from the controller file's directory to find a .swcrc.\n * Returns the parsed JSON or null if none found.\n * Caches the result — .swcrc doesn't change at runtime.\n */\nfunction readConsumerSwcrc(startDir: string): Record<string, unknown> | null {\n if (consumerSwcrcCache !== undefined) return consumerSwcrcCache\n\n let dir = startDir\n const root = dirname(dir) // stop at filesystem root\n while (dir !== root) {\n const candidate = join(dir, '.swcrc')\n try {\n const raw = readFileSync(candidate, 'utf-8')\n const parsed = JSON.parse(raw) as Record<string, unknown>\n // Strip $schema — not an SWC transform option\n delete parsed.$schema\n consumerSwcrcCache = parsed\n return parsed\n } catch {\n // File doesn't exist or invalid JSON — walk up\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n\n consumerSwcrcCache = null\n return null\n}\n\nexport interface SwcCore {\n transformSync: (src: string, opts: unknown) => { code: string }\n}\n\n/** Cached @swc/core instance — loaded once, reused across all controller files. */\nlet swcCoreCache: SwcCore | null | undefined\n\n/**\n * Dynamically load @swc/core with singleton cache.\n *\n * Handles pnpm strict node_modules: @swc/core is only directly importable\n * from the package that declares it as a dependency. We use createRequire\n * rooted at THIS package's directory to resolve correctly.\n *\n * The cache ensures the ~50ms dynamic import() cost is paid ONCE,\n * not per-controller-file.\n */\nasync function loadSwcCore(): Promise<SwcCore | null> {\n if (swcCoreCache !== undefined) return swcCoreCache\n\n try {\n swcCoreCache = (await import('@swc/core')) as SwcCore\n } catch {\n try {\n const thisDir = dirname(fileURLToPath(import.meta.url))\n const req = createRequire(resolve(thisDir, 'index.js'))\n const resolved = req.resolve('@swc/core')\n swcCoreCache = (await import(pathToFileURL(resolved).href)) as SwcCore\n } catch {\n swcCoreCache = null\n }\n }\n return swcCoreCache\n}\n\n/**\n * Transform TypeScript controller SOURCE (with parameter decorators) into\n * ESM code, emitting the `design:paramtypes` / decorator metadata that esbuild\n * cannot produce. Pure code→code — no file I/O, no module load — so it is\n * reusable both by {@link loadControllerWithSwc} (which then temp-writes +\n * imports) and by a build-tool transform hook that returns `{ code }` directly.\n *\n * The `@swc/core` loader is injectable (`loadSwc`) for testability; it defaults\n * to the cached singleton.\n *\n * @throws HttpDecoratorsConfigError when @swc/core is unavailable.\n */\nexport async function transformControllerSource(\n source: string,\n filename: string,\n loadSwc: () => Promise<SwcCore | null> = loadSwcCore,\n): Promise<string> {\n const swc = await loadSwc()\n if (!swc) {\n throw new HttpDecoratorsConfigError(\n `@swc/core is required for parameter decorators (@Body, @Param, @Query). ` +\n `Install it:\\n\\n pnpm add -D @swc/core\\n\\n` +\n `esbuild (used by tsx/Vite) cannot parse parameter decorators. ` +\n `SWC handles them correctly with full metadata emission.`,\n )\n }\n\n const consumerSwcrc = readConsumerSwcrc(dirname(filename))\n const consumerJsc =\n consumerSwcrc?.jsc && typeof consumerSwcrc.jsc === 'object'\n ? (consumerSwcrc.jsc as Record<string, unknown>)\n : null\n const { code } = swc.transformSync(source, {\n filename,\n jsc: {\n parser: {\n syntax: 'typescript',\n decorators: true,\n ...(consumerJsc?.parser as Record<string, unknown> | undefined),\n },\n transform: {\n ...(consumerJsc?.transform as Record<string, unknown> | undefined),\n // NON-NEGOTIABLE — always enforce decorator metadata emission\n // regardless of consumer .swcrc overrides\n legacyDecorator: true,\n decoratorMetadata: true,\n },\n target: getSwcrcTarget(consumerSwcrc),\n },\n module: { type: 'es6' },\n sourceMaps: false,\n })\n return code\n}\n\n/**\n * Load a TypeScript controller file using @swc/core for decorator support.\n *\n * Strategy:\n * 1. Read source .ts file\n * 2. Transform via {@link transformControllerSource} (legacyDecorator + metadata)\n * 3. Write temp .mjs in SAME directory (relative imports resolve correctly)\n * 4. Dynamic import() the .mjs — transitive .ts imports go through\n * tsx/Vite's global hook (they don't have parameter decorators)\n * 5. Cleanup temp file\n */\nexport async function loadControllerWithSwc(\n absoluteFilePath: string,\n): Promise<Record<string, unknown>> {\n const source = readFileSync(absoluteFilePath, 'utf-8')\n const code = await transformControllerSource(source, absoluteFilePath)\n\n // Write temp .mjs in SAME directory so relative imports resolve identically.\n // .mjs = Node treats as ESM regardless of package.json type field.\n // Transitive .ts imports go through tsx's global hook (no param decorators there).\n const tmpPath = absoluteFilePath.replace(/\\.ts$/, '.__decorated__.mjs')\n writeFileSync(tmpPath, code, 'utf-8')\n try {\n const url = pathToFileURL(tmpPath).href + `?t=${Date.now()}`\n return (await import(url)) as Record<string, unknown>\n } finally {\n try {\n unlinkSync(tmpPath)\n } catch {\n // Best-effort cleanup\n }\n }\n}\n\n/**\n * Scan a glob pattern for controller files and load them all via SWC.\n * Returns an array of controller class constructors found.\n */\nexport async function loadControllersFromGlob(\n rootDir: string,\n pattern: string,\n): Promise<Function[]> {\n const files = scanControllerFiles(rootDir, pattern)\n if (files.length === 0) {\n console.warn(\n `[@theokit/http] No controller files found matching \"${pattern}\" ` +\n `in ${rootDir}. Ensure files match the pattern and export @Controller classes.`,\n )\n return []\n }\n\n const controllers: Function[] = []\n for (const file of files) {\n const absPath = resolve(rootDir, file)\n const mod = await loadControllerWithSwc(absPath)\n for (const exported of Object.values(mod)) {\n if (typeof exported === 'function' && isControllerClass(exported)) {\n controllers.push(exported)\n }\n }\n }\n\n return controllers\n}\n\n/**\n * Check if a function has @Controller metadata.\n * Uses Symbol.for() global registry key — same Symbol instance across\n * module boundaries (SWC-loaded controllers share the global registry).\n */\nexport function isControllerClass(fn: Function): boolean {\n try {\n return Reflect.hasMetadata(Symbol.for('theokit:http-decorators:controller-prefix'), fn)\n } catch {\n return false\n }\n}\n\n/**\n * Scan for files matching a controller glob pattern.\n * Extracts the static directory prefix and file suffix from the pattern,\n * then recursively walks the directory.\n */\nfunction scanControllerFiles(rootDir: string, pattern: string): string[] {\n const parts = pattern.split('/')\n const dirParts: string[] = []\n for (const part of parts) {\n if (part.includes('*')) break\n dirParts.push(part)\n }\n const baseDir = join(rootDir, ...dirParts)\n\n // Extract file suffix (e.g., '*.controller.ts' → '.controller.ts')\n const lastPart = parts[parts.length - 1]\n const suffix = lastPart.replace(/\\*/g, '')\n\n const files: string[] = []\n function walk(dir: string) {\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory()) walk(full)\n else if (entry.name.endsWith(suffix)) files.push(relative(rootDir, full))\n }\n } catch {\n // Directory doesn't exist\n }\n }\n walk(baseDir)\n return files\n}\n"],"mappings":"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","names":["MiddlewareConsumerImpl","entries","container","apply","middleware","resolved","map","m","resolveMiddleware","excludePatterns","proxy","exclude","routes","r","push","path","forRoutes","routePatterns","handler","getEntries","prototype","use","instance","resolveOrNew","request","next","middlewareMatchesPath","entry","requestPath","pattern","pathMatches","normPath","replace","normPattern","startsWith","runMiddleware","response","Promise","resolve","readFileSync","writeFileSync","unlinkSync","readdirSync","createRequire","resolve","dirname","join","relative","pathToFileURL","fileURLToPath","getSwcrcTarget","swcrc","jsc","target","consumerSwcrcCache","readConsumerSwcrc","startDir","undefined","dir","root","dirname","candidate","join","raw","readFileSync","parsed","JSON","parse","$schema","parent","swcCoreCache","loadSwcCore","thisDir","fileURLToPath","url","req","createRequire","resolve","resolved","pathToFileURL","href","transformControllerSource","source","filename","loadSwc","swc","HttpDecoratorsConfigError","consumerSwcrc","consumerJsc","code","transformSync","parser","syntax","decorators","transform","legacyDecorator","decoratorMetadata","module","type","sourceMaps","loadControllerWithSwc","absoluteFilePath","tmpPath","replace","writeFileSync","Date","now","unlinkSync","loadControllersFromGlob","rootDir","pattern","files","scanControllerFiles","length","console","warn","controllers","file","absPath","mod","exported","Object","values","isControllerClass","push","fn","Reflect","hasMetadata","Symbol","for","parts","split","dirParts","part","includes","baseDir","lastPart","suffix","walk","entry","readdirSync","withFileTypes","full","name","isDirectory","endsWith","relative"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|