@theokit/http 0.5.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/app.d.ts +16 -0
- package/dist/app.js +3 -3
- package/dist/{chunk-34KOKJ5M.js → chunk-CMPP4ULU.js} +3 -3
- package/dist/{chunk-U46H4CGF.js → chunk-ELCXHPAD.js} +2 -2
- package/dist/{chunk-NDD7ANXZ.js → chunk-GXTGOPRU.js} +124 -6
- package/dist/chunk-GXTGOPRU.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-LKNI6QEP.js → chunk-MQAJWR3K.js} +1 -1
- package/dist/chunk-MQAJWR3K.js.map +1 -0
- package/dist/chunk-OBHHOS6E.js +257 -0
- package/dist/chunk-OBHHOS6E.js.map +1 -0
- package/dist/exception-filter-chain-V2MFO4WV.js +10 -0
- package/dist/index.d.ts +343 -8
- package/dist/index.js +230 -23
- package/dist/index.js.map +1 -1
- package/dist/interceptor-chain-ELSL6KZT.js +9 -0
- package/dist/{middleware-consumer-ljxK1fU_.d.ts → middleware-consumer-DcaksawH.d.ts} +1 -1
- package/dist/theokit-plugin.d.ts +1 -1
- package/dist/theokit-plugin.js +7 -167
- package/dist/theokit-plugin.js.map +1 -1
- package/package.json +19 -17
- package/dist/chunk-3PGQVQWG.js.map +0 -1
- package/dist/chunk-LKNI6QEP.js.map +0 -1
- package/dist/chunk-LWCNTZN6.js +0 -87
- package/dist/chunk-LWCNTZN6.js.map +0 -1
- package/dist/chunk-NDD7ANXZ.js.map +0 -1
- package/dist/chunk-QGB5YC4T.js.map +0 -1
- package/dist/exception-filter-chain-BCSQ3MZ2.js +0 -10
- package/dist/interceptor-chain-6S3PUV7J.js +0 -9
- /package/dist/{chunk-34KOKJ5M.js.map → chunk-CMPP4ULU.js.map} +0 -0
- /package/dist/{chunk-U46H4CGF.js.map → chunk-ELCXHPAD.js.map} +0 -0
- /package/dist/{exception-filter-chain-BCSQ3MZ2.js.map → exception-filter-chain-V2MFO4WV.js.map} +0 -0
- /package/dist/{interceptor-chain-6S3PUV7J.js.map → interceptor-chain-ELSL6KZT.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { D as DiContainer, M as MiddlewareConsumerImpl } from './middleware-consumer-
|
|
3
|
-
export { a as MiddlewareConfigProxy, b as MiddlewareFn, N as NestMiddleware, R as ResolvedMiddleware, m as middlewareMatchesPath, r as resolveOrNew, c as runMiddleware } from './middleware-consumer-
|
|
2
|
+
import { D as DiContainer, M as MiddlewareConsumerImpl } from './middleware-consumer-DcaksawH.js';
|
|
3
|
+
export { a as MiddlewareConfigProxy, b as MiddlewareFn, N as NestMiddleware, R as ResolvedMiddleware, m as middlewareMatchesPath, r as resolveOrNew, c as runMiddleware } from './middleware-consumer-DcaksawH.js';
|
|
4
4
|
import { S as ServerHandle } from './types-CGthbcon.js';
|
|
5
5
|
export { ReadinessCheck, TheoApp, TheoAppOptions } from './app.js';
|
|
6
|
+
import * as ReactTypes from 'react';
|
|
6
7
|
|
|
7
8
|
interface ControllerOptions {
|
|
8
9
|
host?: string;
|
|
@@ -69,6 +70,50 @@ declare function Res(opts?: {
|
|
|
69
70
|
passthrough?: boolean;
|
|
70
71
|
}): ParameterDecorator;
|
|
71
72
|
|
|
73
|
+
/**
|
|
74
|
+
* M47 (ADR-M47-1) — `@Expose(agent, opts?)` binds a SEPARATELY-BUILT agent (a pure `agent()…build()` from
|
|
75
|
+
* `agents/<name>.ts`) to a controller PROPERTY, making the exposure (route, auth via `@UseGuards`, streaming)
|
|
76
|
+
* visible in one code review. It mirrors the #122 verb decorators (`@Post`) — storing metadata via the same
|
|
77
|
+
* `Symbol.for()` seam — but records the agent instead of an HTTP verb, so the controller walker turns the
|
|
78
|
+
* property into an agent-serving route (`POST <prefix>/<property>`) delegated to the ONE runtime
|
|
79
|
+
* (`mountAgent`), never a JSON handler. It is a new AUTHORING surface over the existing runtime, not a
|
|
80
|
+
* parallel runtime (G2). CSRF is enforced once at the controller-dispatch boundary. Interceptors do NOT run
|
|
81
|
+
* for agent routes (the dispatcher delegates straight to `mountAgent`); guards DO (G5). The served path is
|
|
82
|
+
* the controller prefix + property name — keep it equal to the agent's convention route (`/api/agents/<name>`
|
|
83
|
+
* for a property named `<name>` under `@Controller('api/agents')`) so the generated `useAgent(handle)` path
|
|
84
|
+
* lines up.
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* Per-binding options for an exposed agent. Reserved for forward-compat — no options are wired yet.
|
|
88
|
+
*
|
|
89
|
+
* Two candidate fields were removed before shipping (M47 review): `path` (a route override) would let the
|
|
90
|
+
* served URL diverge from the generated handle's path — the codegen derives the handle from the agent's
|
|
91
|
+
* convention route (`/api/agents/<name>`), so an overridden route would make `useAgent(handle)` hit the
|
|
92
|
+
* wrong URL. And `csrf` was a no-op — CSRF is enforced exactly once at the controller-dispatch boundary
|
|
93
|
+
* regardless. Both return only when they can be wired end-to-end (codegen reads `@Expose` metadata / a
|
|
94
|
+
* per-route CSRF opt-out threads through the dispatcher). Until then, `@Expose(agent)` is the shape, and the
|
|
95
|
+
* exposure's path MUST be the convention route — put `@Expose` on a property named after the agent under
|
|
96
|
+
* `@Controller('api/agents')` (e.g. `chat` for `agents/chat.ts` → `/api/agents/chat`).
|
|
97
|
+
*/
|
|
98
|
+
type ExposeOptions = Record<string, never>;
|
|
99
|
+
/** Metadata recorded per `@Expose`-decorated controller member. */
|
|
100
|
+
interface ExposeEntry {
|
|
101
|
+
/** The separately-built agent module bound to this member. */
|
|
102
|
+
agent: unknown;
|
|
103
|
+
/** The per-binding options (defaulted to `{}`). */
|
|
104
|
+
opts: ExposeOptions;
|
|
105
|
+
/** The controller member the binding is attached to. */
|
|
106
|
+
propertyKey: string | symbol;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Bind an agent to a controller PROPERTY. Accumulates one {@link ExposeEntry} per member under the
|
|
110
|
+
* `EXPOSE_AGENT` metadata key on the controller constructor — the same accumulation shape `@Post` uses for
|
|
111
|
+
* `ROUTE_METHODS`, so `walkControllerMetadata` reads both alongside each other. Typed as `PropertyDecorator`
|
|
112
|
+
* (the exposure is declared as a property, e.g. `@Expose(chatAgent) chat!: typeof chatAgent`); the agent's
|
|
113
|
+
* behavior lives in its own `agents/<name>.ts`, never in a controller method body.
|
|
114
|
+
*/
|
|
115
|
+
declare function Expose(agent: unknown, opts?: ExposeOptions): PropertyDecorator;
|
|
116
|
+
|
|
72
117
|
declare function HttpCode(status: number): MethodDecorator;
|
|
73
118
|
declare function Header(name: string, value: string): MethodDecorator;
|
|
74
119
|
interface RedirectMeta {
|
|
@@ -77,7 +122,7 @@ interface RedirectMeta {
|
|
|
77
122
|
}
|
|
78
123
|
declare function Redirect(url: string, status?: number): MethodDecorator;
|
|
79
124
|
|
|
80
|
-
declare function UseGuards(...guards: Function[]): ClassDecorator & MethodDecorator;
|
|
125
|
+
declare function UseGuards(...guards: Function[]): ClassDecorator & MethodDecorator & PropertyDecorator;
|
|
81
126
|
declare function UseInterceptors(...interceptors: Function[]): ClassDecorator & MethodDecorator;
|
|
82
127
|
declare function UseFilters(...filters: Function[]): ClassDecorator & MethodDecorator;
|
|
83
128
|
/** @Catch(ExceptionType, ...) — marks which exception types an ExceptionFilter handles.
|
|
@@ -222,6 +267,7 @@ declare const USE_GUARDS: unique symbol;
|
|
|
222
267
|
declare const USE_INTERCEPTORS: unique symbol;
|
|
223
268
|
declare const USE_FILTERS: unique symbol;
|
|
224
269
|
declare const CATCH_EXCEPTIONS: unique symbol;
|
|
270
|
+
declare const EXPOSE_AGENT: unique symbol;
|
|
225
271
|
|
|
226
272
|
/**
|
|
227
273
|
* Typed facade over Reflect.defineMetadata / Reflect.getMetadata.
|
|
@@ -342,6 +388,14 @@ interface WalkResult {
|
|
|
342
388
|
guards: Function[];
|
|
343
389
|
interceptors: Function[];
|
|
344
390
|
filters: Function[];
|
|
391
|
+
/**
|
|
392
|
+
* M47 — set when the member is bound via `@Expose(agent, opts)`. The dispatcher delegates such routes to
|
|
393
|
+
* the agent runtime (`mountAgent`) instead of invoking a JSON handler. `undefined` for normal verb routes.
|
|
394
|
+
*/
|
|
395
|
+
agent?: {
|
|
396
|
+
module: unknown;
|
|
397
|
+
opts: ExposeOptions;
|
|
398
|
+
};
|
|
345
399
|
}
|
|
346
400
|
/**
|
|
347
401
|
* Normalize a joined path: strip doubles, trim trailing, ensure leading.
|
|
@@ -354,6 +408,63 @@ declare function joinPath(prefix: string, path: string): string;
|
|
|
354
408
|
*/
|
|
355
409
|
declare function walkControllerMetadata(ControllerClass: Function): WalkResult[];
|
|
356
410
|
|
|
411
|
+
/**
|
|
412
|
+
* SWC-powered module loader for controller files with parameter decorators.
|
|
413
|
+
*
|
|
414
|
+
* esbuild (used by tsx/Vite SSR) fundamentally cannot parse TypeScript
|
|
415
|
+
* parameter decorators (`@Body()`, `@Param()`, `@Query()`). This loader
|
|
416
|
+
* uses @swc/core to transform controller files with full decorator support
|
|
417
|
+
* (legacyDecorator + decoratorMetadata), then imports them via a temp .mjs
|
|
418
|
+
* file written in the SAME directory (preserving relative import resolution).
|
|
419
|
+
*
|
|
420
|
+
* Pattern: follows Next.js's approach (read tsconfig → configure SWC)
|
|
421
|
+
* but scoped to the http-decorators package, not the framework core.
|
|
422
|
+
*
|
|
423
|
+
* @see references/next.js/packages/next/src/build/swc/options.ts
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
interface SwcCore {
|
|
427
|
+
transformSync: (src: string, opts: unknown) => {
|
|
428
|
+
code: string;
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Transform TypeScript controller SOURCE (with parameter decorators) into
|
|
433
|
+
* ESM code, emitting the `design:paramtypes` / decorator metadata that esbuild
|
|
434
|
+
* cannot produce. Pure code→code — no file I/O, no module load — so it is
|
|
435
|
+
* reusable both by {@link loadControllerWithSwc} (which then temp-writes +
|
|
436
|
+
* imports) and by a build-tool transform hook that returns `{ code }` directly.
|
|
437
|
+
*
|
|
438
|
+
* The `@swc/core` loader is injectable (`loadSwc`) for testability; it defaults
|
|
439
|
+
* to the cached singleton.
|
|
440
|
+
*
|
|
441
|
+
* @throws HttpDecoratorsConfigError when @swc/core is unavailable.
|
|
442
|
+
*/
|
|
443
|
+
declare function transformControllerSource(source: string, filename: string, loadSwc?: () => Promise<SwcCore | null>): Promise<string>;
|
|
444
|
+
/**
|
|
445
|
+
* Load a TypeScript controller file using @swc/core for decorator support.
|
|
446
|
+
*
|
|
447
|
+
* Strategy:
|
|
448
|
+
* 1. Read source .ts file
|
|
449
|
+
* 2. Transform via {@link transformControllerSource} (legacyDecorator + metadata)
|
|
450
|
+
* 3. Write temp .mjs in SAME directory (relative imports resolve correctly)
|
|
451
|
+
* 4. Dynamic import() the .mjs — transitive .ts imports go through
|
|
452
|
+
* tsx/Vite's global hook (they don't have parameter decorators)
|
|
453
|
+
* 5. Cleanup temp file
|
|
454
|
+
*/
|
|
455
|
+
declare function loadControllerWithSwc(absoluteFilePath: string): Promise<Record<string, unknown>>;
|
|
456
|
+
/**
|
|
457
|
+
* Scan a glob pattern for controller files and load them all via SWC.
|
|
458
|
+
* Returns an array of controller class constructors found.
|
|
459
|
+
*/
|
|
460
|
+
declare function loadControllersFromGlob(rootDir: string, pattern: string): Promise<Function[]>;
|
|
461
|
+
/**
|
|
462
|
+
* Check if a function has @Controller metadata.
|
|
463
|
+
* Uses Symbol.for() global registry key — same Symbol instance across
|
|
464
|
+
* module boundaries (SWC-loaded controllers share the global registry).
|
|
465
|
+
*/
|
|
466
|
+
declare function isControllerClass(fn: Function): boolean;
|
|
467
|
+
|
|
357
468
|
interface RouteRegistration {
|
|
358
469
|
verb: HttpVerb;
|
|
359
470
|
fullPath: string;
|
|
@@ -369,14 +480,40 @@ interface RouteRegistration {
|
|
|
369
480
|
declare function registerControllers(controllers: Function[]): RouteRegistration[];
|
|
370
481
|
|
|
371
482
|
/**
|
|
372
|
-
*
|
|
373
|
-
*
|
|
483
|
+
* M47 — serves an `@Expose`-bound agent route. http is agent-runtime agnostic (G1/G2): it invokes this
|
|
484
|
+
* injected callback (theo supplies a `mountAgent`-backed impl) instead of calling a controller method.
|
|
374
485
|
*/
|
|
486
|
+
type ServeAgent = (agent: unknown, request: Request, opts: ExposeOptions) => Promise<Response>;
|
|
375
487
|
interface CreateDecoratorServerOptions {
|
|
376
488
|
controllers: Function[];
|
|
377
489
|
container?: DiContainer;
|
|
378
490
|
configure?: (consumer: MiddlewareConsumerImpl) => void;
|
|
491
|
+
/** M47 — required when any controller `@Expose`-binds an agent; serves the agent route. */
|
|
492
|
+
serveAgent?: ServeAgent;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* A pure Web-Standard controller handler: callable as `(request) => Response | null`
|
|
496
|
+
* plus a non-executing `matches(method, pathname)` route probe (so a host can gate
|
|
497
|
+
* — e.g. CSRF — before dispatch runs a handler).
|
|
498
|
+
*/
|
|
499
|
+
interface DecoratorHandler {
|
|
500
|
+
(request: Request): Promise<Response | null>;
|
|
501
|
+
/** True when a controller route owns `method` + `pathname` (no handler executed). */
|
|
502
|
+
matches(method: string, pathname: string): boolean;
|
|
379
503
|
}
|
|
504
|
+
/**
|
|
505
|
+
* Build a pure Web-Standard request handler from decorated controller classes,
|
|
506
|
+
* WITHOUT binding a network listener. Returns a {@link DecoratorHandler} whose
|
|
507
|
+
* call returns `null` when no controller route matched — the caller decides the
|
|
508
|
+
* miss (a standalone server answers 404; a host middleware falls through to its
|
|
509
|
+
* own routing). This is the reusable dispatch seam consumed by the framework's
|
|
510
|
+
* controller dispatch (#122) so it never re-implements match/bind/validate.
|
|
511
|
+
*/
|
|
512
|
+
declare function createDecoratorHandler(controllersOrOpts: Function[] | CreateDecoratorServerOptions): DecoratorHandler;
|
|
513
|
+
/**
|
|
514
|
+
* Creates a real HTTP server from decorated controller classes.
|
|
515
|
+
* Uses Web Standard Request/Response internally; Node adapter at the boundary.
|
|
516
|
+
*/
|
|
380
517
|
declare function createDecoratorServer(controllersOrOpts: Function[] | CreateDecoratorServerOptions): ServerHandle;
|
|
381
518
|
|
|
382
519
|
/**
|
|
@@ -998,10 +1135,10 @@ type InferResponse<D> = D extends {
|
|
|
998
1135
|
response: infer R;
|
|
999
1136
|
} ? R : unknown;
|
|
1000
1137
|
interface TypedClient<M extends RouteMap> {
|
|
1001
|
-
get<P extends string
|
|
1138
|
+
get<P extends string>(path: P, opts?: {
|
|
1002
1139
|
query?: Record<string, string>;
|
|
1003
1140
|
headers?: Record<string, string>;
|
|
1004
|
-
}): Promise<InferResponse<M[`GET ${P}`]
|
|
1141
|
+
}): Promise<InferResponse<M[`GET ${P}`]>>;
|
|
1005
1142
|
post<P extends string>(path: P, body?: InferBody<M[`POST ${P}`]>, opts?: {
|
|
1006
1143
|
headers?: Record<string, string>;
|
|
1007
1144
|
}): Promise<InferResponse<M[`POST ${P}`]>>;
|
|
@@ -1091,4 +1228,202 @@ declare function isSafePath(pathname: string): boolean;
|
|
|
1091
1228
|
*/
|
|
1092
1229
|
declare function createStaticHandler(options?: StaticOptions): (request: Request) => Promise<Response | null>;
|
|
1093
1230
|
|
|
1094
|
-
|
|
1231
|
+
interface TheoRequestContext {
|
|
1232
|
+
/** The raw Web Standard Request object. */
|
|
1233
|
+
request: Request;
|
|
1234
|
+
/** URL pathname (e.g., '/api/tasks'). */
|
|
1235
|
+
pathname: string;
|
|
1236
|
+
/** HTTP method (e.g., 'GET', 'POST'). */
|
|
1237
|
+
method: string;
|
|
1238
|
+
/** Route params extracted from URL (e.g., { id: '42' }). */
|
|
1239
|
+
params: Record<string, string>;
|
|
1240
|
+
/** Matched controller or agent class name (if resolved). */
|
|
1241
|
+
handler?: string;
|
|
1242
|
+
/** Request start time (ms). */
|
|
1243
|
+
startedAt: number;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Get the current request context.
|
|
1247
|
+
*
|
|
1248
|
+
* @throws Error if called outside a request (e.g., at module load time).
|
|
1249
|
+
*
|
|
1250
|
+
* @example
|
|
1251
|
+
* ```typescript
|
|
1252
|
+
* import { getRequestContext } from '@theokit/http'
|
|
1253
|
+
*
|
|
1254
|
+
* class AuthGuard {
|
|
1255
|
+
* canActivate() {
|
|
1256
|
+
* const { request } = getRequestContext()
|
|
1257
|
+
* return request.headers.get('authorization') !== null
|
|
1258
|
+
* }
|
|
1259
|
+
* }
|
|
1260
|
+
* ```
|
|
1261
|
+
*/
|
|
1262
|
+
declare function getRequestContext(): TheoRequestContext;
|
|
1263
|
+
/**
|
|
1264
|
+
* Try to get the current request context, or null if not in a request.
|
|
1265
|
+
* Useful for code that may run both inside and outside requests.
|
|
1266
|
+
*/
|
|
1267
|
+
declare function tryGetRequestContext(): TheoRequestContext | null;
|
|
1268
|
+
|
|
1269
|
+
/**
|
|
1270
|
+
* Error digestion — converts any thrown value into a stable hash + context.
|
|
1271
|
+
*
|
|
1272
|
+
* Inspired by Next.js `create-error-handler.tsx`. Produces a deterministic
|
|
1273
|
+
* digest ID suitable for logging and client-safe error references without
|
|
1274
|
+
* leaking stack traces in production.
|
|
1275
|
+
*
|
|
1276
|
+
* Uses djb2 hash (sync, no crypto dependency) per ADR D3.
|
|
1277
|
+
*/
|
|
1278
|
+
interface ErrorContext {
|
|
1279
|
+
route?: string;
|
|
1280
|
+
phase?: 'guard' | 'interceptor' | 'handler' | 'filter' | 'agent';
|
|
1281
|
+
source?: string;
|
|
1282
|
+
}
|
|
1283
|
+
interface DigestedError {
|
|
1284
|
+
digest: string;
|
|
1285
|
+
message: string;
|
|
1286
|
+
status: number;
|
|
1287
|
+
context: ErrorContext;
|
|
1288
|
+
stack?: string;
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Converts any thrown value into a structured {@link DigestedError}.
|
|
1292
|
+
*
|
|
1293
|
+
* - Sync (never async) — safe to call inside catch blocks.
|
|
1294
|
+
* - Stack trace stripped when `process.env.NODE_ENV === 'production'`.
|
|
1295
|
+
* - Preserves {@link HttpException} status codes.
|
|
1296
|
+
* - Handles non-Error throws (string, number, object).
|
|
1297
|
+
*/
|
|
1298
|
+
declare function digestError(err: unknown, context?: ErrorContext): DigestedError;
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Component tree composition — recursive wrapping of file-convention
|
|
1302
|
+
* components (layout, page, loading, error, not-found) into a React
|
|
1303
|
+
* element tree with Suspense and error boundaries.
|
|
1304
|
+
*
|
|
1305
|
+
* Inspired by Next.js `create-component-tree.tsx`.
|
|
1306
|
+
*
|
|
1307
|
+
* React is loaded via dynamic `import('react')` because it is an
|
|
1308
|
+
* optional peerDep of @theokit/http (EC-2).
|
|
1309
|
+
*/
|
|
1310
|
+
|
|
1311
|
+
interface RouteTree {
|
|
1312
|
+
layout?: ReactTypes.ComponentType<{
|
|
1313
|
+
children: ReactTypes.ReactNode;
|
|
1314
|
+
}>;
|
|
1315
|
+
page?: ReactTypes.ComponentType;
|
|
1316
|
+
loading?: ReactTypes.ComponentType;
|
|
1317
|
+
error?: ReactTypes.ComponentType;
|
|
1318
|
+
notFound?: ReactTypes.ComponentType;
|
|
1319
|
+
children?: Record<string, RouteTree>;
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Composes a {@link RouteTree} into a nested React element tree.
|
|
1323
|
+
*
|
|
1324
|
+
* Wrapping order (outermost → innermost):
|
|
1325
|
+
* layout → ErrorBoundary(error) → Suspense(loading) → page
|
|
1326
|
+
*
|
|
1327
|
+
* Returns `null` when no `page` component is found in the tree.
|
|
1328
|
+
*
|
|
1329
|
+
* @param tree - The route tree describing file conventions found.
|
|
1330
|
+
* @returns A React element or `null`.
|
|
1331
|
+
*/
|
|
1332
|
+
declare function composeComponentTree(tree: RouteTree): Promise<ReactTypes.ReactElement | null>;
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Streaming SSR — renders a React element tree to a `ReadableStream<Uint8Array>`.
|
|
1336
|
+
*
|
|
1337
|
+
* Inspired by Next.js `stream-ops.ts`. Uses Web Standard `renderToReadableStream`
|
|
1338
|
+
* (works on Node 18+, Bun, Deno). Falls back to `renderToString` wrapped in a
|
|
1339
|
+
* ReadableStream when `renderToReadableStream` is not available (React 17 — EC-4).
|
|
1340
|
+
*
|
|
1341
|
+
* React is loaded via dynamic `import('react-dom/server')` because react-dom
|
|
1342
|
+
* is an optional peerDep of @theokit/http (ADR D2).
|
|
1343
|
+
*/
|
|
1344
|
+
|
|
1345
|
+
interface StreamRenderOptions {
|
|
1346
|
+
/** React element to render */
|
|
1347
|
+
root: ReactTypes.ReactElement;
|
|
1348
|
+
/** Whether to wait for all Suspense to resolve (default: false — stream immediately) */
|
|
1349
|
+
waitForAll?: boolean;
|
|
1350
|
+
}
|
|
1351
|
+
interface StreamRenderResult {
|
|
1352
|
+
/** The HTML stream */
|
|
1353
|
+
stream: ReadableStream<Uint8Array>;
|
|
1354
|
+
/** Promise that resolves when all content has been flushed */
|
|
1355
|
+
allReady: Promise<void>;
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Renders a React element to a `ReadableStream<Uint8Array>` (Web Standard).
|
|
1359
|
+
*
|
|
1360
|
+
* 1. Tries `renderToReadableStream` first (React 18+ — Web Standard API).
|
|
1361
|
+
* 2. Falls back to `renderToString` wrapped in a ReadableStream when
|
|
1362
|
+
* `renderToReadableStream` is not available (React 17 compat — EC-4).
|
|
1363
|
+
* 3. Prepends `<!DOCTYPE html>` to the stream.
|
|
1364
|
+
*
|
|
1365
|
+
* **EC-7 — Streaming error handling:** In streaming mode, errors thrown inside
|
|
1366
|
+
* Suspense boundaries are caught by React's streaming error handler and result
|
|
1367
|
+
* in a client-side error boundary activation (the shell is already sent). In
|
|
1368
|
+
* string mode (`renderToString`), errors throw synchronously before any bytes
|
|
1369
|
+
* are sent, allowing a full 500 error page. Choose streaming when you want
|
|
1370
|
+
* progressive rendering; choose string mode when you want atomic error handling.
|
|
1371
|
+
*/
|
|
1372
|
+
declare function renderToStream(options: StreamRenderOptions): Promise<StreamRenderResult>;
|
|
1373
|
+
/**
|
|
1374
|
+
* Converts a {@link StreamRenderResult} into a Web Standard `Response`.
|
|
1375
|
+
*
|
|
1376
|
+
* Convenience wrapper for use in request handlers:
|
|
1377
|
+
* ```ts
|
|
1378
|
+
* const result = await renderToStream({ root: <App /> })
|
|
1379
|
+
* return streamToResponse(result)
|
|
1380
|
+
* ```
|
|
1381
|
+
*/
|
|
1382
|
+
declare function streamToResponse(result: StreamRenderResult): Response;
|
|
1383
|
+
|
|
1384
|
+
interface RevalidationSignal {
|
|
1385
|
+
kind: 'tag' | 'path';
|
|
1386
|
+
value: string;
|
|
1387
|
+
timestamp: number;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Signal that a cache tag should be revalidated.
|
|
1391
|
+
*
|
|
1392
|
+
* Safe to call from any request handler (controller, agent, action).
|
|
1393
|
+
* Signals are accumulated per-request and consumed by the cache engine.
|
|
1394
|
+
*
|
|
1395
|
+
* @example
|
|
1396
|
+
* ```typescript
|
|
1397
|
+
* import { revalidateTag } from '@theokit/http'
|
|
1398
|
+
*
|
|
1399
|
+
* @Post()
|
|
1400
|
+
* async createTask(@Body(schema) body) {
|
|
1401
|
+
* const task = await db.tasks.create(body)
|
|
1402
|
+
* revalidateTag('tasks') // invalidate cached task lists
|
|
1403
|
+
* return task
|
|
1404
|
+
* }
|
|
1405
|
+
* ```
|
|
1406
|
+
*/
|
|
1407
|
+
declare function revalidateTag(tag: string): void;
|
|
1408
|
+
/**
|
|
1409
|
+
* Signal that a cached path should be revalidated.
|
|
1410
|
+
*
|
|
1411
|
+
* @example
|
|
1412
|
+
* ```typescript
|
|
1413
|
+
* import { revalidatePath } from '@theokit/http'
|
|
1414
|
+
*
|
|
1415
|
+
* @Delete(':id')
|
|
1416
|
+
* async removeTask(@Param('id') id: string) {
|
|
1417
|
+
* await db.tasks.delete(id)
|
|
1418
|
+
* revalidatePath('/api/tasks')
|
|
1419
|
+
* }
|
|
1420
|
+
* ```
|
|
1421
|
+
*/
|
|
1422
|
+
declare function revalidatePath(path: string): void;
|
|
1423
|
+
/**
|
|
1424
|
+
* Get all revalidation signals collected during the current request.
|
|
1425
|
+
* Called by the cache engine after the handler completes.
|
|
1426
|
+
*/
|
|
1427
|
+
declare function getRevalidationSignals(): RevalidationSignal[];
|
|
1428
|
+
|
|
1429
|
+
export { All, type ArgumentsHost, BadGatewayException, BadRequestException, Body, CATCH_EXCEPTIONS, CONTROLLER_PREFIX, type CanActivate, Catch, ConflictException, Controller, type ControllerMeta, type ControllerOptions, type CreateDecoratorServerOptions, type DecoratorHandler, Delete, DiContainer, type DigestedError, EXPOSE_AGENT, type ErrorContext, type ExceptionFilter, type ExecutionContext, Expose, type ExposeEntry, type ExposeOptions, ForbiddenException, GatewayTimeoutException, Get, GoneException, Head, Header, Headers, HostParam, HttpCode, HttpDecoratorsConfigError, HttpException, type HttpExceptionOptions, HttpStatus, type HttpStatusCode, type HttpVerb, HttpVersionNotSupportedException, ImATeapotException, type Interceptor, InternalServerErrorException, Ip, type MetadataKey, MethodNotAllowedException, MiddlewareConsumerImpl, NotAcceptableException, NotFoundException, NotImplementedException, Options, Param, type ParamEntry, type ParamSource, Patch, PayloadTooLargeException, Post, PreconditionFailedException, Put, Query, ROUTE_HEADERS, ROUTE_METHODS, ROUTE_PARAMS, ROUTE_REDIRECT, ROUTE_STATUS, Redirect, type RedirectMeta, Reflector, Req, RequestTimeoutException, Res, type RevalidationSignal, type RouteDefinition, type RouteMap, type RouteMethodEntry, type RouteRegistration, type RouteTree, type ServeAgent, ServiceUnavailableException, Session, SetMetadata, SkipThrottle, type StaticOptions, type StreamRenderOptions, type StreamRenderResult, type SwcCore, type TheoRequestContext, Throttle, type ThrottleOptions, TooManyRequestsException, type TypedClient, TypedClientError, USE_FILTERS, USE_GUARDS, USE_INTERCEPTORS, UnauthorizedException, UnprocessableEntityException, UnsupportedMediaTypeException, UseFilters, UseGuards, UseInterceptors, type WalkResult, composeComponentTree, contract, createDecorator, createDecoratorHandler, createDecoratorServer, createExecutionContext, createStaticHandler, createTypedClient, digestError, getMeta, getMimeType, getRequestContext, getRevalidationSignals, getThrottleOptions, isControllerClass, isSafePath, isThrottleSkipped, joinPath, loadControllerWithSwc, loadControllersFromGlob, registerControllers, renderToStream, resolveDtoSchema, revalidatePath, revalidateTag, runExceptionFilters, runInterceptors, setMeta, streamToResponse, transformControllerSource, tryGetRequestContext, walkControllerMetadata };
|