theokit 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{actions-virtual-module-SQDY3V5X.js → actions-virtual-module-3CDQTWOC.js} +6 -6
- package/dist/{actions-virtual-module-PNPRCEOS.js → actions-virtual-module-EIPXX4ZB.js} +3 -3
- package/dist/adapters/web-shim.d.ts +67 -0
- package/dist/adapters/ws-shim.d.ts +55 -0
- package/dist/agent-events-DosDXkSV.d.ts +94 -0
- package/dist/agents-typed-client-SAWAAH7K.js +142 -0
- package/dist/agents-typed-client-SAWAAH7K.js.map +1 -0
- package/dist/agents-typed-client-UTEQUA63.js +143 -0
- package/dist/agents-typed-client-UTEQUA63.js.map +1 -0
- package/dist/{app-typed-client-5GYEOYP3.js → app-typed-client-7PBFWZUE.js} +3 -3
- package/dist/{app-typed-client-QG7BVZYW.js → app-typed-client-CSOK7NPC.js} +6 -6
- package/dist/audit-log-BQWM5YLG.d.ts +60 -0
- package/dist/body-parser-web-FV5HWCY3.js +71 -0
- package/dist/body-parser-web-FV5HWCY3.js.map +1 -0
- package/dist/boot/index.d.ts +39 -0
- package/dist/{build-QFRLSEZ4.js → build-HXND27XG.js} +11 -11
- package/dist/{chunk-223EFY5X.js → chunk-2J7XU3PW.js} +68 -27
- package/dist/chunk-2J7XU3PW.js.map +1 -0
- package/dist/{chunk-RESN62GB.js → chunk-2KZQPDYR.js} +5 -48
- package/dist/chunk-2KZQPDYR.js.map +1 -0
- package/dist/chunk-3S3BNW5K.js +445 -0
- package/dist/chunk-3S3BNW5K.js.map +1 -0
- package/dist/{chunk-6FYD34NX.js → chunk-BQDGES7C.js} +28 -28
- package/dist/{chunk-6FYD34NX.js.map → chunk-BQDGES7C.js.map} +1 -1
- package/dist/chunk-EXP56GFQ.js +52 -0
- package/dist/chunk-EXP56GFQ.js.map +1 -0
- package/dist/chunk-F4YUPDJ2.js +115 -0
- package/dist/chunk-F4YUPDJ2.js.map +1 -0
- package/dist/{chunk-NAZ4E2GT.js → chunk-KXA37ONC.js} +2 -2
- package/dist/chunk-NHJMZCAS.js +32 -0
- package/dist/chunk-NHJMZCAS.js.map +1 -0
- package/dist/{chunk-43D6XNDR.js → chunk-O62MW4MT.js} +91 -18
- package/dist/chunk-O62MW4MT.js.map +1 -0
- package/dist/chunk-RSVN727G.js +1 -0
- package/dist/{chunk-7CBRKNQA.js → chunk-RYTZYFSD.js} +198 -6
- package/dist/chunk-RYTZYFSD.js.map +1 -0
- package/dist/chunk-UNLA45FY.js +235 -0
- package/dist/chunk-UNLA45FY.js.map +1 -0
- package/dist/{chunk-GFMQJHXX.js → chunk-WR4F4EEZ.js} +1082 -1074
- package/dist/chunk-WR4F4EEZ.js.map +1 -0
- package/dist/{chunk-AD74EAK3.js → chunk-ZSTZXR2D.js} +1 -30
- package/dist/chunk-ZSTZXR2D.js.map +1 -0
- package/dist/cli/index.js +5 -5
- package/dist/client/index.d.ts +418 -0
- package/dist/client/index.js +84 -3
- package/dist/client/index.js.map +1 -1
- package/dist/csrf-BBrEZSBW.d.ts +107 -0
- package/dist/csrf-readiness-store-CjIoub3U.d.ts +43 -0
- package/dist/define-websocket-CdK94O-D.d.ts +64 -0
- package/dist/{dev-GBXOTXUP.js → dev-OWW4XVIH.js} +10 -10
- package/dist/{dev-emit-FEFEDLZF.js → dev-emit-5MDSBP5D.js} +3 -3
- package/dist/{dev-emit-O4EGOSNV.js → dev-emit-QH2YGZXN.js} +2 -2
- package/dist/devtools/entry.d.ts +5 -0
- package/dist/error-envelope-BsNzzAV5.d.ts +62 -0
- package/dist/health-route-C0hk64_U.d.ts +57 -0
- package/dist/index-B40qUSrQ.d.ts +575 -0
- package/dist/index.d.ts +361 -0
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/internal-api-4YTJDITC.js +83 -0
- package/dist/internal-api-EFKZWIYZ.js +66 -0
- package/dist/internal-api-EFKZWIYZ.js.map +1 -0
- package/dist/job-backend-CgC8Xf33.d.ts +68 -0
- package/dist/match-CfbEFRG4.d.ts +26 -0
- package/dist/{openapi-VR6AFBLJ.js → openapi-FHY6HC6I.js} +7 -7
- package/dist/plugin-runner-BGBkzgi0.d.ts +95 -0
- package/dist/plugin-types-DNJGxr4Z.d.ts +79 -0
- package/dist/rate-limit-BdNDZ3vt.d.ts +58 -0
- package/dist/rate-limit-store-BEJnhWdw.d.ts +72 -0
- package/dist/react-query/index.d.ts +33 -0
- package/dist/{registry-Q2TZQLUH.js → registry-34LL7NF4.js} +1 -1
- package/dist/{routes-LRYOIIAI.js → routes-EW7TP7NJ.js} +2 -2
- package/dist/schema-BpH6ivDY.d.ts +74 -0
- package/dist/server/agent/index.d.ts +229 -0
- package/dist/server/agent/index.js +2 -1
- package/dist/server/auth/index.d.ts +419 -0
- package/dist/server/cost/index.d.ts +177 -0
- package/dist/server/cron/index.d.ts +208 -0
- package/dist/server/define/index.d.ts +313 -0
- package/dist/server/define/index.js +4 -2
- package/dist/server/http/index.d.ts +11 -0
- package/dist/server/index.d.ts +848 -0
- package/dist/server/index.js +9 -294
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.d.ts +348 -0
- package/dist/server/observability/index.d.ts +324 -0
- package/dist/server/plugins/index.d.ts +17 -0
- package/dist/server/rate-limit/index.d.ts +105 -0
- package/dist/server/realtime/index.d.ts +15 -0
- package/dist/server/scan/index.d.ts +126 -0
- package/dist/server/scan/index.js +1 -1
- package/dist/server/security/index.d.ts +193 -0
- package/dist/server/storage/index.d.ts +22 -0
- package/dist/server/webhook/index.d.ts +148 -0
- package/dist/{start-3ZHAXSJE.js → start-KIQ5TTLR.js} +76 -13
- package/dist/start-KIQ5TTLR.js.map +1 -0
- package/dist/storage-manager-C4jsO0Tp.d.ts +89 -0
- package/dist/storage-types-DsDTCPbp.d.ts +96 -0
- package/dist/vite-plugin/index.d.ts +115 -0
- package/dist/vite-plugin/index.js +6 -4
- package/dist/{vite-plugin-WO72VLYR.js → vite-plugin-RK66K26Z.js} +7 -7
- package/dist/vite-plugin-RK66K26Z.js.map +1 -0
- package/package.json +4 -4
- package/dist/chunk-223EFY5X.js.map +0 -1
- package/dist/chunk-3LVRAGAZ.js +0 -73
- package/dist/chunk-3LVRAGAZ.js.map +0 -1
- package/dist/chunk-43D6XNDR.js.map +0 -1
- package/dist/chunk-7CBRKNQA.js.map +0 -1
- package/dist/chunk-AD74EAK3.js.map +0 -1
- package/dist/chunk-GFMQJHXX.js.map +0 -1
- package/dist/chunk-PBEH6NXR.js +0 -44
- package/dist/chunk-PBEH6NXR.js.map +0 -1
- package/dist/chunk-PIVX3DYW.js +0 -142
- package/dist/chunk-PIVX3DYW.js.map +0 -1
- package/dist/chunk-PPPR5DGR.js +0 -1
- package/dist/chunk-RESN62GB.js.map +0 -1
- package/dist/start-3ZHAXSJE.js.map +0 -1
- /package/dist/{actions-virtual-module-SQDY3V5X.js.map → actions-virtual-module-3CDQTWOC.js.map} +0 -0
- /package/dist/{actions-virtual-module-PNPRCEOS.js.map → actions-virtual-module-EIPXX4ZB.js.map} +0 -0
- /package/dist/{app-typed-client-5GYEOYP3.js.map → app-typed-client-7PBFWZUE.js.map} +0 -0
- /package/dist/{app-typed-client-QG7BVZYW.js.map → app-typed-client-CSOK7NPC.js.map} +0 -0
- /package/dist/{build-QFRLSEZ4.js.map → build-HXND27XG.js.map} +0 -0
- /package/dist/{chunk-NAZ4E2GT.js.map → chunk-KXA37ONC.js.map} +0 -0
- /package/dist/{chunk-PPPR5DGR.js.map → chunk-RSVN727G.js.map} +0 -0
- /package/dist/{dev-GBXOTXUP.js.map → dev-OWW4XVIH.js.map} +0 -0
- /package/dist/{dev-emit-FEFEDLZF.js.map → dev-emit-5MDSBP5D.js.map} +0 -0
- /package/dist/{dev-emit-O4EGOSNV.js.map → dev-emit-QH2YGZXN.js.map} +0 -0
- /package/dist/{vite-plugin-WO72VLYR.js.map → internal-api-4YTJDITC.js.map} +0 -0
- /package/dist/{openapi-VR6AFBLJ.js.map → openapi-FHY6HC6I.js.map} +0 -0
- /package/dist/{registry-Q2TZQLUH.js.map → registry-34LL7NF4.js.map} +0 -0
- /package/dist/{routes-LRYOIIAI.js.map → routes-EW7TP7NJ.js.map} +0 -0
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "tsx/esm";
|
|
3
|
+
import {
|
|
4
|
+
emitOpenApi,
|
|
5
|
+
loadRoutesForOpenApi
|
|
6
|
+
} from "./chunk-JAIKGP3Q.js";
|
|
3
7
|
import {
|
|
4
8
|
loadConfig
|
|
5
9
|
} from "./chunk-7YZHAQU7.js";
|
|
6
10
|
import "./chunk-YJAUJXZS.js";
|
|
7
11
|
import "./chunk-45C3WUQ7.js";
|
|
8
|
-
import {
|
|
9
|
-
emitOpenApi,
|
|
10
|
-
loadRoutesForOpenApi
|
|
11
|
-
} from "./chunk-JAIKGP3Q.js";
|
|
12
12
|
import {
|
|
13
13
|
generateManifest
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-F4YUPDJ2.js";
|
|
15
|
+
import "./chunk-BQDGES7C.js";
|
|
16
16
|
|
|
17
17
|
// src/cli/commands/openapi.ts
|
|
18
18
|
import { mkdtempSync, rmSync } from "fs";
|
|
@@ -79,4 +79,4 @@ function emitOpenApiInMemory(manifest, config) {
|
|
|
79
79
|
export {
|
|
80
80
|
openapiCommand
|
|
81
81
|
};
|
|
82
|
-
//# sourceMappingURL=openapi-
|
|
82
|
+
//# sourceMappingURL=openapi-FHY6HC6I.js.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { T as TheoPlugin, a as TheoApp, P as PluginContext, H as HookResult, R as RunHookOptions } from './plugin-types-DNJGxr4Z.js';
|
|
2
|
+
|
|
3
|
+
declare class DuplicatePluginError extends Error {
|
|
4
|
+
constructor(name: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Per T3.1 (C1 plugin scope encapsulation) — duplicate decoration
|
|
8
|
+
* keys across sibling plugins are now PERMITTED because each plugin gets its
|
|
9
|
+
* own child scope via `Object.create(parent)` (Fastify pattern, ADR-0028
|
|
10
|
+
* blueprint D1). This class is retained for one minor cycle so consumers who
|
|
11
|
+
* `instanceof DuplicateDecorationError` continue to compile; the constructor
|
|
12
|
+
* is no longer reachable from `PluginRunner.register()`. Removal scheduled
|
|
13
|
+
* for 0.x+2 per CHANGELOG.
|
|
14
|
+
*/
|
|
15
|
+
declare class DuplicateDecorationError extends Error {
|
|
16
|
+
constructor(key: string, existingPlugin: string, newPlugin: string);
|
|
17
|
+
}
|
|
18
|
+
declare class PluginRunner {
|
|
19
|
+
private plugins;
|
|
20
|
+
private pluginScopes;
|
|
21
|
+
private onRequestHooks;
|
|
22
|
+
private preHandlerHooks;
|
|
23
|
+
private onResponseHooks;
|
|
24
|
+
private onErrorHooks;
|
|
25
|
+
/**
|
|
26
|
+
* Parent app — proto-chain root for all child scopes. Has its OWN empty
|
|
27
|
+
* decorations map (parent never receives `decorateRequest` calls under
|
|
28
|
+
* the T3.1 contract; only child scopes do).
|
|
29
|
+
*/
|
|
30
|
+
private parentDecorations;
|
|
31
|
+
private parentApp;
|
|
32
|
+
has(name: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Per T3.1 (C1 plugin scope encapsulation):
|
|
35
|
+
* 1. Reserve the plugin name (still rejects duplicates).
|
|
36
|
+
* 2. Build a CHILD TheoApp via `Object.create(parentApp)` — Fastify
|
|
37
|
+
* `plugin-override.js:38` pattern. The child's own `decorateRequest`
|
|
38
|
+
* populates per-scope `decorations`; the child's `addHook` still
|
|
39
|
+
* forwards into the shared hook lists (hooks ARE process-global —
|
|
40
|
+
* only decorations are scoped, mirroring Fastify's decoration vs
|
|
41
|
+
* hook semantics).
|
|
42
|
+
* 3. Invoke `plugin.register(childApp)`.
|
|
43
|
+
*
|
|
44
|
+
* Cross-plugin decoration-key collisions are PERMITTED (per blueprint
|
|
45
|
+
* D1). The legacy `DuplicateDecorationError` is no longer thrown.
|
|
46
|
+
*/
|
|
47
|
+
register(plugin: TheoPlugin): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Build the parent app facade. Hooks forward to shared lists.
|
|
50
|
+
* `decorateRequest` writes into the parent decorations map — used only
|
|
51
|
+
* if a future consumer registers a non-plugin "app-level" decoration
|
|
52
|
+
* directly. T3.1 contract: plugins decorate ONLY through child scopes.
|
|
53
|
+
*/
|
|
54
|
+
private buildParentAppFacade;
|
|
55
|
+
/**
|
|
56
|
+
* Build a child scope via `Object.create(parentApp)` so the child
|
|
57
|
+
* inherits the parent's facade methods through the prototype chain.
|
|
58
|
+
* Then override `decorateRequest` on the child instance so writes
|
|
59
|
+
* land in the per-scope `decorations` map (parent is NOT mutated).
|
|
60
|
+
*/
|
|
61
|
+
private buildPluginScope;
|
|
62
|
+
private routeHookByName;
|
|
63
|
+
/**
|
|
64
|
+
* Apply ALL plugin scopes' decorations into the request ctx. Per T3.1,
|
|
65
|
+
* sibling plugins MAY decorate the same key — last-writer-wins at apply
|
|
66
|
+
* time (ordering = registration order). This keeps the legacy
|
|
67
|
+
* `ctx.<key>` flat surface working for consumers that already aggregate
|
|
68
|
+
* decorations into a single bag.
|
|
69
|
+
*/
|
|
70
|
+
applyDecorations(ctx: Record<string, unknown>): void;
|
|
71
|
+
/**
|
|
72
|
+
* Apply ONLY one plugin's scoped decorations into `target`. Used by
|
|
73
|
+
* the T1.1 RED-3 test (sibling isolation proof) and by future scope-aware
|
|
74
|
+
* dispatch paths. Throws if the plugin name isn't registered.
|
|
75
|
+
*/
|
|
76
|
+
applyScopedDecorations(pluginName: string, target: Record<string, unknown>): void;
|
|
77
|
+
/** T1.1 RED-1/RED-4 introspection: returns the child TheoApp built for `pluginName`. */
|
|
78
|
+
getPluginScope(pluginName: string): TheoApp;
|
|
79
|
+
/** T1.1 RED-4: returns the parent TheoApp (root of every child's proto chain). */
|
|
80
|
+
getParentApp(): TheoApp;
|
|
81
|
+
/** T1.1 RED-2: returns the parent's decorations map (NEVER touched by plugin decorate calls under T3.1 contract). */
|
|
82
|
+
getParentDecorations(): Map<string, unknown>;
|
|
83
|
+
runOnRequest(ctx: PluginContext): Promise<HookResult>;
|
|
84
|
+
runPreHandler(ctx: PluginContext): Promise<HookResult>;
|
|
85
|
+
runOnResponse(ctx: PluginContext, options?: RunHookOptions): Promise<HookResult>;
|
|
86
|
+
/**
|
|
87
|
+
* Run all onError hooks. Swallows errors thrown inside hooks themselves to
|
|
88
|
+
* prevent recursion (an error in an error handler must not trigger onError
|
|
89
|
+
* again).
|
|
90
|
+
*/
|
|
91
|
+
runOnError(ctx: PluginContext, error: unknown): Promise<HookResult>;
|
|
92
|
+
private runHookList;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { DuplicateDecorationError as D, PluginRunner as P, DuplicatePluginError as a };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
|
|
3
|
+
interface PluginContext {
|
|
4
|
+
request: IncomingMessage;
|
|
5
|
+
response: ServerResponse;
|
|
6
|
+
ctx: Record<string, unknown>;
|
|
7
|
+
requestId: string;
|
|
8
|
+
}
|
|
9
|
+
interface PluginErrorContext extends PluginContext {
|
|
10
|
+
error: unknown;
|
|
11
|
+
}
|
|
12
|
+
interface RunHookOptions {
|
|
13
|
+
inErrorPath?: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface HookResult {
|
|
16
|
+
shortCircuited: boolean;
|
|
17
|
+
}
|
|
18
|
+
type OnRequestHook = (ctx: PluginContext) => void | Promise<void>;
|
|
19
|
+
type PreHandlerHook = (ctx: PluginContext) => void | Promise<void>;
|
|
20
|
+
type OnResponseHook = (ctx: PluginContext) => void | Promise<void>;
|
|
21
|
+
type OnErrorHook = (ctx: PluginErrorContext) => void | Promise<void>;
|
|
22
|
+
type HookName = 'onRequest' | 'preHandler' | 'onResponse' | 'onError';
|
|
23
|
+
type HookByName<K extends HookName> = K extends 'onError' ? OnErrorHook : K extends 'onRequest' ? OnRequestHook : K extends 'preHandler' ? PreHandlerHook : K extends 'onResponse' ? OnResponseHook : never;
|
|
24
|
+
interface TheoApp {
|
|
25
|
+
addHook<K extends HookName>(name: K, fn: HookByName<K>): void;
|
|
26
|
+
decorateRequest<T>(key: string, value: T): void;
|
|
27
|
+
}
|
|
28
|
+
interface TheoPlugin {
|
|
29
|
+
name: string;
|
|
30
|
+
register(app: TheoApp): void | Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Identity function for plugin authors. Provides auto-completion + type
|
|
34
|
+
* inference at the call site (TanStack/Vite/Astro pattern). Pure runtime
|
|
35
|
+
* no-op — returns the input unchanged.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* import { definePlugin } from 'theokit/server'
|
|
39
|
+
* export default definePlugin({
|
|
40
|
+
* name: 'my-plugin',
|
|
41
|
+
* register(app) {
|
|
42
|
+
* app.addHook('onRequest', (req) => { ... })
|
|
43
|
+
* },
|
|
44
|
+
* })
|
|
45
|
+
*
|
|
46
|
+
* Equivalent to `const p: TheoPlugin = {...}` but more ergonomic. See
|
|
47
|
+
* ADR-0008 (D1 + D6) for the rationale.
|
|
48
|
+
*/
|
|
49
|
+
declare function definePlugin(plugin: TheoPlugin): TheoPlugin;
|
|
50
|
+
/**
|
|
51
|
+
* Web-Standards plugin context. Available during all 4 hook lifecycle
|
|
52
|
+
* stages (onRequest, preHandler, onResponse, onError).
|
|
53
|
+
*
|
|
54
|
+
* - `request` — the incoming Web Request (read-only at the runtime level;
|
|
55
|
+
* plugins can call `request.headers.get()`, `request.clone()`, etc.).
|
|
56
|
+
* - `responseHeaders` — a mutable `Headers` instance the runtime threads
|
|
57
|
+
* through the hook chain. Plugins append (e.g., CORS, Set-Cookie); the
|
|
58
|
+
* final Response composes these.
|
|
59
|
+
* - `response` — set to the handler's Response AFTER the handler returns.
|
|
60
|
+
* Available during `onResponse` / `onError`. `undefined` during
|
|
61
|
+
* `onRequest` / `preHandler` (which fire before the handler runs).
|
|
62
|
+
* - `ctx` / `requestId` — same semantics as the IncomingMessage path.
|
|
63
|
+
*/
|
|
64
|
+
interface WebPluginContext {
|
|
65
|
+
request: Request;
|
|
66
|
+
responseHeaders: Headers;
|
|
67
|
+
response?: Response;
|
|
68
|
+
ctx: Record<string, unknown>;
|
|
69
|
+
requestId: string;
|
|
70
|
+
}
|
|
71
|
+
interface WebPluginErrorContext extends WebPluginContext {
|
|
72
|
+
error: unknown;
|
|
73
|
+
}
|
|
74
|
+
type WebOnRequestHook = (ctx: WebPluginContext) => void | Promise<void>;
|
|
75
|
+
type WebPreHandlerHook = (ctx: WebPluginContext) => void | Promise<void>;
|
|
76
|
+
type WebOnResponseHook = (ctx: WebPluginContext) => void | Promise<void>;
|
|
77
|
+
type WebOnErrorHook = (ctx: WebPluginErrorContext) => void | Promise<void>;
|
|
78
|
+
|
|
79
|
+
export { type HookResult as H, type OnErrorHook as O, type PluginContext as P, type RunHookOptions as R, type TheoPlugin as T, type WebOnRequestHook as W, type TheoApp as a, type WebPreHandlerHook as b, type WebOnResponseHook as c, type WebOnErrorHook as d, type HookName as e, type OnRequestHook as f, type OnResponseHook as g, type PluginErrorContext as h, type PreHandlerHook as i, definePlugin as j };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { IncomingMessage } from 'node:http';
|
|
2
|
+
import { R as RateLimitStore } from './rate-limit-store-BEJnhWdw.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rate limit configuration — basic single-bucket shape. Per ADR D2, the
|
|
6
|
+
* per-route + per-user variant is layered on top via T2.2; this base
|
|
7
|
+
* struct is the smallest unit.
|
|
8
|
+
*/
|
|
9
|
+
interface RateLimitConfig {
|
|
10
|
+
windowMs: number;
|
|
11
|
+
max: number;
|
|
12
|
+
}
|
|
13
|
+
interface RateLimitResult {
|
|
14
|
+
limited: boolean;
|
|
15
|
+
headers: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a rate limiter that consumes a pluggable `RateLimitStore`.
|
|
19
|
+
*
|
|
20
|
+
* Backwards-compatible signature: callers passing only `config` get the
|
|
21
|
+
* default `InMemoryStore`. Distributed deployments pass a Redis adapter
|
|
22
|
+
* (or any other `RateLimitStore` implementation) via `opts.store`.
|
|
23
|
+
*
|
|
24
|
+
* T2.1: synchronous return for back-compat with the current
|
|
25
|
+
* `api-middleware.ts` integration point. The async store contract is
|
|
26
|
+
* exercised lazily — we use a sync fast-path against the in-memory store
|
|
27
|
+
* (single-thread JS makes this safe). External stores remain async and
|
|
28
|
+
* would require a different async wrapper at the middleware layer.
|
|
29
|
+
*/
|
|
30
|
+
declare function createRateLimiter(config: RateLimitConfig, opts?: {
|
|
31
|
+
store?: RateLimitStore;
|
|
32
|
+
}): (req: IncomingMessage) => RateLimitResult;
|
|
33
|
+
/**
|
|
34
|
+
* T5a.2 Phase D slice 2/3 — Web-Standards single-bucket rate limiter.
|
|
35
|
+
*
|
|
36
|
+
* Mirror of `createRateLimiter(config, opts)` returning a checker that
|
|
37
|
+
* accepts `(clientIp: string)` instead of `(req: IncomingMessage)`. Web
|
|
38
|
+
* `Request` has no `req.socket.remoteAddress` — the IP is resolved by
|
|
39
|
+
* the caller per-runtime (Node adapter from socket; CF Workers from
|
|
40
|
+
* `cf-connecting-ip`; etc., same convention as Phase D slice 1/3's
|
|
41
|
+
* `DeriveKeyRequestContext.clientIp`).
|
|
42
|
+
*
|
|
43
|
+
* Same `RateLimitConfig`, same `InMemoryStore` default, same async
|
|
44
|
+
* store rejection (use a dedicated async middleware for external stores).
|
|
45
|
+
* Same `RateLimitResult` return shape.
|
|
46
|
+
*
|
|
47
|
+
* **Signature difference from `createRateLimiter`:** this Web factory's
|
|
48
|
+
* checker takes a raw IP string instead of a Request object. The IP is
|
|
49
|
+
* the ONLY input the bucket needs; passing a Request object would force
|
|
50
|
+
* the caller to populate `request.headers.get('x-forwarded-for')` or
|
|
51
|
+
* similar without giving us any safer extraction. KISS — accept the IP
|
|
52
|
+
* directly, document the per-runtime resolution at the adapter boundary.
|
|
53
|
+
*/
|
|
54
|
+
declare function createRateLimiterWeb(config: RateLimitConfig, opts?: {
|
|
55
|
+
store?: RateLimitStore;
|
|
56
|
+
}): (clientIp: string) => RateLimitResult;
|
|
57
|
+
|
|
58
|
+
export { type RateLimitConfig as R, type RateLimitResult as a, createRateLimiterWeb as b, createRateLimiter as c };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T2.1 — RateLimitStore interface.
|
|
3
|
+
*
|
|
4
|
+
* Pluggable backend for the rate limiter. The default `InMemoryStore`
|
|
5
|
+
* preserves current single-instance behavior. Multi-instance deployments
|
|
6
|
+
* (TheoCloud canary, K8s replicas) opt in to a distributed adapter
|
|
7
|
+
* (Redis, Cloudflare KV) without bloating single-instance apps.
|
|
8
|
+
*
|
|
9
|
+
* Contract per ADR D1:
|
|
10
|
+
* - `incr` is atomic — concurrent calls for the same key both observe
|
|
11
|
+
* the same `resetAt` and increment count by 1.
|
|
12
|
+
* - `get` returns `null` for expired entries (not just absent — checks
|
|
13
|
+
* `now > resetAt`).
|
|
14
|
+
* - `reset` removes the key entirely; next `incr` creates fresh.
|
|
15
|
+
*
|
|
16
|
+
* Async signature is honest about Redis adapters even though in-memory
|
|
17
|
+
* implementation is synchronous. Callers MUST await.
|
|
18
|
+
*/
|
|
19
|
+
interface RateLimitState {
|
|
20
|
+
/** Number of requests counted in the current window. */
|
|
21
|
+
count: number;
|
|
22
|
+
/** Absolute timestamp (ms since epoch) when this window expires. */
|
|
23
|
+
resetAt: number;
|
|
24
|
+
}
|
|
25
|
+
interface RateLimitStore {
|
|
26
|
+
/**
|
|
27
|
+
* Atomic increment-and-get. If the key is missing OR the previous
|
|
28
|
+
* window expired (`now >= resetAt`), create with `count=1, resetAt=now+windowMs`.
|
|
29
|
+
* Otherwise increment count by 1, preserving the original resetAt.
|
|
30
|
+
*/
|
|
31
|
+
incr(key: string, windowMs: number): Promise<RateLimitState>;
|
|
32
|
+
/** Read current state. Returns `null` for missing or expired entries. */
|
|
33
|
+
get(key: string): Promise<RateLimitState | null>;
|
|
34
|
+
/** Remove a key. Used by login throttling on success (T6.1). */
|
|
35
|
+
reset(key: string): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Default in-memory store. Backed by `Map<string, RateLimitState>`.
|
|
39
|
+
*
|
|
40
|
+
* GC: every 1000 `incr` calls, expired entries are removed. Pathological
|
|
41
|
+
* key explosion is bounded by `MAX_ENTRIES` (LRU-evict oldest insertion).
|
|
42
|
+
*
|
|
43
|
+
* Single-thread by virtue of Node's event loop — `incr` is atomic at the
|
|
44
|
+
* JavaScript level (no preemption between Map.get and Map.set).
|
|
45
|
+
*/
|
|
46
|
+
declare class InMemoryStore implements RateLimitStore {
|
|
47
|
+
private store;
|
|
48
|
+
/** Bound the map to prevent unbounded growth from pathological inputs. */
|
|
49
|
+
static readonly MAX_ENTRIES = 100000;
|
|
50
|
+
/** GC sweep interval, milliseconds. */
|
|
51
|
+
static readonly GC_INTERVAL_MS = 30000;
|
|
52
|
+
private gcTimer;
|
|
53
|
+
constructor();
|
|
54
|
+
/**
|
|
55
|
+
* Synchronous fast-path used by the legacy sync `createRateLimiter`
|
|
56
|
+
* surface (`api-middleware.ts` is sync). The async `incr` delegates to
|
|
57
|
+
* this for in-memory; external adapters override `incr` directly.
|
|
58
|
+
*/
|
|
59
|
+
incrSync(key: string, windowMs: number): RateLimitState;
|
|
60
|
+
/** Sweep expired entries. Called by the GC timer; safe to call manually. */
|
|
61
|
+
sweepExpired(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Stop the GC timer. Call from tests or when discarding the store. After
|
|
64
|
+
* `dispose`, the store still works but no longer auto-sweeps.
|
|
65
|
+
*/
|
|
66
|
+
dispose(): void;
|
|
67
|
+
incr(key: string, windowMs: number): Promise<RateLimitState>;
|
|
68
|
+
get(key: string): Promise<RateLimitState | null>;
|
|
69
|
+
reset(key: string): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { InMemoryStore as I, type RateLimitStore as R, type RateLimitState as a };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T5.3 — React Query adapter primitives.
|
|
3
|
+
*
|
|
4
|
+
* Exposes:
|
|
5
|
+
* - `stableQueryKey(path, options)` — produces a deterministic queryKey
|
|
6
|
+
* that is equal across calls when the logical content of query/body is
|
|
7
|
+
* equal, regardless of property order or inline-object identity. Solves
|
|
8
|
+
* EC-10 (inline-object → infinite refetch).
|
|
9
|
+
* - `buildUseTheoQueryConfig(path, options, fetcher)` — produces the
|
|
10
|
+
* `{ queryKey, queryFn }` pair that consumers pass to `useQuery` from
|
|
11
|
+
* `@tanstack/react-query`.
|
|
12
|
+
*
|
|
13
|
+
* The canonical implementation lives here in `theokit/client`. The
|
|
14
|
+
* dedicated subpath `theokit/react-query` re-exports this surface so
|
|
15
|
+
* consumers who only need the React Query bridge can import from a
|
|
16
|
+
* clearly named entry point — same shape as `theokit/server`,
|
|
17
|
+
* `theokit/vite-plugin`, etc. No separate npm package.
|
|
18
|
+
*/
|
|
19
|
+
interface FetchOptionsLike {
|
|
20
|
+
query?: unknown;
|
|
21
|
+
body?: unknown;
|
|
22
|
+
params?: unknown;
|
|
23
|
+
}
|
|
24
|
+
type QueryKey = readonly unknown[];
|
|
25
|
+
declare function stableQueryKey(path: string, options: FetchOptionsLike): QueryKey;
|
|
26
|
+
type Fetcher<TResult = unknown> = (path: string, options: FetchOptionsLike) => Promise<TResult>;
|
|
27
|
+
interface UseTheoQueryConfig<TResult = unknown> {
|
|
28
|
+
queryKey: QueryKey;
|
|
29
|
+
queryFn: () => Promise<TResult>;
|
|
30
|
+
}
|
|
31
|
+
declare function buildUseTheoQueryConfig<TResult = unknown>(path: string, options: FetchOptionsLike, fetcher: Fetcher<TResult>): UseTheoQueryConfig<TResult>;
|
|
32
|
+
|
|
33
|
+
export { type FetchOptionsLike, type Fetcher, type Fetcher as FetcherFn, type QueryKey, type UseTheoQueryConfig, type UseTheoQueryConfig as UseTheoQueryInternals, buildUseTheoQueryConfig, buildUseTheoQueryConfig as buildUseTheoQueryInternals, stableQueryKey };
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
scanServerActions,
|
|
13
13
|
scanServerRoutes,
|
|
14
14
|
scanWebSocketRoutes
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-BQDGES7C.js";
|
|
16
16
|
|
|
17
17
|
// src/cli/commands/routes.ts
|
|
18
18
|
import { resolve, relative } from "path";
|
|
@@ -60,4 +60,4 @@ async function routesCommand() {
|
|
|
60
60
|
export {
|
|
61
61
|
routesCommand
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=routes-
|
|
63
|
+
//# sourceMappingURL=routes-EW7TP7NJ.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wave 2 — Polyglot Services Orchestration (T1.1).
|
|
5
|
+
*
|
|
6
|
+
* Declarative `services: {}` primitive for `theo.config.ts`. Each entry
|
|
7
|
+
* declares an external sidecar process (Python FastAPI / Node Hono) that
|
|
8
|
+
* boots alongside the TheoKit TS app. Empty `services: {}` is the default
|
|
9
|
+
* and preserves Wave 1 behavior (no impact on TS-only apps).
|
|
10
|
+
*
|
|
11
|
+
* See ADRs 0012-0015 + plan: docs/plans/wave-2-polyglot-services-plan.md
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Single service definition. All commands run from `services/<name>/` cwd.
|
|
16
|
+
*
|
|
17
|
+
* EC-4 fix: `proxy` regex requires NON-EMPTY path after `/` (the `+` quantifier)
|
|
18
|
+
* to reject `/` which would catch-all and conflict with TheoKit's own routing.
|
|
19
|
+
*/
|
|
20
|
+
declare const ServiceDefinitionSchema: z.ZodObject<{
|
|
21
|
+
runtime: z.ZodEnum<{
|
|
22
|
+
python: "python";
|
|
23
|
+
node: "node";
|
|
24
|
+
}>;
|
|
25
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
26
|
+
server: "server";
|
|
27
|
+
worker: "worker";
|
|
28
|
+
}>>;
|
|
29
|
+
port: z.ZodNumber;
|
|
30
|
+
proxy: z.ZodString;
|
|
31
|
+
dev: z.ZodString;
|
|
32
|
+
build: z.ZodOptional<z.ZodString>;
|
|
33
|
+
start: z.ZodString;
|
|
34
|
+
openapi: z.ZodOptional<z.ZodURL>;
|
|
35
|
+
healthcheck: z.ZodDefault<z.ZodString>;
|
|
36
|
+
cors: z.ZodDefault<z.ZodBoolean>;
|
|
37
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
38
|
+
dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
39
|
+
passSetCookie: z.ZodDefault<z.ZodBoolean>;
|
|
40
|
+
}, z.core.$strip>;
|
|
41
|
+
type ServiceDefinition = z.infer<typeof ServiceDefinitionSchema>;
|
|
42
|
+
type ServicesConfig = Record<string, ServiceDefinition>;
|
|
43
|
+
/**
|
|
44
|
+
* Full services config schema with cross-service refines.
|
|
45
|
+
*
|
|
46
|
+
* EC-1 fix: detect duplicate ports across services.
|
|
47
|
+
* EC-13: empty `dependsOn: []` accepted as no-deps.
|
|
48
|
+
* Self-dep, missing-ref, and cycles rejected via topological check.
|
|
49
|
+
*/
|
|
50
|
+
declare const servicesConfigSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
51
|
+
runtime: z.ZodEnum<{
|
|
52
|
+
python: "python";
|
|
53
|
+
node: "node";
|
|
54
|
+
}>;
|
|
55
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
56
|
+
server: "server";
|
|
57
|
+
worker: "worker";
|
|
58
|
+
}>>;
|
|
59
|
+
port: z.ZodNumber;
|
|
60
|
+
proxy: z.ZodString;
|
|
61
|
+
dev: z.ZodString;
|
|
62
|
+
build: z.ZodOptional<z.ZodString>;
|
|
63
|
+
start: z.ZodString;
|
|
64
|
+
openapi: z.ZodOptional<z.ZodURL>;
|
|
65
|
+
healthcheck: z.ZodDefault<z.ZodString>;
|
|
66
|
+
cors: z.ZodDefault<z.ZodBoolean>;
|
|
67
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
68
|
+
dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
69
|
+
passSetCookie: z.ZodDefault<z.ZodBoolean>;
|
|
70
|
+
}, z.core.$strip>>>;
|
|
71
|
+
type ServicesConfigInput = z.input<typeof servicesConfigSchema>;
|
|
72
|
+
type ServicesConfigOutput = z.output<typeof servicesConfigSchema>;
|
|
73
|
+
|
|
74
|
+
export type { ServicesConfig as S, ServiceDefinition as a, ServicesConfigInput as b, ServicesConfigOutput as c };
|