theokit 0.27.0 → 0.28.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/client/index.d.ts +48 -1
- package/dist/client/index.js +97 -9
- package/dist/client/index.js.map +1 -1
- package/package.json +1 -1
package/dist/client/index.d.ts
CHANGED
|
@@ -334,6 +334,53 @@ declare class InProcessTransport implements AgentTransport {
|
|
|
334
334
|
approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
/** Handlers the transport hands to the injected push source for one turn. */
|
|
338
|
+
interface ChannelTurnHandlers {
|
|
339
|
+
/** One pushed JSONL line (a serialized `UIMessageChunk`). */
|
|
340
|
+
onLine: (line: string) => void;
|
|
341
|
+
/** The turn ended — no more lines. */
|
|
342
|
+
onClose: () => void;
|
|
343
|
+
/** The push source failed. */
|
|
344
|
+
onError?: (err: unknown) => void;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* The injected push source — a Tauri `Channel`/`invoke` bridge, kept STRUCTURAL so core adds no
|
|
348
|
+
* `@tauri-apps/*` dependency and the transport is testable with a fake (ADR-0051 D2). The Tauri app
|
|
349
|
+
* wires it: `new Channel()`, `channel.onmessage = onLine`, `invoke('run_agent', { message, channel })`,
|
|
350
|
+
* returning a teardown that aborts the sidecar turn.
|
|
351
|
+
*/
|
|
352
|
+
interface ChannelPushSource {
|
|
353
|
+
/** Start a turn; deliver each JSONL `UIMessageChunk` line to `onLine`, then `onClose`. Return a teardown. */
|
|
354
|
+
start(turn: {
|
|
355
|
+
message: string;
|
|
356
|
+
}, handlers: ChannelTurnHandlers): () => void;
|
|
357
|
+
/** Optional HITL settle (another Tauri `invoke`). */
|
|
358
|
+
settle?(approvalId: string, decision: ApprovalDecision): Promise<void>;
|
|
359
|
+
}
|
|
360
|
+
interface ChannelTransportOptions {
|
|
361
|
+
source: ChannelPushSource;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* M42 (ADR-0051) — `ChatTransport` over a Tauri-`Channel`-shaped push source, for the desktop webview.
|
|
365
|
+
*
|
|
366
|
+
* - `sendMessages`: start the turn via the injected source and bridge its pushed JSONL frames into a
|
|
367
|
+
* `ReadableStream<UIMessageChunk>` (built in `start` — a Channel is push, so the stream's queue buffers
|
|
368
|
+
* frames; ADR-0051 D3). A malformed JSONL line is SKIPPED, never fatal (ADR-0051 D4, Rule 8). `abortSignal`
|
|
369
|
+
* tears down the source and closes the stream.
|
|
370
|
+
* - `reconnectToStream`: always `null` — the M36 sidecar runs the turn directly (no durable server stream);
|
|
371
|
+
* this is the honest parity for a single-process push surface (ADR-0051 D5; mirrors `InProcessTransport`).
|
|
372
|
+
* - `approve`: routes to the injected `settle` (another Tauri `invoke`); absent `settle` → a typed error.
|
|
373
|
+
*
|
|
374
|
+
* The push source is INJECTED — core stays Tauri-agnostic and this transport is unit-tested with a fake.
|
|
375
|
+
*/
|
|
376
|
+
declare class ChannelTransport implements AgentTransport {
|
|
377
|
+
#private;
|
|
378
|
+
constructor(options: ChannelTransportOptions);
|
|
379
|
+
sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
|
|
380
|
+
reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
|
|
381
|
+
approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
|
|
382
|
+
}
|
|
383
|
+
|
|
337
384
|
type PrefetchBehavior = 'none' | 'intent' | 'viewport';
|
|
338
385
|
interface LinkProps extends LinkProps$1 {
|
|
339
386
|
/** Prefetch strategy. Default: 'intent' (on hover + focus). */
|
|
@@ -481,4 +528,4 @@ declare function mountMcpApp(container: HTMLElement, resource: {
|
|
|
481
528
|
html: string;
|
|
482
529
|
}, opts: McpAppHostOptions): McpAppHandle;
|
|
483
530
|
|
|
484
|
-
export { AgentClient, type AgentClientState, type AgentTransport, type ApprovalDecision, type BatchRequest, type BatchResponse, type BatchTransport, type Batcher, type BatcherOptions, type CreateAppClientOptions, type GuestMessage, HttpTransport, type HttpTransportOptions, Image, type ImageProps, type InProcessApprovalRequestLike, type InProcessAwaitApproval, type InProcessRunInput, type InProcessRunner, InProcessTransport, type InProcessTransportOptions, type InferBody, type InferQuery, type InferResponse, Link, type LinkProps, MCP_APP_SANDBOX, type McpAppHandle, type McpAppHostOptions, Metadata, type MetadataProps, type PrefetchBehavior, TheoFetchError, type TheoFetchOptions, type UseAgentOptions, type UseAgentReturn, type UseAgentStatus, consumeChunkStream, consumeUIMessageStream, createAppClient, createBatcher, createGuestMessageHandler, mountMcpApp, responseToChunkStream, theoFetch, useAgent };
|
|
531
|
+
export { AgentClient, type AgentClientState, type AgentTransport, type ApprovalDecision, type BatchRequest, type BatchResponse, type BatchTransport, type Batcher, type BatcherOptions, type ChannelPushSource, ChannelTransport, type ChannelTransportOptions, type ChannelTurnHandlers, type CreateAppClientOptions, type GuestMessage, HttpTransport, type HttpTransportOptions, Image, type ImageProps, type InProcessApprovalRequestLike, type InProcessAwaitApproval, type InProcessRunInput, type InProcessRunner, InProcessTransport, type InProcessTransportOptions, type InferBody, type InferQuery, type InferResponse, Link, type LinkProps, MCP_APP_SANDBOX, type McpAppHandle, type McpAppHostOptions, Metadata, type MetadataProps, type PrefetchBehavior, TheoFetchError, type TheoFetchOptions, type UseAgentOptions, type UseAgentReturn, type UseAgentStatus, consumeChunkStream, consumeUIMessageStream, createAppClient, createBatcher, createGuestMessageHandler, mountMcpApp, responseToChunkStream, theoFetch, useAgent };
|
package/dist/client/index.js
CHANGED
|
@@ -642,6 +642,17 @@ function useAgent(pathOrTransport, options = {}) {
|
|
|
642
642
|
};
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
+
// src/client/last-user-text.ts
|
|
646
|
+
function extractLastUserText(messages) {
|
|
647
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
648
|
+
const message = messages[i];
|
|
649
|
+
if (message.role !== "user") continue;
|
|
650
|
+
const text = message.parts.filter((part) => part.type === "text").map((part) => part.text).join("");
|
|
651
|
+
if (text.length > 0) return text;
|
|
652
|
+
}
|
|
653
|
+
return "";
|
|
654
|
+
}
|
|
655
|
+
|
|
645
656
|
// src/client/in-process-transport.ts
|
|
646
657
|
function generatorToStream(gen) {
|
|
647
658
|
return new ReadableStream({
|
|
@@ -662,15 +673,6 @@ function generatorToStream(gen) {
|
|
|
662
673
|
}
|
|
663
674
|
});
|
|
664
675
|
}
|
|
665
|
-
function extractLastUserText(messages) {
|
|
666
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
667
|
-
const message = messages[i];
|
|
668
|
-
if (message.role !== "user") continue;
|
|
669
|
-
const text = message.parts.filter((part) => part.type === "text").map((part) => part.text).join("");
|
|
670
|
-
if (text.length > 0) return text;
|
|
671
|
-
}
|
|
672
|
-
return "";
|
|
673
|
-
}
|
|
674
676
|
var InProcessTransport = class {
|
|
675
677
|
#run;
|
|
676
678
|
/** Pending inline approvals: approvalId → resolver of the parked `awaitApproval` promise. */
|
|
@@ -710,6 +712,91 @@ var InProcessTransport = class {
|
|
|
710
712
|
}
|
|
711
713
|
};
|
|
712
714
|
|
|
715
|
+
// src/client/channel-transport.ts
|
|
716
|
+
var ChannelTransport = class {
|
|
717
|
+
#source;
|
|
718
|
+
constructor(options) {
|
|
719
|
+
this.#source = options.source;
|
|
720
|
+
}
|
|
721
|
+
sendMessages(options) {
|
|
722
|
+
const { messages, abortSignal } = options;
|
|
723
|
+
const message = extractLastUserText(messages);
|
|
724
|
+
const source = this.#source;
|
|
725
|
+
let closed = false;
|
|
726
|
+
let teardown = () => void 0;
|
|
727
|
+
let detachAbort = () => void 0;
|
|
728
|
+
const stream = new ReadableStream({
|
|
729
|
+
start(controller) {
|
|
730
|
+
const finish = (settle) => {
|
|
731
|
+
if (closed) return;
|
|
732
|
+
closed = true;
|
|
733
|
+
detachAbort();
|
|
734
|
+
settle();
|
|
735
|
+
};
|
|
736
|
+
teardown = source.start(
|
|
737
|
+
{ message },
|
|
738
|
+
{
|
|
739
|
+
onLine: (line) => {
|
|
740
|
+
if (closed) return;
|
|
741
|
+
let parsed;
|
|
742
|
+
try {
|
|
743
|
+
parsed = JSON.parse(line);
|
|
744
|
+
} catch {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
if (typeof parsed !== "object" || parsed === null || typeof parsed.type !== "string") {
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
controller.enqueue(parsed);
|
|
751
|
+
},
|
|
752
|
+
onClose: () => {
|
|
753
|
+
finish(() => {
|
|
754
|
+
controller.close();
|
|
755
|
+
});
|
|
756
|
+
},
|
|
757
|
+
onError: (err) => {
|
|
758
|
+
finish(() => {
|
|
759
|
+
controller.error(err);
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
);
|
|
764
|
+
if (abortSignal !== void 0) {
|
|
765
|
+
const onAbort = () => {
|
|
766
|
+
finish(() => {
|
|
767
|
+
teardown();
|
|
768
|
+
controller.close();
|
|
769
|
+
});
|
|
770
|
+
};
|
|
771
|
+
if (abortSignal.aborted) onAbort();
|
|
772
|
+
else {
|
|
773
|
+
abortSignal.addEventListener("abort", onAbort);
|
|
774
|
+
detachAbort = () => {
|
|
775
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
cancel() {
|
|
781
|
+
if (closed) return;
|
|
782
|
+
closed = true;
|
|
783
|
+
detachAbort();
|
|
784
|
+
teardown();
|
|
785
|
+
}
|
|
786
|
+
});
|
|
787
|
+
return Promise.resolve(stream);
|
|
788
|
+
}
|
|
789
|
+
reconnectToStream() {
|
|
790
|
+
return Promise.resolve(null);
|
|
791
|
+
}
|
|
792
|
+
async approve(approvalId, decision) {
|
|
793
|
+
if (this.#source.settle === void 0) {
|
|
794
|
+
throw new Error(`This channel source has no HITL settle \u2014 cannot approve '${approvalId}'.`);
|
|
795
|
+
}
|
|
796
|
+
await this.#source.settle(approvalId, decision);
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
|
|
713
800
|
// src/client/link.tsx
|
|
714
801
|
import {
|
|
715
802
|
Link as RouterLink
|
|
@@ -849,6 +936,7 @@ function mountMcpApp(container, resource, opts) {
|
|
|
849
936
|
}
|
|
850
937
|
export {
|
|
851
938
|
AgentClient,
|
|
939
|
+
ChannelTransport,
|
|
852
940
|
HttpTransport,
|
|
853
941
|
Image,
|
|
854
942
|
InProcessTransport,
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/theo-fetch.ts","../../src/client/batch.ts","../../src/client/batch-transport.ts","../../src/client/app-client.ts","../../src/client/consume-ui-message-stream.ts","../../src/client/use-agent.ts","../../src/client/agent-client.ts","../../src/client/http-transport.ts","../../src/client/in-process-transport.ts","../../src/client/link.tsx","../../src/client/metadata.tsx","../../src/client/image.tsx","../../src/client/mcp-app-host.ts"],"sourcesContent":["import superjson from 'superjson'\nimport type { z } from 'zod'\n\nimport type { TheoErrorCode, TheoErrorEnvelope } from '../core/contracts/error-envelope.js'\n\nimport { getGlobalBatcher } from './batch-transport.js'\n\n// --- Transformer (T1.3) ---\n\n/**\n * Module-scoped flag preventing the transformer-mismatch warning from\n * firing more than once per session (EC-6).\n */\nlet mismatchWarned = false\n\n/** Test-only helper to reset the warned flag between assertions. */\nexport function __resetMismatchWarningForTests(): void {\n mismatchWarned = false\n}\n\n/**\n * Deserialize a fetch response body according to the negotiated transformer.\n *\n * `serverTransformerName` comes from the `x-theo-transformer` response header\n * (null when absent — server is using the default JSON path).\n * `clientTransformerName` is the transformer the client was built with\n * (typically injected via a Vite virtual module; falls back to `'json'`).\n *\n * Mismatch fires a single console.warn and falls back to JSON.parse (EC-5/EC-6).\n */\nexport function deserializeFetchResponse(\n raw: string,\n serverTransformerName: string | null,\n clientTransformerName: string,\n): unknown {\n // `raw` is typed `string`, but stay defensive: callers pass `await response.text()`\n // which can be empty.\n if (raw === '') {\n return null\n }\n\n const serverEffective = serverTransformerName ?? 'json'\n if (serverEffective !== clientTransformerName && !mismatchWarned) {\n mismatchWarned = true\n console.warn(\n `[theokit] transformer mismatch: server=${serverEffective}, client=${clientTransformerName}. Falling back to JSON.parse.`,\n )\n }\n\n if (serverEffective === 'superjson' && clientTransformerName === 'superjson') {\n const wrapped = JSON.parse(raw) as Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize(wrapped)\n }\n\n // Default path (json) or mismatch fallback\n return JSON.parse(raw)\n}\n\n// --- Utility Types ---\n\n/** Infer the response type from a route's handler return */\nexport type InferResponse<T> = T extends { handler: (...args: never[]) => infer R }\n ? Awaited<R>\n : unknown\n\n/** Extract the query Zod schema type, handling optional properties */\ntype ExtractQuery<T> = T extends { query?: infer Q } ? (Q extends z.ZodType ? Q : never) : never\n\n/** Extract the body Zod schema type, handling optional properties */\ntype ExtractBody<T> = T extends { body?: infer B } ? (B extends z.ZodType ? B : never) : never\n\n/** Infer query type from a route's query Zod schema */\nexport type InferQuery<T> = [ExtractQuery<T>] extends [never]\n ? undefined\n : ExtractQuery<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractQuery<T>>\n\n/** Infer body type from a route's body Zod schema */\nexport type InferBody<T> = [ExtractBody<T>] extends [never]\n ? undefined\n : ExtractBody<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractBody<T>>\n\n/** Build the options type based on what schemas the route has */\nexport type TheoFetchOptions<T> = Omit<RequestInit, 'body' | 'method'> &\n (InferQuery<T> extends undefined ? { query?: never } : { query: InferQuery<T> }) &\n (InferBody<T> extends undefined ? { body?: never } : { body: InferBody<T> })\n\n// --- Error Class ---\n\n/**\n * G5 T2.1 — extract a TheoErrorEnvelope from a response body. Supports both\n * the new envelope-at-root shape (`{ code, message, ext?, ... }`, blueprint\n * Recommendations § concrete shape) and the legacy nested shape\n * (`{ error: { code, message, issues? } }`, G3 SerializedActionResult).\n *\n * Falls back to `INTERNAL_SERVER_ERROR` with a synthetic message when the\n * body shape is unrecognized. Pure; no I/O.\n */\nfunction extractEnvelope(status: number, body: unknown): TheoErrorEnvelope {\n if (!body || typeof body !== 'object') {\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n // New shape — envelope at root\n if (typeof obj.code === 'string' && typeof obj.message === 'string') {\n return {\n code: obj.code as TheoErrorCode,\n message: obj.message,\n cause: obj.cause,\n meta: obj.meta as Record<string, unknown> | undefined,\n ext: obj.ext,\n }\n }\n // Legacy shape — { error: { code, message, ... } }\n if (obj.error && typeof obj.error === 'object') {\n const nested = obj.error as Record<string, unknown>\n return {\n code:\n typeof nested.code === 'string' ? (nested.code as TheoErrorCode) : 'INTERNAL_SERVER_ERROR',\n message: typeof nested.message === 'string' ? nested.message : `HTTP ${String(status)}`,\n }\n }\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n}\n\n/**\n * Pull a single string field from an object, returning undefined if missing\n * or non-string. Helper for `extractLegacyFields` to stay under the\n * complexity ceiling.\n */\nfunction strField(obj: Record<string, unknown> | null, key: string): string | undefined {\n const v = obj?.[key]\n return typeof v === 'string' ? v : undefined\n}\n\n/**\n * Pull the canonical {message, code, issues} from either an envelope-at-root\n * body or the legacy { error: {...} } body. Pure.\n */\nfunction extractLegacyFields(\n status: number,\n body: unknown,\n): { message: string; code?: string; issues?: unknown[] } {\n if (!body || typeof body !== 'object') {\n return { message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n const nested =\n obj.error && typeof obj.error === 'object' ? (obj.error as Record<string, unknown>) : null\n const issues = Array.isArray(nested?.issues) ? nested.issues : undefined\n return {\n message: strField(obj, 'message') ?? strField(nested, 'message') ?? `HTTP ${String(status)}`,\n code: strField(obj, 'code') ?? strField(nested, 'code'),\n issues,\n }\n}\n\nexport class TheoFetchError extends Error {\n status: number\n code?: string\n issues?: unknown[]\n /**\n * G5 T2.1 — canonical envelope view of the server-side error. Use this in\n * consumer code that wants to switch on a typed TheoErrorCode instead of\n * coupling to the legacy `.status` / `.code` flat fields.\n */\n readonly envelope: TheoErrorEnvelope\n\n constructor(status: number, body?: unknown) {\n const legacy = extractLegacyFields(status, body)\n super(legacy.message)\n this.name = 'TheoFetchError'\n this.status = status\n this.code = legacy.code\n this.issues = legacy.issues\n this.envelope = extractEnvelope(status, body)\n }\n}\n\n/**\n * Serialize a query-param value to a string. Handles primitives, dates,\n * and falls back to JSON for arrays/objects. Avoids the\n * `[object Object]` foot-gun that `no-base-to-string` warns against.\n */\nfunction stringifyQueryValue(value: unknown): string {\n if (value === null) return 'null'\n if (value instanceof Date) return value.toISOString()\n switch (typeof value) {\n case 'string':\n return value\n case 'number':\n case 'boolean':\n case 'bigint':\n return String(value)\n default:\n return JSON.stringify(value)\n }\n}\n\n// --- Main Function ---\n\ninterface TheoFetchInternalOptions {\n method?: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\n/**\n * Resolve the request origin per the documented fallback hierarchy. Pure\n * helper extracted to keep `theoFetch` under the complexity ceiling.\n * 1. `globalThis.location.origin` (browser)\n * 2. `globalThis.__THEO_ORIGIN__` (build-time literal)\n * 3. `process.env.THEO_ORIGIN` (escape hatch)\n * 4. `http://localhost` (placeholder for URL parsing — the URL is built\n * relative so only pathname+search ever flows to the wire)\n */\nfunction resolveRequestOrigin(): string {\n const g = globalThis as { location?: { origin?: string }; __THEO_ORIGIN__?: string }\n const fromEnv = typeof process !== 'undefined' ? process.env.THEO_ORIGIN : undefined\n return g.location?.origin ?? g.__THEO_ORIGIN__ ?? fromEnv ?? 'http://localhost'\n}\n\nfunction buildFetchUrl(path: string, query: Record<string, unknown> | undefined): URL {\n const fetchUrl = new URL(path, resolveRequestOrigin())\n if (!query) return fetchUrl\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) {\n fetchUrl.searchParams.set(k, stringifyQueryValue(v))\n }\n }\n return fetchUrl\n}\n\n/**\n * Normalize `HeadersInit` (Headers / `[string, string][]` / Record) into a\n * single plain `Record<string, string>`. Plain-object output is required\n * by callers that introspect headers via index access (test fixtures use\n * `(init.headers as Record<string, string>)['Content-Type']`).\n */\nfunction normalizeHeaders(input: HeadersInit | undefined): Record<string, string> {\n const out: Record<string, string> = {}\n if (!input) return out\n if (input instanceof Headers) {\n input.forEach((value, key) => {\n out[key] = value\n })\n return out\n }\n if (Array.isArray(input)) {\n for (const [key, value] of input) out[key] = value\n return out\n }\n for (const [key, value] of Object.entries(input)) {\n out[key] = value\n }\n return out\n}\n\nfunction buildRequestInit(opts: TheoFetchInternalOptions): RequestInit {\n const init: RequestInit = {}\n if (opts.method !== undefined) init.method = opts.method\n if (opts.signal !== undefined) init.signal = opts.signal\n\n const headers = normalizeHeaders(opts.headers)\n init.headers = headers\n\n if (opts.body !== undefined) {\n init.body = JSON.stringify(opts.body)\n headers['Content-Type'] = 'application/json'\n }\n\n // Phase 5 — Auto-attach `X-Theo-Action: 1` for state-mutating methods so\n // the framework's CSRF check passes when servers run in `strict` mode.\n // Safe methods (GET/HEAD/OPTIONS) skip the header to keep them cacheable.\n const method = (opts.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {\n headers['X-Theo-Action'] = '1'\n }\n return init\n}\n\nasync function tryBatcher(\n url: string,\n options: TheoFetchInternalOptions,\n): Promise<{ matched: true; result: unknown } | { matched: false }> {\n const batcher = getGlobalBatcher()\n if (!batcher) return { matched: false }\n try {\n const result = await batcher.dispatch({\n path: url,\n method: options.method ?? 'GET',\n query: options.query,\n body: options.body,\n })\n return { matched: true, result }\n } catch {\n // Batcher failure: fall through to direct fetch (graceful degrade).\n return { matched: false }\n }\n}\n\nexport async function theoFetch<T>(\n url: string,\n options?: TheoFetchOptions<T>,\n): Promise<InferResponse<T>> {\n const internal = (options ?? {}) as unknown as TheoFetchInternalOptions\n\n // T1.5 — Transparent batching when globalThis.__THEO_BATCHING__ is truthy.\n const batchAttempt = await tryBatcher(url, internal)\n if (batchAttempt.matched) {\n return batchAttempt.result as InferResponse<T>\n }\n\n const fetchUrl = buildFetchUrl(url, internal.query)\n const init = buildRequestInit(internal)\n const response = await fetch(fetchUrl.toString(), init)\n\n if (!response.ok) {\n let errorBody: unknown\n try {\n errorBody = await response.json()\n } catch {\n // Non-JSON error response\n }\n throw new TheoFetchError(response.status, errorBody)\n }\n\n // Handle 204 No Content (EC-1)\n if (response.status === 204) {\n return null as InferResponse<T>\n }\n\n // Check for empty body\n const contentLength = response.headers.get('content-length')\n if (contentLength === '0') {\n return null as InferResponse<T>\n }\n\n // T1.3 — transformer-aware deserialization\n const serverTransformerName = response.headers.get('x-theo-transformer')\n const clientTransformerName = resolveClientTransformerName()\n const text = await response.text()\n return deserializeFetchResponse(\n text,\n serverTransformerName,\n clientTransformerName,\n ) as InferResponse<T>\n}\n\n/**\n * Read the client-configured transformer name. Default `'json'`.\n *\n * In a Vite build, this is overridden by virtual module\n * `/@theo/runtime-config` which sets `globalThis.__THEO_TRANSFORMER__`.\n * Outside Vite (Node SSR, tests) the default applies.\n */\nfunction resolveClientTransformerName(): string {\n const g = globalThis as { __THEO_TRANSFORMER__?: string }\n return g.__THEO_TRANSFORMER__ ?? 'json'\n}\n","/**\n * T5.1 — client-side microtask batching.\n *\n * Collects all `dispatch` calls within the same microtask and sends them as a\n * single HTTP POST to the configured transport. Each caller's promise resolves\n * with its own result; one failed item does not break the others (per-item\n * error isolation).\n *\n * Designed as a transport-agnostic primitive so unit tests do not require\n * network access. The default transport (fetch to `/api/__theo_batch__`)\n * lives alongside this module but is created by the consumer (e.g., theoFetch).\n */\n\nexport interface BatchRequest {\n path: string\n method: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: Record<string, string>\n}\n\nexport type BatchResponse =\n | { index: number; data: unknown }\n | { index: number; error: { message: string; code?: string } }\n\nexport type BatchTransport = (requests: BatchRequest[]) => Promise<BatchResponse[]>\n\nexport interface BatcherOptions {\n transport: BatchTransport\n /** Maximum batch size before flushing into multiple parallel batches. */\n max?: number\n}\n\nexport interface Batcher {\n dispatch(req: BatchRequest): Promise<unknown>\n}\n\ninterface PendingCall {\n req: BatchRequest\n resolve: (value: unknown) => void\n reject: (reason: unknown) => void\n}\n\nexport function createBatcher(options: BatcherOptions): Batcher {\n const max = options.max ?? 32\n let queue: PendingCall[] = []\n let flushScheduled = false\n\n function flush(): void {\n flushScheduled = false\n const current = queue\n queue = []\n if (current.length === 0) return\n\n // Split into chunks respecting max\n const chunks: PendingCall[][] = []\n for (let i = 0; i < current.length; i += max) {\n chunks.push(current.slice(i, i + max))\n }\n\n for (const chunk of chunks) {\n const payload: BatchRequest[] = chunk.map((p) => p.req)\n options\n .transport(payload)\n .then((results) => {\n for (let i = 0; i < chunk.length; i++) {\n // `results[i]` could be undefined at runtime when the transport\n // returns fewer entries than the chunk; TypeScript's strict\n // typing without `noUncheckedIndexedAccess` does not surface\n // this, so we hand-narrow.\n const result = results.length > i ? results[i] : undefined\n if (result === undefined) {\n chunk[i].reject(new Error(`Batch transport returned no result for index ${i}`))\n continue\n }\n if ('error' in result) {\n const err = new Error(result.error.message)\n ;(err as { code?: string }).code = result.error.code\n chunk[i].reject(err)\n } else {\n chunk[i].resolve(result.data)\n }\n }\n })\n .catch((err: unknown) => {\n for (const item of chunk) item.reject(err)\n })\n }\n }\n\n return {\n dispatch(req: BatchRequest): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n queue.push({ req, resolve, reject })\n if (!flushScheduled) {\n flushScheduled = true\n queueMicrotask(flush)\n }\n })\n },\n }\n}\n","/**\n * T1.5 — Default HTTP transport for the client batcher.\n *\n * Wraps `fetch` to POST `/api/__theo_batch__` with the collected requests\n * and return the array of per-item results.\n */\n\nimport {\n createBatcher,\n type BatchTransport,\n type Batcher,\n type BatchRequest,\n type BatchResponse,\n} from './batch.js'\n\nconst BATCH_ENDPOINT = '/api/__theo_batch__'\n\nexport interface CreateBatchTransportOptions {\n /** Override fetch (default: globalThis.fetch). Used by tests. */\n fetchImpl?: typeof fetch\n /** Override endpoint (default '/api/__theo_batch__'). */\n endpoint?: string\n}\n\nexport function createBatchTransport(options: CreateBatchTransportOptions = {}): BatchTransport {\n const fetchImpl = options.fetchImpl ?? fetch\n const endpoint = options.endpoint ?? BATCH_ENDPOINT\n return async (requests: BatchRequest[]): Promise<BatchResponse[]> => {\n const response = await fetchImpl(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requests }),\n })\n if (!response.ok) {\n throw new Error(`Batch transport returned ${response.status}`)\n }\n const payload = (await response.json()) as { results?: BatchResponse[] }\n if (!Array.isArray(payload.results)) {\n throw new Error('Batch response missing results array')\n }\n // Map results to indexed BatchResponse shape (server already returns the right form)\n return payload.results.map((item, index) => {\n if ('error' in item) {\n return { index, error: (item as { error: { message: string; code?: string } }).error }\n }\n return { index, data: (item as { data: unknown }).data }\n })\n }\n}\n\n// --- EC-7: singleton batcher per page, lazy-instantiated ---\n\nlet globalBatcher: Batcher | undefined\n\n/** Test-only — reset the module-scope singleton between assertions. */\nexport function __resetGlobalBatcherForTests(): void {\n globalBatcher = undefined\n}\n\n/**\n * Returns the global batcher singleton when `globalThis.__THEO_BATCHING__` is\n * truthy; undefined otherwise. Lazy-instantiated on first call.\n */\nexport function getGlobalBatcher(): Batcher | undefined {\n const g = globalThis as { __THEO_BATCHING__?: boolean }\n if (!g.__THEO_BATCHING__) return undefined\n globalBatcher ??= createBatcher({ transport: createBatchTransport() })\n return globalBatcher\n}\n","/**\n * Phase 3 of G1 (g1-client-codegen-plan.md):\n *\n * `createAppClient(baseUrl?, fetchImpl?)` returns a Proxy that walks property\n * access (`client.posts.id.get(...)`) into a `theoFetch` invocation against\n * `{baseUrl}/posts/{params.id}` with method `GET`.\n *\n * Type safety is delivered by the `.d.ts` file emitted in Phase 2 — this\n * runtime is structurally untyped. Power users may use `theoFetch` directly\n * when they need to escape the Proxy facade.\n *\n * Edge cases absorbed:\n * - EC-1 (thenable trap): `then` / `catch` / `finally` / `toJSON` / `Symbol.*`\n * return `undefined` so that accidental `await client.posts` resolves to a\n * plain Proxy value (it is NOT thenable) instead of looping.\n * - EC-7 (abort signal): `opts.signal` is spread through to the underlying\n * fetchImpl unchanged — verified in unit tests.\n *\n * Bundle target: ≤ 2KB gzipped.\n */\n\nimport { theoFetch, TheoFetchError } from './theo-fetch.js'\nimport type { TheoFetchOptions } from './theo-fetch.js'\nimport { HTTP_METHOD_LOWERCASE } from '../core/contracts/http-methods.js'\n\nconst HTTP_METHODS_SET = new Set(HTTP_METHOD_LOWERCASE)\n\n/**\n * Keys that JavaScript runtime / inspectors / Promise resolution probe\n * unconditionally. Returning `undefined` for these keeps the Proxy from\n * pretending to be a thenable / iterable / serializable thing.\n */\nconst NON_INTERCEPT_KEYS = new Set([\n 'then',\n 'catch',\n 'finally',\n 'toJSON',\n 'toString',\n 'valueOf',\n 'constructor',\n 'prototype',\n])\n\ntype FetchImpl = typeof theoFetch\n\ninterface CallOptions {\n params?: Record<string, string | number>\n query?: Record<string, unknown>\n body?: unknown\n signal?: AbortSignal\n headers?: HeadersInit\n // arbitrary RequestInit fields (mode, credentials, cache, etc.)\n [k: string]: unknown\n}\n\nfunction injectParams(path: string, params?: Record<string, string | number>): string {\n if (!params) {\n if (/:(?:\\.\\.\\.)?[A-Za-z_]/.test(path)) {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Route ${path} requires params but none were provided. Pass them via opts.params, e.g. client.posts.get({ params: { id: '123' } }).`,\n },\n })\n }\n return path\n }\n return path.replace(/:(?:\\.\\.\\.)?([A-Za-z_][A-Za-z0-9_]*)/g, (_match, key: string) => {\n const value = params[key]\n if (value === undefined || value === null || value === '') {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Param '${key}' is required for path '${path}' but was missing/empty.`,\n },\n })\n }\n return encodeURIComponent(String(value))\n })\n}\n\ninterface ProxyContext {\n segments: string[]\n baseUrl: string\n fetchImpl: FetchImpl\n}\n\nfunction makeProxy(ctx: ProxyContext): unknown {\n const handler: ProxyHandler<() => void> = {\n get(_target, key) {\n if (typeof key !== 'string') return undefined\n if (NON_INTERCEPT_KEYS.has(key)) return undefined\n if (HTTP_METHODS_SET.has(key)) {\n return async (opts?: CallOptions) => {\n if (ctx.segments.length === 0) {\n throw new TheoFetchError(0, {\n error: {\n code: 'INVALID_PATH',\n message: `client.${key}() called without a route segment. Use client.<resource>.${key}(...) instead.`,\n },\n })\n }\n let finalPath = `${ctx.baseUrl}/${ctx.segments.join('/')}`\n if (opts?.params) {\n // Build a path with `:name` placeholders re-inserted from segments\n // whose name matches a key in opts.params (treat as dynamic).\n const segmentsWithDynamic = ctx.segments.map((seg) =>\n Object.prototype.hasOwnProperty.call(opts.params, seg) ? `:${seg}` : seg,\n )\n finalPath = injectParams(\n `${ctx.baseUrl}/${segmentsWithDynamic.join('/')}`,\n opts.params,\n )\n }\n const { params: _ignored, ...rest } = opts ?? {}\n const init = { method: key.toUpperCase(), ...rest } as unknown as TheoFetchOptions<unknown>\n return ctx.fetchImpl(finalPath, init)\n }\n }\n // Continue traversal — append segment to the path.\n return makeProxy({ ...ctx, segments: [...ctx.segments, key] })\n },\n apply() {\n return Promise.reject(\n new TheoFetchError(0, {\n error: {\n code: 'INVALID_CALL',\n message:\n 'client(...) is not callable. Use client.<resource>.<method>(opts?) — e.g. client.posts.get().',\n },\n }),\n )\n },\n }\n return new Proxy(() => undefined, handler)\n}\n\nexport interface CreateAppClientOptions {\n /** Base URL for the API. Defaults to `/api`. */\n baseUrl?: string\n /** Test-only fetch override. Production callers should not pass this. */\n fetchImpl?: FetchImpl\n}\n\nexport function createAppClient<TAppClient = unknown>(\n baseUrlOrOptions?: string | CreateAppClientOptions,\n legacyFetchImpl?: FetchImpl,\n): TAppClient {\n let baseUrl = '/api'\n let fetchImpl: FetchImpl = theoFetch\n if (typeof baseUrlOrOptions === 'string') {\n baseUrl = baseUrlOrOptions || '/api'\n } else if (baseUrlOrOptions && typeof baseUrlOrOptions === 'object') {\n if (baseUrlOrOptions.baseUrl) baseUrl = baseUrlOrOptions.baseUrl\n if (baseUrlOrOptions.fetchImpl) fetchImpl = baseUrlOrOptions.fetchImpl\n }\n // Legacy 2nd-arg fetchImpl overrides regardless of 1st-arg shape (test seam).\n if (legacyFetchImpl) fetchImpl = legacyFetchImpl\n // Strip trailing slash for predictable joining.\n if (baseUrl.length > 1 && baseUrl.endsWith('/')) baseUrl = baseUrl.slice(0, -1)\n return makeProxy({ segments: [], baseUrl, fetchImpl }) as TAppClient\n}\n","import type { UIMessage, UIMessageChunk } from 'ai'\n\n/**\n * M2 (theokit-ai-first) — read a TheoKit agent endpoint's `UIMessageStream` SSE `Response`\n * into reconstructed assistant `UIMessage`s, reusing the `ai` package's own consumer\n * primitives (`parseJsonEventStream` + `readUIMessageStream`) — the exact path\n * `@ai-sdk/react`'s `useChat` runs internally. No reinvented wire parser (Rule 9).\n *\n * `ai` is an OPTIONAL peer dependency, so it is imported dynamically: an app that never\n * calls an agent never pays for it, and importing `theokit/client` does not hard-require\n * `ai` (mirrors how the agent runtime dynamically imports `@theokit/sdk`). An agent app\n * always has `ai` installed (it is the UIMessageStream consumer).\n *\n * `onMessage` is invoked on every reconstruction step with the latest snapshot of the\n * assistant message, so a caller (the `useAgent` hook) can render streaming updates.\n */\nexport async function consumeUIMessageStream(\n response: Response,\n onMessage: (message: UIMessage) => void,\n): Promise<void> {\n const chunkStream = await responseToChunkStream(response)\n await consumeChunkStream(chunkStream, onMessage)\n}\n\n/**\n * M41 (ADR-0050 D3) — the reusable middle piece: a UIMessageStream SSE `Response` →\n * `ReadableStream<UIMessageChunk>`, reusing `ai`'s own `parseJsonEventStream` (the exact primitive\n * `useChat` runs). This is precisely what a `ChatTransport.sendMessages` returns, so `HttpTransport`\n * builds on it directly (no reinvented wire parser — Rule 9). A body-less response yields an empty stream.\n */\nexport async function responseToChunkStream(\n response: Response,\n): Promise<ReadableStream<UIMessageChunk>> {\n if (response.body === null) {\n return new ReadableStream<UIMessageChunk>({\n start(controller) {\n controller.close()\n },\n })\n }\n\n const { parseJsonEventStream, uiMessageChunkSchema } = await import('ai')\n\n // ai validates each SSE JSON frame against its own strict chunk schema (the exact gate `useChat`\n // runs), then yields `{ success, value }`; forward the valid chunks.\n const parsed = parseJsonEventStream({ stream: response.body, schema: uiMessageChunkSchema })\n return new ReadableStream<UIMessageChunk>({\n async start(controller) {\n for await (const result of parsed) {\n if (result.success) controller.enqueue(result.value)\n }\n controller.close()\n },\n })\n}\n\n/**\n * M41 (ADR-0050 D6) — read a `ReadableStream<UIMessageChunk>` into reconstructed assistant\n * `UIMessage`s via `ai`'s `readUIMessageStream`. Shared by `consumeUIMessageStream` (Response path)\n * and the framework-agnostic `AgentClient` store (transport path). `onMessage` fires on every\n * reconstruction step so a caller can render streaming updates.\n */\nexport async function consumeChunkStream(\n stream: ReadableStream<UIMessageChunk>,\n onMessage: (message: UIMessage) => void,\n): Promise<void> {\n const { readUIMessageStream } = await import('ai')\n for await (const message of readUIMessageStream({ stream })) {\n onMessage(message)\n }\n}\n","import type { UIMessage } from 'ai'\nimport { useMemo, useRef, useSyncExternalStore } from 'react'\n\nimport { AgentClient, type UseAgentStatus } from './agent-client.js'\nimport { HttpTransport } from './http-transport.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\n/**\n * M2 (theokit-ai-first) / M41 (ADR-0050) — `useAgent`, the ONE typed client hook for the\n * `agents/*.ts` convention, unified across surfaces.\n *\n * Pass an endpoint path (web) OR an {@link AgentTransport} (terminal/desktop). A string is wrapped in\n * an {@link HttpTransport} (exact back-compat with the pre-M41 fetch+SSE hook); an `InProcessTransport`\n * drives the SAME hook in a single process. The hook is a thin binding over the framework-agnostic\n * {@link AgentClient} store via React's native `useSyncExternalStore` (no test-DOM dependency). The\n * generated `@theo/agents` module types `send` to the agent's `input` schema — inferred end-to-end\n * from the server `defineAgent({ input })` with ZERO manual wiring.\n */\nexport type { UseAgentStatus }\n\nexport interface UseAgentReturn<TInput = unknown, TToolNames extends string = string> {\n /** Reconstructed assistant messages so far (ai `UIMessage[]`). */\n messages: UIMessage[]\n status: UseAgentStatus\n /** The last error, or `undefined`. */\n error: Error | undefined\n /** Send a request; opens a new stream. Typed to the agent's `input` schema. */\n send: (input: TInput) => void\n /** Abort an in-flight stream. */\n abort: () => void\n /** Clear messages + error, back to idle. */\n reset: () => void\n /** Settle a paused HITL approval (HTTP `POST /approve/<id>` for web; the inline callback in-process). */\n approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>\n /** Resume an interrupted stream (M37 durable transport for web; a no-op in-process). */\n reconnect: () => void\n /**\n * The union of tool names this agent can emit (M8), carried end-to-end from the `agent()` builder's\n * accumulated tool-name type through the generated `@theo/agents` client. Type-only witness (never\n * populated at runtime). Resolves to the literal union for builder agents, `string` otherwise.\n */\n readonly __toolNames?: TToolNames\n}\n\nexport interface UseAgentOptions {\n /**\n * Extra request headers (e.g., auth) — applied when a string path builds an `HttpTransport`. Read on\n * EVERY request, so a value that changes across renders (a rotating JWT) is never sent stale.\n */\n headers?: Record<string, string>\n /** Override fetch (primarily for tests) — captured when a string path builds an `HttpTransport`. */\n fetch?: typeof fetch\n}\n\n/**\n * Bind to an agent by endpoint path (`/api/agents/<name>`) or by an explicit {@link AgentTransport}.\n * Prefer the generated `useAgent` from `@theo/agents` (typed by agent name); this base accepts a path\n * or a transport. The store is created once per binding identity — memoize a transport before passing it.\n */\nexport function useAgent<TInput = unknown>(\n pathOrTransport: string | AgentTransport,\n options: UseAgentOptions = {},\n): UseAgentReturn<TInput> {\n // Track the latest options so the built HttpTransport reads current headers per request (dynamic\n // auth is never stale) without rebuilding the store — which would drop in-flight messages.\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n const client = useMemo(\n () =>\n new AgentClient<TInput>(\n typeof pathOrTransport === 'string'\n ? new HttpTransport({\n api: pathOrTransport,\n headers: () => optionsRef.current.headers,\n fetch: optionsRef.current.fetch,\n })\n : pathOrTransport,\n ),\n // Identity is the binding; headers are resolved live via optionsRef, fetch captured at creation.\n [pathOrTransport],\n )\n\n const state = useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n\n return {\n messages: state.messages,\n status: state.status,\n error: state.error,\n send: client.send,\n abort: client.abort,\n reset: client.reset,\n approve: client.approve,\n reconnect: client.reconnect,\n }\n}\n","import type { UIMessage, UIMessageChunk } from 'ai'\n\nimport { consumeChunkStream } from './consume-ui-message-stream.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\nexport type UseAgentStatus = 'idle' | 'streaming' | 'done' | 'error'\n\n/** The observable state the store exposes (stable reference between emits — `useSyncExternalStore` contract). */\nexport interface AgentClientState {\n messages: UIMessage[]\n status: UseAgentStatus\n error: Error | undefined\n}\n\n/** Derive the turn text from a typed input: `input.message` when present, else the serialized input. */\nfunction inputToText(input: unknown): string {\n if (\n typeof input === 'object' &&\n input !== null &&\n typeof (input as { message?: unknown }).message === 'string'\n ) {\n return (input as { message: string }).message\n }\n if (typeof input === 'string') return input\n return JSON.stringify(input)\n}\n\n/** Build a user `UIMessage` from a typed input (text from `{ message }`, else the serialized input). */\nfunction buildUserMessage(input: unknown): UIMessage {\n return {\n id: crypto.randomUUID(),\n role: 'user',\n parts: [{ type: 'text', text: inputToText(input) }],\n }\n}\n\n/**\n * M41 (ADR-0050 D6) — the framework-agnostic agent client store.\n *\n * Holds `messages`/`status`/`error`, drives an {@link AgentTransport}, and notifies subscribers on\n * change. It is the SINGLE consolidation point: web (`HttpTransport`) and terminal/desktop\n * (`InProcessTransport`) run the SAME store. `useAgent` is a thin React binding over it via\n * `useSyncExternalStore`; a standalone (no-React) client (M44) can subscribe directly. Being\n * framework-agnostic, it is unit-tested without a DOM.\n */\nexport class AgentClient<TInput = unknown> {\n readonly #transport: AgentTransport\n readonly #chatId = crypto.randomUUID()\n readonly #listeners = new Set<() => void>()\n\n #messages: UIMessage[] = []\n #status: UseAgentStatus = 'idle'\n #error: Error | undefined\n #controller: AbortController | null = null\n #snapshot: AgentClientState = { messages: [], status: 'idle', error: undefined }\n\n constructor(transport: AgentTransport) {\n this.#transport = transport\n }\n\n /** Subscribe to state changes; returns an unsubscribe fn. */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener)\n return () => {\n this.#listeners.delete(listener)\n }\n }\n\n /** The current immutable snapshot (stable reference until the next emit). */\n getSnapshot = (): AgentClientState => this.#snapshot\n\n #emit(): void {\n this.#snapshot = { messages: this.#messages, status: this.#status, error: this.#error }\n for (const listener of this.#listeners) listener()\n }\n\n #upsert(message: UIMessage): void {\n const next = [...this.#messages]\n const idx = next.findIndex((existing) => existing.id === message.id)\n if (idx >= 0) next[idx] = message\n else next.push(message)\n this.#messages = next\n }\n\n async #drive(\n open: () => Promise<ReadableStream<UIMessageChunk> | null>,\n controller: AbortController,\n ): Promise<void> {\n // Read via a function (not a narrowed local) — `aborted` flips ASYNC across the awaits below, so the\n // control-flow narrowing of a direct `signal.aborted` read would be wrong. A stale drive (its\n // controller aborted because a newer send/abort took over) MUST NOT clobber the newer status.\n const aborted = (): boolean => controller.signal.aborted\n try {\n const stream = await open()\n if (aborted()) return\n if (stream === null) {\n // Nothing to resume (e.g. reconnect after the run completed). Settle without error.\n this.#status = this.#messages.length > 0 ? 'done' : 'idle'\n this.#emit()\n return\n }\n await consumeChunkStream(stream, (message) => {\n if (aborted()) return\n this.#upsert(message)\n this.#emit()\n })\n if (aborted()) return\n this.#status = 'done'\n this.#emit()\n } catch (err) {\n if (aborted()) return\n this.#error = err instanceof Error ? err : new Error(String(err))\n this.#status = 'error'\n this.#emit()\n }\n }\n\n /** Send a typed input; opens a fresh stream (replaces prior messages). */\n send = (input: TInput): void => {\n this.abort()\n const controller = new AbortController()\n this.#controller = controller\n this.#messages = []\n this.#error = undefined\n this.#status = 'streaming'\n this.#emit()\n void this.#drive(\n () =>\n this.#transport.sendMessages({\n trigger: 'submit-message',\n chatId: this.#chatId,\n messageId: undefined,\n messages: [buildUserMessage(input)],\n abortSignal: controller.signal,\n // Only object inputs flow as the request `body` (the turn text is always in `messages`);\n // a primitive input is carried by the user message, never spread into the body.\n body: typeof input === 'object' && input !== null ? input : undefined,\n }),\n controller,\n )\n }\n\n /** Resume an interrupted stream via the transport's `reconnectToStream` (no-op when unavailable). */\n reconnect = (): void => {\n const controller = new AbortController()\n this.#controller = controller\n this.#status = 'streaming'\n this.#emit()\n void this.#drive(() => this.#transport.reconnectToStream({ chatId: this.#chatId }), controller)\n }\n\n /** Abort an in-flight stream (not an error — leaves messages as-is). */\n abort = (): void => {\n this.#controller?.abort()\n this.#controller = null\n }\n\n /** Clear messages + error, back to idle. */\n reset = (): void => {\n this.abort()\n this.#messages = []\n this.#error = undefined\n this.#status = 'idle'\n this.#emit()\n }\n\n /** Settle a paused HITL approval via the transport's HITL path (HTTP POST or inline callback). */\n approve = async (approvalId: string, decision: ApprovalDecision): Promise<void> => {\n await this.#transport.approve?.(approvalId, decision)\n }\n}\n","import type { ChatTransport, UIMessage, UIMessageChunk } from 'ai'\n\nimport { responseToChunkStream } from './consume-ui-message-stream.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\n/** Extra request headers — a static record OR a resolver called per request (for dynamic auth). */\nexport type HeadersResolver = Record<string, string> | (() => Record<string, string> | undefined)\n\nexport interface HttpTransportOptions {\n /** Agent endpoint path or URL, e.g. `/api/agents/support`. */\n api: string\n /**\n * Extra request headers (e.g. auth). Static record OR a resolver evaluated on EVERY request — pass a\n * resolver when the value is dynamic (a rotating JWT), so a stale header is never sent. Merged UNDER\n * per-request headers.\n */\n headers?: HeadersResolver\n /** Override fetch (primarily for tests / non-browser hosts) — static; resolved once at construction. */\n fetch?: typeof fetch\n}\n\n/** Normalize `ai`'s `Record | Headers | undefined` header option into a plain record. */\nfunction toRecord(headers: Record<string, string> | Headers | undefined): Record<string, string> {\n if (headers === undefined) return {}\n if (headers instanceof Headers) return Object.fromEntries(headers.entries())\n return headers\n}\n\n/**\n * M41 (ADR-0050 D3) — `ChatTransport` over the web agent path.\n *\n * - `sendMessages`: `POST <api>` with the UIMessageStream `accept` + the `X-Theo-Action` CSRF header\n * (HTTP method + headers are identical to the pre-M41 `useAgent` fetch; the body shape is a superset —\n * `{ ...input, messages: [UIMessage] }` — which the server's dual-path parser accepts, so no\n * regression), captures the server-minted `x-theokit-run-id`, and returns `ReadableStream<UIMessageChunk>`\n * via `ai`'s own SSE parser (`responseToChunkStream`).\n * - `reconnectToStream`: `GET <api>/runs/<runId>/stream` (M37 durable transport); 404 → `null` (the run\n * completed / was evicted). A caller may pass a `Last-Event-ID` header to resume only the tail; by\n * default the server replays the run from the start and the client upserts by message id (idempotent).\n * - `approve`: `POST <api>/approve/<id>` (out-of-band HITL settle).\n *\n * Implemented directly (not by subclassing `DefaultChatTransport`) because reconnect keys on our\n * server-minted `runId` captured from a response header, which the base class does not expose — see\n * ADR-0050 D3.\n */\nexport class HttpTransport implements AgentTransport {\n readonly #api: string\n readonly #headers: HeadersResolver\n readonly #fetch: typeof fetch\n /** Server-minted id of the last run (from `x-theokit-run-id`) — the reconnect key. */\n #lastRunId: string | undefined\n\n constructor(options: HttpTransportOptions) {\n this.#api = options.api\n this.#headers = options.headers ?? {}\n this.#fetch = options.fetch ?? globalThis.fetch\n }\n\n /** Resolve the configured headers per request (a resolver evaluates now — dynamic auth is never stale). */\n #resolveHeaders(): Record<string, string> {\n return (typeof this.#headers === 'function' ? this.#headers() : this.#headers) ?? {}\n }\n\n async sendMessages(\n options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0],\n ): Promise<ReadableStream<UIMessageChunk>> {\n const { messages, abortSignal, headers, body } = options\n // Only spread an object body (never a primitive — that would emit char-indexed keys). The server\n // accepts `{ messages }` (ai shape) AND `{ ...input }` (typed input), preferring the turn text.\n const extra = typeof body === 'object' ? (body as Record<string, unknown>) : undefined\n const response = await this.#fetch(this.#api, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n 'X-Theo-Action': '1',\n ...this.#resolveHeaders(),\n ...toRecord(headers),\n },\n body: JSON.stringify({ ...extra, messages }),\n signal: abortSignal,\n })\n if (!response.ok) {\n throw new Error(\n `Agent request to ${this.#api} failed: ${response.status} ${response.statusText}`,\n )\n }\n this.#lastRunId = response.headers.get('x-theokit-run-id') ?? undefined\n return responseToChunkStream(response)\n }\n\n async reconnectToStream(\n options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0],\n ): Promise<ReadableStream<UIMessageChunk> | null> {\n if (this.#lastRunId === undefined) return null\n const response = await this.#fetch(`${this.#api}/runs/${this.#lastRunId}/stream`, {\n method: 'GET',\n headers: { ...this.#resolveHeaders(), ...toRecord(options.headers) },\n })\n if (response.status === 404) return null\n if (!response.ok) {\n throw new Error(\n `Agent reconnect to run ${this.#lastRunId} failed: ${response.status} ${response.statusText}`,\n )\n }\n return responseToChunkStream(response)\n }\n\n async approve(approvalId: string, decision: ApprovalDecision): Promise<void> {\n const response = await this.#fetch(`${this.#api}/approve/${approvalId}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'X-Theo-Action': '1',\n ...this.#resolveHeaders(),\n },\n body: JSON.stringify(decision),\n })\n if (!response.ok) {\n throw new Error(`Approve ${approvalId} failed: ${response.status} ${response.statusText}`)\n }\n }\n}\n","import type { ChatTransport, UIMessage, UIMessageChunk } from 'ai'\n\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\n/** An inline approval request handed to the transport's resolver (structural — no server import). */\nexport interface InProcessApprovalRequestLike {\n approvalId: string\n toolName: string\n opts: unknown\n}\n\n/** Resolve one gated-tool approval inline (mirrors the SDK's `boolean | HitlDecision` return). */\nexport type InProcessAwaitApproval = (\n req: InProcessApprovalRequestLike,\n) => Promise<boolean | ApprovalDecision>\n\n/** The input the injected runner receives (structurally compatible with `StreamAgentTurnInProcessInput`). */\nexport interface InProcessRunInput {\n message: string\n sessionId?: string\n signal?: AbortSignal\n awaitApproval?: InProcessAwaitApproval\n}\n\n/**\n * The in-process turn runner. The consumer binds `streamAgentTurnInProcess(mod, apiKey, …)`:\n * `new InProcessTransport({ run: (input) => streamAgentTurnInProcess(mod, apiKey, input) })`.\n * Injecting it keeps this client module decoupled from `server/` and makes the transport testable.\n */\nexport type InProcessRunner = (input: InProcessRunInput) => AsyncGenerator<UIMessageChunk>\n\nexport interface InProcessTransportOptions {\n run: InProcessRunner\n}\n\n/** Bridge an `AsyncGenerator<UIMessageChunk>` into a pull-based `ReadableStream<UIMessageChunk>`. */\nfunction generatorToStream(gen: AsyncGenerator<UIMessageChunk>): ReadableStream<UIMessageChunk> {\n return new ReadableStream<UIMessageChunk>({\n async pull(controller) {\n try {\n const result = await gen.next()\n if (result.done === true) {\n controller.close()\n return\n }\n // After the done-guard, `result` is an IteratorYieldResult<UIMessageChunk> — value is typed.\n controller.enqueue(result.value)\n } catch (err) {\n controller.error(err)\n }\n },\n async cancel() {\n await gen.return(undefined)\n },\n })\n}\n\n/** Extract the turn text from the last user message's text parts. */\nfunction extractLastUserText(messages: readonly UIMessage[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i]\n if (message.role !== 'user') continue\n const text = message.parts\n .filter((part): part is { type: 'text'; text: string } => part.type === 'text')\n .map((part) => part.text)\n .join('')\n if (text.length > 0) return text\n }\n return ''\n}\n\n/**\n * M41 (ADR-0050 D4) — `ChatTransport` over the in-process seam (`streamAgentTurnInProcess`), for the\n * terminal/desktop surfaces that run client + server in ONE process (no HTTP loopback).\n *\n * - `sendMessages`: bridge the injected runner's `AsyncGenerator<UIMessageChunk>` into a\n * `ReadableStream<UIMessageChunk>` (honoring `abortSignal`, which the runner forwards to the SDK).\n * - `reconnectToStream`: always `null` — a single process has no dropped server-side stream to resume\n * (mirrors `ai`'s `DirectChatTransport`).\n * - `approve`: resolve the pending inline approval by id (the run parks on `awaitApproval`). An unknown\n * id rejects (fail-fast, Rule 8 — never a silent resolve).\n *\n * Error asymmetry vs `HttpTransport` (by design, matching the `ChatTransport` contract): a runner that\n * throws SYNCHRONOUSLY surfaces the error when the stream is READ (via `controller.error`), not from the\n * `sendMessages` promise — whereas `HttpTransport` throws from `sendMessages` on a non-2xx response.\n */\nexport class InProcessTransport implements AgentTransport {\n readonly #run: InProcessRunner\n /** Pending inline approvals: approvalId → resolver of the parked `awaitApproval` promise. */\n readonly #pending = new Map<string, (decision: boolean | ApprovalDecision) => void>()\n\n constructor(options: InProcessTransportOptions) {\n this.#run = options.run\n }\n\n #awaitApproval: InProcessAwaitApproval = (req) =>\n new Promise<boolean | ApprovalDecision>((resolve, reject) => {\n // Approval ids are server-minted UUIDs — a collision means a real bug (two turns reusing an id).\n // Fail fast rather than silently overwrite the earlier turn's parked resolver (Rule 8).\n if (this.#pending.has(req.approvalId)) {\n reject(new Error(`Duplicate pending approval id '${req.approvalId}' — ids must be unique.`))\n return\n }\n this.#pending.set(req.approvalId, resolve)\n })\n\n sendMessages(\n options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0],\n ): Promise<ReadableStream<UIMessageChunk>> {\n const { messages, abortSignal } = options\n const generator = this.#run({\n message: extractLastUserText(messages),\n signal: abortSignal ?? undefined,\n awaitApproval: this.#awaitApproval,\n })\n return Promise.resolve(generatorToStream(generator))\n }\n\n reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null> {\n return Promise.resolve(null)\n }\n\n approve(approvalId: string, decision: ApprovalDecision): Promise<void> {\n const resolve = this.#pending.get(approvalId)\n if (resolve === undefined) {\n return Promise.reject(\n new Error(`No pending approval '${approvalId}' (unknown or already settled).`),\n )\n }\n this.#pending.delete(approvalId)\n resolve(decision)\n return Promise.resolve()\n }\n}\n","/**\n * <Link> — React Router Link with route prefetching.\n *\n * Wraps react-router's <Link> with prefetch behavior:\n * - `intent` (default): prefetch on hover + focus (~200ms before click)\n * - `viewport`: prefetch when visible (IntersectionObserver)\n * - `none`: no prefetch (same as plain react-router Link)\n *\n * Uses `<link rel=\"prefetch\">` (not modulepreload) because route paths\n * can be prefetched directly — no Vite manifest resolution needed (EC-1).\n */\nimport {\n Link as RouterLink,\n type LinkProps as RouterLinkProps,\n} from 'react-router'\nimport { useRef, useCallback, useEffect } from 'react'\n\nexport type PrefetchBehavior = 'none' | 'intent' | 'viewport'\n\nexport interface LinkProps extends RouterLinkProps {\n /** Prefetch strategy. Default: 'intent' (on hover + focus). */\n prefetch?: PrefetchBehavior\n}\n\n/** Deduplication — each URL prefetched at most once per session. */\nconst prefetched = new Set<string>()\n\nfunction injectPrefetch(href: string): void {\n // EC-2: SSR guard — document unavailable on server\n if (typeof document === 'undefined') return\n if (prefetched.has(href)) return\n prefetched.add(href)\n\n const link = document.createElement('link')\n link.rel = 'prefetch'\n link.href = href\n document.head.appendChild(link)\n}\n\nfunction resolveTo(to: LinkProps['to']): string {\n if (typeof to === 'string') return to\n return to?.pathname ?? ''\n}\n\n/**\n * TheoKit Link — drop-in replacement for react-router Link with prefetch.\n *\n * @example\n * ```tsx\n * import { Link } from 'theokit/client'\n *\n * <Link to=\"/contacts\">Contacts</Link>\n * <Link to=\"/dashboard\" prefetch=\"viewport\">Dashboard</Link>\n * <Link to=\"/settings\" prefetch=\"none\">Settings</Link>\n * ```\n */\nexport function Link({ prefetch = 'intent', to, onMouseEnter, onFocus, ...rest }: LinkProps) {\n const ref = useRef<HTMLAnchorElement>(null)\n\n const handleIntent = useCallback(\n (event: React.MouseEvent<HTMLAnchorElement> | React.FocusEvent<HTMLAnchorElement>) => {\n if (prefetch === 'intent') {\n injectPrefetch(resolveTo(to))\n }\n // Forward original handlers\n if (event.type === 'mouseenter' && onMouseEnter) {\n ;(onMouseEnter as React.MouseEventHandler<HTMLAnchorElement>)(event as React.MouseEvent<HTMLAnchorElement>)\n }\n if (event.type === 'focus' && onFocus) {\n ;(onFocus as React.FocusEventHandler<HTMLAnchorElement>)(event as React.FocusEvent<HTMLAnchorElement>)\n }\n },\n [prefetch, to, onMouseEnter, onFocus],\n )\n\n // Viewport mode: IntersectionObserver\n useEffect(() => {\n if (prefetch !== 'viewport' || !ref.current) return\n if (typeof IntersectionObserver === 'undefined') return // SSR guard\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n injectPrefetch(resolveTo(to))\n observer.disconnect()\n }\n },\n { rootMargin: '200px' }, // prefetch slightly before visible\n )\n observer.observe(ref.current)\n return () => observer.disconnect()\n }, [prefetch, to])\n\n return (\n <RouterLink\n ref={ref}\n to={to}\n onMouseEnter={handleIntent}\n onFocus={handleIntent}\n {...rest}\n />\n )\n}\n","/**\n * <Metadata> — SEO-ready head tags from a single component.\n *\n * Uses React 19's native <title>/<meta>/<link> hoisting to <head>.\n * No build-time extraction needed — works in SSR and client.\n *\n * @example\n * ```tsx\n * import { Metadata } from 'theokit/client'\n *\n * export default function ContactsPage() {\n * return (\n * <>\n * <Metadata\n * title=\"Contacts | My CRM\"\n * description=\"Manage your contacts\"\n * ogImage=\"/og/contacts.png\"\n * canonical=\"https://mycrm.com/contacts\"\n * />\n * <h1>Contacts</h1>\n * </>\n * )\n * }\n * ```\n */\n\nexport interface MetadataProps {\n title?: string\n description?: string\n canonical?: string\n ogTitle?: string\n ogDescription?: string\n ogImage?: string\n ogType?: string\n ogUrl?: string\n twitterCard?: 'summary' | 'summary_large_image'\n /** Custom meta tags rendered as children */\n children?: React.ReactNode\n}\n\nexport function Metadata(props: MetadataProps) {\n const ogTitle = props.ogTitle ?? props.title\n const ogDesc = props.ogDescription ?? props.description\n\n return (\n <>\n {props.title && <title>{props.title}</title>}\n {props.description && <meta name=\"description\" content={props.description} />}\n {props.canonical && <link rel=\"canonical\" href={props.canonical} />}\n {ogTitle && <meta property=\"og:title\" content={ogTitle} />}\n {ogDesc && <meta property=\"og:description\" content={ogDesc} />}\n {props.ogImage && <meta property=\"og:image\" content={props.ogImage} />}\n {props.ogType && <meta property=\"og:type\" content={props.ogType} />}\n {props.ogUrl && <meta property=\"og:url\" content={props.ogUrl} />}\n {props.twitterCard && <meta name=\"twitter:card\" content={props.twitterCard} />}\n {props.children}\n </>\n )\n}\n","/**\n * <Image> — optimized image component with lazy loading.\n *\n * Renders a standard <img> with:\n * - loading=\"lazy\" by default (eager with priority={true})\n * - decoding=\"async\" for non-blocking decode\n * - width/height for CLS prevention\n * - srcSet/sizes forwarded for responsive images\n *\n * No CDN, no Sharp, no build-time optimization — pure HTML attributes\n * that deliver 80% of the performance value at zero complexity.\n *\n * @example\n * ```tsx\n * import { Image } from 'theokit/client'\n *\n * <Image src=\"/team.jpg\" alt=\"Team photo\" width={800} height={600} />\n * <Image src=\"/hero.jpg\" alt=\"Hero\" priority />\n * <Image\n * src=\"/product.jpg\"\n * alt=\"Product\"\n * width={400}\n * height={300}\n * srcSet=\"/product-400.jpg 400w, /product-800.jpg 800w\"\n * sizes=\"(max-width: 768px) 100vw, 400px\"\n * />\n * ```\n */\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL (required). */\n src: string\n /** Alt text for accessibility (required). */\n alt: string\n /** If true, loading=\"eager\" — use for above-the-fold images. */\n priority?: boolean\n}\n\nexport function Image({ priority, loading, decoding, ...props }: ImageProps) {\n return (\n <img\n loading={loading ?? (priority ? 'eager' : 'lazy')}\n decoding={decoding ?? 'async'}\n {...props}\n />\n )\n}\n","/**\n * M30 (ADR-0041) — client host for MCP App `ui://` resources.\n *\n * Renders a tool's `ui://` HTML in a SANDBOXED iframe and bridges a capability-scoped guest API over\n * `postMessage`. Security is load-bearing:\n * - the iframe is `sandbox=\"allow-scripts\"` ONLY — NOT `allow-same-origin`, so the guest runs at a\n * null origin and cannot touch the parent DOM, cookies, or storage;\n * - the host only honors messages whose `source` is the iframe's own `contentWindow`;\n * - the guest API is a fixed, capability-scoped vocabulary (`callServerTool`, `sendMessage`) — any\n * other message type is ignored.\n */\n\n/** The guest → host message vocabulary (capability-scoped). */\nexport type GuestMessage =\n | { type: 'callServerTool'; id: string; tool: string; args?: unknown }\n | { type: 'sendMessage'; text: string }\n\n/** Callbacks the host wires for the guest API. */\nexport interface McpAppHostOptions {\n /** Guest asked to call a server tool — return its result (posted back to the guest by id). */\n onCallServerTool: (tool: string, args: unknown) => unknown\n /** Guest emitted a chat message to the host app. */\n onSendMessage?: (text: string) => void\n}\n\n/**\n * Pure bridge: interpret one guest message and (for `callServerTool`) post the result back via\n * `post`. Exported for unit testing without a DOM. Unknown message shapes are ignored — the guest\n * API is capability-scoped, not an open RPC surface.\n */\nexport function createGuestMessageHandler(\n opts: McpAppHostOptions,\n post: (message: unknown) => void,\n): (data: unknown) => Promise<void> {\n return async (data: unknown): Promise<void> => {\n if (typeof data !== 'object' || data === null) return\n const msg = data as Partial<GuestMessage> & { type?: string }\n if (\n msg.type === 'callServerTool' &&\n typeof msg.id === 'string' &&\n typeof msg.tool === 'string'\n ) {\n const result = await opts.onCallServerTool(msg.tool, msg.args)\n post({ type: 'callServerTool:result', id: msg.id, result })\n return\n }\n if (msg.type === 'sendMessage' && typeof (msg as { text?: unknown }).text === 'string') {\n opts.onSendMessage?.((msg as { text: string }).text)\n }\n }\n}\n\n/** Handle returned by {@link mountMcpApp}. */\nexport interface McpAppHandle {\n iframe: HTMLIFrameElement\n /** Remove the message listener and the iframe. */\n dispose: () => void\n}\n\n/** The sandbox tokens the guest iframe is allowed — scripts only, NEVER `allow-same-origin`. */\nexport const MCP_APP_SANDBOX = 'allow-scripts'\n\n/**\n * Mount an MCP App resource's HTML in a sandboxed iframe inside `container`, wiring the guest API.\n * The HTML comes from `resources/read` (see `mcp-app-resources.ts`). Returns a handle to dispose.\n */\nexport function mountMcpApp(\n container: HTMLElement,\n resource: { html: string },\n opts: McpAppHostOptions,\n): McpAppHandle {\n const iframe = container.ownerDocument.createElement('iframe')\n // Security: scripts only, null origin. Do NOT add allow-same-origin.\n iframe.setAttribute('sandbox', MCP_APP_SANDBOX)\n iframe.srcdoc = resource.html\n container.appendChild(iframe)\n\n const post = (message: unknown): void => {\n // The guest is a sandboxed srcdoc iframe (allow-scripts, NO allow-same-origin) → its origin is\n // the opaque string \"null\", which cannot be used as a reliable targetOrigin. '*' is the only\n // valid target for a null-origin sandboxed guest; the sandbox (no navigation, no same-origin)\n // is what prevents a cross-origin leak, not the targetOrigin string.\n // eslint-disable-next-line sonarjs/post-message -- sandboxed null-origin iframe: '*' is correct\n iframe.contentWindow?.postMessage(message, '*')\n }\n const handle = createGuestMessageHandler(opts, post)\n\n const onMessage = (event: MessageEvent): void => {\n // Only trust messages from THIS iframe's guest window.\n if (event.source !== iframe.contentWindow) return\n void handle(event.data)\n }\n const view = container.ownerDocument.defaultView\n view?.addEventListener('message', onMessage)\n\n return {\n iframe,\n dispose: () => {\n view?.removeEventListener('message', onMessage)\n iframe.remove()\n },\n }\n}\n"],"mappings":"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","names":["useRef","jsx","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/theo-fetch.ts","../../src/client/batch.ts","../../src/client/batch-transport.ts","../../src/client/app-client.ts","../../src/client/consume-ui-message-stream.ts","../../src/client/use-agent.ts","../../src/client/agent-client.ts","../../src/client/http-transport.ts","../../src/client/last-user-text.ts","../../src/client/in-process-transport.ts","../../src/client/channel-transport.ts","../../src/client/link.tsx","../../src/client/metadata.tsx","../../src/client/image.tsx","../../src/client/mcp-app-host.ts"],"sourcesContent":["import superjson from 'superjson'\nimport type { z } from 'zod'\n\nimport type { TheoErrorCode, TheoErrorEnvelope } from '../core/contracts/error-envelope.js'\n\nimport { getGlobalBatcher } from './batch-transport.js'\n\n// --- Transformer (T1.3) ---\n\n/**\n * Module-scoped flag preventing the transformer-mismatch warning from\n * firing more than once per session (EC-6).\n */\nlet mismatchWarned = false\n\n/** Test-only helper to reset the warned flag between assertions. */\nexport function __resetMismatchWarningForTests(): void {\n mismatchWarned = false\n}\n\n/**\n * Deserialize a fetch response body according to the negotiated transformer.\n *\n * `serverTransformerName` comes from the `x-theo-transformer` response header\n * (null when absent — server is using the default JSON path).\n * `clientTransformerName` is the transformer the client was built with\n * (typically injected via a Vite virtual module; falls back to `'json'`).\n *\n * Mismatch fires a single console.warn and falls back to JSON.parse (EC-5/EC-6).\n */\nexport function deserializeFetchResponse(\n raw: string,\n serverTransformerName: string | null,\n clientTransformerName: string,\n): unknown {\n // `raw` is typed `string`, but stay defensive: callers pass `await response.text()`\n // which can be empty.\n if (raw === '') {\n return null\n }\n\n const serverEffective = serverTransformerName ?? 'json'\n if (serverEffective !== clientTransformerName && !mismatchWarned) {\n mismatchWarned = true\n console.warn(\n `[theokit] transformer mismatch: server=${serverEffective}, client=${clientTransformerName}. Falling back to JSON.parse.`,\n )\n }\n\n if (serverEffective === 'superjson' && clientTransformerName === 'superjson') {\n const wrapped = JSON.parse(raw) as Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize(wrapped)\n }\n\n // Default path (json) or mismatch fallback\n return JSON.parse(raw)\n}\n\n// --- Utility Types ---\n\n/** Infer the response type from a route's handler return */\nexport type InferResponse<T> = T extends { handler: (...args: never[]) => infer R }\n ? Awaited<R>\n : unknown\n\n/** Extract the query Zod schema type, handling optional properties */\ntype ExtractQuery<T> = T extends { query?: infer Q } ? (Q extends z.ZodType ? Q : never) : never\n\n/** Extract the body Zod schema type, handling optional properties */\ntype ExtractBody<T> = T extends { body?: infer B } ? (B extends z.ZodType ? B : never) : never\n\n/** Infer query type from a route's query Zod schema */\nexport type InferQuery<T> = [ExtractQuery<T>] extends [never]\n ? undefined\n : ExtractQuery<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractQuery<T>>\n\n/** Infer body type from a route's body Zod schema */\nexport type InferBody<T> = [ExtractBody<T>] extends [never]\n ? undefined\n : ExtractBody<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractBody<T>>\n\n/** Build the options type based on what schemas the route has */\nexport type TheoFetchOptions<T> = Omit<RequestInit, 'body' | 'method'> &\n (InferQuery<T> extends undefined ? { query?: never } : { query: InferQuery<T> }) &\n (InferBody<T> extends undefined ? { body?: never } : { body: InferBody<T> })\n\n// --- Error Class ---\n\n/**\n * G5 T2.1 — extract a TheoErrorEnvelope from a response body. Supports both\n * the new envelope-at-root shape (`{ code, message, ext?, ... }`, blueprint\n * Recommendations § concrete shape) and the legacy nested shape\n * (`{ error: { code, message, issues? } }`, G3 SerializedActionResult).\n *\n * Falls back to `INTERNAL_SERVER_ERROR` with a synthetic message when the\n * body shape is unrecognized. Pure; no I/O.\n */\nfunction extractEnvelope(status: number, body: unknown): TheoErrorEnvelope {\n if (!body || typeof body !== 'object') {\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n // New shape — envelope at root\n if (typeof obj.code === 'string' && typeof obj.message === 'string') {\n return {\n code: obj.code as TheoErrorCode,\n message: obj.message,\n cause: obj.cause,\n meta: obj.meta as Record<string, unknown> | undefined,\n ext: obj.ext,\n }\n }\n // Legacy shape — { error: { code, message, ... } }\n if (obj.error && typeof obj.error === 'object') {\n const nested = obj.error as Record<string, unknown>\n return {\n code:\n typeof nested.code === 'string' ? (nested.code as TheoErrorCode) : 'INTERNAL_SERVER_ERROR',\n message: typeof nested.message === 'string' ? nested.message : `HTTP ${String(status)}`,\n }\n }\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n}\n\n/**\n * Pull a single string field from an object, returning undefined if missing\n * or non-string. Helper for `extractLegacyFields` to stay under the\n * complexity ceiling.\n */\nfunction strField(obj: Record<string, unknown> | null, key: string): string | undefined {\n const v = obj?.[key]\n return typeof v === 'string' ? v : undefined\n}\n\n/**\n * Pull the canonical {message, code, issues} from either an envelope-at-root\n * body or the legacy { error: {...} } body. Pure.\n */\nfunction extractLegacyFields(\n status: number,\n body: unknown,\n): { message: string; code?: string; issues?: unknown[] } {\n if (!body || typeof body !== 'object') {\n return { message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n const nested =\n obj.error && typeof obj.error === 'object' ? (obj.error as Record<string, unknown>) : null\n const issues = Array.isArray(nested?.issues) ? nested.issues : undefined\n return {\n message: strField(obj, 'message') ?? strField(nested, 'message') ?? `HTTP ${String(status)}`,\n code: strField(obj, 'code') ?? strField(nested, 'code'),\n issues,\n }\n}\n\nexport class TheoFetchError extends Error {\n status: number\n code?: string\n issues?: unknown[]\n /**\n * G5 T2.1 — canonical envelope view of the server-side error. Use this in\n * consumer code that wants to switch on a typed TheoErrorCode instead of\n * coupling to the legacy `.status` / `.code` flat fields.\n */\n readonly envelope: TheoErrorEnvelope\n\n constructor(status: number, body?: unknown) {\n const legacy = extractLegacyFields(status, body)\n super(legacy.message)\n this.name = 'TheoFetchError'\n this.status = status\n this.code = legacy.code\n this.issues = legacy.issues\n this.envelope = extractEnvelope(status, body)\n }\n}\n\n/**\n * Serialize a query-param value to a string. Handles primitives, dates,\n * and falls back to JSON for arrays/objects. Avoids the\n * `[object Object]` foot-gun that `no-base-to-string` warns against.\n */\nfunction stringifyQueryValue(value: unknown): string {\n if (value === null) return 'null'\n if (value instanceof Date) return value.toISOString()\n switch (typeof value) {\n case 'string':\n return value\n case 'number':\n case 'boolean':\n case 'bigint':\n return String(value)\n default:\n return JSON.stringify(value)\n }\n}\n\n// --- Main Function ---\n\ninterface TheoFetchInternalOptions {\n method?: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\n/**\n * Resolve the request origin per the documented fallback hierarchy. Pure\n * helper extracted to keep `theoFetch` under the complexity ceiling.\n * 1. `globalThis.location.origin` (browser)\n * 2. `globalThis.__THEO_ORIGIN__` (build-time literal)\n * 3. `process.env.THEO_ORIGIN` (escape hatch)\n * 4. `http://localhost` (placeholder for URL parsing — the URL is built\n * relative so only pathname+search ever flows to the wire)\n */\nfunction resolveRequestOrigin(): string {\n const g = globalThis as { location?: { origin?: string }; __THEO_ORIGIN__?: string }\n const fromEnv = typeof process !== 'undefined' ? process.env.THEO_ORIGIN : undefined\n return g.location?.origin ?? g.__THEO_ORIGIN__ ?? fromEnv ?? 'http://localhost'\n}\n\nfunction buildFetchUrl(path: string, query: Record<string, unknown> | undefined): URL {\n const fetchUrl = new URL(path, resolveRequestOrigin())\n if (!query) return fetchUrl\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) {\n fetchUrl.searchParams.set(k, stringifyQueryValue(v))\n }\n }\n return fetchUrl\n}\n\n/**\n * Normalize `HeadersInit` (Headers / `[string, string][]` / Record) into a\n * single plain `Record<string, string>`. Plain-object output is required\n * by callers that introspect headers via index access (test fixtures use\n * `(init.headers as Record<string, string>)['Content-Type']`).\n */\nfunction normalizeHeaders(input: HeadersInit | undefined): Record<string, string> {\n const out: Record<string, string> = {}\n if (!input) return out\n if (input instanceof Headers) {\n input.forEach((value, key) => {\n out[key] = value\n })\n return out\n }\n if (Array.isArray(input)) {\n for (const [key, value] of input) out[key] = value\n return out\n }\n for (const [key, value] of Object.entries(input)) {\n out[key] = value\n }\n return out\n}\n\nfunction buildRequestInit(opts: TheoFetchInternalOptions): RequestInit {\n const init: RequestInit = {}\n if (opts.method !== undefined) init.method = opts.method\n if (opts.signal !== undefined) init.signal = opts.signal\n\n const headers = normalizeHeaders(opts.headers)\n init.headers = headers\n\n if (opts.body !== undefined) {\n init.body = JSON.stringify(opts.body)\n headers['Content-Type'] = 'application/json'\n }\n\n // Phase 5 — Auto-attach `X-Theo-Action: 1` for state-mutating methods so\n // the framework's CSRF check passes when servers run in `strict` mode.\n // Safe methods (GET/HEAD/OPTIONS) skip the header to keep them cacheable.\n const method = (opts.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {\n headers['X-Theo-Action'] = '1'\n }\n return init\n}\n\nasync function tryBatcher(\n url: string,\n options: TheoFetchInternalOptions,\n): Promise<{ matched: true; result: unknown } | { matched: false }> {\n const batcher = getGlobalBatcher()\n if (!batcher) return { matched: false }\n try {\n const result = await batcher.dispatch({\n path: url,\n method: options.method ?? 'GET',\n query: options.query,\n body: options.body,\n })\n return { matched: true, result }\n } catch {\n // Batcher failure: fall through to direct fetch (graceful degrade).\n return { matched: false }\n }\n}\n\nexport async function theoFetch<T>(\n url: string,\n options?: TheoFetchOptions<T>,\n): Promise<InferResponse<T>> {\n const internal = (options ?? {}) as unknown as TheoFetchInternalOptions\n\n // T1.5 — Transparent batching when globalThis.__THEO_BATCHING__ is truthy.\n const batchAttempt = await tryBatcher(url, internal)\n if (batchAttempt.matched) {\n return batchAttempt.result as InferResponse<T>\n }\n\n const fetchUrl = buildFetchUrl(url, internal.query)\n const init = buildRequestInit(internal)\n const response = await fetch(fetchUrl.toString(), init)\n\n if (!response.ok) {\n let errorBody: unknown\n try {\n errorBody = await response.json()\n } catch {\n // Non-JSON error response\n }\n throw new TheoFetchError(response.status, errorBody)\n }\n\n // Handle 204 No Content (EC-1)\n if (response.status === 204) {\n return null as InferResponse<T>\n }\n\n // Check for empty body\n const contentLength = response.headers.get('content-length')\n if (contentLength === '0') {\n return null as InferResponse<T>\n }\n\n // T1.3 — transformer-aware deserialization\n const serverTransformerName = response.headers.get('x-theo-transformer')\n const clientTransformerName = resolveClientTransformerName()\n const text = await response.text()\n return deserializeFetchResponse(\n text,\n serverTransformerName,\n clientTransformerName,\n ) as InferResponse<T>\n}\n\n/**\n * Read the client-configured transformer name. Default `'json'`.\n *\n * In a Vite build, this is overridden by virtual module\n * `/@theo/runtime-config` which sets `globalThis.__THEO_TRANSFORMER__`.\n * Outside Vite (Node SSR, tests) the default applies.\n */\nfunction resolveClientTransformerName(): string {\n const g = globalThis as { __THEO_TRANSFORMER__?: string }\n return g.__THEO_TRANSFORMER__ ?? 'json'\n}\n","/**\n * T5.1 — client-side microtask batching.\n *\n * Collects all `dispatch` calls within the same microtask and sends them as a\n * single HTTP POST to the configured transport. Each caller's promise resolves\n * with its own result; one failed item does not break the others (per-item\n * error isolation).\n *\n * Designed as a transport-agnostic primitive so unit tests do not require\n * network access. The default transport (fetch to `/api/__theo_batch__`)\n * lives alongside this module but is created by the consumer (e.g., theoFetch).\n */\n\nexport interface BatchRequest {\n path: string\n method: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: Record<string, string>\n}\n\nexport type BatchResponse =\n | { index: number; data: unknown }\n | { index: number; error: { message: string; code?: string } }\n\nexport type BatchTransport = (requests: BatchRequest[]) => Promise<BatchResponse[]>\n\nexport interface BatcherOptions {\n transport: BatchTransport\n /** Maximum batch size before flushing into multiple parallel batches. */\n max?: number\n}\n\nexport interface Batcher {\n dispatch(req: BatchRequest): Promise<unknown>\n}\n\ninterface PendingCall {\n req: BatchRequest\n resolve: (value: unknown) => void\n reject: (reason: unknown) => void\n}\n\nexport function createBatcher(options: BatcherOptions): Batcher {\n const max = options.max ?? 32\n let queue: PendingCall[] = []\n let flushScheduled = false\n\n function flush(): void {\n flushScheduled = false\n const current = queue\n queue = []\n if (current.length === 0) return\n\n // Split into chunks respecting max\n const chunks: PendingCall[][] = []\n for (let i = 0; i < current.length; i += max) {\n chunks.push(current.slice(i, i + max))\n }\n\n for (const chunk of chunks) {\n const payload: BatchRequest[] = chunk.map((p) => p.req)\n options\n .transport(payload)\n .then((results) => {\n for (let i = 0; i < chunk.length; i++) {\n // `results[i]` could be undefined at runtime when the transport\n // returns fewer entries than the chunk; TypeScript's strict\n // typing without `noUncheckedIndexedAccess` does not surface\n // this, so we hand-narrow.\n const result = results.length > i ? results[i] : undefined\n if (result === undefined) {\n chunk[i].reject(new Error(`Batch transport returned no result for index ${i}`))\n continue\n }\n if ('error' in result) {\n const err = new Error(result.error.message)\n ;(err as { code?: string }).code = result.error.code\n chunk[i].reject(err)\n } else {\n chunk[i].resolve(result.data)\n }\n }\n })\n .catch((err: unknown) => {\n for (const item of chunk) item.reject(err)\n })\n }\n }\n\n return {\n dispatch(req: BatchRequest): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n queue.push({ req, resolve, reject })\n if (!flushScheduled) {\n flushScheduled = true\n queueMicrotask(flush)\n }\n })\n },\n }\n}\n","/**\n * T1.5 — Default HTTP transport for the client batcher.\n *\n * Wraps `fetch` to POST `/api/__theo_batch__` with the collected requests\n * and return the array of per-item results.\n */\n\nimport {\n createBatcher,\n type BatchTransport,\n type Batcher,\n type BatchRequest,\n type BatchResponse,\n} from './batch.js'\n\nconst BATCH_ENDPOINT = '/api/__theo_batch__'\n\nexport interface CreateBatchTransportOptions {\n /** Override fetch (default: globalThis.fetch). Used by tests. */\n fetchImpl?: typeof fetch\n /** Override endpoint (default '/api/__theo_batch__'). */\n endpoint?: string\n}\n\nexport function createBatchTransport(options: CreateBatchTransportOptions = {}): BatchTransport {\n const fetchImpl = options.fetchImpl ?? fetch\n const endpoint = options.endpoint ?? BATCH_ENDPOINT\n return async (requests: BatchRequest[]): Promise<BatchResponse[]> => {\n const response = await fetchImpl(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requests }),\n })\n if (!response.ok) {\n throw new Error(`Batch transport returned ${response.status}`)\n }\n const payload = (await response.json()) as { results?: BatchResponse[] }\n if (!Array.isArray(payload.results)) {\n throw new Error('Batch response missing results array')\n }\n // Map results to indexed BatchResponse shape (server already returns the right form)\n return payload.results.map((item, index) => {\n if ('error' in item) {\n return { index, error: (item as { error: { message: string; code?: string } }).error }\n }\n return { index, data: (item as { data: unknown }).data }\n })\n }\n}\n\n// --- EC-7: singleton batcher per page, lazy-instantiated ---\n\nlet globalBatcher: Batcher | undefined\n\n/** Test-only — reset the module-scope singleton between assertions. */\nexport function __resetGlobalBatcherForTests(): void {\n globalBatcher = undefined\n}\n\n/**\n * Returns the global batcher singleton when `globalThis.__THEO_BATCHING__` is\n * truthy; undefined otherwise. Lazy-instantiated on first call.\n */\nexport function getGlobalBatcher(): Batcher | undefined {\n const g = globalThis as { __THEO_BATCHING__?: boolean }\n if (!g.__THEO_BATCHING__) return undefined\n globalBatcher ??= createBatcher({ transport: createBatchTransport() })\n return globalBatcher\n}\n","/**\n * Phase 3 of G1 (g1-client-codegen-plan.md):\n *\n * `createAppClient(baseUrl?, fetchImpl?)` returns a Proxy that walks property\n * access (`client.posts.id.get(...)`) into a `theoFetch` invocation against\n * `{baseUrl}/posts/{params.id}` with method `GET`.\n *\n * Type safety is delivered by the `.d.ts` file emitted in Phase 2 — this\n * runtime is structurally untyped. Power users may use `theoFetch` directly\n * when they need to escape the Proxy facade.\n *\n * Edge cases absorbed:\n * - EC-1 (thenable trap): `then` / `catch` / `finally` / `toJSON` / `Symbol.*`\n * return `undefined` so that accidental `await client.posts` resolves to a\n * plain Proxy value (it is NOT thenable) instead of looping.\n * - EC-7 (abort signal): `opts.signal` is spread through to the underlying\n * fetchImpl unchanged — verified in unit tests.\n *\n * Bundle target: ≤ 2KB gzipped.\n */\n\nimport { theoFetch, TheoFetchError } from './theo-fetch.js'\nimport type { TheoFetchOptions } from './theo-fetch.js'\nimport { HTTP_METHOD_LOWERCASE } from '../core/contracts/http-methods.js'\n\nconst HTTP_METHODS_SET = new Set(HTTP_METHOD_LOWERCASE)\n\n/**\n * Keys that JavaScript runtime / inspectors / Promise resolution probe\n * unconditionally. Returning `undefined` for these keeps the Proxy from\n * pretending to be a thenable / iterable / serializable thing.\n */\nconst NON_INTERCEPT_KEYS = new Set([\n 'then',\n 'catch',\n 'finally',\n 'toJSON',\n 'toString',\n 'valueOf',\n 'constructor',\n 'prototype',\n])\n\ntype FetchImpl = typeof theoFetch\n\ninterface CallOptions {\n params?: Record<string, string | number>\n query?: Record<string, unknown>\n body?: unknown\n signal?: AbortSignal\n headers?: HeadersInit\n // arbitrary RequestInit fields (mode, credentials, cache, etc.)\n [k: string]: unknown\n}\n\nfunction injectParams(path: string, params?: Record<string, string | number>): string {\n if (!params) {\n if (/:(?:\\.\\.\\.)?[A-Za-z_]/.test(path)) {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Route ${path} requires params but none were provided. Pass them via opts.params, e.g. client.posts.get({ params: { id: '123' } }).`,\n },\n })\n }\n return path\n }\n return path.replace(/:(?:\\.\\.\\.)?([A-Za-z_][A-Za-z0-9_]*)/g, (_match, key: string) => {\n const value = params[key]\n if (value === undefined || value === null || value === '') {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Param '${key}' is required for path '${path}' but was missing/empty.`,\n },\n })\n }\n return encodeURIComponent(String(value))\n })\n}\n\ninterface ProxyContext {\n segments: string[]\n baseUrl: string\n fetchImpl: FetchImpl\n}\n\nfunction makeProxy(ctx: ProxyContext): unknown {\n const handler: ProxyHandler<() => void> = {\n get(_target, key) {\n if (typeof key !== 'string') return undefined\n if (NON_INTERCEPT_KEYS.has(key)) return undefined\n if (HTTP_METHODS_SET.has(key)) {\n return async (opts?: CallOptions) => {\n if (ctx.segments.length === 0) {\n throw new TheoFetchError(0, {\n error: {\n code: 'INVALID_PATH',\n message: `client.${key}() called without a route segment. Use client.<resource>.${key}(...) instead.`,\n },\n })\n }\n let finalPath = `${ctx.baseUrl}/${ctx.segments.join('/')}`\n if (opts?.params) {\n // Build a path with `:name` placeholders re-inserted from segments\n // whose name matches a key in opts.params (treat as dynamic).\n const segmentsWithDynamic = ctx.segments.map((seg) =>\n Object.prototype.hasOwnProperty.call(opts.params, seg) ? `:${seg}` : seg,\n )\n finalPath = injectParams(\n `${ctx.baseUrl}/${segmentsWithDynamic.join('/')}`,\n opts.params,\n )\n }\n const { params: _ignored, ...rest } = opts ?? {}\n const init = { method: key.toUpperCase(), ...rest } as unknown as TheoFetchOptions<unknown>\n return ctx.fetchImpl(finalPath, init)\n }\n }\n // Continue traversal — append segment to the path.\n return makeProxy({ ...ctx, segments: [...ctx.segments, key] })\n },\n apply() {\n return Promise.reject(\n new TheoFetchError(0, {\n error: {\n code: 'INVALID_CALL',\n message:\n 'client(...) is not callable. Use client.<resource>.<method>(opts?) — e.g. client.posts.get().',\n },\n }),\n )\n },\n }\n return new Proxy(() => undefined, handler)\n}\n\nexport interface CreateAppClientOptions {\n /** Base URL for the API. Defaults to `/api`. */\n baseUrl?: string\n /** Test-only fetch override. Production callers should not pass this. */\n fetchImpl?: FetchImpl\n}\n\nexport function createAppClient<TAppClient = unknown>(\n baseUrlOrOptions?: string | CreateAppClientOptions,\n legacyFetchImpl?: FetchImpl,\n): TAppClient {\n let baseUrl = '/api'\n let fetchImpl: FetchImpl = theoFetch\n if (typeof baseUrlOrOptions === 'string') {\n baseUrl = baseUrlOrOptions || '/api'\n } else if (baseUrlOrOptions && typeof baseUrlOrOptions === 'object') {\n if (baseUrlOrOptions.baseUrl) baseUrl = baseUrlOrOptions.baseUrl\n if (baseUrlOrOptions.fetchImpl) fetchImpl = baseUrlOrOptions.fetchImpl\n }\n // Legacy 2nd-arg fetchImpl overrides regardless of 1st-arg shape (test seam).\n if (legacyFetchImpl) fetchImpl = legacyFetchImpl\n // Strip trailing slash for predictable joining.\n if (baseUrl.length > 1 && baseUrl.endsWith('/')) baseUrl = baseUrl.slice(0, -1)\n return makeProxy({ segments: [], baseUrl, fetchImpl }) as TAppClient\n}\n","import type { UIMessage, UIMessageChunk } from 'ai'\n\n/**\n * M2 (theokit-ai-first) — read a TheoKit agent endpoint's `UIMessageStream` SSE `Response`\n * into reconstructed assistant `UIMessage`s, reusing the `ai` package's own consumer\n * primitives (`parseJsonEventStream` + `readUIMessageStream`) — the exact path\n * `@ai-sdk/react`'s `useChat` runs internally. No reinvented wire parser (Rule 9).\n *\n * `ai` is an OPTIONAL peer dependency, so it is imported dynamically: an app that never\n * calls an agent never pays for it, and importing `theokit/client` does not hard-require\n * `ai` (mirrors how the agent runtime dynamically imports `@theokit/sdk`). An agent app\n * always has `ai` installed (it is the UIMessageStream consumer).\n *\n * `onMessage` is invoked on every reconstruction step with the latest snapshot of the\n * assistant message, so a caller (the `useAgent` hook) can render streaming updates.\n */\nexport async function consumeUIMessageStream(\n response: Response,\n onMessage: (message: UIMessage) => void,\n): Promise<void> {\n const chunkStream = await responseToChunkStream(response)\n await consumeChunkStream(chunkStream, onMessage)\n}\n\n/**\n * M41 (ADR-0050 D3) — the reusable middle piece: a UIMessageStream SSE `Response` →\n * `ReadableStream<UIMessageChunk>`, reusing `ai`'s own `parseJsonEventStream` (the exact primitive\n * `useChat` runs). This is precisely what a `ChatTransport.sendMessages` returns, so `HttpTransport`\n * builds on it directly (no reinvented wire parser — Rule 9). A body-less response yields an empty stream.\n */\nexport async function responseToChunkStream(\n response: Response,\n): Promise<ReadableStream<UIMessageChunk>> {\n if (response.body === null) {\n return new ReadableStream<UIMessageChunk>({\n start(controller) {\n controller.close()\n },\n })\n }\n\n const { parseJsonEventStream, uiMessageChunkSchema } = await import('ai')\n\n // ai validates each SSE JSON frame against its own strict chunk schema (the exact gate `useChat`\n // runs), then yields `{ success, value }`; forward the valid chunks.\n const parsed = parseJsonEventStream({ stream: response.body, schema: uiMessageChunkSchema })\n return new ReadableStream<UIMessageChunk>({\n async start(controller) {\n for await (const result of parsed) {\n if (result.success) controller.enqueue(result.value)\n }\n controller.close()\n },\n })\n}\n\n/**\n * M41 (ADR-0050 D6) — read a `ReadableStream<UIMessageChunk>` into reconstructed assistant\n * `UIMessage`s via `ai`'s `readUIMessageStream`. Shared by `consumeUIMessageStream` (Response path)\n * and the framework-agnostic `AgentClient` store (transport path). `onMessage` fires on every\n * reconstruction step so a caller can render streaming updates.\n */\nexport async function consumeChunkStream(\n stream: ReadableStream<UIMessageChunk>,\n onMessage: (message: UIMessage) => void,\n): Promise<void> {\n const { readUIMessageStream } = await import('ai')\n for await (const message of readUIMessageStream({ stream })) {\n onMessage(message)\n }\n}\n","import type { UIMessage } from 'ai'\nimport { useMemo, useRef, useSyncExternalStore } from 'react'\n\nimport { AgentClient, type UseAgentStatus } from './agent-client.js'\nimport { HttpTransport } from './http-transport.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\n/**\n * M2 (theokit-ai-first) / M41 (ADR-0050) — `useAgent`, the ONE typed client hook for the\n * `agents/*.ts` convention, unified across surfaces.\n *\n * Pass an endpoint path (web) OR an {@link AgentTransport} (terminal/desktop). A string is wrapped in\n * an {@link HttpTransport} (exact back-compat with the pre-M41 fetch+SSE hook); an `InProcessTransport`\n * drives the SAME hook in a single process. The hook is a thin binding over the framework-agnostic\n * {@link AgentClient} store via React's native `useSyncExternalStore` (no test-DOM dependency). The\n * generated `@theo/agents` module types `send` to the agent's `input` schema — inferred end-to-end\n * from the server `defineAgent({ input })` with ZERO manual wiring.\n */\nexport type { UseAgentStatus }\n\nexport interface UseAgentReturn<TInput = unknown, TToolNames extends string = string> {\n /** Reconstructed assistant messages so far (ai `UIMessage[]`). */\n messages: UIMessage[]\n status: UseAgentStatus\n /** The last error, or `undefined`. */\n error: Error | undefined\n /** Send a request; opens a new stream. Typed to the agent's `input` schema. */\n send: (input: TInput) => void\n /** Abort an in-flight stream. */\n abort: () => void\n /** Clear messages + error, back to idle. */\n reset: () => void\n /** Settle a paused HITL approval (HTTP `POST /approve/<id>` for web; the inline callback in-process). */\n approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>\n /** Resume an interrupted stream (M37 durable transport for web; a no-op in-process). */\n reconnect: () => void\n /**\n * The union of tool names this agent can emit (M8), carried end-to-end from the `agent()` builder's\n * accumulated tool-name type through the generated `@theo/agents` client. Type-only witness (never\n * populated at runtime). Resolves to the literal union for builder agents, `string` otherwise.\n */\n readonly __toolNames?: TToolNames\n}\n\nexport interface UseAgentOptions {\n /**\n * Extra request headers (e.g., auth) — applied when a string path builds an `HttpTransport`. Read on\n * EVERY request, so a value that changes across renders (a rotating JWT) is never sent stale.\n */\n headers?: Record<string, string>\n /** Override fetch (primarily for tests) — captured when a string path builds an `HttpTransport`. */\n fetch?: typeof fetch\n}\n\n/**\n * Bind to an agent by endpoint path (`/api/agents/<name>`) or by an explicit {@link AgentTransport}.\n * Prefer the generated `useAgent` from `@theo/agents` (typed by agent name); this base accepts a path\n * or a transport. The store is created once per binding identity — memoize a transport before passing it.\n */\nexport function useAgent<TInput = unknown>(\n pathOrTransport: string | AgentTransport,\n options: UseAgentOptions = {},\n): UseAgentReturn<TInput> {\n // Track the latest options so the built HttpTransport reads current headers per request (dynamic\n // auth is never stale) without rebuilding the store — which would drop in-flight messages.\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n const client = useMemo(\n () =>\n new AgentClient<TInput>(\n typeof pathOrTransport === 'string'\n ? new HttpTransport({\n api: pathOrTransport,\n headers: () => optionsRef.current.headers,\n fetch: optionsRef.current.fetch,\n })\n : pathOrTransport,\n ),\n // Identity is the binding; headers are resolved live via optionsRef, fetch captured at creation.\n [pathOrTransport],\n )\n\n const state = useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n\n return {\n messages: state.messages,\n status: state.status,\n error: state.error,\n send: client.send,\n abort: client.abort,\n reset: client.reset,\n approve: client.approve,\n reconnect: client.reconnect,\n }\n}\n","import type { UIMessage, UIMessageChunk } from 'ai'\n\nimport { consumeChunkStream } from './consume-ui-message-stream.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\nexport type UseAgentStatus = 'idle' | 'streaming' | 'done' | 'error'\n\n/** The observable state the store exposes (stable reference between emits — `useSyncExternalStore` contract). */\nexport interface AgentClientState {\n messages: UIMessage[]\n status: UseAgentStatus\n error: Error | undefined\n}\n\n/** Derive the turn text from a typed input: `input.message` when present, else the serialized input. */\nfunction inputToText(input: unknown): string {\n if (\n typeof input === 'object' &&\n input !== null &&\n typeof (input as { message?: unknown }).message === 'string'\n ) {\n return (input as { message: string }).message\n }\n if (typeof input === 'string') return input\n return JSON.stringify(input)\n}\n\n/** Build a user `UIMessage` from a typed input (text from `{ message }`, else the serialized input). */\nfunction buildUserMessage(input: unknown): UIMessage {\n return {\n id: crypto.randomUUID(),\n role: 'user',\n parts: [{ type: 'text', text: inputToText(input) }],\n }\n}\n\n/**\n * M41 (ADR-0050 D6) — the framework-agnostic agent client store.\n *\n * Holds `messages`/`status`/`error`, drives an {@link AgentTransport}, and notifies subscribers on\n * change. It is the SINGLE consolidation point: web (`HttpTransport`) and terminal/desktop\n * (`InProcessTransport`) run the SAME store. `useAgent` is a thin React binding over it via\n * `useSyncExternalStore`; a standalone (no-React) client (M44) can subscribe directly. Being\n * framework-agnostic, it is unit-tested without a DOM.\n */\nexport class AgentClient<TInput = unknown> {\n readonly #transport: AgentTransport\n readonly #chatId = crypto.randomUUID()\n readonly #listeners = new Set<() => void>()\n\n #messages: UIMessage[] = []\n #status: UseAgentStatus = 'idle'\n #error: Error | undefined\n #controller: AbortController | null = null\n #snapshot: AgentClientState = { messages: [], status: 'idle', error: undefined }\n\n constructor(transport: AgentTransport) {\n this.#transport = transport\n }\n\n /** Subscribe to state changes; returns an unsubscribe fn. */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener)\n return () => {\n this.#listeners.delete(listener)\n }\n }\n\n /** The current immutable snapshot (stable reference until the next emit). */\n getSnapshot = (): AgentClientState => this.#snapshot\n\n #emit(): void {\n this.#snapshot = { messages: this.#messages, status: this.#status, error: this.#error }\n for (const listener of this.#listeners) listener()\n }\n\n #upsert(message: UIMessage): void {\n const next = [...this.#messages]\n const idx = next.findIndex((existing) => existing.id === message.id)\n if (idx >= 0) next[idx] = message\n else next.push(message)\n this.#messages = next\n }\n\n async #drive(\n open: () => Promise<ReadableStream<UIMessageChunk> | null>,\n controller: AbortController,\n ): Promise<void> {\n // Read via a function (not a narrowed local) — `aborted` flips ASYNC across the awaits below, so the\n // control-flow narrowing of a direct `signal.aborted` read would be wrong. A stale drive (its\n // controller aborted because a newer send/abort took over) MUST NOT clobber the newer status.\n const aborted = (): boolean => controller.signal.aborted\n try {\n const stream = await open()\n if (aborted()) return\n if (stream === null) {\n // Nothing to resume (e.g. reconnect after the run completed). Settle without error.\n this.#status = this.#messages.length > 0 ? 'done' : 'idle'\n this.#emit()\n return\n }\n await consumeChunkStream(stream, (message) => {\n if (aborted()) return\n this.#upsert(message)\n this.#emit()\n })\n if (aborted()) return\n this.#status = 'done'\n this.#emit()\n } catch (err) {\n if (aborted()) return\n this.#error = err instanceof Error ? err : new Error(String(err))\n this.#status = 'error'\n this.#emit()\n }\n }\n\n /** Send a typed input; opens a fresh stream (replaces prior messages). */\n send = (input: TInput): void => {\n this.abort()\n const controller = new AbortController()\n this.#controller = controller\n this.#messages = []\n this.#error = undefined\n this.#status = 'streaming'\n this.#emit()\n void this.#drive(\n () =>\n this.#transport.sendMessages({\n trigger: 'submit-message',\n chatId: this.#chatId,\n messageId: undefined,\n messages: [buildUserMessage(input)],\n abortSignal: controller.signal,\n // Only object inputs flow as the request `body` (the turn text is always in `messages`);\n // a primitive input is carried by the user message, never spread into the body.\n body: typeof input === 'object' && input !== null ? input : undefined,\n }),\n controller,\n )\n }\n\n /** Resume an interrupted stream via the transport's `reconnectToStream` (no-op when unavailable). */\n reconnect = (): void => {\n const controller = new AbortController()\n this.#controller = controller\n this.#status = 'streaming'\n this.#emit()\n void this.#drive(() => this.#transport.reconnectToStream({ chatId: this.#chatId }), controller)\n }\n\n /** Abort an in-flight stream (not an error — leaves messages as-is). */\n abort = (): void => {\n this.#controller?.abort()\n this.#controller = null\n }\n\n /** Clear messages + error, back to idle. */\n reset = (): void => {\n this.abort()\n this.#messages = []\n this.#error = undefined\n this.#status = 'idle'\n this.#emit()\n }\n\n /** Settle a paused HITL approval via the transport's HITL path (HTTP POST or inline callback). */\n approve = async (approvalId: string, decision: ApprovalDecision): Promise<void> => {\n await this.#transport.approve?.(approvalId, decision)\n }\n}\n","import type { ChatTransport, UIMessage, UIMessageChunk } from 'ai'\n\nimport { responseToChunkStream } from './consume-ui-message-stream.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\n/** Extra request headers — a static record OR a resolver called per request (for dynamic auth). */\nexport type HeadersResolver = Record<string, string> | (() => Record<string, string> | undefined)\n\nexport interface HttpTransportOptions {\n /** Agent endpoint path or URL, e.g. `/api/agents/support`. */\n api: string\n /**\n * Extra request headers (e.g. auth). Static record OR a resolver evaluated on EVERY request — pass a\n * resolver when the value is dynamic (a rotating JWT), so a stale header is never sent. Merged UNDER\n * per-request headers.\n */\n headers?: HeadersResolver\n /** Override fetch (primarily for tests / non-browser hosts) — static; resolved once at construction. */\n fetch?: typeof fetch\n}\n\n/** Normalize `ai`'s `Record | Headers | undefined` header option into a plain record. */\nfunction toRecord(headers: Record<string, string> | Headers | undefined): Record<string, string> {\n if (headers === undefined) return {}\n if (headers instanceof Headers) return Object.fromEntries(headers.entries())\n return headers\n}\n\n/**\n * M41 (ADR-0050 D3) — `ChatTransport` over the web agent path.\n *\n * - `sendMessages`: `POST <api>` with the UIMessageStream `accept` + the `X-Theo-Action` CSRF header\n * (HTTP method + headers are identical to the pre-M41 `useAgent` fetch; the body shape is a superset —\n * `{ ...input, messages: [UIMessage] }` — which the server's dual-path parser accepts, so no\n * regression), captures the server-minted `x-theokit-run-id`, and returns `ReadableStream<UIMessageChunk>`\n * via `ai`'s own SSE parser (`responseToChunkStream`).\n * - `reconnectToStream`: `GET <api>/runs/<runId>/stream` (M37 durable transport); 404 → `null` (the run\n * completed / was evicted). A caller may pass a `Last-Event-ID` header to resume only the tail; by\n * default the server replays the run from the start and the client upserts by message id (idempotent).\n * - `approve`: `POST <api>/approve/<id>` (out-of-band HITL settle).\n *\n * Implemented directly (not by subclassing `DefaultChatTransport`) because reconnect keys on our\n * server-minted `runId` captured from a response header, which the base class does not expose — see\n * ADR-0050 D3.\n */\nexport class HttpTransport implements AgentTransport {\n readonly #api: string\n readonly #headers: HeadersResolver\n readonly #fetch: typeof fetch\n /** Server-minted id of the last run (from `x-theokit-run-id`) — the reconnect key. */\n #lastRunId: string | undefined\n\n constructor(options: HttpTransportOptions) {\n this.#api = options.api\n this.#headers = options.headers ?? {}\n this.#fetch = options.fetch ?? globalThis.fetch\n }\n\n /** Resolve the configured headers per request (a resolver evaluates now — dynamic auth is never stale). */\n #resolveHeaders(): Record<string, string> {\n return (typeof this.#headers === 'function' ? this.#headers() : this.#headers) ?? {}\n }\n\n async sendMessages(\n options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0],\n ): Promise<ReadableStream<UIMessageChunk>> {\n const { messages, abortSignal, headers, body } = options\n // Only spread an object body (never a primitive — that would emit char-indexed keys). The server\n // accepts `{ messages }` (ai shape) AND `{ ...input }` (typed input), preferring the turn text.\n const extra = typeof body === 'object' ? (body as Record<string, unknown>) : undefined\n const response = await this.#fetch(this.#api, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n 'X-Theo-Action': '1',\n ...this.#resolveHeaders(),\n ...toRecord(headers),\n },\n body: JSON.stringify({ ...extra, messages }),\n signal: abortSignal,\n })\n if (!response.ok) {\n throw new Error(\n `Agent request to ${this.#api} failed: ${response.status} ${response.statusText}`,\n )\n }\n this.#lastRunId = response.headers.get('x-theokit-run-id') ?? undefined\n return responseToChunkStream(response)\n }\n\n async reconnectToStream(\n options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0],\n ): Promise<ReadableStream<UIMessageChunk> | null> {\n if (this.#lastRunId === undefined) return null\n const response = await this.#fetch(`${this.#api}/runs/${this.#lastRunId}/stream`, {\n method: 'GET',\n headers: { ...this.#resolveHeaders(), ...toRecord(options.headers) },\n })\n if (response.status === 404) return null\n if (!response.ok) {\n throw new Error(\n `Agent reconnect to run ${this.#lastRunId} failed: ${response.status} ${response.statusText}`,\n )\n }\n return responseToChunkStream(response)\n }\n\n async approve(approvalId: string, decision: ApprovalDecision): Promise<void> {\n const response = await this.#fetch(`${this.#api}/approve/${approvalId}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'X-Theo-Action': '1',\n ...this.#resolveHeaders(),\n },\n body: JSON.stringify(decision),\n })\n if (!response.ok) {\n throw new Error(`Approve ${approvalId} failed: ${response.status} ${response.statusText}`)\n }\n }\n}\n","import type { UIMessage } from 'ai'\n\n/**\n * M41/M42 — extract the turn text from the last user message's text parts. Shared by the transports\n * that hand a plain `message` string to an in-process/push runner (`InProcessTransport`,\n * `ChannelTransport`) rather than POSTing the `messages[]` array (`HttpTransport`). One definition (G12).\n */\nexport function extractLastUserText(messages: readonly UIMessage[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i]\n if (message.role !== 'user') continue\n const text = message.parts\n .filter((part): part is { type: 'text'; text: string } => part.type === 'text')\n .map((part) => part.text)\n .join('')\n if (text.length > 0) return text\n }\n return ''\n}\n","import type { ChatTransport, UIMessage, UIMessageChunk } from 'ai'\n\nimport { extractLastUserText } from './last-user-text.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\n/** An inline approval request handed to the transport's resolver (structural — no server import). */\nexport interface InProcessApprovalRequestLike {\n approvalId: string\n toolName: string\n opts: unknown\n}\n\n/** Resolve one gated-tool approval inline (mirrors the SDK's `boolean | HitlDecision` return). */\nexport type InProcessAwaitApproval = (\n req: InProcessApprovalRequestLike,\n) => Promise<boolean | ApprovalDecision>\n\n/** The input the injected runner receives (structurally compatible with `StreamAgentTurnInProcessInput`). */\nexport interface InProcessRunInput {\n message: string\n sessionId?: string\n signal?: AbortSignal\n awaitApproval?: InProcessAwaitApproval\n}\n\n/**\n * The in-process turn runner. The consumer binds `streamAgentTurnInProcess(mod, apiKey, …)`:\n * `new InProcessTransport({ run: (input) => streamAgentTurnInProcess(mod, apiKey, input) })`.\n * Injecting it keeps this client module decoupled from `server/` and makes the transport testable.\n */\nexport type InProcessRunner = (input: InProcessRunInput) => AsyncGenerator<UIMessageChunk>\n\nexport interface InProcessTransportOptions {\n run: InProcessRunner\n}\n\n/** Bridge an `AsyncGenerator<UIMessageChunk>` into a pull-based `ReadableStream<UIMessageChunk>`. */\nfunction generatorToStream(gen: AsyncGenerator<UIMessageChunk>): ReadableStream<UIMessageChunk> {\n return new ReadableStream<UIMessageChunk>({\n async pull(controller) {\n try {\n const result = await gen.next()\n if (result.done === true) {\n controller.close()\n return\n }\n // After the done-guard, `result` is an IteratorYieldResult<UIMessageChunk> — value is typed.\n controller.enqueue(result.value)\n } catch (err) {\n controller.error(err)\n }\n },\n async cancel() {\n await gen.return(undefined)\n },\n })\n}\n\n/**\n * M41 (ADR-0050 D4) — `ChatTransport` over the in-process seam (`streamAgentTurnInProcess`), for the\n * terminal/desktop surfaces that run client + server in ONE process (no HTTP loopback).\n *\n * - `sendMessages`: bridge the injected runner's `AsyncGenerator<UIMessageChunk>` into a\n * `ReadableStream<UIMessageChunk>` (honoring `abortSignal`, which the runner forwards to the SDK).\n * - `reconnectToStream`: always `null` — a single process has no dropped server-side stream to resume\n * (mirrors `ai`'s `DirectChatTransport`).\n * - `approve`: resolve the pending inline approval by id (the run parks on `awaitApproval`). An unknown\n * id rejects (fail-fast, Rule 8 — never a silent resolve).\n *\n * Error asymmetry vs `HttpTransport` (by design, matching the `ChatTransport` contract): a runner that\n * throws SYNCHRONOUSLY surfaces the error when the stream is READ (via `controller.error`), not from the\n * `sendMessages` promise — whereas `HttpTransport` throws from `sendMessages` on a non-2xx response.\n */\nexport class InProcessTransport implements AgentTransport {\n readonly #run: InProcessRunner\n /** Pending inline approvals: approvalId → resolver of the parked `awaitApproval` promise. */\n readonly #pending = new Map<string, (decision: boolean | ApprovalDecision) => void>()\n\n constructor(options: InProcessTransportOptions) {\n this.#run = options.run\n }\n\n #awaitApproval: InProcessAwaitApproval = (req) =>\n new Promise<boolean | ApprovalDecision>((resolve, reject) => {\n // Approval ids are server-minted UUIDs — a collision means a real bug (two turns reusing an id).\n // Fail fast rather than silently overwrite the earlier turn's parked resolver (Rule 8).\n if (this.#pending.has(req.approvalId)) {\n reject(new Error(`Duplicate pending approval id '${req.approvalId}' — ids must be unique.`))\n return\n }\n this.#pending.set(req.approvalId, resolve)\n })\n\n sendMessages(\n options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0],\n ): Promise<ReadableStream<UIMessageChunk>> {\n const { messages, abortSignal } = options\n const generator = this.#run({\n message: extractLastUserText(messages),\n signal: abortSignal ?? undefined,\n awaitApproval: this.#awaitApproval,\n })\n return Promise.resolve(generatorToStream(generator))\n }\n\n reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null> {\n return Promise.resolve(null)\n }\n\n approve(approvalId: string, decision: ApprovalDecision): Promise<void> {\n const resolve = this.#pending.get(approvalId)\n if (resolve === undefined) {\n return Promise.reject(\n new Error(`No pending approval '${approvalId}' (unknown or already settled).`),\n )\n }\n this.#pending.delete(approvalId)\n resolve(decision)\n return Promise.resolve()\n }\n}\n","import type { ChatTransport, UIMessage, UIMessageChunk } from 'ai'\n\nimport { extractLastUserText } from './last-user-text.js'\nimport type { AgentTransport, ApprovalDecision } from './transport.js'\n\n/** Handlers the transport hands to the injected push source for one turn. */\nexport interface ChannelTurnHandlers {\n /** One pushed JSONL line (a serialized `UIMessageChunk`). */\n onLine: (line: string) => void\n /** The turn ended — no more lines. */\n onClose: () => void\n /** The push source failed. */\n onError?: (err: unknown) => void\n}\n\n/**\n * The injected push source — a Tauri `Channel`/`invoke` bridge, kept STRUCTURAL so core adds no\n * `@tauri-apps/*` dependency and the transport is testable with a fake (ADR-0051 D2). The Tauri app\n * wires it: `new Channel()`, `channel.onmessage = onLine`, `invoke('run_agent', { message, channel })`,\n * returning a teardown that aborts the sidecar turn.\n */\nexport interface ChannelPushSource {\n /** Start a turn; deliver each JSONL `UIMessageChunk` line to `onLine`, then `onClose`. Return a teardown. */\n start(turn: { message: string }, handlers: ChannelTurnHandlers): () => void\n /** Optional HITL settle (another Tauri `invoke`). */\n settle?(approvalId: string, decision: ApprovalDecision): Promise<void>\n}\n\nexport interface ChannelTransportOptions {\n source: ChannelPushSource\n}\n\n/**\n * M42 (ADR-0051) — `ChatTransport` over a Tauri-`Channel`-shaped push source, for the desktop webview.\n *\n * - `sendMessages`: start the turn via the injected source and bridge its pushed JSONL frames into a\n * `ReadableStream<UIMessageChunk>` (built in `start` — a Channel is push, so the stream's queue buffers\n * frames; ADR-0051 D3). A malformed JSONL line is SKIPPED, never fatal (ADR-0051 D4, Rule 8). `abortSignal`\n * tears down the source and closes the stream.\n * - `reconnectToStream`: always `null` — the M36 sidecar runs the turn directly (no durable server stream);\n * this is the honest parity for a single-process push surface (ADR-0051 D5; mirrors `InProcessTransport`).\n * - `approve`: routes to the injected `settle` (another Tauri `invoke`); absent `settle` → a typed error.\n *\n * The push source is INJECTED — core stays Tauri-agnostic and this transport is unit-tested with a fake.\n */\nexport class ChannelTransport implements AgentTransport {\n readonly #source: ChannelPushSource\n\n constructor(options: ChannelTransportOptions) {\n this.#source = options.source\n }\n\n sendMessages(\n options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0],\n ): Promise<ReadableStream<UIMessageChunk>> {\n const { messages, abortSignal } = options\n const message = extractLastUserText(messages)\n const source = this.#source\n\n // Per-stream teardown/abort-detach, hoisted so `cancel` (consumer stops reading) can also tear the\n // source down. `closed` makes every terminal transition idempotent (no enqueue/close after close).\n let closed = false\n let teardown: () => void = () => undefined\n let detachAbort: () => void = () => undefined\n\n const stream = new ReadableStream<UIMessageChunk>({\n start(controller) {\n const finish = (settle: () => void): void => {\n if (closed) return\n closed = true\n detachAbort()\n settle()\n }\n teardown = source.start(\n { message },\n {\n onLine: (line) => {\n if (closed) return\n // Skip a malformed pushed line — one bad frame must never crash the webview (ADR-0051 D4).\n let parsed: unknown\n try {\n parsed = JSON.parse(line)\n } catch {\n return\n }\n // Discriminant guard: a `UIMessageChunk` is an object with a string `type`. The trust\n // boundary here is the LOCAL sidecar (not the network), so a discriminant check — not the\n // full `ai` schema (which isn't exposed standalone) — is proportionate: it rejects\n // structureless / wrong-shape payloads before they reach `readUIMessageStream`. Same\n // skip-not-crash policy as a parse error.\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n typeof (parsed as { type?: unknown }).type !== 'string'\n ) {\n return\n }\n controller.enqueue(parsed as UIMessageChunk)\n },\n onClose: () => {\n finish(() => {\n controller.close()\n })\n },\n onError: (err) => {\n finish(() => {\n controller.error(err)\n })\n },\n },\n )\n if (abortSignal !== undefined) {\n const onAbort = (): void => {\n finish(() => {\n teardown()\n controller.close()\n })\n }\n if (abortSignal.aborted) onAbort()\n else {\n abortSignal.addEventListener('abort', onAbort)\n detachAbort = () => {\n abortSignal.removeEventListener('abort', onAbort)\n }\n }\n }\n },\n cancel() {\n // The consumer stopped reading (reader.cancel) — abort the source turn + drop the abort listener.\n if (closed) return\n closed = true\n detachAbort()\n teardown()\n },\n })\n return Promise.resolve(stream)\n }\n\n reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null> {\n return Promise.resolve(null)\n }\n\n async approve(approvalId: string, decision: ApprovalDecision): Promise<void> {\n if (this.#source.settle === undefined) {\n throw new Error(`This channel source has no HITL settle — cannot approve '${approvalId}'.`)\n }\n await this.#source.settle(approvalId, decision)\n }\n}\n","/**\n * <Link> — React Router Link with route prefetching.\n *\n * Wraps react-router's <Link> with prefetch behavior:\n * - `intent` (default): prefetch on hover + focus (~200ms before click)\n * - `viewport`: prefetch when visible (IntersectionObserver)\n * - `none`: no prefetch (same as plain react-router Link)\n *\n * Uses `<link rel=\"prefetch\">` (not modulepreload) because route paths\n * can be prefetched directly — no Vite manifest resolution needed (EC-1).\n */\nimport {\n Link as RouterLink,\n type LinkProps as RouterLinkProps,\n} from 'react-router'\nimport { useRef, useCallback, useEffect } from 'react'\n\nexport type PrefetchBehavior = 'none' | 'intent' | 'viewport'\n\nexport interface LinkProps extends RouterLinkProps {\n /** Prefetch strategy. Default: 'intent' (on hover + focus). */\n prefetch?: PrefetchBehavior\n}\n\n/** Deduplication — each URL prefetched at most once per session. */\nconst prefetched = new Set<string>()\n\nfunction injectPrefetch(href: string): void {\n // EC-2: SSR guard — document unavailable on server\n if (typeof document === 'undefined') return\n if (prefetched.has(href)) return\n prefetched.add(href)\n\n const link = document.createElement('link')\n link.rel = 'prefetch'\n link.href = href\n document.head.appendChild(link)\n}\n\nfunction resolveTo(to: LinkProps['to']): string {\n if (typeof to === 'string') return to\n return to?.pathname ?? ''\n}\n\n/**\n * TheoKit Link — drop-in replacement for react-router Link with prefetch.\n *\n * @example\n * ```tsx\n * import { Link } from 'theokit/client'\n *\n * <Link to=\"/contacts\">Contacts</Link>\n * <Link to=\"/dashboard\" prefetch=\"viewport\">Dashboard</Link>\n * <Link to=\"/settings\" prefetch=\"none\">Settings</Link>\n * ```\n */\nexport function Link({ prefetch = 'intent', to, onMouseEnter, onFocus, ...rest }: LinkProps) {\n const ref = useRef<HTMLAnchorElement>(null)\n\n const handleIntent = useCallback(\n (event: React.MouseEvent<HTMLAnchorElement> | React.FocusEvent<HTMLAnchorElement>) => {\n if (prefetch === 'intent') {\n injectPrefetch(resolveTo(to))\n }\n // Forward original handlers\n if (event.type === 'mouseenter' && onMouseEnter) {\n ;(onMouseEnter as React.MouseEventHandler<HTMLAnchorElement>)(event as React.MouseEvent<HTMLAnchorElement>)\n }\n if (event.type === 'focus' && onFocus) {\n ;(onFocus as React.FocusEventHandler<HTMLAnchorElement>)(event as React.FocusEvent<HTMLAnchorElement>)\n }\n },\n [prefetch, to, onMouseEnter, onFocus],\n )\n\n // Viewport mode: IntersectionObserver\n useEffect(() => {\n if (prefetch !== 'viewport' || !ref.current) return\n if (typeof IntersectionObserver === 'undefined') return // SSR guard\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n injectPrefetch(resolveTo(to))\n observer.disconnect()\n }\n },\n { rootMargin: '200px' }, // prefetch slightly before visible\n )\n observer.observe(ref.current)\n return () => observer.disconnect()\n }, [prefetch, to])\n\n return (\n <RouterLink\n ref={ref}\n to={to}\n onMouseEnter={handleIntent}\n onFocus={handleIntent}\n {...rest}\n />\n )\n}\n","/**\n * <Metadata> — SEO-ready head tags from a single component.\n *\n * Uses React 19's native <title>/<meta>/<link> hoisting to <head>.\n * No build-time extraction needed — works in SSR and client.\n *\n * @example\n * ```tsx\n * import { Metadata } from 'theokit/client'\n *\n * export default function ContactsPage() {\n * return (\n * <>\n * <Metadata\n * title=\"Contacts | My CRM\"\n * description=\"Manage your contacts\"\n * ogImage=\"/og/contacts.png\"\n * canonical=\"https://mycrm.com/contacts\"\n * />\n * <h1>Contacts</h1>\n * </>\n * )\n * }\n * ```\n */\n\nexport interface MetadataProps {\n title?: string\n description?: string\n canonical?: string\n ogTitle?: string\n ogDescription?: string\n ogImage?: string\n ogType?: string\n ogUrl?: string\n twitterCard?: 'summary' | 'summary_large_image'\n /** Custom meta tags rendered as children */\n children?: React.ReactNode\n}\n\nexport function Metadata(props: MetadataProps) {\n const ogTitle = props.ogTitle ?? props.title\n const ogDesc = props.ogDescription ?? props.description\n\n return (\n <>\n {props.title && <title>{props.title}</title>}\n {props.description && <meta name=\"description\" content={props.description} />}\n {props.canonical && <link rel=\"canonical\" href={props.canonical} />}\n {ogTitle && <meta property=\"og:title\" content={ogTitle} />}\n {ogDesc && <meta property=\"og:description\" content={ogDesc} />}\n {props.ogImage && <meta property=\"og:image\" content={props.ogImage} />}\n {props.ogType && <meta property=\"og:type\" content={props.ogType} />}\n {props.ogUrl && <meta property=\"og:url\" content={props.ogUrl} />}\n {props.twitterCard && <meta name=\"twitter:card\" content={props.twitterCard} />}\n {props.children}\n </>\n )\n}\n","/**\n * <Image> — optimized image component with lazy loading.\n *\n * Renders a standard <img> with:\n * - loading=\"lazy\" by default (eager with priority={true})\n * - decoding=\"async\" for non-blocking decode\n * - width/height for CLS prevention\n * - srcSet/sizes forwarded for responsive images\n *\n * No CDN, no Sharp, no build-time optimization — pure HTML attributes\n * that deliver 80% of the performance value at zero complexity.\n *\n * @example\n * ```tsx\n * import { Image } from 'theokit/client'\n *\n * <Image src=\"/team.jpg\" alt=\"Team photo\" width={800} height={600} />\n * <Image src=\"/hero.jpg\" alt=\"Hero\" priority />\n * <Image\n * src=\"/product.jpg\"\n * alt=\"Product\"\n * width={400}\n * height={300}\n * srcSet=\"/product-400.jpg 400w, /product-800.jpg 800w\"\n * sizes=\"(max-width: 768px) 100vw, 400px\"\n * />\n * ```\n */\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL (required). */\n src: string\n /** Alt text for accessibility (required). */\n alt: string\n /** If true, loading=\"eager\" — use for above-the-fold images. */\n priority?: boolean\n}\n\nexport function Image({ priority, loading, decoding, ...props }: ImageProps) {\n return (\n <img\n loading={loading ?? (priority ? 'eager' : 'lazy')}\n decoding={decoding ?? 'async'}\n {...props}\n />\n )\n}\n","/**\n * M30 (ADR-0041) — client host for MCP App `ui://` resources.\n *\n * Renders a tool's `ui://` HTML in a SANDBOXED iframe and bridges a capability-scoped guest API over\n * `postMessage`. Security is load-bearing:\n * - the iframe is `sandbox=\"allow-scripts\"` ONLY — NOT `allow-same-origin`, so the guest runs at a\n * null origin and cannot touch the parent DOM, cookies, or storage;\n * - the host only honors messages whose `source` is the iframe's own `contentWindow`;\n * - the guest API is a fixed, capability-scoped vocabulary (`callServerTool`, `sendMessage`) — any\n * other message type is ignored.\n */\n\n/** The guest → host message vocabulary (capability-scoped). */\nexport type GuestMessage =\n | { type: 'callServerTool'; id: string; tool: string; args?: unknown }\n | { type: 'sendMessage'; text: string }\n\n/** Callbacks the host wires for the guest API. */\nexport interface McpAppHostOptions {\n /** Guest asked to call a server tool — return its result (posted back to the guest by id). */\n onCallServerTool: (tool: string, args: unknown) => unknown\n /** Guest emitted a chat message to the host app. */\n onSendMessage?: (text: string) => void\n}\n\n/**\n * Pure bridge: interpret one guest message and (for `callServerTool`) post the result back via\n * `post`. Exported for unit testing without a DOM. Unknown message shapes are ignored — the guest\n * API is capability-scoped, not an open RPC surface.\n */\nexport function createGuestMessageHandler(\n opts: McpAppHostOptions,\n post: (message: unknown) => void,\n): (data: unknown) => Promise<void> {\n return async (data: unknown): Promise<void> => {\n if (typeof data !== 'object' || data === null) return\n const msg = data as Partial<GuestMessage> & { type?: string }\n if (\n msg.type === 'callServerTool' &&\n typeof msg.id === 'string' &&\n typeof msg.tool === 'string'\n ) {\n const result = await opts.onCallServerTool(msg.tool, msg.args)\n post({ type: 'callServerTool:result', id: msg.id, result })\n return\n }\n if (msg.type === 'sendMessage' && typeof (msg as { text?: unknown }).text === 'string') {\n opts.onSendMessage?.((msg as { text: string }).text)\n }\n }\n}\n\n/** Handle returned by {@link mountMcpApp}. */\nexport interface McpAppHandle {\n iframe: HTMLIFrameElement\n /** Remove the message listener and the iframe. */\n dispose: () => void\n}\n\n/** The sandbox tokens the guest iframe is allowed — scripts only, NEVER `allow-same-origin`. */\nexport const MCP_APP_SANDBOX = 'allow-scripts'\n\n/**\n * Mount an MCP App resource's HTML in a sandboxed iframe inside `container`, wiring the guest API.\n * The HTML comes from `resources/read` (see `mcp-app-resources.ts`). Returns a handle to dispose.\n */\nexport function mountMcpApp(\n container: HTMLElement,\n resource: { html: string },\n opts: McpAppHostOptions,\n): McpAppHandle {\n const iframe = container.ownerDocument.createElement('iframe')\n // Security: scripts only, null origin. Do NOT add allow-same-origin.\n iframe.setAttribute('sandbox', MCP_APP_SANDBOX)\n iframe.srcdoc = resource.html\n container.appendChild(iframe)\n\n const post = (message: unknown): void => {\n // The guest is a sandboxed srcdoc iframe (allow-scripts, NO allow-same-origin) → its origin is\n // the opaque string \"null\", which cannot be used as a reliable targetOrigin. '*' is the only\n // valid target for a null-origin sandboxed guest; the sandbox (no navigation, no same-origin)\n // is what prevents a cross-origin leak, not the targetOrigin string.\n // eslint-disable-next-line sonarjs/post-message -- sandboxed null-origin iframe: '*' is correct\n iframe.contentWindow?.postMessage(message, '*')\n }\n const handle = createGuestMessageHandler(opts, post)\n\n const onMessage = (event: MessageEvent): void => {\n // Only trust messages from THIS iframe's guest window.\n if (event.source !== iframe.contentWindow) return\n void handle(event.data)\n }\n const view = container.ownerDocument.defaultView\n view?.addEventListener('message', onMessage)\n\n return {\n iframe,\n dispose: () => {\n view?.removeEventListener('message', onMessage)\n iframe.remove()\n },\n }\n}\n"],"mappings":"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","names":["useRef","jsx","jsx"]}
|