@123toto/ai-app-assistant-server 0.1.0 → 0.2.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @123toto/ai-app-assistant-server
2
2
 
3
- Framework-neutral Node.js backend for contextual in-app AI documentation.
3
+ Framework-neutral Node.js backend for contextual AI App Assistant integrations.
4
4
 
5
5
  ```bash
6
6
  npm install @123toto/ai-app-assistant-server
@@ -11,9 +11,9 @@ Node.js 20 or later is required.
11
11
  ## Minimal server
12
12
 
13
13
  ```ts
14
- import { createAiDocsServer } from "@123toto/ai-app-assistant-server";
14
+ import { createAiAppAssistantServer } from "@123toto/ai-app-assistant-server";
15
15
 
16
- const aiDocs = createAiDocsServer({
16
+ const aiAppAssistant = createAiAppAssistantServer({
17
17
  model: "mistral:mistral-small-latest",
18
18
  documents,
19
19
  http: {
@@ -22,14 +22,14 @@ const aiDocs = createAiDocsServer({
22
22
  }
23
23
  });
24
24
 
25
- export const POST = (request: Request) => aiDocs.fetch.handle(request);
25
+ export const POST = (request: Request) => aiAppAssistant.fetch.handle(request);
26
26
  ```
27
27
 
28
28
  The selected provider reads its conventional API key from the backend environment. `allowAnonymous: true` is available only for deliberately public prototypes.
29
29
 
30
30
  ## Managed server
31
31
 
32
- `createManagedAiDocsServer()` adds optional administration features without changing the minimal API:
32
+ `createManagedAiAppAssistantServer()` adds optional administration features without changing the minimal API:
33
33
 
34
34
  - provider and model discovery;
35
35
  - encrypted API-key persistence;
@@ -40,12 +40,12 @@ The selected provider reads its conventional API key from the backend environmen
40
40
  - complete Fetch API handlers for chat and administration.
41
41
 
42
42
  ```ts
43
- import { createManagedAiDocsServer } from "@123toto/ai-app-assistant-server";
43
+ import { createManagedAiAppAssistantServer } from "@123toto/ai-app-assistant-server";
44
44
 
45
- const aiDocs = createManagedAiDocsServer({
45
+ const aiAppAssistant = createManagedAiAppAssistantServer({
46
46
  configuration: {
47
47
  storage: { type: "redis", client: redis },
48
- encryptionKey: process.env.AI_DOCS_SECRET_ENCRYPTION_KEY!,
48
+ encryptionKey: process.env.AI_APP_ASSISTANT_SECRET_ENCRYPTION_KEY!,
49
49
  defaultConfiguration: {
50
50
  provider: "mistral",
51
51
  model: "mistral-small-latest",
@@ -60,22 +60,22 @@ const aiDocs = createManagedAiDocsServer({
60
60
  }
61
61
  });
62
62
 
63
- await aiDocs.initialize();
63
+ await aiAppAssistant.initialize();
64
64
  ```
65
65
 
66
- Documents may also be loaded after application bootstrap with `aiDocs.setDocuments(documents)`.
66
+ Documents may also be loaded after application bootstrap with `aiAppAssistant.setDocuments(documents)`.
67
67
 
68
68
  ## Framework connectors
69
69
 
70
70
  ```ts
71
- import { createManagedAiDocsExpressHandler } from "@123toto/ai-app-assistant-server/express";
71
+ import { createManagedAiAppAssistantExpressHandler } from "@123toto/ai-app-assistant-server/express";
72
72
 
73
- app.use("/api/ai-docs", createManagedAiDocsExpressHandler(aiDocs));
73
+ app.use("/api/ai-app-assistant", createManagedAiAppAssistantExpressHandler(aiAppAssistant));
74
74
  ```
75
75
 
76
- For Nest, import `createManagedAiDocsNestModule` from `@123toto/ai-app-assistant-server/nest`. Nest, RxJS and reflect-metadata are optional peer dependencies and are not required by other consumers.
76
+ For Nest, import `createManagedAiAppAssistantNestModule` from `@123toto/ai-app-assistant-server/nest`. Nest, RxJS and reflect-metadata are optional peer dependencies and are not required by other consumers.
77
77
 
78
- Native Node and Fetch-compatible runtimes can use `createAiDocsNodeHttpListener` or the standard `Request`/`Response` handlers.
78
+ Native Node and Fetch-compatible runtimes can use `createAiAppAssistantNodeHttpListener` or the standard `Request`/`Response` handlers.
79
79
 
80
80
  ## Providers
81
81
 
@@ -85,4 +85,4 @@ OpenAI, Anthropic, Mistral, Google/Gemini and Ollama are supported through `prov
85
85
 
86
86
  The managed server records counts, durations, token usage and normalized failures. It never records questions, HTML, user identities or credentials. Redis persistence is selected automatically when managed Redis storage is configured; use `telemetry: false` to disable it.
87
87
 
88
- Full documentation: [github.com/123toto/ai-docs-asker](https://github.com/123toto/ai-docs-asker)
88
+ Full documentation: [github.com/123toto/ai-app-assistant](https://github.com/123toto/ai-app-assistant)
@@ -76,7 +76,7 @@ interface AnswerGenerator {
76
76
  stream?(input: EvidenceBundle, options?: GenerationOptions): AsyncGenerator<GenerationProgress, GenerationResult>;
77
77
  }
78
78
  /** Configuration shared by all calls made through an assistant instance. */
79
- interface DocsAssistantOptions {
79
+ interface AiAppAssistantOptions {
80
80
  generator: AnswerGenerator;
81
81
  /**
82
82
  * Application documentation loaded and serialized once when the assistant is
@@ -185,4 +185,4 @@ declare function normalizeAiSdkGenerationError(error: unknown, attempts: number)
185
185
  /** Retries only failures that may succeed unchanged; configuration stays immediate. */
186
186
  declare function isRetryableProviderError(error: unknown): boolean;
187
187
 
188
- export { type AnswerGenerator as A, type DocumentationSource as D, type EvidenceBundle as E, type GenerationOptions as G, type ModelCapabilities as M, type OpenApiDocument as O, type DocsAssistantOptions as a, AiSdkConfigurationError as b, type AiSdkConnectionTestOptions as c, type AiSdkConnectionTestResult as d, type AiSdkFailureCode as e, AiSdkGenerationError as f, type AiSdkGeneratorOptions as g, type EvidenceItem as h, type GenerationProgress as i, createAiSdkGenerator as j, isRetryableProviderError as k, normalizeAiSdkGenerationError as n, testAiSdkConnection as t };
188
+ export { type AnswerGenerator as A, type DocumentationSource as D, type EvidenceBundle as E, type GenerationOptions as G, type ModelCapabilities as M, type OpenApiDocument as O, type AiAppAssistantOptions as a, AiSdkConfigurationError as b, type AiSdkConnectionTestOptions as c, type AiSdkConnectionTestResult as d, type AiSdkFailureCode as e, AiSdkGenerationError as f, type AiSdkGeneratorOptions as g, type EvidenceItem as h, type GenerationProgress as i, createAiSdkGenerator as j, isRetryableProviderError as k, normalizeAiSdkGenerationError as n, testAiSdkConnection as t };
@@ -76,7 +76,7 @@ interface AnswerGenerator {
76
76
  stream?(input: EvidenceBundle, options?: GenerationOptions): AsyncGenerator<GenerationProgress, GenerationResult>;
77
77
  }
78
78
  /** Configuration shared by all calls made through an assistant instance. */
79
- interface DocsAssistantOptions {
79
+ interface AiAppAssistantOptions {
80
80
  generator: AnswerGenerator;
81
81
  /**
82
82
  * Application documentation loaded and serialized once when the assistant is
@@ -185,4 +185,4 @@ declare function normalizeAiSdkGenerationError(error: unknown, attempts: number)
185
185
  /** Retries only failures that may succeed unchanged; configuration stays immediate. */
186
186
  declare function isRetryableProviderError(error: unknown): boolean;
187
187
 
188
- export { type AnswerGenerator as A, type DocumentationSource as D, type EvidenceBundle as E, type GenerationOptions as G, type ModelCapabilities as M, type OpenApiDocument as O, type DocsAssistantOptions as a, AiSdkConfigurationError as b, type AiSdkConnectionTestOptions as c, type AiSdkConnectionTestResult as d, type AiSdkFailureCode as e, AiSdkGenerationError as f, type AiSdkGeneratorOptions as g, type EvidenceItem as h, type GenerationProgress as i, createAiSdkGenerator as j, isRetryableProviderError as k, normalizeAiSdkGenerationError as n, testAiSdkConnection as t };
188
+ export { type AnswerGenerator as A, type DocumentationSource as D, type EvidenceBundle as E, type GenerationOptions as G, type ModelCapabilities as M, type OpenApiDocument as O, type AiAppAssistantOptions as a, AiSdkConfigurationError as b, type AiSdkConnectionTestOptions as c, type AiSdkConnectionTestResult as d, type AiSdkFailureCode as e, AiSdkGenerationError as f, type AiSdkGeneratorOptions as g, type EvidenceItem as h, type GenerationProgress as i, createAiSdkGenerator as j, isRetryableProviderError as k, normalizeAiSdkGenerationError as n, testAiSdkConnection as t };
package/dist/ai-sdk.d.cts CHANGED
@@ -1,3 +1,3 @@
1
1
  import 'ai';
2
- export { b as AiSdkConfigurationError, c as AiSdkConnectionTestOptions, d as AiSdkConnectionTestResult, e as AiSdkFailureCode, f as AiSdkGenerationError, g as AiSdkGeneratorOptions, j as createAiSdkGenerator, k as isRetryableProviderError, n as normalizeAiSdkGenerationError, t as testAiSdkConnection } from './ai-sdk-QImICd56.cjs';
2
+ export { b as AiSdkConfigurationError, c as AiSdkConnectionTestOptions, d as AiSdkConnectionTestResult, e as AiSdkFailureCode, f as AiSdkGenerationError, g as AiSdkGeneratorOptions, j as createAiSdkGenerator, k as isRetryableProviderError, n as normalizeAiSdkGenerationError, t as testAiSdkConnection } from './ai-sdk-qU3KgNu-.cjs';
3
3
  import '@123toto/ai-app-assistant-contracts';
package/dist/ai-sdk.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import 'ai';
2
- export { b as AiSdkConfigurationError, c as AiSdkConnectionTestOptions, d as AiSdkConnectionTestResult, e as AiSdkFailureCode, f as AiSdkGenerationError, g as AiSdkGeneratorOptions, j as createAiSdkGenerator, k as isRetryableProviderError, n as normalizeAiSdkGenerationError, t as testAiSdkConnection } from './ai-sdk-QImICd56.js';
2
+ export { b as AiSdkConfigurationError, c as AiSdkConnectionTestOptions, d as AiSdkConnectionTestResult, e as AiSdkFailureCode, f as AiSdkGenerationError, g as AiSdkGeneratorOptions, j as createAiSdkGenerator, k as isRetryableProviderError, n as normalizeAiSdkGenerationError, t as testAiSdkConnection } from './ai-sdk-qU3KgNu-.js';
3
3
  import '@123toto/ai-app-assistant-contracts';
@@ -1,30 +1,30 @@
1
1
  // src/http.ts
2
2
  import {
3
- askDocumentationRequestSchema
3
+ aiAppAssistantRequestSchema
4
4
  } from "@123toto/ai-app-assistant-contracts";
5
5
  import { ZodError } from "zod";
6
- var AiDocsRequestError = class extends Error {
6
+ var AiAppAssistantRequestError = class extends Error {
7
7
  constructor(status, code, message) {
8
8
  super(message);
9
9
  this.status = status;
10
10
  this.code = code;
11
- this.name = "AiDocsRequestError";
11
+ this.name = "AiAppAssistantRequestError";
12
12
  }
13
13
  status;
14
14
  code;
15
15
  };
16
- function createAiDocsFetchHandlers(options) {
16
+ function createAiAppAssistantFetchHandlers(options) {
17
17
  const prepare = async (request) => {
18
18
  assertPost(request);
19
19
  const raw = await readJson(request, options.maxBodyBytes ?? 86e5);
20
- const validated = askDocumentationRequestSchema.parse(raw);
20
+ const validated = aiAppAssistantRequestSchema.parse(raw);
21
21
  if (!options.resolveContext && !options.authorize && !options.allowAnonymous) {
22
- throw new AiDocsRequestError(401, "unauthorized", "Authentication is required");
22
+ throw new AiAppAssistantRequestError(401, "unauthorized", "Authentication is required");
23
23
  }
24
24
  const context = options.resolveContext ? await options.resolveContext(request) : void 0;
25
25
  await options.authorize?.(context, request);
26
26
  const input = options.transformRequest ? await options.transformRequest(validated, context) : validated;
27
- return { input: askDocumentationRequestSchema.parse(input), context };
27
+ return { input: aiAppAssistantRequestSchema.parse(input), context };
28
28
  };
29
29
  const present = async (response, context) => options.transformResponse ? options.transformResponse(response, context) : response;
30
30
  const ask = async (request) => {
@@ -87,27 +87,27 @@ function createAiDocsFetchHandlers(options) {
87
87
  }
88
88
  function assertPost(request) {
89
89
  if (request.method !== "POST") {
90
- throw new AiDocsRequestError(405, "method_not_allowed", "Only POST is supported");
90
+ throw new AiAppAssistantRequestError(405, "method_not_allowed", "Only POST is supported");
91
91
  }
92
92
  }
93
93
  async function readJson(request, maxBodyBytes) {
94
94
  const contentLength = Number(request.headers.get("content-length"));
95
95
  if (Number.isFinite(contentLength) && contentLength > maxBodyBytes) {
96
- throw new AiDocsRequestError(413, "request_too_large", "Request body is too large");
96
+ throw new AiAppAssistantRequestError(413, "request_too_large", "Request body is too large");
97
97
  }
98
98
  const text = await request.text();
99
99
  if (new TextEncoder().encode(text).byteLength > maxBodyBytes) {
100
- throw new AiDocsRequestError(413, "request_too_large", "Request body is too large");
100
+ throw new AiAppAssistantRequestError(413, "request_too_large", "Request body is too large");
101
101
  }
102
102
  try {
103
103
  return JSON.parse(text);
104
104
  } catch {
105
- throw new AiDocsRequestError(400, "invalid_json", "Request body must be valid JSON");
105
+ throw new AiAppAssistantRequestError(400, "invalid_json", "Request body must be valid JSON");
106
106
  }
107
107
  }
108
108
  async function mapError(error, request, customMapper) {
109
109
  if (customMapper) return customMapper(error, request);
110
- if (error instanceof AiDocsRequestError) {
110
+ if (error instanceof AiAppAssistantRequestError) {
111
111
  return jsonResponse({ error: error.code, message: error.message }, error.status);
112
112
  }
113
113
  if (error instanceof ZodError) {
@@ -130,7 +130,7 @@ function jsonResponse(value, status = 200) {
130
130
  }
131
131
 
132
132
  export {
133
- AiDocsRequestError,
134
- createAiDocsFetchHandlers
133
+ AiAppAssistantRequestError,
134
+ createAiAppAssistantFetchHandlers
135
135
  };
136
- //# sourceMappingURL=chunk-OA7OXUK7.js.map
136
+ //# sourceMappingURL=chunk-Z4IVCZ5M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/http.ts"],"sourcesContent":["import {\n aiAppAssistantRequestSchema,\n type AiAppAssistantRequest,\n type AiAppAssistantResponse\n} from \"@123toto/ai-app-assistant-contracts\";\nimport { ZodError } from \"zod\";\nimport type { AiAppAssistant, AiAppAssistantStreamEvent } from \"./assistant.js\";\n\nexport interface AiAppAssistantFetchHandlerOptions<TContext = undefined> {\n assistant: AiAppAssistant;\n /** Resolves framework-specific authentication into an application context. */\n resolveContext?: (request: Request) => Promise<TContext> | TContext;\n /** Optional application authorization executed before assistant work. */\n authorize?: (context: TContext, request: Request) => Promise<void> | void;\n /** Explicit opt-in for public prototypes without authentication hooks. */\n allowAnonymous?: boolean;\n /** Optional privacy/input policy applied after protocol validation. */\n transformRequest?: (\n input: AiAppAssistantRequest,\n context: TContext\n ) => Promise<AiAppAssistantRequest> | AiAppAssistantRequest;\n /** Optional privacy/output policy applied before serialization. */\n transformResponse?: (\n response: AiAppAssistantResponse,\n context: TContext\n ) => Promise<AiAppAssistantResponse> | AiAppAssistantResponse;\n /** Applies privacy rules to progressive text before it leaves the backend. */\n transformStreamEvent?: (\n event: AiAppAssistantStreamEvent,\n context: TContext\n ) => Promise<AiAppAssistantStreamEvent> | AiAppAssistantStreamEvent;\n /** Maximum HTTP request size. Defaults slightly above the protocol limit. */\n maxBodyBytes?: number;\n /** Maps application errors without coupling the library to one framework. */\n onError?: (error: unknown, request: Request) => Promise<Response> | Response;\n}\n\nexport interface AiAppAssistantFetchHandlers {\n ask(request: Request): Promise<Response>;\n stream(request: Request): Promise<Response>;\n /** Dispatches to `stream` when the pathname ends in `/stream`, otherwise to `ask`. */\n handle(request: Request): Promise<Response>;\n}\n\n/** Explicit safe HTTP error that host authorization hooks can throw. */\nexport class AiAppAssistantRequestError extends Error {\n public constructor(\n readonly status: number,\n readonly code: string,\n message: string\n ) {\n super(message);\n this.name = \"AiAppAssistantRequestError\";\n }\n}\n\n/**\n * Creates Fetch API handlers usable by standards-based runtimes and thin\n * Express, Fastify, Nest, Next.js, Hono, Bun or serverless adapters.\n */\nexport function createAiAppAssistantFetchHandlers<TContext = undefined>(\n options: AiAppAssistantFetchHandlerOptions<TContext>\n): AiAppAssistantFetchHandlers {\n const prepare = async (request: Request): Promise<{\n input: AiAppAssistantRequest;\n context: TContext;\n }> => {\n assertPost(request);\n const raw = await readJson(request, options.maxBodyBytes ?? 8_600_000);\n const validated = aiAppAssistantRequestSchema.parse(raw);\n if (!options.resolveContext && !options.authorize && !options.allowAnonymous) {\n throw new AiAppAssistantRequestError(401, \"unauthorized\", \"Authentication is required\");\n }\n const context = options.resolveContext\n ? await options.resolveContext(request)\n : undefined as TContext;\n await options.authorize?.(context, request);\n const input = options.transformRequest\n ? await options.transformRequest(validated, context)\n : validated;\n return { input: aiAppAssistantRequestSchema.parse(input), context };\n };\n\n const present = async (\n response: AiAppAssistantResponse,\n context: TContext\n ): Promise<AiAppAssistantResponse> => options.transformResponse\n ? options.transformResponse(response, context)\n : response;\n\n const ask = async (request: Request): Promise<Response> => {\n try {\n const { input, context } = await prepare(request);\n return jsonResponse(await present(await options.assistant.answer(input, {\n signal: request.signal\n }), context));\n } catch (error) {\n return mapError(error, request, options.onError);\n }\n };\n\n const stream = async (request: Request): Promise<Response> => {\n try {\n const { input, context } = await prepare(request);\n const encoder = new TextEncoder();\n const body = new ReadableStream<Uint8Array>({\n async start(controller) {\n try {\n const generation = options.assistant.stream(input, { signal: request.signal });\n while (true) {\n const next = await generation.next();\n if (next.done) break;\n let event = next.value.type === \"complete\"\n ? { ...next.value, response: await present(next.value.response, context) }\n : next.value;\n if (options.transformStreamEvent) {\n event = await options.transformStreamEvent(event, context);\n }\n controller.enqueue(encoder.encode(`${JSON.stringify(event)}\\n`));\n }\n } catch {\n controller.enqueue(encoder.encode(`${JSON.stringify({\n type: \"error\",\n message: \"The assistant response could not be generated.\",\n retryable: false\n })}\\n`));\n } finally {\n controller.close();\n }\n }\n });\n return new Response(body, {\n status: 200,\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/x-ndjson; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\"\n }\n });\n } catch (error) {\n return mapError(error, request, options.onError);\n }\n };\n\n return {\n ask,\n stream,\n handle: (request) => new URL(request.url).pathname.endsWith(\"/stream\")\n ? stream(request)\n : ask(request)\n };\n}\n\nfunction assertPost(request: Request): void {\n if (request.method !== \"POST\") {\n throw new AiAppAssistantRequestError(405, \"method_not_allowed\", \"Only POST is supported\");\n }\n}\n\nasync function readJson(request: Request, maxBodyBytes: number): Promise<unknown> {\n const contentLength = Number(request.headers.get(\"content-length\"));\n if (Number.isFinite(contentLength) && contentLength > maxBodyBytes) {\n throw new AiAppAssistantRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n const text = await request.text();\n if (new TextEncoder().encode(text).byteLength > maxBodyBytes) {\n throw new AiAppAssistantRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new AiAppAssistantRequestError(400, \"invalid_json\", \"Request body must be valid JSON\");\n }\n}\n\nasync function mapError(\n error: unknown,\n request: Request,\n customMapper?: AiAppAssistantFetchHandlerOptions<unknown>[\"onError\"]\n): Promise<Response> {\n if (customMapper) return customMapper(error, request);\n if (error instanceof AiAppAssistantRequestError) {\n return jsonResponse({ error: error.code, message: error.message }, error.status);\n }\n if (error instanceof ZodError) {\n return jsonResponse({ error: \"invalid_request\", message: \"The assistant request is invalid.\" }, 400);\n }\n return jsonResponse({\n error: \"assistant_error\",\n message: \"The assistant response could not be generated.\"\n }, 500);\n}\n\nfunction jsonResponse(value: unknown, status = 200): Response {\n return new Response(JSON.stringify(value), {\n status,\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/json; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\"\n }\n });\n}\n"],"mappings":"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","names":[]}
package/dist/express.cjs CHANGED
@@ -20,26 +20,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/express.ts
21
21
  var express_exports = {};
22
22
  __export(express_exports, {
23
- createManagedAiDocsExpressHandler: () => createManagedAiDocsExpressHandler
23
+ createManagedAiAppAssistantExpressHandler: () => createManagedAiAppAssistantExpressHandler
24
24
  });
25
25
  module.exports = __toCommonJS(express_exports);
26
26
 
27
27
  // src/http.ts
28
28
  var import_ai_app_assistant_contracts = require("@123toto/ai-app-assistant-contracts");
29
29
  var import_zod = require("zod");
30
- var AiDocsRequestError = class extends Error {
30
+ var AiAppAssistantRequestError = class extends Error {
31
31
  constructor(status, code, message) {
32
32
  super(message);
33
33
  this.status = status;
34
34
  this.code = code;
35
- this.name = "AiDocsRequestError";
35
+ this.name = "AiAppAssistantRequestError";
36
36
  }
37
37
  status;
38
38
  code;
39
39
  };
40
40
 
41
41
  // src/express.ts
42
- function createManagedAiDocsExpressHandler(server, options = {}) {
42
+ function createManagedAiAppAssistantExpressHandler(server, options = {}) {
43
43
  return async (request, response, next) => {
44
44
  const abortController = new AbortController();
45
45
  const abort = () => abortController.abort(new DOMException("Client disconnected", "AbortError"));
@@ -96,7 +96,7 @@ async function readBody(request, maxBodyBytes) {
96
96
  const bytes = typeof chunk === "string" ? Buffer.from(chunk) : new Uint8Array(chunk);
97
97
  size += bytes.byteLength;
98
98
  if (size > maxBodyBytes) {
99
- throw new AiDocsRequestError(413, "request_too_large", "Request body is too large");
99
+ throw new AiAppAssistantRequestError(413, "request_too_large", "Request body is too large");
100
100
  }
101
101
  chunks.push(bytes);
102
102
  }
@@ -124,14 +124,14 @@ async function writeFetchResponse(response, result) {
124
124
  }
125
125
  }
126
126
  function writeConnectorError(response, error) {
127
- const status = error instanceof AiDocsRequestError ? error.status : 500;
128
- const code = error instanceof AiDocsRequestError ? error.code : "assistant_error";
127
+ const status = error instanceof AiAppAssistantRequestError ? error.status : 500;
128
+ const code = error instanceof AiAppAssistantRequestError ? error.code : "assistant_error";
129
129
  response.statusCode = status;
130
130
  response.setHeader("content-type", "application/json; charset=utf-8");
131
131
  response.end(JSON.stringify({ error: code }));
132
132
  }
133
133
  // Annotate the CommonJS export names for ESM import in node:
134
134
  0 && (module.exports = {
135
- createManagedAiDocsExpressHandler
135
+ createManagedAiAppAssistantExpressHandler
136
136
  });
137
137
  //# sourceMappingURL=express.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/express.ts","../src/http.ts"],"sourcesContent":["import { AiDocsRequestError } from \"./http.js\";\nimport type { ManagedAiDocsServer } from \"./managed-server.js\";\n\n/** Minimal Express request shape; importing Express types is intentionally unnecessary. */\nexport interface AiDocsExpressRequest {\n method?: string;\n originalUrl?: string;\n url?: string;\n protocol?: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n on?(event: string, listener: () => void): unknown;\n off?(event: string, listener: () => void): unknown;\n [key: string]: unknown;\n}\n\n/** Minimal Express response shape used by the connector. */\nexport interface AiDocsExpressResponse {\n statusCode: number;\n setHeader(name: string, value: string): unknown;\n write(chunk: Uint8Array): boolean;\n end(chunk?: string): unknown;\n once?(event: string, listener: () => void): unknown;\n destroyed?: boolean;\n}\n\nexport type AiDocsExpressNext = (error?: unknown) => void;\n\nexport type AiDocsExpressManagedServer<\n TRequest extends AiDocsExpressRequest = AiDocsExpressRequest\n> = Pick<ManagedAiDocsServer<{ id: string; label: string }, TRequest>, \"fetch\">;\n\nexport interface AiDocsExpressHandlerOptions {\n /** Origin used only when Express does not expose a Host header. */\n origin?: string;\n /** Maximum size accepted when no JSON body parser populated request.body. */\n maxBodyBytes?: number;\n /** Lets another Express handler process unknown routes below the mounted prefix. */\n fallthrough?: boolean;\n}\n\nexport type AiDocsExpressHandler<TRequest extends AiDocsExpressRequest> = (\n request: TRequest,\n response: AiDocsExpressResponse,\n next?: AiDocsExpressNext\n) => Promise<void>;\n\n/**\n * Creates an Express-compatible handler for the complete managed API.\n *\n * @example\n * `app.use(\"/api/ai-docs\", createManagedAiDocsExpressHandler(aiDocs));`\n */\nexport function createManagedAiDocsExpressHandler<\n TRequest extends AiDocsExpressRequest = AiDocsExpressRequest\n>(\n server: AiDocsExpressManagedServer<TRequest>,\n options: AiDocsExpressHandlerOptions = {}\n): AiDocsExpressHandler<TRequest> {\n return async (request, response, next) => {\n const abortController = new AbortController();\n const abort = (): void => abortController.abort(new DOMException(\"Client disconnected\", \"AbortError\"));\n request.on?.(\"close\", abort);\n try {\n const webRequest = await toFetchRequest(request, abortController.signal, options);\n const result = await server.fetch.handle(webRequest, request);\n if (options.fallthrough && result.status === 404 && next) {\n next();\n return;\n }\n await writeFetchResponse(response, result);\n } catch (error) {\n if (next) {\n next(error);\n return;\n }\n writeConnectorError(response, error);\n } finally {\n request.off?.(\"close\", abort);\n }\n };\n}\n\nasync function toFetchRequest(\n request: AiDocsExpressRequest,\n signal: AbortSignal,\n options: AiDocsExpressHandlerOptions\n): Promise<Request> {\n const headers = new Headers();\n for (const [name, value] of Object.entries(request.headers)) {\n if (Array.isArray(value)) value.forEach((item) => headers.append(name, item));\n else if (value !== undefined) headers.set(name, value);\n }\n const method = request.method?.toUpperCase() || \"GET\";\n const host = headers.get(\"host\");\n const protocol = request.protocol || headers.get(\"x-forwarded-proto\") || \"http\";\n const origin = options.origin ?? `${protocol}://${host || \"localhost\"}`;\n // originalUrl preserves the mount prefix stripped from request.url by Express.\n const url = new URL(request.originalUrl || request.url || \"/\", origin);\n const body = method === \"GET\" || method === \"HEAD\"\n ? undefined\n : request.body !== undefined\n ? serializeBody(request.body, headers)\n : await readBody(request, options.maxBodyBytes ?? 8_600_000);\n return new Request(url, {\n method,\n headers,\n signal,\n ...(body !== undefined ? { body } : {})\n });\n}\n\nfunction serializeBody(body: unknown, headers: Headers): string {\n if (typeof body === \"string\") return body;\n if (body instanceof Uint8Array) return new TextDecoder().decode(body);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return JSON.stringify(body) ?? \"null\";\n}\n\nasync function readBody(request: AiDocsExpressRequest, maxBodyBytes: number): Promise<string | undefined> {\n if (!(Symbol.asyncIterator in request)) return undefined;\n const chunks: Uint8Array[] = [];\n let size = 0;\n for await (const chunk of request as AsyncIterable<string | Uint8Array>) {\n const bytes = typeof chunk === \"string\" ? Buffer.from(chunk) : new Uint8Array(chunk);\n size += bytes.byteLength;\n if (size > maxBodyBytes) {\n throw new AiDocsRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n chunks.push(bytes);\n }\n return chunks.length ? Buffer.concat(chunks).toString(\"utf8\") : undefined;\n}\n\nasync function writeFetchResponse(response: AiDocsExpressResponse, result: Response): Promise<void> {\n response.statusCode = result.status;\n result.headers.forEach((value, name) => response.setHeader(name, value));\n if (!result.body) {\n response.end();\n return;\n }\n const reader = result.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!response.write(value) && response.once) {\n await new Promise<void>((resolve) => response.once!(\"drain\", resolve));\n }\n }\n if (!response.destroyed) response.end();\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction writeConnectorError(response: AiDocsExpressResponse, error: unknown): void {\n const status = error instanceof AiDocsRequestError ? error.status : 500;\n const code = error instanceof AiDocsRequestError ? error.code : \"assistant_error\";\n response.statusCode = status;\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n response.end(JSON.stringify({ error: code }));\n}\n","import {\n askDocumentationRequestSchema,\n type AskDocumentationRequest,\n type AskDocumentationResponse\n} from \"@123toto/ai-app-assistant-contracts\";\nimport { ZodError } from \"zod\";\nimport type { DocsAssistant, DocsAssistantStreamEvent } from \"./assistant.js\";\n\nexport interface AiDocsFetchHandlerOptions<TContext = undefined> {\n assistant: DocsAssistant;\n /** Resolves framework-specific authentication into an application context. */\n resolveContext?: (request: Request) => Promise<TContext> | TContext;\n /** Optional application authorization executed before assistant work. */\n authorize?: (context: TContext, request: Request) => Promise<void> | void;\n /** Explicit opt-in for public prototypes without authentication hooks. */\n allowAnonymous?: boolean;\n /** Optional privacy/input policy applied after protocol validation. */\n transformRequest?: (\n input: AskDocumentationRequest,\n context: TContext\n ) => Promise<AskDocumentationRequest> | AskDocumentationRequest;\n /** Optional privacy/output policy applied before serialization. */\n transformResponse?: (\n response: AskDocumentationResponse,\n context: TContext\n ) => Promise<AskDocumentationResponse> | AskDocumentationResponse;\n /** Applies privacy rules to progressive text before it leaves the backend. */\n transformStreamEvent?: (\n event: DocsAssistantStreamEvent,\n context: TContext\n ) => Promise<DocsAssistantStreamEvent> | DocsAssistantStreamEvent;\n /** Maximum HTTP request size. Defaults slightly above the protocol limit. */\n maxBodyBytes?: number;\n /** Maps application errors without coupling the library to one framework. */\n onError?: (error: unknown, request: Request) => Promise<Response> | Response;\n}\n\nexport interface AiDocsFetchHandlers {\n ask(request: Request): Promise<Response>;\n stream(request: Request): Promise<Response>;\n /** Dispatches to `stream` when the pathname ends in `/stream`, otherwise to `ask`. */\n handle(request: Request): Promise<Response>;\n}\n\n/** Explicit safe HTTP error that host authorization hooks can throw. */\nexport class AiDocsRequestError extends Error {\n public constructor(\n readonly status: number,\n readonly code: string,\n message: string\n ) {\n super(message);\n this.name = \"AiDocsRequestError\";\n }\n}\n\n/**\n * Creates Fetch API handlers usable by standards-based runtimes and thin\n * Express, Fastify, Nest, Next.js, Hono, Bun or serverless adapters.\n */\nexport function createAiDocsFetchHandlers<TContext = undefined>(\n options: AiDocsFetchHandlerOptions<TContext>\n): AiDocsFetchHandlers {\n const prepare = async (request: Request): Promise<{\n input: AskDocumentationRequest;\n context: TContext;\n }> => {\n assertPost(request);\n const raw = await readJson(request, options.maxBodyBytes ?? 8_600_000);\n const validated = askDocumentationRequestSchema.parse(raw);\n if (!options.resolveContext && !options.authorize && !options.allowAnonymous) {\n throw new AiDocsRequestError(401, \"unauthorized\", \"Authentication is required\");\n }\n const context = options.resolveContext\n ? await options.resolveContext(request)\n : undefined as TContext;\n await options.authorize?.(context, request);\n const input = options.transformRequest\n ? await options.transformRequest(validated, context)\n : validated;\n return { input: askDocumentationRequestSchema.parse(input), context };\n };\n\n const present = async (\n response: AskDocumentationResponse,\n context: TContext\n ): Promise<AskDocumentationResponse> => options.transformResponse\n ? options.transformResponse(response, context)\n : response;\n\n const ask = async (request: Request): Promise<Response> => {\n try {\n const { input, context } = await prepare(request);\n return jsonResponse(await present(await options.assistant.answer(input, {\n signal: request.signal\n }), context));\n } catch (error) {\n return mapError(error, request, options.onError);\n }\n };\n\n const stream = async (request: Request): Promise<Response> => {\n try {\n const { input, context } = await prepare(request);\n const encoder = new TextEncoder();\n const body = new ReadableStream<Uint8Array>({\n async start(controller) {\n try {\n const generation = options.assistant.stream(input, { signal: request.signal });\n while (true) {\n const next = await generation.next();\n if (next.done) break;\n let event = next.value.type === \"complete\"\n ? { ...next.value, response: await present(next.value.response, context) }\n : next.value;\n if (options.transformStreamEvent) {\n event = await options.transformStreamEvent(event, context);\n }\n controller.enqueue(encoder.encode(`${JSON.stringify(event)}\\n`));\n }\n } catch {\n controller.enqueue(encoder.encode(`${JSON.stringify({\n type: \"error\",\n message: \"The assistant response could not be generated.\",\n retryable: false\n })}\\n`));\n } finally {\n controller.close();\n }\n }\n });\n return new Response(body, {\n status: 200,\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/x-ndjson; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\"\n }\n });\n } catch (error) {\n return mapError(error, request, options.onError);\n }\n };\n\n return {\n ask,\n stream,\n handle: (request) => new URL(request.url).pathname.endsWith(\"/stream\")\n ? stream(request)\n : ask(request)\n };\n}\n\nfunction assertPost(request: Request): void {\n if (request.method !== \"POST\") {\n throw new AiDocsRequestError(405, \"method_not_allowed\", \"Only POST is supported\");\n }\n}\n\nasync function readJson(request: Request, maxBodyBytes: number): Promise<unknown> {\n const contentLength = Number(request.headers.get(\"content-length\"));\n if (Number.isFinite(contentLength) && contentLength > maxBodyBytes) {\n throw new AiDocsRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n const text = await request.text();\n if (new TextEncoder().encode(text).byteLength > maxBodyBytes) {\n throw new AiDocsRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new AiDocsRequestError(400, \"invalid_json\", \"Request body must be valid JSON\");\n }\n}\n\nasync function mapError(\n error: unknown,\n request: Request,\n customMapper?: AiDocsFetchHandlerOptions<unknown>[\"onError\"]\n): Promise<Response> {\n if (customMapper) return customMapper(error, request);\n if (error instanceof AiDocsRequestError) {\n return jsonResponse({ error: error.code, message: error.message }, error.status);\n }\n if (error instanceof ZodError) {\n return jsonResponse({ error: \"invalid_request\", message: \"The assistant request is invalid.\" }, 400);\n }\n return jsonResponse({\n error: \"assistant_error\",\n message: \"The assistant response could not be generated.\"\n }, 500);\n}\n\nfunction jsonResponse(value: unknown, status = 200): Response {\n return new Response(JSON.stringify(value), {\n status,\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/json; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\"\n }\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/express.ts","../src/http.ts"],"sourcesContent":["import { AiAppAssistantRequestError } from \"./http.js\";\nimport type { ManagedAiAppAssistantServer } from \"./managed-server.js\";\n\n/** Minimal Express request shape; importing Express types is intentionally unnecessary. */\nexport interface AiAppAssistantExpressRequest {\n method?: string;\n originalUrl?: string;\n url?: string;\n protocol?: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n on?(event: string, listener: () => void): unknown;\n off?(event: string, listener: () => void): unknown;\n [key: string]: unknown;\n}\n\n/** Minimal Express response shape used by the connector. */\nexport interface AiAppAssistantExpressResponse {\n statusCode: number;\n setHeader(name: string, value: string): unknown;\n write(chunk: Uint8Array): boolean;\n end(chunk?: string): unknown;\n once?(event: string, listener: () => void): unknown;\n destroyed?: boolean;\n}\n\nexport type AiAppAssistantExpressNext = (error?: unknown) => void;\n\nexport type AiAppAssistantExpressManagedServer<\n TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest\n> = Pick<ManagedAiAppAssistantServer<{ id: string; label: string }, TRequest>, \"fetch\">;\n\nexport interface AiAppAssistantExpressHandlerOptions {\n /** Origin used only when Express does not expose a Host header. */\n origin?: string;\n /** Maximum size accepted when no JSON body parser populated request.body. */\n maxBodyBytes?: number;\n /** Lets another Express handler process unknown routes below the mounted prefix. */\n fallthrough?: boolean;\n}\n\nexport type AiAppAssistantExpressHandler<TRequest extends AiAppAssistantExpressRequest> = (\n request: TRequest,\n response: AiAppAssistantExpressResponse,\n next?: AiAppAssistantExpressNext\n) => Promise<void>;\n\n/**\n * Creates an Express-compatible handler for the complete managed API.\n *\n * @example\n * `app.use(\"/api/ai-app-assistant\", createManagedAiAppAssistantExpressHandler(aiAppAssistant));`\n */\nexport function createManagedAiAppAssistantExpressHandler<\n TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest\n>(\n server: AiAppAssistantExpressManagedServer<TRequest>,\n options: AiAppAssistantExpressHandlerOptions = {}\n): AiAppAssistantExpressHandler<TRequest> {\n return async (request, response, next) => {\n const abortController = new AbortController();\n const abort = (): void => abortController.abort(new DOMException(\"Client disconnected\", \"AbortError\"));\n request.on?.(\"close\", abort);\n try {\n const webRequest = await toFetchRequest(request, abortController.signal, options);\n const result = await server.fetch.handle(webRequest, request);\n if (options.fallthrough && result.status === 404 && next) {\n next();\n return;\n }\n await writeFetchResponse(response, result);\n } catch (error) {\n if (next) {\n next(error);\n return;\n }\n writeConnectorError(response, error);\n } finally {\n request.off?.(\"close\", abort);\n }\n };\n}\n\nasync function toFetchRequest(\n request: AiAppAssistantExpressRequest,\n signal: AbortSignal,\n options: AiAppAssistantExpressHandlerOptions\n): Promise<Request> {\n const headers = new Headers();\n for (const [name, value] of Object.entries(request.headers)) {\n if (Array.isArray(value)) value.forEach((item) => headers.append(name, item));\n else if (value !== undefined) headers.set(name, value);\n }\n const method = request.method?.toUpperCase() || \"GET\";\n const host = headers.get(\"host\");\n const protocol = request.protocol || headers.get(\"x-forwarded-proto\") || \"http\";\n const origin = options.origin ?? `${protocol}://${host || \"localhost\"}`;\n // originalUrl preserves the mount prefix stripped from request.url by Express.\n const url = new URL(request.originalUrl || request.url || \"/\", origin);\n const body = method === \"GET\" || method === \"HEAD\"\n ? undefined\n : request.body !== undefined\n ? serializeBody(request.body, headers)\n : await readBody(request, options.maxBodyBytes ?? 8_600_000);\n return new Request(url, {\n method,\n headers,\n signal,\n ...(body !== undefined ? { body } : {})\n });\n}\n\nfunction serializeBody(body: unknown, headers: Headers): string {\n if (typeof body === \"string\") return body;\n if (body instanceof Uint8Array) return new TextDecoder().decode(body);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return JSON.stringify(body) ?? \"null\";\n}\n\nasync function readBody(request: AiAppAssistantExpressRequest, maxBodyBytes: number): Promise<string | undefined> {\n if (!(Symbol.asyncIterator in request)) return undefined;\n const chunks: Uint8Array[] = [];\n let size = 0;\n for await (const chunk of request as AsyncIterable<string | Uint8Array>) {\n const bytes = typeof chunk === \"string\" ? Buffer.from(chunk) : new Uint8Array(chunk);\n size += bytes.byteLength;\n if (size > maxBodyBytes) {\n throw new AiAppAssistantRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n chunks.push(bytes);\n }\n return chunks.length ? Buffer.concat(chunks).toString(\"utf8\") : undefined;\n}\n\nasync function writeFetchResponse(response: AiAppAssistantExpressResponse, result: Response): Promise<void> {\n response.statusCode = result.status;\n result.headers.forEach((value, name) => response.setHeader(name, value));\n if (!result.body) {\n response.end();\n return;\n }\n const reader = result.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!response.write(value) && response.once) {\n await new Promise<void>((resolve) => response.once!(\"drain\", resolve));\n }\n }\n if (!response.destroyed) response.end();\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction writeConnectorError(response: AiAppAssistantExpressResponse, error: unknown): void {\n const status = error instanceof AiAppAssistantRequestError ? error.status : 500;\n const code = error instanceof AiAppAssistantRequestError ? error.code : \"assistant_error\";\n response.statusCode = status;\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n response.end(JSON.stringify({ error: code }));\n}\n","import {\n aiAppAssistantRequestSchema,\n type AiAppAssistantRequest,\n type AiAppAssistantResponse\n} from \"@123toto/ai-app-assistant-contracts\";\nimport { ZodError } from \"zod\";\nimport type { AiAppAssistant, AiAppAssistantStreamEvent } from \"./assistant.js\";\n\nexport interface AiAppAssistantFetchHandlerOptions<TContext = undefined> {\n assistant: AiAppAssistant;\n /** Resolves framework-specific authentication into an application context. */\n resolveContext?: (request: Request) => Promise<TContext> | TContext;\n /** Optional application authorization executed before assistant work. */\n authorize?: (context: TContext, request: Request) => Promise<void> | void;\n /** Explicit opt-in for public prototypes without authentication hooks. */\n allowAnonymous?: boolean;\n /** Optional privacy/input policy applied after protocol validation. */\n transformRequest?: (\n input: AiAppAssistantRequest,\n context: TContext\n ) => Promise<AiAppAssistantRequest> | AiAppAssistantRequest;\n /** Optional privacy/output policy applied before serialization. */\n transformResponse?: (\n response: AiAppAssistantResponse,\n context: TContext\n ) => Promise<AiAppAssistantResponse> | AiAppAssistantResponse;\n /** Applies privacy rules to progressive text before it leaves the backend. */\n transformStreamEvent?: (\n event: AiAppAssistantStreamEvent,\n context: TContext\n ) => Promise<AiAppAssistantStreamEvent> | AiAppAssistantStreamEvent;\n /** Maximum HTTP request size. Defaults slightly above the protocol limit. */\n maxBodyBytes?: number;\n /** Maps application errors without coupling the library to one framework. */\n onError?: (error: unknown, request: Request) => Promise<Response> | Response;\n}\n\nexport interface AiAppAssistantFetchHandlers {\n ask(request: Request): Promise<Response>;\n stream(request: Request): Promise<Response>;\n /** Dispatches to `stream` when the pathname ends in `/stream`, otherwise to `ask`. */\n handle(request: Request): Promise<Response>;\n}\n\n/** Explicit safe HTTP error that host authorization hooks can throw. */\nexport class AiAppAssistantRequestError extends Error {\n public constructor(\n readonly status: number,\n readonly code: string,\n message: string\n ) {\n super(message);\n this.name = \"AiAppAssistantRequestError\";\n }\n}\n\n/**\n * Creates Fetch API handlers usable by standards-based runtimes and thin\n * Express, Fastify, Nest, Next.js, Hono, Bun or serverless adapters.\n */\nexport function createAiAppAssistantFetchHandlers<TContext = undefined>(\n options: AiAppAssistantFetchHandlerOptions<TContext>\n): AiAppAssistantFetchHandlers {\n const prepare = async (request: Request): Promise<{\n input: AiAppAssistantRequest;\n context: TContext;\n }> => {\n assertPost(request);\n const raw = await readJson(request, options.maxBodyBytes ?? 8_600_000);\n const validated = aiAppAssistantRequestSchema.parse(raw);\n if (!options.resolveContext && !options.authorize && !options.allowAnonymous) {\n throw new AiAppAssistantRequestError(401, \"unauthorized\", \"Authentication is required\");\n }\n const context = options.resolveContext\n ? await options.resolveContext(request)\n : undefined as TContext;\n await options.authorize?.(context, request);\n const input = options.transformRequest\n ? await options.transformRequest(validated, context)\n : validated;\n return { input: aiAppAssistantRequestSchema.parse(input), context };\n };\n\n const present = async (\n response: AiAppAssistantResponse,\n context: TContext\n ): Promise<AiAppAssistantResponse> => options.transformResponse\n ? options.transformResponse(response, context)\n : response;\n\n const ask = async (request: Request): Promise<Response> => {\n try {\n const { input, context } = await prepare(request);\n return jsonResponse(await present(await options.assistant.answer(input, {\n signal: request.signal\n }), context));\n } catch (error) {\n return mapError(error, request, options.onError);\n }\n };\n\n const stream = async (request: Request): Promise<Response> => {\n try {\n const { input, context } = await prepare(request);\n const encoder = new TextEncoder();\n const body = new ReadableStream<Uint8Array>({\n async start(controller) {\n try {\n const generation = options.assistant.stream(input, { signal: request.signal });\n while (true) {\n const next = await generation.next();\n if (next.done) break;\n let event = next.value.type === \"complete\"\n ? { ...next.value, response: await present(next.value.response, context) }\n : next.value;\n if (options.transformStreamEvent) {\n event = await options.transformStreamEvent(event, context);\n }\n controller.enqueue(encoder.encode(`${JSON.stringify(event)}\\n`));\n }\n } catch {\n controller.enqueue(encoder.encode(`${JSON.stringify({\n type: \"error\",\n message: \"The assistant response could not be generated.\",\n retryable: false\n })}\\n`));\n } finally {\n controller.close();\n }\n }\n });\n return new Response(body, {\n status: 200,\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/x-ndjson; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\"\n }\n });\n } catch (error) {\n return mapError(error, request, options.onError);\n }\n };\n\n return {\n ask,\n stream,\n handle: (request) => new URL(request.url).pathname.endsWith(\"/stream\")\n ? stream(request)\n : ask(request)\n };\n}\n\nfunction assertPost(request: Request): void {\n if (request.method !== \"POST\") {\n throw new AiAppAssistantRequestError(405, \"method_not_allowed\", \"Only POST is supported\");\n }\n}\n\nasync function readJson(request: Request, maxBodyBytes: number): Promise<unknown> {\n const contentLength = Number(request.headers.get(\"content-length\"));\n if (Number.isFinite(contentLength) && contentLength > maxBodyBytes) {\n throw new AiAppAssistantRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n const text = await request.text();\n if (new TextEncoder().encode(text).byteLength > maxBodyBytes) {\n throw new AiAppAssistantRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new AiAppAssistantRequestError(400, \"invalid_json\", \"Request body must be valid JSON\");\n }\n}\n\nasync function mapError(\n error: unknown,\n request: Request,\n customMapper?: AiAppAssistantFetchHandlerOptions<unknown>[\"onError\"]\n): Promise<Response> {\n if (customMapper) return customMapper(error, request);\n if (error instanceof AiAppAssistantRequestError) {\n return jsonResponse({ error: error.code, message: error.message }, error.status);\n }\n if (error instanceof ZodError) {\n return jsonResponse({ error: \"invalid_request\", message: \"The assistant request is invalid.\" }, 400);\n }\n return jsonResponse({\n error: \"assistant_error\",\n message: \"The assistant response could not be generated.\"\n }, 500);\n}\n\nfunction jsonResponse(value: unknown, status = 200): Response {\n return new Response(JSON.stringify(value), {\n status,\n headers: {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/json; charset=utf-8\",\n \"x-content-type-options\": \"nosniff\"\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -1,10 +1,10 @@
1
- import { M as ManagedAiDocsServer } from './managed-server-7iurKxF1.cjs';
2
- import './ai-sdk-QImICd56.cjs';
1
+ import { M as ManagedAiAppAssistantServer } from './managed-server-CthTKEQ6.cjs';
2
+ import './ai-sdk-qU3KgNu-.cjs';
3
3
  import 'ai';
4
4
  import '@123toto/ai-app-assistant-contracts';
5
5
 
6
6
  /** Minimal Express request shape; importing Express types is intentionally unnecessary. */
7
- interface AiDocsExpressRequest {
7
+ interface AiAppAssistantExpressRequest {
8
8
  method?: string;
9
9
  originalUrl?: string;
10
10
  url?: string;
@@ -16,7 +16,7 @@ interface AiDocsExpressRequest {
16
16
  [key: string]: unknown;
17
17
  }
18
18
  /** Minimal Express response shape used by the connector. */
19
- interface AiDocsExpressResponse {
19
+ interface AiAppAssistantExpressResponse {
20
20
  statusCode: number;
21
21
  setHeader(name: string, value: string): unknown;
22
22
  write(chunk: Uint8Array): boolean;
@@ -24,12 +24,12 @@ interface AiDocsExpressResponse {
24
24
  once?(event: string, listener: () => void): unknown;
25
25
  destroyed?: boolean;
26
26
  }
27
- type AiDocsExpressNext = (error?: unknown) => void;
28
- type AiDocsExpressManagedServer<TRequest extends AiDocsExpressRequest = AiDocsExpressRequest> = Pick<ManagedAiDocsServer<{
27
+ type AiAppAssistantExpressNext = (error?: unknown) => void;
28
+ type AiAppAssistantExpressManagedServer<TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest> = Pick<ManagedAiAppAssistantServer<{
29
29
  id: string;
30
30
  label: string;
31
31
  }, TRequest>, "fetch">;
32
- interface AiDocsExpressHandlerOptions {
32
+ interface AiAppAssistantExpressHandlerOptions {
33
33
  /** Origin used only when Express does not expose a Host header. */
34
34
  origin?: string;
35
35
  /** Maximum size accepted when no JSON body parser populated request.body. */
@@ -37,13 +37,13 @@ interface AiDocsExpressHandlerOptions {
37
37
  /** Lets another Express handler process unknown routes below the mounted prefix. */
38
38
  fallthrough?: boolean;
39
39
  }
40
- type AiDocsExpressHandler<TRequest extends AiDocsExpressRequest> = (request: TRequest, response: AiDocsExpressResponse, next?: AiDocsExpressNext) => Promise<void>;
40
+ type AiAppAssistantExpressHandler<TRequest extends AiAppAssistantExpressRequest> = (request: TRequest, response: AiAppAssistantExpressResponse, next?: AiAppAssistantExpressNext) => Promise<void>;
41
41
  /**
42
42
  * Creates an Express-compatible handler for the complete managed API.
43
43
  *
44
44
  * @example
45
- * `app.use("/api/ai-docs", createManagedAiDocsExpressHandler(aiDocs));`
45
+ * `app.use("/api/ai-app-assistant", createManagedAiAppAssistantExpressHandler(aiAppAssistant));`
46
46
  */
47
- declare function createManagedAiDocsExpressHandler<TRequest extends AiDocsExpressRequest = AiDocsExpressRequest>(server: AiDocsExpressManagedServer<TRequest>, options?: AiDocsExpressHandlerOptions): AiDocsExpressHandler<TRequest>;
47
+ declare function createManagedAiAppAssistantExpressHandler<TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest>(server: AiAppAssistantExpressManagedServer<TRequest>, options?: AiAppAssistantExpressHandlerOptions): AiAppAssistantExpressHandler<TRequest>;
48
48
 
49
- export { type AiDocsExpressHandler, type AiDocsExpressHandlerOptions, type AiDocsExpressManagedServer, type AiDocsExpressNext, type AiDocsExpressRequest, type AiDocsExpressResponse, createManagedAiDocsExpressHandler };
49
+ export { type AiAppAssistantExpressHandler, type AiAppAssistantExpressHandlerOptions, type AiAppAssistantExpressManagedServer, type AiAppAssistantExpressNext, type AiAppAssistantExpressRequest, type AiAppAssistantExpressResponse, createManagedAiAppAssistantExpressHandler };
package/dist/express.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { M as ManagedAiDocsServer } from './managed-server-CrZumvVU.js';
2
- import './ai-sdk-QImICd56.js';
1
+ import { M as ManagedAiAppAssistantServer } from './managed-server-BGQ-1jkx.js';
2
+ import './ai-sdk-qU3KgNu-.js';
3
3
  import 'ai';
4
4
  import '@123toto/ai-app-assistant-contracts';
5
5
 
6
6
  /** Minimal Express request shape; importing Express types is intentionally unnecessary. */
7
- interface AiDocsExpressRequest {
7
+ interface AiAppAssistantExpressRequest {
8
8
  method?: string;
9
9
  originalUrl?: string;
10
10
  url?: string;
@@ -16,7 +16,7 @@ interface AiDocsExpressRequest {
16
16
  [key: string]: unknown;
17
17
  }
18
18
  /** Minimal Express response shape used by the connector. */
19
- interface AiDocsExpressResponse {
19
+ interface AiAppAssistantExpressResponse {
20
20
  statusCode: number;
21
21
  setHeader(name: string, value: string): unknown;
22
22
  write(chunk: Uint8Array): boolean;
@@ -24,12 +24,12 @@ interface AiDocsExpressResponse {
24
24
  once?(event: string, listener: () => void): unknown;
25
25
  destroyed?: boolean;
26
26
  }
27
- type AiDocsExpressNext = (error?: unknown) => void;
28
- type AiDocsExpressManagedServer<TRequest extends AiDocsExpressRequest = AiDocsExpressRequest> = Pick<ManagedAiDocsServer<{
27
+ type AiAppAssistantExpressNext = (error?: unknown) => void;
28
+ type AiAppAssistantExpressManagedServer<TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest> = Pick<ManagedAiAppAssistantServer<{
29
29
  id: string;
30
30
  label: string;
31
31
  }, TRequest>, "fetch">;
32
- interface AiDocsExpressHandlerOptions {
32
+ interface AiAppAssistantExpressHandlerOptions {
33
33
  /** Origin used only when Express does not expose a Host header. */
34
34
  origin?: string;
35
35
  /** Maximum size accepted when no JSON body parser populated request.body. */
@@ -37,13 +37,13 @@ interface AiDocsExpressHandlerOptions {
37
37
  /** Lets another Express handler process unknown routes below the mounted prefix. */
38
38
  fallthrough?: boolean;
39
39
  }
40
- type AiDocsExpressHandler<TRequest extends AiDocsExpressRequest> = (request: TRequest, response: AiDocsExpressResponse, next?: AiDocsExpressNext) => Promise<void>;
40
+ type AiAppAssistantExpressHandler<TRequest extends AiAppAssistantExpressRequest> = (request: TRequest, response: AiAppAssistantExpressResponse, next?: AiAppAssistantExpressNext) => Promise<void>;
41
41
  /**
42
42
  * Creates an Express-compatible handler for the complete managed API.
43
43
  *
44
44
  * @example
45
- * `app.use("/api/ai-docs", createManagedAiDocsExpressHandler(aiDocs));`
45
+ * `app.use("/api/ai-app-assistant", createManagedAiAppAssistantExpressHandler(aiAppAssistant));`
46
46
  */
47
- declare function createManagedAiDocsExpressHandler<TRequest extends AiDocsExpressRequest = AiDocsExpressRequest>(server: AiDocsExpressManagedServer<TRequest>, options?: AiDocsExpressHandlerOptions): AiDocsExpressHandler<TRequest>;
47
+ declare function createManagedAiAppAssistantExpressHandler<TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest>(server: AiAppAssistantExpressManagedServer<TRequest>, options?: AiAppAssistantExpressHandlerOptions): AiAppAssistantExpressHandler<TRequest>;
48
48
 
49
- export { type AiDocsExpressHandler, type AiDocsExpressHandlerOptions, type AiDocsExpressManagedServer, type AiDocsExpressNext, type AiDocsExpressRequest, type AiDocsExpressResponse, createManagedAiDocsExpressHandler };
49
+ export { type AiAppAssistantExpressHandler, type AiAppAssistantExpressHandlerOptions, type AiAppAssistantExpressManagedServer, type AiAppAssistantExpressNext, type AiAppAssistantExpressRequest, type AiAppAssistantExpressResponse, createManagedAiAppAssistantExpressHandler };
package/dist/express.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
- AiDocsRequestError
3
- } from "./chunk-OA7OXUK7.js";
2
+ AiAppAssistantRequestError
3
+ } from "./chunk-Z4IVCZ5M.js";
4
4
 
5
5
  // src/express.ts
6
- function createManagedAiDocsExpressHandler(server, options = {}) {
6
+ function createManagedAiAppAssistantExpressHandler(server, options = {}) {
7
7
  return async (request, response, next) => {
8
8
  const abortController = new AbortController();
9
9
  const abort = () => abortController.abort(new DOMException("Client disconnected", "AbortError"));
@@ -60,7 +60,7 @@ async function readBody(request, maxBodyBytes) {
60
60
  const bytes = typeof chunk === "string" ? Buffer.from(chunk) : new Uint8Array(chunk);
61
61
  size += bytes.byteLength;
62
62
  if (size > maxBodyBytes) {
63
- throw new AiDocsRequestError(413, "request_too_large", "Request body is too large");
63
+ throw new AiAppAssistantRequestError(413, "request_too_large", "Request body is too large");
64
64
  }
65
65
  chunks.push(bytes);
66
66
  }
@@ -88,13 +88,13 @@ async function writeFetchResponse(response, result) {
88
88
  }
89
89
  }
90
90
  function writeConnectorError(response, error) {
91
- const status = error instanceof AiDocsRequestError ? error.status : 500;
92
- const code = error instanceof AiDocsRequestError ? error.code : "assistant_error";
91
+ const status = error instanceof AiAppAssistantRequestError ? error.status : 500;
92
+ const code = error instanceof AiAppAssistantRequestError ? error.code : "assistant_error";
93
93
  response.statusCode = status;
94
94
  response.setHeader("content-type", "application/json; charset=utf-8");
95
95
  response.end(JSON.stringify({ error: code }));
96
96
  }
97
97
  export {
98
- createManagedAiDocsExpressHandler
98
+ createManagedAiAppAssistantExpressHandler
99
99
  };
100
100
  //# sourceMappingURL=express.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/express.ts"],"sourcesContent":["import { AiDocsRequestError } from \"./http.js\";\nimport type { ManagedAiDocsServer } from \"./managed-server.js\";\n\n/** Minimal Express request shape; importing Express types is intentionally unnecessary. */\nexport interface AiDocsExpressRequest {\n method?: string;\n originalUrl?: string;\n url?: string;\n protocol?: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n on?(event: string, listener: () => void): unknown;\n off?(event: string, listener: () => void): unknown;\n [key: string]: unknown;\n}\n\n/** Minimal Express response shape used by the connector. */\nexport interface AiDocsExpressResponse {\n statusCode: number;\n setHeader(name: string, value: string): unknown;\n write(chunk: Uint8Array): boolean;\n end(chunk?: string): unknown;\n once?(event: string, listener: () => void): unknown;\n destroyed?: boolean;\n}\n\nexport type AiDocsExpressNext = (error?: unknown) => void;\n\nexport type AiDocsExpressManagedServer<\n TRequest extends AiDocsExpressRequest = AiDocsExpressRequest\n> = Pick<ManagedAiDocsServer<{ id: string; label: string }, TRequest>, \"fetch\">;\n\nexport interface AiDocsExpressHandlerOptions {\n /** Origin used only when Express does not expose a Host header. */\n origin?: string;\n /** Maximum size accepted when no JSON body parser populated request.body. */\n maxBodyBytes?: number;\n /** Lets another Express handler process unknown routes below the mounted prefix. */\n fallthrough?: boolean;\n}\n\nexport type AiDocsExpressHandler<TRequest extends AiDocsExpressRequest> = (\n request: TRequest,\n response: AiDocsExpressResponse,\n next?: AiDocsExpressNext\n) => Promise<void>;\n\n/**\n * Creates an Express-compatible handler for the complete managed API.\n *\n * @example\n * `app.use(\"/api/ai-docs\", createManagedAiDocsExpressHandler(aiDocs));`\n */\nexport function createManagedAiDocsExpressHandler<\n TRequest extends AiDocsExpressRequest = AiDocsExpressRequest\n>(\n server: AiDocsExpressManagedServer<TRequest>,\n options: AiDocsExpressHandlerOptions = {}\n): AiDocsExpressHandler<TRequest> {\n return async (request, response, next) => {\n const abortController = new AbortController();\n const abort = (): void => abortController.abort(new DOMException(\"Client disconnected\", \"AbortError\"));\n request.on?.(\"close\", abort);\n try {\n const webRequest = await toFetchRequest(request, abortController.signal, options);\n const result = await server.fetch.handle(webRequest, request);\n if (options.fallthrough && result.status === 404 && next) {\n next();\n return;\n }\n await writeFetchResponse(response, result);\n } catch (error) {\n if (next) {\n next(error);\n return;\n }\n writeConnectorError(response, error);\n } finally {\n request.off?.(\"close\", abort);\n }\n };\n}\n\nasync function toFetchRequest(\n request: AiDocsExpressRequest,\n signal: AbortSignal,\n options: AiDocsExpressHandlerOptions\n): Promise<Request> {\n const headers = new Headers();\n for (const [name, value] of Object.entries(request.headers)) {\n if (Array.isArray(value)) value.forEach((item) => headers.append(name, item));\n else if (value !== undefined) headers.set(name, value);\n }\n const method = request.method?.toUpperCase() || \"GET\";\n const host = headers.get(\"host\");\n const protocol = request.protocol || headers.get(\"x-forwarded-proto\") || \"http\";\n const origin = options.origin ?? `${protocol}://${host || \"localhost\"}`;\n // originalUrl preserves the mount prefix stripped from request.url by Express.\n const url = new URL(request.originalUrl || request.url || \"/\", origin);\n const body = method === \"GET\" || method === \"HEAD\"\n ? undefined\n : request.body !== undefined\n ? serializeBody(request.body, headers)\n : await readBody(request, options.maxBodyBytes ?? 8_600_000);\n return new Request(url, {\n method,\n headers,\n signal,\n ...(body !== undefined ? { body } : {})\n });\n}\n\nfunction serializeBody(body: unknown, headers: Headers): string {\n if (typeof body === \"string\") return body;\n if (body instanceof Uint8Array) return new TextDecoder().decode(body);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return JSON.stringify(body) ?? \"null\";\n}\n\nasync function readBody(request: AiDocsExpressRequest, maxBodyBytes: number): Promise<string | undefined> {\n if (!(Symbol.asyncIterator in request)) return undefined;\n const chunks: Uint8Array[] = [];\n let size = 0;\n for await (const chunk of request as AsyncIterable<string | Uint8Array>) {\n const bytes = typeof chunk === \"string\" ? Buffer.from(chunk) : new Uint8Array(chunk);\n size += bytes.byteLength;\n if (size > maxBodyBytes) {\n throw new AiDocsRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n chunks.push(bytes);\n }\n return chunks.length ? Buffer.concat(chunks).toString(\"utf8\") : undefined;\n}\n\nasync function writeFetchResponse(response: AiDocsExpressResponse, result: Response): Promise<void> {\n response.statusCode = result.status;\n result.headers.forEach((value, name) => response.setHeader(name, value));\n if (!result.body) {\n response.end();\n return;\n }\n const reader = result.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!response.write(value) && response.once) {\n await new Promise<void>((resolve) => response.once!(\"drain\", resolve));\n }\n }\n if (!response.destroyed) response.end();\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction writeConnectorError(response: AiDocsExpressResponse, error: unknown): void {\n const status = error instanceof AiDocsRequestError ? error.status : 500;\n const code = error instanceof AiDocsRequestError ? error.code : \"assistant_error\";\n response.statusCode = status;\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n response.end(JSON.stringify({ error: code }));\n}\n"],"mappings":";;;;;AAqDO,SAAS,kCAGd,QACA,UAAuC,CAAC,GACR;AAChC,SAAO,OAAO,SAAS,UAAU,SAAS;AACxC,UAAM,kBAAkB,IAAI,gBAAgB;AAC5C,UAAM,QAAQ,MAAY,gBAAgB,MAAM,IAAI,aAAa,uBAAuB,YAAY,CAAC;AACrG,YAAQ,KAAK,SAAS,KAAK;AAC3B,QAAI;AACF,YAAM,aAAa,MAAM,eAAe,SAAS,gBAAgB,QAAQ,OAAO;AAChF,YAAM,SAAS,MAAM,OAAO,MAAM,OAAO,YAAY,OAAO;AAC5D,UAAI,QAAQ,eAAe,OAAO,WAAW,OAAO,MAAM;AACxD,aAAK;AACL;AAAA,MACF;AACA,YAAM,mBAAmB,UAAU,MAAM;AAAA,IAC3C,SAAS,OAAO;AACd,UAAI,MAAM;AACR,aAAK,KAAK;AACV;AAAA,MACF;AACA,0BAAoB,UAAU,KAAK;AAAA,IACrC,UAAE;AACA,cAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,EACF;AACF;AAEA,eAAe,eACb,SACA,QACA,SACkB;AAClB,QAAM,UAAU,IAAI,QAAQ;AAC5B,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC3D,QAAI,MAAM,QAAQ,KAAK,EAAG,OAAM,QAAQ,CAAC,SAAS,QAAQ,OAAO,MAAM,IAAI,CAAC;AAAA,aACnE,UAAU,OAAW,SAAQ,IAAI,MAAM,KAAK;AAAA,EACvD;AACA,QAAM,SAAS,QAAQ,QAAQ,YAAY,KAAK;AAChD,QAAM,OAAO,QAAQ,IAAI,MAAM;AAC/B,QAAM,WAAW,QAAQ,YAAY,QAAQ,IAAI,mBAAmB,KAAK;AACzE,QAAM,SAAS,QAAQ,UAAU,GAAG,QAAQ,MAAM,QAAQ,WAAW;AAErE,QAAM,MAAM,IAAI,IAAI,QAAQ,eAAe,QAAQ,OAAO,KAAK,MAAM;AACrE,QAAM,OAAO,WAAW,SAAS,WAAW,SACxC,SACA,QAAQ,SAAS,SACf,cAAc,QAAQ,MAAM,OAAO,IACnC,MAAM,SAAS,SAAS,QAAQ,gBAAgB,IAAS;AAC/D,SAAO,IAAI,QAAQ,KAAK;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,EACvC,CAAC;AACH;AAEA,SAAS,cAAc,MAAe,SAA0B;AAC9D,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI,gBAAgB,WAAY,QAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AACpE,MAAI,CAAC,QAAQ,IAAI,cAAc,EAAG,SAAQ,IAAI,gBAAgB,kBAAkB;AAChF,SAAO,KAAK,UAAU,IAAI,KAAK;AACjC;AAEA,eAAe,SAAS,SAA+B,cAAmD;AACxG,MAAI,EAAE,OAAO,iBAAiB,SAAU,QAAO;AAC/C,QAAM,SAAuB,CAAC;AAC9B,MAAI,OAAO;AACX,mBAAiB,SAAS,SAA+C;AACvE,UAAM,QAAQ,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,IAAI,WAAW,KAAK;AACnF,YAAQ,MAAM;AACd,QAAI,OAAO,cAAc;AACvB,YAAM,IAAI,mBAAmB,KAAK,qBAAqB,2BAA2B;AAAA,IACpF;AACA,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,IAAI;AAClE;AAEA,eAAe,mBAAmB,UAAiC,QAAiC;AAClG,WAAS,aAAa,OAAO;AAC7B,SAAO,QAAQ,QAAQ,CAAC,OAAO,SAAS,SAAS,UAAU,MAAM,KAAK,CAAC;AACvE,MAAI,CAAC,OAAO,MAAM;AAChB,aAAS,IAAI;AACb;AAAA,EACF;AACA,QAAM,SAAS,OAAO,KAAK,UAAU;AACrC,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,UAAI,CAAC,SAAS,MAAM,KAAK,KAAK,SAAS,MAAM;AAC3C,cAAM,IAAI,QAAc,CAAC,YAAY,SAAS,KAAM,SAAS,OAAO,CAAC;AAAA,MACvE;AAAA,IACF;AACA,QAAI,CAAC,SAAS,UAAW,UAAS,IAAI;AAAA,EACxC,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;AAEA,SAAS,oBAAoB,UAAiC,OAAsB;AAClF,QAAM,SAAS,iBAAiB,qBAAqB,MAAM,SAAS;AACpE,QAAM,OAAO,iBAAiB,qBAAqB,MAAM,OAAO;AAChE,WAAS,aAAa;AACtB,WAAS,UAAU,gBAAgB,iCAAiC;AACpE,WAAS,IAAI,KAAK,UAAU,EAAE,OAAO,KAAK,CAAC,CAAC;AAC9C;","names":[]}
1
+ {"version":3,"sources":["../src/express.ts"],"sourcesContent":["import { AiAppAssistantRequestError } from \"./http.js\";\nimport type { ManagedAiAppAssistantServer } from \"./managed-server.js\";\n\n/** Minimal Express request shape; importing Express types is intentionally unnecessary. */\nexport interface AiAppAssistantExpressRequest {\n method?: string;\n originalUrl?: string;\n url?: string;\n protocol?: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n on?(event: string, listener: () => void): unknown;\n off?(event: string, listener: () => void): unknown;\n [key: string]: unknown;\n}\n\n/** Minimal Express response shape used by the connector. */\nexport interface AiAppAssistantExpressResponse {\n statusCode: number;\n setHeader(name: string, value: string): unknown;\n write(chunk: Uint8Array): boolean;\n end(chunk?: string): unknown;\n once?(event: string, listener: () => void): unknown;\n destroyed?: boolean;\n}\n\nexport type AiAppAssistantExpressNext = (error?: unknown) => void;\n\nexport type AiAppAssistantExpressManagedServer<\n TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest\n> = Pick<ManagedAiAppAssistantServer<{ id: string; label: string }, TRequest>, \"fetch\">;\n\nexport interface AiAppAssistantExpressHandlerOptions {\n /** Origin used only when Express does not expose a Host header. */\n origin?: string;\n /** Maximum size accepted when no JSON body parser populated request.body. */\n maxBodyBytes?: number;\n /** Lets another Express handler process unknown routes below the mounted prefix. */\n fallthrough?: boolean;\n}\n\nexport type AiAppAssistantExpressHandler<TRequest extends AiAppAssistantExpressRequest> = (\n request: TRequest,\n response: AiAppAssistantExpressResponse,\n next?: AiAppAssistantExpressNext\n) => Promise<void>;\n\n/**\n * Creates an Express-compatible handler for the complete managed API.\n *\n * @example\n * `app.use(\"/api/ai-app-assistant\", createManagedAiAppAssistantExpressHandler(aiAppAssistant));`\n */\nexport function createManagedAiAppAssistantExpressHandler<\n TRequest extends AiAppAssistantExpressRequest = AiAppAssistantExpressRequest\n>(\n server: AiAppAssistantExpressManagedServer<TRequest>,\n options: AiAppAssistantExpressHandlerOptions = {}\n): AiAppAssistantExpressHandler<TRequest> {\n return async (request, response, next) => {\n const abortController = new AbortController();\n const abort = (): void => abortController.abort(new DOMException(\"Client disconnected\", \"AbortError\"));\n request.on?.(\"close\", abort);\n try {\n const webRequest = await toFetchRequest(request, abortController.signal, options);\n const result = await server.fetch.handle(webRequest, request);\n if (options.fallthrough && result.status === 404 && next) {\n next();\n return;\n }\n await writeFetchResponse(response, result);\n } catch (error) {\n if (next) {\n next(error);\n return;\n }\n writeConnectorError(response, error);\n } finally {\n request.off?.(\"close\", abort);\n }\n };\n}\n\nasync function toFetchRequest(\n request: AiAppAssistantExpressRequest,\n signal: AbortSignal,\n options: AiAppAssistantExpressHandlerOptions\n): Promise<Request> {\n const headers = new Headers();\n for (const [name, value] of Object.entries(request.headers)) {\n if (Array.isArray(value)) value.forEach((item) => headers.append(name, item));\n else if (value !== undefined) headers.set(name, value);\n }\n const method = request.method?.toUpperCase() || \"GET\";\n const host = headers.get(\"host\");\n const protocol = request.protocol || headers.get(\"x-forwarded-proto\") || \"http\";\n const origin = options.origin ?? `${protocol}://${host || \"localhost\"}`;\n // originalUrl preserves the mount prefix stripped from request.url by Express.\n const url = new URL(request.originalUrl || request.url || \"/\", origin);\n const body = method === \"GET\" || method === \"HEAD\"\n ? undefined\n : request.body !== undefined\n ? serializeBody(request.body, headers)\n : await readBody(request, options.maxBodyBytes ?? 8_600_000);\n return new Request(url, {\n method,\n headers,\n signal,\n ...(body !== undefined ? { body } : {})\n });\n}\n\nfunction serializeBody(body: unknown, headers: Headers): string {\n if (typeof body === \"string\") return body;\n if (body instanceof Uint8Array) return new TextDecoder().decode(body);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return JSON.stringify(body) ?? \"null\";\n}\n\nasync function readBody(request: AiAppAssistantExpressRequest, maxBodyBytes: number): Promise<string | undefined> {\n if (!(Symbol.asyncIterator in request)) return undefined;\n const chunks: Uint8Array[] = [];\n let size = 0;\n for await (const chunk of request as AsyncIterable<string | Uint8Array>) {\n const bytes = typeof chunk === \"string\" ? Buffer.from(chunk) : new Uint8Array(chunk);\n size += bytes.byteLength;\n if (size > maxBodyBytes) {\n throw new AiAppAssistantRequestError(413, \"request_too_large\", \"Request body is too large\");\n }\n chunks.push(bytes);\n }\n return chunks.length ? Buffer.concat(chunks).toString(\"utf8\") : undefined;\n}\n\nasync function writeFetchResponse(response: AiAppAssistantExpressResponse, result: Response): Promise<void> {\n response.statusCode = result.status;\n result.headers.forEach((value, name) => response.setHeader(name, value));\n if (!result.body) {\n response.end();\n return;\n }\n const reader = result.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!response.write(value) && response.once) {\n await new Promise<void>((resolve) => response.once!(\"drain\", resolve));\n }\n }\n if (!response.destroyed) response.end();\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction writeConnectorError(response: AiAppAssistantExpressResponse, error: unknown): void {\n const status = error instanceof AiAppAssistantRequestError ? error.status : 500;\n const code = error instanceof AiAppAssistantRequestError ? error.code : \"assistant_error\";\n response.statusCode = status;\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n response.end(JSON.stringify({ error: code }));\n}\n"],"mappings":";;;;;AAqDO,SAAS,0CAGd,QACA,UAA+C,CAAC,GACR;AACxC,SAAO,OAAO,SAAS,UAAU,SAAS;AACxC,UAAM,kBAAkB,IAAI,gBAAgB;AAC5C,UAAM,QAAQ,MAAY,gBAAgB,MAAM,IAAI,aAAa,uBAAuB,YAAY,CAAC;AACrG,YAAQ,KAAK,SAAS,KAAK;AAC3B,QAAI;AACF,YAAM,aAAa,MAAM,eAAe,SAAS,gBAAgB,QAAQ,OAAO;AAChF,YAAM,SAAS,MAAM,OAAO,MAAM,OAAO,YAAY,OAAO;AAC5D,UAAI,QAAQ,eAAe,OAAO,WAAW,OAAO,MAAM;AACxD,aAAK;AACL;AAAA,MACF;AACA,YAAM,mBAAmB,UAAU,MAAM;AAAA,IAC3C,SAAS,OAAO;AACd,UAAI,MAAM;AACR,aAAK,KAAK;AACV;AAAA,MACF;AACA,0BAAoB,UAAU,KAAK;AAAA,IACrC,UAAE;AACA,cAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,EACF;AACF;AAEA,eAAe,eACb,SACA,QACA,SACkB;AAClB,QAAM,UAAU,IAAI,QAAQ;AAC5B,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC3D,QAAI,MAAM,QAAQ,KAAK,EAAG,OAAM,QAAQ,CAAC,SAAS,QAAQ,OAAO,MAAM,IAAI,CAAC;AAAA,aACnE,UAAU,OAAW,SAAQ,IAAI,MAAM,KAAK;AAAA,EACvD;AACA,QAAM,SAAS,QAAQ,QAAQ,YAAY,KAAK;AAChD,QAAM,OAAO,QAAQ,IAAI,MAAM;AAC/B,QAAM,WAAW,QAAQ,YAAY,QAAQ,IAAI,mBAAmB,KAAK;AACzE,QAAM,SAAS,QAAQ,UAAU,GAAG,QAAQ,MAAM,QAAQ,WAAW;AAErE,QAAM,MAAM,IAAI,IAAI,QAAQ,eAAe,QAAQ,OAAO,KAAK,MAAM;AACrE,QAAM,OAAO,WAAW,SAAS,WAAW,SACxC,SACA,QAAQ,SAAS,SACf,cAAc,QAAQ,MAAM,OAAO,IACnC,MAAM,SAAS,SAAS,QAAQ,gBAAgB,IAAS;AAC/D,SAAO,IAAI,QAAQ,KAAK;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,EACvC,CAAC;AACH;AAEA,SAAS,cAAc,MAAe,SAA0B;AAC9D,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI,gBAAgB,WAAY,QAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AACpE,MAAI,CAAC,QAAQ,IAAI,cAAc,EAAG,SAAQ,IAAI,gBAAgB,kBAAkB;AAChF,SAAO,KAAK,UAAU,IAAI,KAAK;AACjC;AAEA,eAAe,SAAS,SAAuC,cAAmD;AAChH,MAAI,EAAE,OAAO,iBAAiB,SAAU,QAAO;AAC/C,QAAM,SAAuB,CAAC;AAC9B,MAAI,OAAO;AACX,mBAAiB,SAAS,SAA+C;AACvE,UAAM,QAAQ,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,IAAI,WAAW,KAAK;AACnF,YAAQ,MAAM;AACd,QAAI,OAAO,cAAc;AACvB,YAAM,IAAI,2BAA2B,KAAK,qBAAqB,2BAA2B;AAAA,IAC5F;AACA,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,IAAI;AAClE;AAEA,eAAe,mBAAmB,UAAyC,QAAiC;AAC1G,WAAS,aAAa,OAAO;AAC7B,SAAO,QAAQ,QAAQ,CAAC,OAAO,SAAS,SAAS,UAAU,MAAM,KAAK,CAAC;AACvE,MAAI,CAAC,OAAO,MAAM;AAChB,aAAS,IAAI;AACb;AAAA,EACF;AACA,QAAM,SAAS,OAAO,KAAK,UAAU;AACrC,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,UAAI,CAAC,SAAS,MAAM,KAAK,KAAK,SAAS,MAAM;AAC3C,cAAM,IAAI,QAAc,CAAC,YAAY,SAAS,KAAM,SAAS,OAAO,CAAC;AAAA,MACvE;AAAA,IACF;AACA,QAAI,CAAC,SAAS,UAAW,UAAS,IAAI;AAAA,EACxC,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;AAEA,SAAS,oBAAoB,UAAyC,OAAsB;AAC1F,QAAM,SAAS,iBAAiB,6BAA6B,MAAM,SAAS;AAC5E,QAAM,OAAO,iBAAiB,6BAA6B,MAAM,OAAO;AACxE,WAAS,aAAa;AACtB,WAAS,UAAU,gBAAgB,iCAAiC;AACpE,WAAS,IAAI,KAAK,UAAU,EAAE,OAAO,KAAK,CAAC,CAAC;AAC9C;","names":[]}