theokit 0.12.0 → 0.12.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/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/audit-log-BQWM5YLG.d.ts +60 -0
- package/dist/boot/index.d.ts +39 -0
- package/dist/client/index.d.ts +362 -0
- 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/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/job-backend-CgC8Xf33.d.ts +68 -0
- package/dist/match-CfbEFRG4.d.ts +26 -0
- 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/schema-BpH6ivDY.d.ts +74 -0
- package/dist/server/agent/index.d.ts +229 -0
- 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/http/index.d.ts +11 -0
- package/dist/server/index.d.ts +848 -0
- 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 +106 -0
- 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/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/package.json +4 -4
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web-to-Node bridge used by adapters whose runtimes provide a `Request`
|
|
3
|
+
* (Web Standard) but where TheoKit's `executeRoute` expects a Node-style
|
|
4
|
+
* IncomingMessage/ServerResponse pair.
|
|
5
|
+
*
|
|
6
|
+
* Used by adapters that target Node-compatible runtimes (Bun, Netlify
|
|
7
|
+
* Functions, AWS Lambda Node). Cloudflare uses an inline version of the same
|
|
8
|
+
* pattern — long-term it should consolidate here too.
|
|
9
|
+
*
|
|
10
|
+
* NOT used by Deno Deploy: Deno's stdlib does not have `Buffer`/`node:http`
|
|
11
|
+
* by default and forcing the shim there bloats the bundle. Deno wiring is
|
|
12
|
+
* tracked separately and will likely require executeRoute to accept Web
|
|
13
|
+
* Standard Request directly.
|
|
14
|
+
*/
|
|
15
|
+
interface ShimRequest {
|
|
16
|
+
method: string;
|
|
17
|
+
url: string;
|
|
18
|
+
headers: Record<string, string>;
|
|
19
|
+
socket: {
|
|
20
|
+
remoteAddress: string;
|
|
21
|
+
};
|
|
22
|
+
on: (event: 'data' | 'end' | 'error', cb: (chunk?: unknown) => void) => unknown;
|
|
23
|
+
}
|
|
24
|
+
interface ShimResponse {
|
|
25
|
+
statusCode: number;
|
|
26
|
+
headersSent: boolean;
|
|
27
|
+
writableEnded: boolean;
|
|
28
|
+
writeHead: (status: number, headers?: Record<string, string>) => void;
|
|
29
|
+
setHeader: (key: string, value: string) => void;
|
|
30
|
+
getHeader: (key: string) => string | undefined;
|
|
31
|
+
write: (chunk: Uint8Array | string) => boolean;
|
|
32
|
+
end: (body?: Uint8Array | string) => void;
|
|
33
|
+
}
|
|
34
|
+
interface ShimContext {
|
|
35
|
+
req: ShimRequest;
|
|
36
|
+
res: ShimResponse;
|
|
37
|
+
/** Resolves to a Web Standard Response once `res.end()` is called. */
|
|
38
|
+
toResponse: () => Promise<Response>;
|
|
39
|
+
}
|
|
40
|
+
interface CreateWebShimOptions {
|
|
41
|
+
/**
|
|
42
|
+
* CR-018 fix: how to resolve the client IP from forwarded headers.
|
|
43
|
+
*
|
|
44
|
+
* - `'platform'` (default for `cf-connecting-ip`): trust runtime-injected
|
|
45
|
+
* headers only (`cf-connecting-ip` on Cloudflare, `x-real-ip` on
|
|
46
|
+
* Netlify/Vercel when the platform writes it). Ignores
|
|
47
|
+
* `x-forwarded-for` because clients can spoof it.
|
|
48
|
+
* - `'trusted-proxy'`: read the **rightmost** entry of `x-forwarded-for`.
|
|
49
|
+
* Only safe when the request literally went through a trusted proxy
|
|
50
|
+
* that strips client-set headers and appends the real client IP last.
|
|
51
|
+
* - `'none'`: skip all forwarded-header lookups and report
|
|
52
|
+
* `'0.0.0.0'`. Force this when the adapter has no reliable way to
|
|
53
|
+
* identify the client (rate-limiters then must use a different key).
|
|
54
|
+
*
|
|
55
|
+
* Default: `'platform'`.
|
|
56
|
+
*/
|
|
57
|
+
trustedProxy?: 'platform' | 'trusted-proxy' | 'none';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build Node-style req/res objects around a Web Standard Request.
|
|
61
|
+
* `toResponse()` returns a Promise that resolves when `res.end()` has been
|
|
62
|
+
* invoked, materializing a Web Standard Response with the accumulated body
|
|
63
|
+
* + headers + status.
|
|
64
|
+
*/
|
|
65
|
+
declare function createWebShim(request: Request, options?: CreateWebShimOptions): ShimContext;
|
|
66
|
+
|
|
67
|
+
export { type CreateWebShimOptions, type ShimContext, type ShimRequest, type ShimResponse, createWebShim };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T3.1 — WebSocket cross-runtime bridges.
|
|
3
|
+
*
|
|
4
|
+
* Exports 4 bridges (Node `ws` package, Bun.serve, Deno.upgradeWebSocket,
|
|
5
|
+
* Cloudflare WebSocketPair) that adapt each runtime's native WebSocket API
|
|
6
|
+
* to a common `WebSocketLike` interface that user handlers (`defineWebSocket`)
|
|
7
|
+
* can consume uniformly.
|
|
8
|
+
*/
|
|
9
|
+
interface WebSocketLike {
|
|
10
|
+
send(data: string | Uint8Array | ArrayBuffer): void;
|
|
11
|
+
close(code?: number, reason?: string): void;
|
|
12
|
+
on(event: 'message' | 'close' | 'error', cb: (data?: unknown) => void): void;
|
|
13
|
+
}
|
|
14
|
+
interface WsHandler {
|
|
15
|
+
onOpen?: (ws: WebSocketLike) => void;
|
|
16
|
+
onMessage?: (ws: WebSocketLike, data: unknown) => void;
|
|
17
|
+
onClose?: (ws: WebSocketLike, code?: number, reason?: string) => void;
|
|
18
|
+
onError?: (ws: WebSocketLike, err: unknown) => void;
|
|
19
|
+
}
|
|
20
|
+
interface NodeWsLike {
|
|
21
|
+
on(event: string, cb: (arg?: unknown) => void): unknown;
|
|
22
|
+
send(data: unknown): void;
|
|
23
|
+
close(code?: number, reason?: string): void;
|
|
24
|
+
}
|
|
25
|
+
declare function createNodeWsBridge(handler: WsHandler): {
|
|
26
|
+
attach(nativeWs: NodeWsLike): WebSocketLike;
|
|
27
|
+
};
|
|
28
|
+
interface BunWsContext {
|
|
29
|
+
send(data: unknown): void;
|
|
30
|
+
close(code?: number, reason?: string): void;
|
|
31
|
+
}
|
|
32
|
+
interface BunWebSocketConfig {
|
|
33
|
+
open: (ws: BunWsContext) => void;
|
|
34
|
+
message: (ws: BunWsContext, message: unknown) => void;
|
|
35
|
+
close: (ws: BunWsContext, code?: number, reason?: string) => void;
|
|
36
|
+
}
|
|
37
|
+
declare function createBunWsBridge(handler: WsHandler): BunWebSocketConfig;
|
|
38
|
+
interface DenoLike {
|
|
39
|
+
upgradeWebSocket(req: Request): {
|
|
40
|
+
response: Response;
|
|
41
|
+
socket: {
|
|
42
|
+
send(data: unknown): void;
|
|
43
|
+
close(code?: number, reason?: string): void;
|
|
44
|
+
addEventListener(event: string, cb: (e: unknown) => void): void;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
declare function createDenoWsBridge(handler: WsHandler, denoNs: DenoLike): {
|
|
49
|
+
handle(request: Request): Response;
|
|
50
|
+
};
|
|
51
|
+
declare function createCloudflareWsBridge(handler: WsHandler): {
|
|
52
|
+
handle(request: Request): Response;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export { type BunWebSocketConfig, type WebSocketLike, type WsHandler, createBunWsBridge, createCloudflareWsBridge, createDenoWsBridge, createNodeWsBridge };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/contracts/agent-events.ts
|
|
3
|
+
*
|
|
4
|
+
* Canonical home for the AgentEvent wire-format contract (T2.2 of
|
|
5
|
+
* architecture-cleanup plan; ADR-0001 v3 invariant #3 exception).
|
|
6
|
+
*
|
|
7
|
+
* Server emits via SSE; client consumes. Discriminated union by `type`.
|
|
8
|
+
* Both `server/agent/*` and `client/*` import from here.
|
|
9
|
+
*
|
|
10
|
+
* Per ADR-0001 v3: `cache → core/contracts`, `client → core/contracts`,
|
|
11
|
+
* `devtools → core/contracts` are LEGAL direct imports (this is the
|
|
12
|
+
* documented exception to the `no-cross-module-deep-import` rule).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Discriminated union for AgentRunError codes (Phase 1 — Production-Readiness #3).
|
|
16
|
+
*
|
|
17
|
+
* Mirrors `@theokit/sdk`'s `AgentRunErrorCode` without hard-importing the SDK
|
|
18
|
+
* type (D2 decoupling). EC-7 forward-compat: `(string & {})` fallback preserves
|
|
19
|
+
* autocompletion for the known codes while accepting future codes the SDK may
|
|
20
|
+
* introduce — autocomplete works AND TS doesn't reject unknown codes.
|
|
21
|
+
*/
|
|
22
|
+
type AgentRunErrorCode = 'auth' | 'rate_limit' | 'quota_exceeded' | 'invalid_model' | 'invalid_request' | 'invalid_input' | 'context_too_large' | 'safety_blocked' | 'provider_unreachable' | 'tool_runtime_error' | 'aborted' | 'unknown' | (string & {});
|
|
23
|
+
interface AgentMessageEvent {
|
|
24
|
+
type: 'message';
|
|
25
|
+
content: string;
|
|
26
|
+
/** Optional id for client-side dedup / animation keys. */
|
|
27
|
+
id?: string;
|
|
28
|
+
}
|
|
29
|
+
interface AgentToolCallEvent {
|
|
30
|
+
type: 'tool_call';
|
|
31
|
+
name: string;
|
|
32
|
+
args: Record<string, unknown>;
|
|
33
|
+
id?: string;
|
|
34
|
+
}
|
|
35
|
+
interface AgentToolResultEvent {
|
|
36
|
+
type: 'tool_result';
|
|
37
|
+
name: string;
|
|
38
|
+
data: unknown;
|
|
39
|
+
id?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Error event emitted via SSE.
|
|
43
|
+
*
|
|
44
|
+
* Phase 1 — Production-Readiness #3:
|
|
45
|
+
* New optional fields `code/provider/retriable/retryAfterMs` discriminate
|
|
46
|
+
* error classes for client-side handling (auth → sign-in CTA; rate_limit →
|
|
47
|
+
* countdown; quota_exceeded → upsell; etc.).
|
|
48
|
+
*
|
|
49
|
+
* Backward compat (D4): all new fields are optional. Existing clients that
|
|
50
|
+
* read only `event.message` keep working unchanged. New clients can safely
|
|
51
|
+
* `switch (event.code)` — `undefined` (legacy server) is a valid case.
|
|
52
|
+
*
|
|
53
|
+
* EC-15 (DOCUMENT): `message` is *trusted* to not contain secrets. SDK's
|
|
54
|
+
* `AgentRunError.message` is propagated verbatim. The SDK's `providerError`
|
|
55
|
+
* is NEVER serialized into this event — quarantined to prevent leakage.
|
|
56
|
+
*/
|
|
57
|
+
interface AgentErrorEvent {
|
|
58
|
+
type: 'error';
|
|
59
|
+
message: string;
|
|
60
|
+
id?: string;
|
|
61
|
+
/** Discriminated error class — see AgentRunErrorCode. */
|
|
62
|
+
code?: AgentRunErrorCode;
|
|
63
|
+
/** Provider id (e.g., 'openai', 'anthropic', 'openrouter'). */
|
|
64
|
+
provider?: string;
|
|
65
|
+
/** Whether the SAME request can be retried as-is. */
|
|
66
|
+
retriable?: boolean;
|
|
67
|
+
/** Hint from provider's Retry-After header (milliseconds). Zero is valid (immediate retry). */
|
|
68
|
+
retryAfterMs?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Extended thinking / reasoning event.
|
|
72
|
+
*
|
|
73
|
+
* Carries the model's reasoning text (when the model supports extended
|
|
74
|
+
* thinking). Mirrors the `@theokit/agents` stream-layer `ThinkingEvent`
|
|
75
|
+
* (`packages/agents/src/bridge/agent-stream-events.ts`) so the two layers
|
|
76
|
+
* agree on the wire form; defined here (not imported) to keep `core/contracts`
|
|
77
|
+
* free of a dependency on `@theokit/agents` (G1 dependency direction).
|
|
78
|
+
*
|
|
79
|
+
* Consumers that switch only on the other variants are unaffected (additive);
|
|
80
|
+
* a consumer that wants to surface reasoning opts in by handling `'thinking'`.
|
|
81
|
+
*/
|
|
82
|
+
interface AgentThinkingEvent {
|
|
83
|
+
type: 'thinking';
|
|
84
|
+
content: string;
|
|
85
|
+
/** Optional id for client-side dedup / animation keys. */
|
|
86
|
+
id?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Runtime AgentEvent — discriminated union of the 5 variants emitted by
|
|
90
|
+
* agent endpoints. Server produces; client consumes.
|
|
91
|
+
*/
|
|
92
|
+
type AgentEvent = AgentMessageEvent | AgentToolCallEvent | AgentToolResultEvent | AgentErrorEvent | AgentThinkingEvent;
|
|
93
|
+
|
|
94
|
+
export type { AgentEvent as A, AgentErrorEvent as a, AgentMessageEvent as b, AgentThinkingEvent as c, AgentToolCallEvent as d, AgentToolResultEvent as e, AgentRunErrorCode as f };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T4.1 — Audit logging interface + default JSON stdout sink.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR D4: define the interface; ship a zero-dep default; reserve
|
|
5
|
+
* adapter shapes for Postgres, File, OpenTelemetry, Sentry as follow-up
|
|
6
|
+
* packages. Persistence has heavy deps (`pg`, `better-sqlite3`); we
|
|
7
|
+
* keep core dep-free and let users opt in.
|
|
8
|
+
*
|
|
9
|
+
* Compatibility:
|
|
10
|
+
* - Node / Bun / Deno / Vercel — console.log is sync, captured.
|
|
11
|
+
* - Edge runtimes (CF Workers, Vercel Edge) — console.log is captured
|
|
12
|
+
* but may be rate-limited by the platform. For high-volume edge audit,
|
|
13
|
+
* implement a custom sink writing to a queue / HTTP endpoint.
|
|
14
|
+
*/
|
|
15
|
+
interface AuditEvent {
|
|
16
|
+
/** Domain-qualified verb. Convention: `<domain>.<verb>` (e.g. csrf.warn, session.rotated). */
|
|
17
|
+
action: string;
|
|
18
|
+
/** Who triggered the event. Anonymous = no auth at time of event. */
|
|
19
|
+
actor?: {
|
|
20
|
+
type: 'user' | 'system' | 'anonymous';
|
|
21
|
+
id?: string;
|
|
22
|
+
};
|
|
23
|
+
/** What was operated on (optional). */
|
|
24
|
+
resource?: {
|
|
25
|
+
type: string;
|
|
26
|
+
id?: string;
|
|
27
|
+
};
|
|
28
|
+
/** Arbitrary event-specific metadata. JSON-serializable. */
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
30
|
+
/** ISO 8601 timestamp. If absent, sink fills in `new Date().toISOString()`. */
|
|
31
|
+
timestamp?: string;
|
|
32
|
+
/** Optional trace id (populated by middleware from `x-trace-id`). */
|
|
33
|
+
traceId?: string;
|
|
34
|
+
}
|
|
35
|
+
interface AuditLogger {
|
|
36
|
+
log(event: AuditEvent): void | Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Default sink: one JSON line per event to stdout. Sync. Never throws.
|
|
40
|
+
*
|
|
41
|
+
* EC: circular refs / BigInt values fall back to a placeholder line so
|
|
42
|
+
* the event is still observable (action + traceId) without crashing the
|
|
43
|
+
* request lifecycle.
|
|
44
|
+
*/
|
|
45
|
+
declare class JsonStdoutSink implements AuditLogger {
|
|
46
|
+
log(event: AuditEvent): void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* No-op logger. Returned when `config.audit` is unset. Zero overhead;
|
|
50
|
+
* framework wiring sites null-check before calling.
|
|
51
|
+
*/
|
|
52
|
+
declare function createNoOpLogger(): AuditLogger;
|
|
53
|
+
/**
|
|
54
|
+
* T4.2 — Safe-emit wrapper. Used by framework wiring sites (csrf.ts,
|
|
55
|
+
* rate-limit.ts, session.ts) so a logger throw NEVER propagates into
|
|
56
|
+
* the request handler.
|
|
57
|
+
*/
|
|
58
|
+
declare function safeAudit(logger: AuditLogger | undefined, event: AuditEvent): void;
|
|
59
|
+
|
|
60
|
+
export { type AuditLogger as A, JsonStdoutSink as J, type AuditEvent as a, createNoOpLogger as c, safeAudit as s };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { R as ReservedRoutes } from '../health-route-C0hk64_U.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* M7-3 — `theokit/boot`: programmatic boot surface for the convention server.
|
|
5
|
+
*
|
|
6
|
+
* The programmatic surface is a Web `fetch` handler (the universal "fetch
|
|
7
|
+
* handler is the entry point" contract — see the hono reference in
|
|
8
|
+
* knowledge-base/discoveries/blueprints/m7-http-dual-surface-blueprint.md
|
|
9
|
+
* "Coverage Corner 4"). It composes M7-1 (typed 404 envelope) + M7-2 (reserved
|
|
10
|
+
* health/ready routes) and binds NO socket, so embedders + integration tests
|
|
11
|
+
* can fire requests in-process via `app.fetch(new Request(...))`.
|
|
12
|
+
*
|
|
13
|
+
* The CLI's `startDevServer`/`startCommand` (Vite/SSR machinery) intentionally
|
|
14
|
+
* stay in the `cli` module — `boot` must not depend on `cli` (architecture DAG:
|
|
15
|
+
* nothing depends on `cli`). The fetch handler IS the portable boot surface.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** Options for {@link createConventionFetchHandler}. */
|
|
21
|
+
interface ConventionFetchHandlerOptions {
|
|
22
|
+
/** Reserved health/ready routes (M7-2). Liveness defaults to 200 even when omitted. */
|
|
23
|
+
readonly reservedRoutes?: ReservedRoutes;
|
|
24
|
+
}
|
|
25
|
+
/** A socketless convention-server handle. */
|
|
26
|
+
interface ConventionFetchHandle {
|
|
27
|
+
/** Serve a single request in-process (no socket). Reserved routes first, else a typed 404. */
|
|
28
|
+
fetch(request: Request): Promise<Response>;
|
|
29
|
+
/** Idempotent teardown. The in-process handler holds no socket, so this is a safe no-op. */
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build an in-process convention-server `fetch` handler. Reserved `/__theo/*`
|
|
34
|
+
* routes (health/ready) are served first; any other path yields a typed
|
|
35
|
+
* `NOT_FOUND` envelope (404) via the same translator the wire boundary uses.
|
|
36
|
+
*/
|
|
37
|
+
declare function createConventionFetchHandler(options?: ConventionFetchHandlerOptions): ConventionFetchHandle;
|
|
38
|
+
|
|
39
|
+
export { type ConventionFetchHandle, type ConventionFetchHandlerOptions, createConventionFetchHandler };
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { T as TheoErrorEnvelope } from '../error-envelope-BsNzzAV5.js';
|
|
3
|
+
export { FetchOptionsLike, Fetcher, QueryKey, UseTheoQueryConfig, buildUseTheoQueryConfig, stableQueryKey } from '../react-query/index.js';
|
|
4
|
+
import { A as AgentEvent, a as AgentErrorEvent } from '../agent-events-DosDXkSV.js';
|
|
5
|
+
export { b as AgentMessageEvent, c as AgentThinkingEvent, d as AgentToolCallEvent, e as AgentToolResultEvent } from '../agent-events-DosDXkSV.js';
|
|
6
|
+
import * as react from 'react';
|
|
7
|
+
import { LinkProps as LinkProps$1 } from 'react-router';
|
|
8
|
+
|
|
9
|
+
/** Infer the response type from a route's handler return */
|
|
10
|
+
type InferResponse<T> = T extends {
|
|
11
|
+
handler: (...args: never[]) => infer R;
|
|
12
|
+
} ? Awaited<R> : unknown;
|
|
13
|
+
/** Extract the query Zod schema type, handling optional properties */
|
|
14
|
+
type ExtractQuery<T> = T extends {
|
|
15
|
+
query?: infer Q;
|
|
16
|
+
} ? (Q extends z.ZodType ? Q : never) : never;
|
|
17
|
+
/** Extract the body Zod schema type, handling optional properties */
|
|
18
|
+
type ExtractBody<T> = T extends {
|
|
19
|
+
body?: infer B;
|
|
20
|
+
} ? (B extends z.ZodType ? B : never) : never;
|
|
21
|
+
/** Infer query type from a route's query Zod schema */
|
|
22
|
+
type InferQuery<T> = [ExtractQuery<T>] extends [never] ? undefined : ExtractQuery<T> extends z.ZodUndefined ? undefined : z.infer<ExtractQuery<T>>;
|
|
23
|
+
/** Infer body type from a route's body Zod schema */
|
|
24
|
+
type InferBody<T> = [ExtractBody<T>] extends [never] ? undefined : ExtractBody<T> extends z.ZodUndefined ? undefined : z.infer<ExtractBody<T>>;
|
|
25
|
+
/** Build the options type based on what schemas the route has */
|
|
26
|
+
type TheoFetchOptions<T> = Omit<RequestInit, 'body' | 'method'> & (InferQuery<T> extends undefined ? {
|
|
27
|
+
query?: never;
|
|
28
|
+
} : {
|
|
29
|
+
query: InferQuery<T>;
|
|
30
|
+
}) & (InferBody<T> extends undefined ? {
|
|
31
|
+
body?: never;
|
|
32
|
+
} : {
|
|
33
|
+
body: InferBody<T>;
|
|
34
|
+
});
|
|
35
|
+
declare class TheoFetchError extends Error {
|
|
36
|
+
status: number;
|
|
37
|
+
code?: string;
|
|
38
|
+
issues?: unknown[];
|
|
39
|
+
/**
|
|
40
|
+
* G5 T2.1 — canonical envelope view of the server-side error. Use this in
|
|
41
|
+
* consumer code that wants to switch on a typed TheoErrorCode instead of
|
|
42
|
+
* coupling to the legacy `.status` / `.code` flat fields.
|
|
43
|
+
*/
|
|
44
|
+
readonly envelope: TheoErrorEnvelope;
|
|
45
|
+
constructor(status: number, body?: unknown);
|
|
46
|
+
}
|
|
47
|
+
declare function theoFetch<T>(url: string, options?: TheoFetchOptions<T>): Promise<InferResponse<T>>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Phase 3 of G1 (g1-client-codegen-plan.md):
|
|
51
|
+
*
|
|
52
|
+
* `createAppClient(baseUrl?, fetchImpl?)` returns a Proxy that walks property
|
|
53
|
+
* access (`client.posts.id.get(...)`) into a `theoFetch` invocation against
|
|
54
|
+
* `{baseUrl}/posts/{params.id}` with method `GET`.
|
|
55
|
+
*
|
|
56
|
+
* Type safety is delivered by the `.d.ts` file emitted in Phase 2 — this
|
|
57
|
+
* runtime is structurally untyped. Power users may use `theoFetch` directly
|
|
58
|
+
* when they need to escape the Proxy facade.
|
|
59
|
+
*
|
|
60
|
+
* Edge cases absorbed:
|
|
61
|
+
* - EC-1 (thenable trap): `then` / `catch` / `finally` / `toJSON` / `Symbol.*`
|
|
62
|
+
* return `undefined` so that accidental `await client.posts` resolves to a
|
|
63
|
+
* plain Proxy value (it is NOT thenable) instead of looping.
|
|
64
|
+
* - EC-7 (abort signal): `opts.signal` is spread through to the underlying
|
|
65
|
+
* fetchImpl unchanged — verified in unit tests.
|
|
66
|
+
*
|
|
67
|
+
* Bundle target: ≤ 2KB gzipped.
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
type FetchImpl = typeof theoFetch;
|
|
71
|
+
interface CreateAppClientOptions {
|
|
72
|
+
/** Base URL for the API. Defaults to `/api`. */
|
|
73
|
+
baseUrl?: string;
|
|
74
|
+
/** Test-only fetch override. Production callers should not pass this. */
|
|
75
|
+
fetchImpl?: FetchImpl;
|
|
76
|
+
}
|
|
77
|
+
declare function createAppClient<TAppClient = unknown>(baseUrlOrOptions?: string | CreateAppClientOptions, legacyFetchImpl?: FetchImpl): TAppClient;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* T5.1 — client-side microtask batching.
|
|
81
|
+
*
|
|
82
|
+
* Collects all `dispatch` calls within the same microtask and sends them as a
|
|
83
|
+
* single HTTP POST to the configured transport. Each caller's promise resolves
|
|
84
|
+
* with its own result; one failed item does not break the others (per-item
|
|
85
|
+
* error isolation).
|
|
86
|
+
*
|
|
87
|
+
* Designed as a transport-agnostic primitive so unit tests do not require
|
|
88
|
+
* network access. The default transport (fetch to `/api/__theo_batch__`)
|
|
89
|
+
* lives alongside this module but is created by the consumer (e.g., theoFetch).
|
|
90
|
+
*/
|
|
91
|
+
interface BatchRequest {
|
|
92
|
+
path: string;
|
|
93
|
+
method: string;
|
|
94
|
+
query?: Record<string, unknown>;
|
|
95
|
+
body?: unknown;
|
|
96
|
+
headers?: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
type BatchResponse = {
|
|
99
|
+
index: number;
|
|
100
|
+
data: unknown;
|
|
101
|
+
} | {
|
|
102
|
+
index: number;
|
|
103
|
+
error: {
|
|
104
|
+
message: string;
|
|
105
|
+
code?: string;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
type BatchTransport = (requests: BatchRequest[]) => Promise<BatchResponse[]>;
|
|
109
|
+
interface BatcherOptions {
|
|
110
|
+
transport: BatchTransport;
|
|
111
|
+
/** Maximum batch size before flushing into multiple parallel batches. */
|
|
112
|
+
max?: number;
|
|
113
|
+
}
|
|
114
|
+
interface Batcher {
|
|
115
|
+
dispatch(req: BatchRequest): Promise<unknown>;
|
|
116
|
+
}
|
|
117
|
+
declare function createBatcher(options: BatcherOptions): Batcher;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Accumulated assistant text (M5-1): the concatenation of every `message`
|
|
121
|
+
* event's `content`. Pure. Assumes append/delta semantics — a server that
|
|
122
|
+
* emits full-snapshot messages should read `events` directly.
|
|
123
|
+
*/
|
|
124
|
+
declare function deriveLiveText(events: readonly AgentEvent[]): string;
|
|
125
|
+
/**
|
|
126
|
+
* The current error (M5-1): the last `error` event, or `undefined`. Surfaces
|
|
127
|
+
* the full `AgentErrorEvent` (with `code`/`retriable`) so the UI can branch.
|
|
128
|
+
* Pure.
|
|
129
|
+
*/
|
|
130
|
+
declare function deriveError(events: readonly AgentEvent[]): AgentErrorEvent | undefined;
|
|
131
|
+
/**
|
|
132
|
+
* T5.2 — useAgentStream
|
|
133
|
+
*
|
|
134
|
+
* React hook to consume an agent endpoint defined with `defineAgentEndpoint`.
|
|
135
|
+
*
|
|
136
|
+
* Transport (ADR D7, EC-3): fetch + ReadableStream — NOT EventSource.
|
|
137
|
+
* EventSource is GET-only; agent endpoints need POST + body.
|
|
138
|
+
*
|
|
139
|
+
* Returns:
|
|
140
|
+
* events — array of AgentEvents accumulated so far
|
|
141
|
+
* send — call with a payload to (re)open a stream
|
|
142
|
+
* status — 'idle' | 'streaming' | 'done' | 'error'
|
|
143
|
+
* abort — manually cancel an in-flight stream
|
|
144
|
+
*
|
|
145
|
+
* Cleanup (EC-8): on unmount, the current AbortController fires .abort(),
|
|
146
|
+
* which propagates to the underlying fetch and the ReadableStream reader.
|
|
147
|
+
* Safe under React.StrictMode double-mount.
|
|
148
|
+
*/
|
|
149
|
+
type AgentStreamStatus = 'idle' | 'streaming' | 'done' | 'error';
|
|
150
|
+
interface UseAgentStreamReturn<TBody = unknown> {
|
|
151
|
+
events: AgentEvent[];
|
|
152
|
+
status: AgentStreamStatus;
|
|
153
|
+
/** Accumulated assistant text — concatenation of all `message` contents (M5-1). */
|
|
154
|
+
liveText: string;
|
|
155
|
+
/** The last `error` event, or `undefined` (M5-1). */
|
|
156
|
+
error: AgentErrorEvent | undefined;
|
|
157
|
+
send: (body: TBody) => void;
|
|
158
|
+
abort: () => void;
|
|
159
|
+
reset: () => void;
|
|
160
|
+
}
|
|
161
|
+
interface UseAgentStreamOptions {
|
|
162
|
+
/** Extra headers (e.g., auth). */
|
|
163
|
+
headers?: Record<string, string>;
|
|
164
|
+
/** Override fetch (rare — primarily for tests). */
|
|
165
|
+
fetch?: typeof fetch;
|
|
166
|
+
}
|
|
167
|
+
declare function useAgentStream<TBody = unknown>(path: string, options?: UseAgentStreamOptions): UseAgentStreamReturn<TBody>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* A correlated, UI-facing view of one tool invocation (M5-2).
|
|
171
|
+
*
|
|
172
|
+
* `foldAgentToolCards` correlates a `tool_call` with its `tool_result` (by
|
|
173
|
+
* `id`, falling back to FIFO-by-name) into a single card so consumers stop
|
|
174
|
+
* hand-rolling `switch(event.type)`.
|
|
175
|
+
*/
|
|
176
|
+
interface AgentToolCard {
|
|
177
|
+
/** Correlation id (the event `id`, or a synthesized `tool-<index>`). */
|
|
178
|
+
id: string;
|
|
179
|
+
name: string;
|
|
180
|
+
args: Record<string, unknown>;
|
|
181
|
+
status: 'running' | 'success' | 'error';
|
|
182
|
+
/** The `tool_result.data` payload, once the result arrives. */
|
|
183
|
+
result?: unknown;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Classifies a `tool_result.data` payload as success/error. Injectable so the
|
|
187
|
+
* correlator is decoupled from any specific tool-result envelope shape.
|
|
188
|
+
*/
|
|
189
|
+
type ToolEnvelopeResolver = (data: unknown) => {
|
|
190
|
+
error: boolean;
|
|
191
|
+
};
|
|
192
|
+
interface FoldAgentToolCardsOptions {
|
|
193
|
+
/** Override the default envelope classifier. */
|
|
194
|
+
resolveEnvelope?: ToolEnvelopeResolver;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Default envelope resolver: an object (or a JSON STRING parsing to an object)
|
|
198
|
+
* with `ok === false` is an error; everything else is success (conservative).
|
|
199
|
+
* sdk-tools handlers return a JSON STRING, so string parsing is intentional.
|
|
200
|
+
*/
|
|
201
|
+
declare function defaultResolveEnvelope(data: unknown): {
|
|
202
|
+
error: boolean;
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Fold an `AgentEvent[]` into correlated {@link AgentToolCard}s (M5-2). Pure.
|
|
206
|
+
*
|
|
207
|
+
* Correlation: a `tool_result` matches its `tool_call` by `id` when both carry
|
|
208
|
+
* one; otherwise it matches the oldest still-`running` card with the same
|
|
209
|
+
* `name` (FIFO). An unmatched `tool_result` becomes its own finished card.
|
|
210
|
+
* A `tool_call` with no result stays `running`. The error status comes from
|
|
211
|
+
* `options.resolveEnvelope` (default {@link defaultResolveEnvelope}).
|
|
212
|
+
*/
|
|
213
|
+
declare function foldAgentToolCards(events: readonly AgentEvent[], options?: FoldAgentToolCardsOptions): AgentToolCard[];
|
|
214
|
+
|
|
215
|
+
/** {@link useAgentToolCards} return — the stream result plus correlated tool cards. */
|
|
216
|
+
interface UseAgentToolCardsReturn<TBody = unknown> extends UseAgentStreamReturn<TBody> {
|
|
217
|
+
/** Correlated tool cards folded from the stream events (M5-2). */
|
|
218
|
+
toolCards: AgentToolCard[];
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* `useAgentStream` + correlated tool cards (M5-2). Composes the stream hook with
|
|
222
|
+
* the pure {@link foldAgentToolCards} reducer; pass `resolveEnvelope` to classify
|
|
223
|
+
* tool-result payloads (default flags `{ ok: false }` envelopes as errors).
|
|
224
|
+
*/
|
|
225
|
+
declare function useAgentToolCards<TBody = unknown>(path: string, options?: UseAgentStreamOptions & FoldAgentToolCardsOptions): UseAgentToolCardsReturn<TBody>;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* T5.2 — Pure SSE consumer used by useAgentStream.
|
|
229
|
+
*
|
|
230
|
+
* Split out from the React hook so the wire behavior can be tested
|
|
231
|
+
* without a DOM. The hook is glue: useState + useEffect + this primitive.
|
|
232
|
+
*
|
|
233
|
+
* Transport (ADR D7, EC-3): fetch + ReadableStream — NOT EventSource.
|
|
234
|
+
* EventSource is GET-only and cannot carry a body. Agent endpoints need
|
|
235
|
+
* POST + JSON body, so we use fetch + manual SSE chunk parsing.
|
|
236
|
+
*/
|
|
237
|
+
interface ConsumeOptions<TBody = unknown> {
|
|
238
|
+
/** Request body — JSON-serialized into the POST. */
|
|
239
|
+
body: TBody;
|
|
240
|
+
/** Called once per SSE event parsed off the stream. */
|
|
241
|
+
onEvent: (event: AgentEvent) => void;
|
|
242
|
+
/** Optional fetch override (tests). */
|
|
243
|
+
fetch?: typeof fetch;
|
|
244
|
+
/** Optional abort signal — passed through to fetch. */
|
|
245
|
+
signal?: AbortSignal;
|
|
246
|
+
/** Extra headers (e.g., auth). */
|
|
247
|
+
headers?: Record<string, string>;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Parse a single SSE line of the form `data: <json>`.
|
|
251
|
+
* Returns null for non-data lines, comments, or malformed JSON.
|
|
252
|
+
*/
|
|
253
|
+
declare function parseSSEChunk(line: string): AgentEvent | null;
|
|
254
|
+
/**
|
|
255
|
+
* POSTs to `path` with `body`, reads the SSE response, and invokes
|
|
256
|
+
* `onEvent` for each parsed AgentEvent. Resolves when the server
|
|
257
|
+
* closes the stream or the signal aborts.
|
|
258
|
+
*
|
|
259
|
+
* T1.1 — Attaches `X-Theo-Action: '1'` so 0.3.0 strict CSRF mode accepts
|
|
260
|
+
* the request. The user can override (or suppress) by passing the header
|
|
261
|
+
* in `options.headers` — spread order ensures their value wins.
|
|
262
|
+
*/
|
|
263
|
+
declare function consumeAgentStream<TBody = unknown>(path: string, options: ConsumeOptions<TBody>): Promise<void>;
|
|
264
|
+
|
|
265
|
+
type PrefetchBehavior = 'none' | 'intent' | 'viewport';
|
|
266
|
+
interface LinkProps extends LinkProps$1 {
|
|
267
|
+
/** Prefetch strategy. Default: 'intent' (on hover + focus). */
|
|
268
|
+
prefetch?: PrefetchBehavior;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* TheoKit Link — drop-in replacement for react-router Link with prefetch.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```tsx
|
|
275
|
+
* import { Link } from 'theokit/client'
|
|
276
|
+
*
|
|
277
|
+
* <Link to="/contacts">Contacts</Link>
|
|
278
|
+
* <Link to="/dashboard" prefetch="viewport">Dashboard</Link>
|
|
279
|
+
* <Link to="/settings" prefetch="none">Settings</Link>
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
declare function Link({ prefetch, to, onMouseEnter, onFocus, ...rest }: LinkProps): react.JSX.Element;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* <Metadata> — SEO-ready head tags from a single component.
|
|
286
|
+
*
|
|
287
|
+
* Uses React 19's native <title>/<meta>/<link> hoisting to <head>.
|
|
288
|
+
* No build-time extraction needed — works in SSR and client.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```tsx
|
|
292
|
+
* import { Metadata } from 'theokit/client'
|
|
293
|
+
*
|
|
294
|
+
* export default function ContactsPage() {
|
|
295
|
+
* return (
|
|
296
|
+
* <>
|
|
297
|
+
* <Metadata
|
|
298
|
+
* title="Contacts | My CRM"
|
|
299
|
+
* description="Manage your contacts"
|
|
300
|
+
* ogImage="/og/contacts.png"
|
|
301
|
+
* canonical="https://mycrm.com/contacts"
|
|
302
|
+
* />
|
|
303
|
+
* <h1>Contacts</h1>
|
|
304
|
+
* </>
|
|
305
|
+
* )
|
|
306
|
+
* }
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
interface MetadataProps {
|
|
310
|
+
title?: string;
|
|
311
|
+
description?: string;
|
|
312
|
+
canonical?: string;
|
|
313
|
+
ogTitle?: string;
|
|
314
|
+
ogDescription?: string;
|
|
315
|
+
ogImage?: string;
|
|
316
|
+
ogType?: string;
|
|
317
|
+
ogUrl?: string;
|
|
318
|
+
twitterCard?: 'summary' | 'summary_large_image';
|
|
319
|
+
/** Custom meta tags rendered as children */
|
|
320
|
+
children?: React.ReactNode;
|
|
321
|
+
}
|
|
322
|
+
declare function Metadata(props: MetadataProps): react.JSX.Element;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* <Image> — optimized image component with lazy loading.
|
|
326
|
+
*
|
|
327
|
+
* Renders a standard <img> with:
|
|
328
|
+
* - loading="lazy" by default (eager with priority={true})
|
|
329
|
+
* - decoding="async" for non-blocking decode
|
|
330
|
+
* - width/height for CLS prevention
|
|
331
|
+
* - srcSet/sizes forwarded for responsive images
|
|
332
|
+
*
|
|
333
|
+
* No CDN, no Sharp, no build-time optimization — pure HTML attributes
|
|
334
|
+
* that deliver 80% of the performance value at zero complexity.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```tsx
|
|
338
|
+
* import { Image } from 'theokit/client'
|
|
339
|
+
*
|
|
340
|
+
* <Image src="/team.jpg" alt="Team photo" width={800} height={600} />
|
|
341
|
+
* <Image src="/hero.jpg" alt="Hero" priority />
|
|
342
|
+
* <Image
|
|
343
|
+
* src="/product.jpg"
|
|
344
|
+
* alt="Product"
|
|
345
|
+
* width={400}
|
|
346
|
+
* height={300}
|
|
347
|
+
* srcSet="/product-400.jpg 400w, /product-800.jpg 800w"
|
|
348
|
+
* sizes="(max-width: 768px) 100vw, 400px"
|
|
349
|
+
* />
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
|
|
353
|
+
/** Image source URL (required). */
|
|
354
|
+
src: string;
|
|
355
|
+
/** Alt text for accessibility (required). */
|
|
356
|
+
alt: string;
|
|
357
|
+
/** If true, loading="eager" — use for above-the-fold images. */
|
|
358
|
+
priority?: boolean;
|
|
359
|
+
}
|
|
360
|
+
declare function Image({ priority, loading, decoding, ...props }: ImageProps): react.JSX.Element;
|
|
361
|
+
|
|
362
|
+
export { AgentErrorEvent, AgentEvent, type AgentStreamStatus, type AgentToolCard, type BatchRequest, type BatchResponse, type BatchTransport, type Batcher, type BatcherOptions, type ConsumeOptions, type CreateAppClientOptions, type FoldAgentToolCardsOptions, Image, type ImageProps, type InferBody, type InferQuery, type InferResponse, Link, type LinkProps, Metadata, type MetadataProps, type PrefetchBehavior, TheoFetchError, type TheoFetchOptions, type ToolEnvelopeResolver, type UseAgentStreamOptions, type UseAgentStreamReturn, type UseAgentToolCardsReturn, consumeAgentStream, createAppClient, createBatcher, defaultResolveEnvelope, deriveError, deriveLiveText, foldAgentToolCards, parseSSEChunk, theoFetch, useAgentStream, useAgentToolCards };
|