@nextclaw/ncp-http-agent-server 0.3.48 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -70,7 +70,7 @@ declare class NcpHttpAgentController implements NcpHttpAgentHandler {
70
70
  handleAbort(request: Request): Promise<Response>;
71
71
  }
72
72
  //#endregion
73
- //#region src/router.d.ts
73
+ //#region src/http-agent.route.d.ts
74
74
  declare function createNcpHttpAgentRouter(options: NcpHttpAgentServerOptions): Hono;
75
75
  declare function mountNcpHttpAgentRoutes(app: Hono, options: NcpHttpAgentServerOptions): void;
76
76
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/handler-interface.ts","../src/controller.ts","../src/router.ts"],"mappings":";;;;;;;;;;;;;;;;;;;AAsCA;KAPY,0BAAA;EACV,MAAA,CAAO,MAAA;IACL,OAAA,EAAS,uBAAA;IACT,MAAA,EAAQ,WAAA;EAAA,IACN,aAAA,CAAc,gBAAA;AAAA;AAAA,KAGR,yBAAA;EAcV,yFAZA,mBAAA,EAAqB,sBAAA;EACrB,QAAA;EAW2C;;;;EAN3C,gBAAA;EC1CkC;;;;;EDgDlC,cAAA,GAAiB,0BAAA;AAAA;;;;UChDF,mBAAA;EACf,UAAA,CAAW,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EACtC,YAAA,CAAa,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EACxC,WAAA,CAAY,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA;AAAA,KAG7B,0BAAA;EACV,mBAAA,EAAqB,sBAAA;EDwBjB;;;;ECnBJ,cAAA,GAAiB,0BAAA;EACjB,SAAA;AAAA;;;;;;ADcF;cEXa,sBAAA,YAAkC,mBAAA;EAAA,iBAChB,OAAA;cAAA,OAAA,EAAS,0BAAA;EAEhC,UAAA,CAAW,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EAoBtC,YAAA,CAAa,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EAmCxC,WAAA,CAAY,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA;;;iBCzE/B,wBAAA,CAAyB,OAAA,EAAS,yBAAA,GAA4B,IAAA;AAAA,iBAM9D,uBAAA,CAAwB,GAAA,EAAK,IAAA,EAAM,OAAA,EAAS,yBAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/handler-interface.ts","../src/controller.ts","../src/http-agent.route.ts"],"mappings":";;;;;;;;;;;;;;;;;;;AAsCA;KAPY,0BAAA;EACV,MAAA,CAAO,MAAA;IACL,OAAA,EAAS,uBAAA;IACT,MAAA,EAAQ,WAAA;EAAA,IACN,aAAA,CAAc,gBAAA;AAAA;AAAA,KAGR,yBAAA;EAcV,yFAZA,mBAAA,EAAqB,sBAAA;EACrB,QAAA;EAW2C;;;;EAN3C,gBAAA;EC1CkC;;;;;EDgDlC,cAAA,GAAiB,0BAAA;AAAA;;;;UChDF,mBAAA;EACf,UAAA,CAAW,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EACtC,YAAA,CAAa,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EACxC,WAAA,CAAY,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA;AAAA,KAG7B,0BAAA;EACV,mBAAA,EAAqB,sBAAA;EDwBjB;;;;ECnBJ,cAAA,GAAiB,0BAAA;EACjB,SAAA;AAAA;;;;;;ADcF;cEXa,sBAAA,YAAkC,mBAAA;EAAA,iBAChB,OAAA;cAAA,OAAA,EAAS,0BAAA;EAEhC,UAAA,CAAW,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EAoBtC,YAAA,CAAa,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;EAoCxC,WAAA,CAAY,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA;;;iBC1E/B,wBAAA,CAAyB,OAAA,EAAS,yBAAA,GAA4B,IAAA;AAAA,iBAM9D,uBAAA,CAAwB,GAAA,EAAK,IAAA,EAAM,OAAA,EAAS,yBAAA"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { Hono } from "hono";
3
3
  //#region src/types.ts
4
4
  const DEFAULT_BASE_PATH = "/ncp/agent";
5
5
  //#endregion
6
- //#region src/parsers.ts
6
+ //#region src/request-parsers.utils.ts
7
7
  function normalizeBasePath(basePath) {
8
8
  const raw = (basePath ?? "/ncp/agent").trim();
9
9
  if (!raw) return DEFAULT_BASE_PATH;
@@ -38,9 +38,15 @@ async function parseAbortPayload(request) {
38
38
  const sessionId = readTrimmedString(payload.sessionId);
39
39
  if (!sessionId) return null;
40
40
  const messageId = readTrimmedString(payload.messageId);
41
+ const runId = readTrimmedString(payload.runId);
42
+ const correlationId = readTrimmedString(payload.correlationId);
43
+ const reason = readAbortReason(payload.reason);
41
44
  return {
42
45
  sessionId,
43
- ...messageId ? { messageId } : {}
46
+ ...messageId ? { messageId } : {},
47
+ ...runId ? { runId } : {},
48
+ ...correlationId ? { correlationId } : {},
49
+ ...reason ? { reason } : {}
44
50
  };
45
51
  } catch {
46
52
  return null;
@@ -52,6 +58,16 @@ function readTrimmedString(value) {
52
58
  function isRecord$1(value) {
53
59
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
54
60
  }
61
+ function readAbortReason(value) {
62
+ if (!isRecord$1(value) || value.code !== "abort-error") return;
63
+ const message = readTrimmedString(value.message);
64
+ if (!message) return;
65
+ return {
66
+ code: "abort-error",
67
+ message,
68
+ ...isRecord$1(value.details) ? { details: value.details } : {}
69
+ };
70
+ }
55
71
  //#endregion
56
72
  //#region src/scope.ts
57
73
  function extractScopeFromEvent(event) {
@@ -307,6 +323,7 @@ var NcpHttpAgentController = class {
307
323
  return createForwardResponse({
308
324
  endpoint: agentClientEndpoint,
309
325
  requestEvent: {
326
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
310
327
  type: NcpEventType.MessageStreamRequest,
311
328
  payload: streamPayload
312
329
  },
@@ -330,7 +347,7 @@ var NcpHttpAgentController = class {
330
347
  }
331
348
  };
332
349
  //#endregion
333
- //#region src/router.ts
350
+ //#region src/http-agent.route.ts
334
351
  function createNcpHttpAgentRouter(options) {
335
352
  const app = new Hono();
336
353
  mountNcpHttpAgentRoutes(app, options);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["isRecord"],"sources":["../src/types.ts","../src/parsers.ts","../src/scope.ts","../src/sse-stream.ts","../src/async-queue.ts","../src/utils.ts","../src/stream-handlers.ts","../src/controller.ts","../src/router.ts"],"sourcesContent":["import type {\n NcpAgentClientEndpoint,\n NcpEndpointEvent,\n NcpStreamRequestPayload,\n} from \"@nextclaw/ncp\";\n\nexport const DEFAULT_BASE_PATH = \"/ncp/agent\";\n\n/** Filters which events belong to the current request (session/run/correlation). */\nexport type EventScope = {\n sessionId: string;\n correlationId?: string;\n runId?: string;\n};\n\n/**\n * Streams live session events for `/stream`.\n *\n * **Scenario**: User sends a message, agent streams SSE back. Network drops mid-stream.\n * User reconnects and requests `GET /stream?sessionId=xxx` to continue following\n * the current live response for that session.\n *\n * **Two paths**:\n * - **Session stream** (with streamProvider): Do not call agent again. Attach to the\n * active session's live event stream.\n * - **Forward** (no streamProvider): Forward `message.stream-request` to the agent\n * and let the upstream endpoint provide the live stream.\n *\n * **Implementation**: `stream` attaches by payload.sessionId and yields live events\n * for that active session.\n */\nexport type NcpHttpAgentStreamProvider = {\n stream(params: {\n payload: NcpStreamRequestPayload;\n signal: AbortSignal;\n }): AsyncIterable<NcpEndpointEvent>;\n};\n\nexport type NcpHttpAgentServerOptions = {\n /** Client endpoint to forward requests to (in-process adapter or remote HTTP client). */\n agentClientEndpoint: NcpAgentClientEndpoint;\n basePath?: string;\n /**\n * Optional forward-stream timeout in milliseconds.\n * When omitted or set to a non-positive value, no server-side timeout is applied.\n */\n requestTimeoutMs?: number | null;\n /**\n * Optional. When set, `/stream` serves live session events from streamProvider instead of\n * forwarding to the agent.\n * When not set, forwards `message.stream-request` to the agent.\n */\n streamProvider?: NcpHttpAgentStreamProvider;\n};\n\nexport type SseEventFrame = {\n event: \"ncp-event\" | \"error\";\n data: unknown;\n};\n","import type {\n NcpAgentSendEnvelope,\n NcpMessageAbortPayload,\n NcpStreamRequestPayload,\n} from \"@nextclaw/ncp\";\nimport { DEFAULT_BASE_PATH } from \"./types.js\";\n\nexport function normalizeBasePath(basePath: string | undefined): string {\n const raw = (basePath ?? DEFAULT_BASE_PATH).trim();\n if (!raw) {\n return DEFAULT_BASE_PATH;\n }\n const withLeadingSlash = raw.startsWith(\"/\") ? raw : `/${raw}`;\n return withLeadingSlash.endsWith(\"/\") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;\n}\n\nexport function sanitizeTimeout(timeoutMs: number | null | undefined): number | null {\n if (typeof timeoutMs !== \"number\" || !Number.isFinite(timeoutMs)) {\n return null;\n }\n if (timeoutMs <= 0) {\n return null;\n }\n return Math.max(1_000, Math.trunc(timeoutMs));\n}\n\nexport async function parseRequestEnvelope(request: Request): Promise<NcpAgentSendEnvelope | null> {\n try {\n const payload = (await request.json()) as unknown;\n if (!isRecord(payload)) {\n return null;\n }\n if (\n Object.prototype.hasOwnProperty.call(payload, \"sessionId\") &&\n (typeof payload.sessionId !== \"string\" || !payload.sessionId.trim())\n ) {\n return null;\n }\n if (!isRecord(payload.message)) {\n return null;\n }\n return payload as NcpAgentSendEnvelope;\n } catch {\n return null;\n }\n}\n\nexport function parseStreamPayloadFromUrl(url: string): NcpStreamRequestPayload | null {\n const query = new URL(url).searchParams;\n const sessionId = query.get(\"sessionId\")?.trim();\n if (!sessionId) {\n return null;\n }\n\n return {\n sessionId,\n };\n}\n\nexport async function parseAbortPayload(request: Request): Promise<NcpMessageAbortPayload | null> {\n try {\n const payload = (await request.json()) as unknown;\n if (!isRecord(payload)) {\n return null;\n }\n const sessionId = readTrimmedString(payload.sessionId);\n if (!sessionId) {\n return null;\n }\n const messageId = readTrimmedString(payload.messageId);\n\n return {\n sessionId,\n ...(messageId ? { messageId } : {}),\n };\n } catch {\n return null;\n }\n}\n\nfunction readTrimmedString(value: unknown): string {\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n","import type { NcpEndpointEvent } from \"@nextclaw/ncp\";\nimport type { EventScope } from \"./types.js\";\n\ntype ExtractedScope = {\n sessionId?: string;\n correlationId?: string;\n runId?: string;\n};\n\nexport function extractScopeFromEvent(event: NcpEndpointEvent): ExtractedScope {\n const payload = readPayload(event);\n if (!payload) {\n return {};\n }\n return {\n sessionId: readString(payload.sessionId),\n correlationId: readString(payload.correlationId),\n runId: readString(payload.runId),\n };\n}\n\nexport function matchesScope(scope: EventScope, event: NcpEndpointEvent): boolean {\n const eventScope = extractScopeFromEvent(event);\n\n if (eventScope.sessionId && eventScope.sessionId !== scope.sessionId) {\n return false;\n }\n if (scope.correlationId && eventScope.correlationId && eventScope.correlationId !== scope.correlationId) {\n return false;\n }\n if (scope.runId && eventScope.runId && eventScope.runId !== scope.runId) {\n return false;\n }\n return true;\n}\n\nexport function isTerminalEvent(event: NcpEndpointEvent): boolean {\n switch (event.type) {\n case \"message.completed\":\n case \"message.failed\":\n case \"run.finished\":\n case \"run.error\":\n case \"message.abort\":\n return true;\n default:\n return false;\n }\n}\n\nfunction readPayload(event: NcpEndpointEvent): Record<string, unknown> | null {\n if (!(\"payload\" in event)) {\n return null;\n }\n return isRecord(event.payload) ? event.payload : null;\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n","import type { NcpEndpointEvent } from \"@nextclaw/ncp\";\nimport type { SseEventFrame } from \"./types.js\";\n\nexport function createSseEventStream(\n events: AsyncIterable<SseEventFrame>,\n signal?: AbortSignal,\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n return new ReadableStream<Uint8Array>({\n start: async (controller) => {\n let closed = false;\n const close = () => {\n if (closed) {\n return;\n }\n closed = true;\n controller.close();\n };\n\n const onAbort = () => {\n close();\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n try {\n for await (const event of events) {\n if (closed || signal?.aborted) {\n break;\n }\n controller.enqueue(encoder.encode(toSseFrame(event.event, event.data)));\n }\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n close();\n }\n },\n });\n}\n\nexport function buildSseResponse(stream: ReadableStream<Uint8Array>): Response {\n return new Response(stream, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n },\n });\n}\n\nexport function toSseFrame(eventName: string, data: unknown): string {\n return `event: ${eventName}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n}\n\nexport function toNcpEventFrame(event: NcpEndpointEvent): SseEventFrame {\n return {\n event: \"ncp-event\",\n data: event,\n };\n}\n\nexport function toErrorFrame(code: string, message: string): SseEventFrame {\n return {\n event: \"error\",\n data: {\n code,\n message,\n },\n };\n}\n","export type AsyncQueue<T> = {\n push(item: T): void;\n close(): void;\n iterable: AsyncIterable<T>;\n};\n\nexport function createAsyncQueue<T>(): AsyncQueue<T> {\n const items: T[] = [];\n let closed = false;\n let pendingResolve: ((result: IteratorResult<T>) => void) | null = null;\n\n const iterable: AsyncIterable<T> = {\n [Symbol.asyncIterator]() {\n return {\n next: () => {\n if (items.length > 0) {\n return Promise.resolve({\n value: items.shift() as T,\n done: false,\n });\n }\n if (closed) {\n return Promise.resolve({\n value: undefined as T,\n done: true,\n });\n }\n return new Promise<IteratorResult<T>>((resolve) => {\n pendingResolve = resolve;\n });\n },\n };\n },\n };\n\n return {\n push(item: T) {\n if (closed) {\n return;\n }\n if (pendingResolve) {\n const resolve = pendingResolve;\n pendingResolve = null;\n resolve({ value: item, done: false });\n return;\n }\n items.push(item);\n },\n close() {\n if (closed) {\n return;\n }\n closed = true;\n if (pendingResolve) {\n const resolve = pendingResolve;\n pendingResolve = null;\n resolve({\n value: undefined as T,\n done: true,\n });\n }\n },\n iterable,\n };\n}\n","export function errorMessage(error: unknown): string {\n if (error instanceof Error && error.message) {\n return error.message;\n }\n return String(error ?? \"Unknown error\");\n}\n\nexport function jsonResponse(body: unknown, status = 200): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n","import type {\n NcpAgentClientEndpoint,\n NcpEndpointEvent,\n NcpStreamRequestPayload,\n} from \"@nextclaw/ncp\";\nimport { matchesScope } from \"./scope.js\";\nimport {\n buildSseResponse,\n createSseEventStream,\n toErrorFrame,\n toNcpEventFrame,\n} from \"./sse-stream.js\";\nimport type {\n EventScope,\n NcpHttpAgentStreamProvider,\n SseEventFrame,\n} from \"./types.js\";\nimport { createAsyncQueue } from \"./async-queue.js\";\nimport { errorMessage } from \"./utils.js\";\n\n/** Options for streaming a live response from the agent (forward path). */\nexport type ForwardResponseOptions = {\n endpoint: NcpAgentClientEndpoint;\n requestEvent: NcpEndpointEvent;\n requestSignal: AbortSignal;\n timeoutMs: number | null;\n scope: EventScope;\n};\n\nexport function createForwardResponse(\n options: ForwardResponseOptions,\n): Response {\n const { requestSignal } = options;\n return buildSseResponse(\n createSseEventStream(createForwardSseEvents(options), requestSignal),\n );\n}\n\nasync function* createForwardSseEvents(\n options: ForwardResponseOptions,\n): AsyncGenerator<SseEventFrame> {\n const { endpoint, requestEvent, requestSignal, timeoutMs, scope } = options;\n const queue = createAsyncQueue<SseEventFrame>();\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let unsubscribe: (() => void) | null = null;\n let stopped = false;\n\n const push = (frame: SseEventFrame) => {\n if (!stopped) {\n queue.push(frame);\n }\n };\n\n const stop = () => {\n if (stopped) {\n return;\n }\n stopped = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n if (unsubscribe) {\n unsubscribe();\n unsubscribe = null;\n }\n requestSignal.removeEventListener(\"abort\", stop);\n queue.close();\n };\n\n requestSignal.addEventListener(\"abort\", stop, { once: true });\n if (timeoutMs !== null) {\n timeoutId = setTimeout(() => {\n push(\n toErrorFrame(\n \"TIMEOUT\",\n \"NCP HTTP stream timed out before terminal event.\",\n ),\n );\n stop();\n }, timeoutMs);\n }\n\n unsubscribe = endpoint.subscribe((event) => {\n if (!matchesScope(scope, event)) {\n return;\n }\n push(toNcpEventFrame(event));\n });\n\n void endpoint\n .emit(requestEvent)\n .catch((error) => {\n push(toErrorFrame(\"EMIT_FAILED\", errorMessage(error)));\n stop();\n })\n .finally(() => {\n if (!requestSignal.aborted) {\n queueMicrotask(stop);\n }\n });\n\n try {\n for await (const frame of queue.iterable) {\n yield frame;\n }\n } finally {\n stop();\n }\n}\n\n/** Live session stream path: read directly from streamProvider, no extra agent call. */\nexport type LiveStreamResponseOptions = {\n streamProvider: NcpHttpAgentStreamProvider;\n payload: NcpStreamRequestPayload;\n signal: AbortSignal;\n};\n\nexport function createLiveStreamResponse(\n options: LiveStreamResponseOptions,\n): Response {\n const { signal } = options;\n return buildSseResponse(\n createSseEventStream(createLiveStreamSseEvents(options), signal),\n );\n}\n\nasync function* createLiveStreamSseEvents(\n options: LiveStreamResponseOptions,\n): AsyncGenerator<SseEventFrame> {\n const { streamProvider, payload, signal } = options;\n try {\n for await (const event of streamProvider.stream({ payload, signal })) {\n if (signal.aborted) {\n break;\n }\n yield toNcpEventFrame(event);\n }\n } catch (error) {\n yield toErrorFrame(\"STREAM_SOURCE_FAILED\", errorMessage(error));\n }\n}\n","import { NcpEventType } from \"@nextclaw/ncp\";\nimport {\n parseAbortPayload,\n parseRequestEnvelope,\n parseStreamPayloadFromUrl,\n} from \"./parsers.js\";\nimport {\n createForwardResponse,\n createLiveStreamResponse,\n} from \"./stream-handlers.js\";\nimport { jsonResponse } from \"./utils.js\";\nimport type {\n NcpHttpAgentHandler,\n NcpHttpAgentHandlerOptions,\n} from \"./handler-interface.js\";\n\n/**\n * Framework-agnostic controller for NCP agent HTTP routes.\n * Forwards /send and /stream to agentClientEndpoint; /stream uses streamProvider when set.\n */\nexport class NcpHttpAgentController implements NcpHttpAgentHandler {\n constructor(private readonly options: NcpHttpAgentHandlerOptions) {}\n\n async handleSend(request: Request): Promise<Response> {\n const { agentClientEndpoint } = this.options;\n const envelope = await parseRequestEnvelope(request);\n if (!envelope) {\n return jsonResponse(\n {\n ok: false,\n error: {\n code: \"INVALID_BODY\",\n message: \"Invalid NCP request envelope.\",\n },\n },\n 400,\n );\n }\n\n const handle = await agentClientEndpoint.send(envelope);\n return jsonResponse({ ok: true, data: handle });\n }\n\n async handleStream(request: Request): Promise<Response> {\n const { agentClientEndpoint, streamProvider } = this.options;\n const streamPayload = parseStreamPayloadFromUrl(request.url);\n if (!streamPayload) {\n return jsonResponse(\n {\n ok: false,\n error: { code: \"INVALID_QUERY\", message: \"sessionId is required.\" },\n },\n 400,\n );\n }\n\n if (streamProvider) {\n return createLiveStreamResponse({\n streamProvider,\n payload: streamPayload,\n signal: request.signal,\n });\n }\n\n return createForwardResponse({\n endpoint: agentClientEndpoint,\n requestEvent: {\n type: NcpEventType.MessageStreamRequest,\n payload: streamPayload,\n },\n requestSignal: request.signal,\n timeoutMs: null,\n scope: {\n sessionId: streamPayload.sessionId,\n },\n });\n }\n\n async handleAbort(request: Request): Promise<Response> {\n const { agentClientEndpoint } = this.options;\n const payload = await parseAbortPayload(request);\n if (!payload) {\n return jsonResponse(\n {\n ok: false,\n error: { code: \"INVALID_BODY\", message: \"sessionId is required.\" },\n },\n 400,\n );\n }\n await agentClientEndpoint.abort(payload);\n return jsonResponse({ ok: true });\n }\n}\n","import { Hono } from \"hono\";\nimport { NcpHttpAgentController } from \"./controller.js\";\nimport { normalizeBasePath, sanitizeTimeout } from \"./parsers.js\";\nimport type { NcpHttpAgentServerOptions } from \"./types.js\";\n\nexport function createNcpHttpAgentRouter(options: NcpHttpAgentServerOptions): Hono {\n const app = new Hono();\n mountNcpHttpAgentRoutes(app, options);\n return app;\n}\n\nexport function mountNcpHttpAgentRoutes(app: Hono, options: NcpHttpAgentServerOptions): void {\n const { basePath: rawBasePath, agentClientEndpoint, streamProvider, requestTimeoutMs } = options;\n const basePath = normalizeBasePath(rawBasePath);\n const controller = new NcpHttpAgentController({\n agentClientEndpoint,\n streamProvider,\n timeoutMs: sanitizeTimeout(requestTimeoutMs),\n });\n\n app.post(`${basePath}/send`, (c) => controller.handleSend(c.req.raw));\n app.get(`${basePath}/stream`, (c) => controller.handleStream(c.req.raw));\n app.post(`${basePath}/abort`, (c) => controller.handleAbort(c.req.raw));\n}\n"],"mappings":";;;AAMA,MAAa,oBAAoB;;;ACCjC,SAAgB,kBAAkB,UAAsC;CACtE,MAAM,OAAO,YAAA,cAA+B,MAAM;AAClD,KAAI,CAAC,IACH,QAAO;CAET,MAAM,mBAAmB,IAAI,WAAW,IAAI,GAAG,MAAM,IAAI;AACzD,QAAO,iBAAiB,SAAS,IAAI,GAAG,iBAAiB,MAAM,GAAG,GAAG,GAAG;;AAG1E,SAAgB,gBAAgB,WAAqD;AACnF,KAAI,OAAO,cAAc,YAAY,CAAC,OAAO,SAAS,UAAU,CAC9D,QAAO;AAET,KAAI,aAAa,EACf,QAAO;AAET,QAAO,KAAK,IAAI,KAAO,KAAK,MAAM,UAAU,CAAC;;AAG/C,eAAsB,qBAAqB,SAAwD;AACjG,KAAI;EACF,MAAM,UAAW,MAAM,QAAQ,MAAM;AACrC,MAAI,CAACA,WAAS,QAAQ,CACpB,QAAO;AAET,MACE,OAAO,UAAU,eAAe,KAAK,SAAS,YAAY,KACzD,OAAO,QAAQ,cAAc,YAAY,CAAC,QAAQ,UAAU,MAAM,EAEnE,QAAO;AAET,MAAI,CAACA,WAAS,QAAQ,QAAQ,CAC5B,QAAO;AAET,SAAO;SACD;AACN,SAAO;;;AAIX,SAAgB,0BAA0B,KAA6C;CAErF,MAAM,YADQ,IAAI,IAAI,IAAI,CAAC,aACH,IAAI,YAAY,EAAE,MAAM;AAChD,KAAI,CAAC,UACH,QAAO;AAGT,QAAO,EACL,WACD;;AAGH,eAAsB,kBAAkB,SAA0D;AAChG,KAAI;EACF,MAAM,UAAW,MAAM,QAAQ,MAAM;AACrC,MAAI,CAACA,WAAS,QAAQ,CACpB,QAAO;EAET,MAAM,YAAY,kBAAkB,QAAQ,UAAU;AACtD,MAAI,CAAC,UACH,QAAO;EAET,MAAM,YAAY,kBAAkB,QAAQ,UAAU;AAEtD,SAAO;GACL;GACA,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;GACnC;SACK;AACN,SAAO;;;AAIX,SAAS,kBAAkB,OAAwB;AACjD,QAAO,OAAO,UAAU,WAAW,MAAM,MAAM,GAAG;;AAGpD,SAASA,WAAS,OAAkD;AAClE,QAAO,QAAQ,MAAM,IAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;;;AC5E7E,SAAgB,sBAAsB,OAAyC;CAC7E,MAAM,UAAU,YAAY,MAAM;AAClC,KAAI,CAAC,QACH,QAAO,EAAE;AAEX,QAAO;EACL,WAAW,WAAW,QAAQ,UAAU;EACxC,eAAe,WAAW,QAAQ,cAAc;EAChD,OAAO,WAAW,QAAQ,MAAM;EACjC;;AAGH,SAAgB,aAAa,OAAmB,OAAkC;CAChF,MAAM,aAAa,sBAAsB,MAAM;AAE/C,KAAI,WAAW,aAAa,WAAW,cAAc,MAAM,UACzD,QAAO;AAET,KAAI,MAAM,iBAAiB,WAAW,iBAAiB,WAAW,kBAAkB,MAAM,cACxF,QAAO;AAET,KAAI,MAAM,SAAS,WAAW,SAAS,WAAW,UAAU,MAAM,MAChE,QAAO;AAET,QAAO;;AAgBT,SAAS,YAAY,OAAyD;AAC5E,KAAI,EAAE,aAAa,OACjB,QAAO;AAET,QAAO,SAAS,MAAM,QAAQ,GAAG,MAAM,UAAU;;AAGnD,SAAS,WAAW,OAAoC;AACtD,QAAO,OAAO,UAAU,YAAY,QAAQ,QAAQ,KAAA;;AAGtD,SAAS,SAAS,OAAkD;AAClE,QAAO,QAAQ,MAAM,IAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;;;AC1D7E,SAAgB,qBACd,QACA,QAC4B;CAC5B,MAAM,UAAU,IAAI,aAAa;AACjC,QAAO,IAAI,eAA2B,EACpC,OAAO,OAAO,eAAe;EAC3B,IAAI,SAAS;EACb,MAAM,cAAc;AAClB,OAAI,OACF;AAEF,YAAS;AACT,cAAW,OAAO;;EAGpB,MAAM,gBAAgB;AACpB,UAAO;;AAET,UAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1D,MAAI;AACF,cAAW,MAAM,SAAS,QAAQ;AAChC,QAAI,UAAU,QAAQ,QACpB;AAEF,eAAW,QAAQ,QAAQ,OAAO,WAAW,MAAM,OAAO,MAAM,KAAK,CAAC,CAAC;;YAEjE;AACR,WAAQ,oBAAoB,SAAS,QAAQ;AAC7C,UAAO;;IAGZ,CAAC;;AAGJ,SAAgB,iBAAiB,QAA8C;AAC7E,QAAO,IAAI,SAAS,QAAQ;EAC1B,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,iBAAiB;GACjB,YAAY;GACZ,qBAAqB;GACtB;EACF,CAAC;;AAGJ,SAAgB,WAAW,WAAmB,MAAuB;AACnE,QAAO,UAAU,UAAU,UAAU,KAAK,UAAU,KAAK,CAAC;;AAG5D,SAAgB,gBAAgB,OAAwC;AACtE,QAAO;EACL,OAAO;EACP,MAAM;EACP;;AAGH,SAAgB,aAAa,MAAc,SAAgC;AACzE,QAAO;EACL,OAAO;EACP,MAAM;GACJ;GACA;GACD;EACF;;;;AC/DH,SAAgB,mBAAqC;CACnD,MAAM,QAAa,EAAE;CACrB,IAAI,SAAS;CACb,IAAI,iBAA+D;AA0BnE,QAAO;EACL,KAAK,MAAS;AACZ,OAAI,OACF;AAEF,OAAI,gBAAgB;IAClB,MAAM,UAAU;AAChB,qBAAiB;AACjB,YAAQ;KAAE,OAAO;KAAM,MAAM;KAAO,CAAC;AACrC;;AAEF,SAAM,KAAK,KAAK;;EAElB,QAAQ;AACN,OAAI,OACF;AAEF,YAAS;AACT,OAAI,gBAAgB;IAClB,MAAM,UAAU;AAChB,qBAAiB;AACjB,YAAQ;KACN,OAAO,KAAA;KACP,MAAM;KACP,CAAC;;;EAGN,UAnDiC,EACjC,CAAC,OAAO,iBAAiB;AACvB,UAAO,EACL,YAAY;AACV,QAAI,MAAM,SAAS,EACjB,QAAO,QAAQ,QAAQ;KACrB,OAAO,MAAM,OAAO;KACpB,MAAM;KACP,CAAC;AAEJ,QAAI,OACF,QAAO,QAAQ,QAAQ;KACrB,OAAO,KAAA;KACP,MAAM;KACP,CAAC;AAEJ,WAAO,IAAI,SAA4B,YAAY;AACjD,sBAAiB;MACjB;MAEL;KAEJ;EA8BA;;;;AC/DH,SAAgB,aAAa,OAAwB;AACnD,KAAI,iBAAiB,SAAS,MAAM,QAClC,QAAO,MAAM;AAEf,QAAO,OAAO,SAAS,gBAAgB;;AAGzC,SAAgB,aAAa,MAAe,SAAS,KAAe;AAClE,QAAO,IAAI,SAAS,KAAK,UAAU,KAAK,EAAE;EACxC;EACA,SAAS,EAAE,gBAAgB,oBAAoB;EAChD,CAAC;;;;ACkBJ,SAAgB,sBACd,SACU;CACV,MAAM,EAAE,kBAAkB;AAC1B,QAAO,iBACL,qBAAqB,uBAAuB,QAAQ,EAAE,cAAc,CACrE;;AAGH,gBAAgB,uBACd,SAC+B;CAC/B,MAAM,EAAE,UAAU,cAAc,eAAe,WAAW,UAAU;CACpE,MAAM,QAAQ,kBAAiC;CAC/C,IAAI,YAAkD;CACtD,IAAI,cAAmC;CACvC,IAAI,UAAU;CAEd,MAAM,QAAQ,UAAyB;AACrC,MAAI,CAAC,QACH,OAAM,KAAK,MAAM;;CAIrB,MAAM,aAAa;AACjB,MAAI,QACF;AAEF,YAAU;AACV,MAAI,WAAW;AACb,gBAAa,UAAU;AACvB,eAAY;;AAEd,MAAI,aAAa;AACf,gBAAa;AACb,iBAAc;;AAEhB,gBAAc,oBAAoB,SAAS,KAAK;AAChD,QAAM,OAAO;;AAGf,eAAc,iBAAiB,SAAS,MAAM,EAAE,MAAM,MAAM,CAAC;AAC7D,KAAI,cAAc,KAChB,aAAY,iBAAiB;AAC3B,OACE,aACE,WACA,mDACD,CACF;AACD,QAAM;IACL,UAAU;AAGf,eAAc,SAAS,WAAW,UAAU;AAC1C,MAAI,CAAC,aAAa,OAAO,MAAM,CAC7B;AAEF,OAAK,gBAAgB,MAAM,CAAC;GAC5B;AAEG,UACF,KAAK,aAAa,CAClB,OAAO,UAAU;AAChB,OAAK,aAAa,eAAe,aAAa,MAAM,CAAC,CAAC;AACtD,QAAM;GACN,CACD,cAAc;AACb,MAAI,CAAC,cAAc,QACjB,gBAAe,KAAK;GAEtB;AAEJ,KAAI;AACF,aAAW,MAAM,SAAS,MAAM,SAC9B,OAAM;WAEA;AACR,QAAM;;;AAWV,SAAgB,yBACd,SACU;CACV,MAAM,EAAE,WAAW;AACnB,QAAO,iBACL,qBAAqB,0BAA0B,QAAQ,EAAE,OAAO,CACjE;;AAGH,gBAAgB,0BACd,SAC+B;CAC/B,MAAM,EAAE,gBAAgB,SAAS,WAAW;AAC5C,KAAI;AACF,aAAW,MAAM,SAAS,eAAe,OAAO;GAAE;GAAS;GAAQ,CAAC,EAAE;AACpE,OAAI,OAAO,QACT;AAEF,SAAM,gBAAgB,MAAM;;UAEvB,OAAO;AACd,QAAM,aAAa,wBAAwB,aAAa,MAAM,CAAC;;;;;;;;;ACvHnE,IAAa,yBAAb,MAAmE;CACjE,YAAY,SAAsD;AAArC,OAAA,UAAA;;CAE7B,MAAM,WAAW,SAAqC;EACpD,MAAM,EAAE,wBAAwB,KAAK;EACrC,MAAM,WAAW,MAAM,qBAAqB,QAAQ;AACpD,MAAI,CAAC,SACH,QAAO,aACL;GACE,IAAI;GACJ,OAAO;IACL,MAAM;IACN,SAAS;IACV;GACF,EACD,IACD;AAIH,SAAO,aAAa;GAAE,IAAI;GAAM,MADjB,MAAM,oBAAoB,KAAK,SAAS;GACT,CAAC;;CAGjD,MAAM,aAAa,SAAqC;EACtD,MAAM,EAAE,qBAAqB,mBAAmB,KAAK;EACrD,MAAM,gBAAgB,0BAA0B,QAAQ,IAAI;AAC5D,MAAI,CAAC,cACH,QAAO,aACL;GACE,IAAI;GACJ,OAAO;IAAE,MAAM;IAAiB,SAAS;IAA0B;GACpE,EACD,IACD;AAGH,MAAI,eACF,QAAO,yBAAyB;GAC9B;GACA,SAAS;GACT,QAAQ,QAAQ;GACjB,CAAC;AAGJ,SAAO,sBAAsB;GAC3B,UAAU;GACV,cAAc;IACZ,MAAM,aAAa;IACnB,SAAS;IACV;GACD,eAAe,QAAQ;GACvB,WAAW;GACX,OAAO,EACL,WAAW,cAAc,WAC1B;GACF,CAAC;;CAGJ,MAAM,YAAY,SAAqC;EACrD,MAAM,EAAE,wBAAwB,KAAK;EACrC,MAAM,UAAU,MAAM,kBAAkB,QAAQ;AAChD,MAAI,CAAC,QACH,QAAO,aACL;GACE,IAAI;GACJ,OAAO;IAAE,MAAM;IAAgB,SAAS;IAA0B;GACnE,EACD,IACD;AAEH,QAAM,oBAAoB,MAAM,QAAQ;AACxC,SAAO,aAAa,EAAE,IAAI,MAAM,CAAC;;;;;ACtFrC,SAAgB,yBAAyB,SAA0C;CACjF,MAAM,MAAM,IAAI,MAAM;AACtB,yBAAwB,KAAK,QAAQ;AACrC,QAAO;;AAGT,SAAgB,wBAAwB,KAAW,SAA0C;CAC3F,MAAM,EAAE,UAAU,aAAa,qBAAqB,gBAAgB,qBAAqB;CACzF,MAAM,WAAW,kBAAkB,YAAY;CAC/C,MAAM,aAAa,IAAI,uBAAuB;EAC5C;EACA;EACA,WAAW,gBAAgB,iBAAiB;EAC7C,CAAC;AAEF,KAAI,KAAK,GAAG,SAAS,SAAS,MAAM,WAAW,WAAW,EAAE,IAAI,IAAI,CAAC;AACrE,KAAI,IAAI,GAAG,SAAS,WAAW,MAAM,WAAW,aAAa,EAAE,IAAI,IAAI,CAAC;AACxE,KAAI,KAAK,GAAG,SAAS,UAAU,MAAM,WAAW,YAAY,EAAE,IAAI,IAAI,CAAC"}
1
+ {"version":3,"file":"index.js","names":["isRecord"],"sources":["../src/types.ts","../src/request-parsers.utils.ts","../src/scope.ts","../src/sse-stream.ts","../src/async-queue.ts","../src/utils.ts","../src/stream-handlers.ts","../src/controller.ts","../src/http-agent.route.ts"],"sourcesContent":["import type {\n NcpAgentClientEndpoint,\n NcpEndpointEvent,\n NcpStreamRequestPayload,\n} from \"@nextclaw/ncp\";\n\nexport const DEFAULT_BASE_PATH = \"/ncp/agent\";\n\n/** Filters which events belong to the current request (session/run/correlation). */\nexport type EventScope = {\n sessionId: string;\n correlationId?: string;\n runId?: string;\n};\n\n/**\n * Streams live session events for `/stream`.\n *\n * **Scenario**: User sends a message, agent streams SSE back. Network drops mid-stream.\n * User reconnects and requests `GET /stream?sessionId=xxx` to continue following\n * the current live response for that session.\n *\n * **Two paths**:\n * - **Session stream** (with streamProvider): Do not call agent again. Attach to the\n * active session's live event stream.\n * - **Forward** (no streamProvider): Forward `message.stream-request` to the agent\n * and let the upstream endpoint provide the live stream.\n *\n * **Implementation**: `stream` attaches by payload.sessionId and yields live events\n * for that active session.\n */\nexport type NcpHttpAgentStreamProvider = {\n stream(params: {\n payload: NcpStreamRequestPayload;\n signal: AbortSignal;\n }): AsyncIterable<NcpEndpointEvent>;\n};\n\nexport type NcpHttpAgentServerOptions = {\n /** Client endpoint to forward requests to (in-process adapter or remote HTTP client). */\n agentClientEndpoint: NcpAgentClientEndpoint;\n basePath?: string;\n /**\n * Optional forward-stream timeout in milliseconds.\n * When omitted or set to a non-positive value, no server-side timeout is applied.\n */\n requestTimeoutMs?: number | null;\n /**\n * Optional. When set, `/stream` serves live session events from streamProvider instead of\n * forwarding to the agent.\n * When not set, forwards `message.stream-request` to the agent.\n */\n streamProvider?: NcpHttpAgentStreamProvider;\n};\n\nexport type SseEventFrame = {\n event: \"ncp-event\" | \"error\";\n data: unknown;\n};\n","import type {\n NcpAgentSendEnvelope,\n NcpMessageAbortPayload,\n NcpStreamRequestPayload,\n} from \"@nextclaw/ncp\";\nimport { DEFAULT_BASE_PATH } from \"./types.js\";\n\nexport function normalizeBasePath(basePath: string | undefined): string {\n const raw = (basePath ?? DEFAULT_BASE_PATH).trim();\n if (!raw) {\n return DEFAULT_BASE_PATH;\n }\n const withLeadingSlash = raw.startsWith(\"/\") ? raw : `/${raw}`;\n return withLeadingSlash.endsWith(\"/\") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;\n}\n\nexport function sanitizeTimeout(timeoutMs: number | null | undefined): number | null {\n if (typeof timeoutMs !== \"number\" || !Number.isFinite(timeoutMs)) {\n return null;\n }\n if (timeoutMs <= 0) {\n return null;\n }\n return Math.max(1_000, Math.trunc(timeoutMs));\n}\n\nexport async function parseRequestEnvelope(request: Request): Promise<NcpAgentSendEnvelope | null> {\n try {\n const payload = (await request.json()) as unknown;\n if (!isRecord(payload)) {\n return null;\n }\n if (\n Object.prototype.hasOwnProperty.call(payload, \"sessionId\") &&\n (typeof payload.sessionId !== \"string\" || !payload.sessionId.trim())\n ) {\n return null;\n }\n if (!isRecord(payload.message)) {\n return null;\n }\n return payload as NcpAgentSendEnvelope;\n } catch {\n return null;\n }\n}\n\nexport function parseStreamPayloadFromUrl(url: string): NcpStreamRequestPayload | null {\n const query = new URL(url).searchParams;\n const sessionId = query.get(\"sessionId\")?.trim();\n if (!sessionId) {\n return null;\n }\n\n return {\n sessionId,\n };\n}\n\nexport async function parseAbortPayload(request: Request): Promise<NcpMessageAbortPayload | null> {\n try {\n const payload = (await request.json()) as unknown;\n if (!isRecord(payload)) {\n return null;\n }\n const sessionId = readTrimmedString(payload.sessionId);\n if (!sessionId) {\n return null;\n }\n const messageId = readTrimmedString(payload.messageId);\n const runId = readTrimmedString(payload.runId);\n const correlationId = readTrimmedString(payload.correlationId);\n const reason = readAbortReason(payload.reason);\n\n return {\n sessionId,\n ...(messageId ? { messageId } : {}),\n ...(runId ? { runId } : {}),\n ...(correlationId ? { correlationId } : {}),\n ...(reason ? { reason } : {}),\n };\n } catch {\n return null;\n }\n}\n\nfunction readTrimmedString(value: unknown): string {\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction readAbortReason(value: unknown): NcpMessageAbortPayload[\"reason\"] {\n if (!isRecord(value) || value.code !== \"abort-error\") {\n return undefined;\n }\n const message = readTrimmedString(value.message);\n if (!message) {\n return undefined;\n }\n return {\n code: \"abort-error\",\n message,\n ...(isRecord(value.details) ? { details: value.details } : {}),\n };\n}\n","import type { NcpEndpointEvent } from \"@nextclaw/ncp\";\nimport type { EventScope } from \"./types.js\";\n\ntype ExtractedScope = {\n sessionId?: string;\n correlationId?: string;\n runId?: string;\n};\n\nexport function extractScopeFromEvent(event: NcpEndpointEvent): ExtractedScope {\n const payload = readPayload(event);\n if (!payload) {\n return {};\n }\n return {\n sessionId: readString(payload.sessionId),\n correlationId: readString(payload.correlationId),\n runId: readString(payload.runId),\n };\n}\n\nexport function matchesScope(scope: EventScope, event: NcpEndpointEvent): boolean {\n const eventScope = extractScopeFromEvent(event);\n\n if (eventScope.sessionId && eventScope.sessionId !== scope.sessionId) {\n return false;\n }\n if (scope.correlationId && eventScope.correlationId && eventScope.correlationId !== scope.correlationId) {\n return false;\n }\n if (scope.runId && eventScope.runId && eventScope.runId !== scope.runId) {\n return false;\n }\n return true;\n}\n\nexport function isTerminalEvent(event: NcpEndpointEvent): boolean {\n switch (event.type) {\n case \"message.completed\":\n case \"message.failed\":\n case \"run.finished\":\n case \"run.error\":\n case \"message.abort\":\n return true;\n default:\n return false;\n }\n}\n\nfunction readPayload(event: NcpEndpointEvent): Record<string, unknown> | null {\n if (!(\"payload\" in event)) {\n return null;\n }\n return isRecord(event.payload) ? event.payload : null;\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n","import type { NcpEndpointEvent } from \"@nextclaw/ncp\";\nimport type { SseEventFrame } from \"./types.js\";\n\nexport function createSseEventStream(\n events: AsyncIterable<SseEventFrame>,\n signal?: AbortSignal,\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n return new ReadableStream<Uint8Array>({\n start: async (controller) => {\n let closed = false;\n const close = () => {\n if (closed) {\n return;\n }\n closed = true;\n controller.close();\n };\n\n const onAbort = () => {\n close();\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n try {\n for await (const event of events) {\n if (closed || signal?.aborted) {\n break;\n }\n controller.enqueue(encoder.encode(toSseFrame(event.event, event.data)));\n }\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n close();\n }\n },\n });\n}\n\nexport function buildSseResponse(stream: ReadableStream<Uint8Array>): Response {\n return new Response(stream, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n },\n });\n}\n\nexport function toSseFrame(eventName: string, data: unknown): string {\n return `event: ${eventName}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n}\n\nexport function toNcpEventFrame(event: NcpEndpointEvent): SseEventFrame {\n return {\n event: \"ncp-event\",\n data: event,\n };\n}\n\nexport function toErrorFrame(code: string, message: string): SseEventFrame {\n return {\n event: \"error\",\n data: {\n code,\n message,\n },\n };\n}\n","export type AsyncQueue<T> = {\n push(item: T): void;\n close(): void;\n iterable: AsyncIterable<T>;\n};\n\nexport function createAsyncQueue<T>(): AsyncQueue<T> {\n const items: T[] = [];\n let closed = false;\n let pendingResolve: ((result: IteratorResult<T>) => void) | null = null;\n\n const iterable: AsyncIterable<T> = {\n [Symbol.asyncIterator]() {\n return {\n next: () => {\n if (items.length > 0) {\n return Promise.resolve({\n value: items.shift() as T,\n done: false,\n });\n }\n if (closed) {\n return Promise.resolve({\n value: undefined as T,\n done: true,\n });\n }\n return new Promise<IteratorResult<T>>((resolve) => {\n pendingResolve = resolve;\n });\n },\n };\n },\n };\n\n return {\n push(item: T) {\n if (closed) {\n return;\n }\n if (pendingResolve) {\n const resolve = pendingResolve;\n pendingResolve = null;\n resolve({ value: item, done: false });\n return;\n }\n items.push(item);\n },\n close() {\n if (closed) {\n return;\n }\n closed = true;\n if (pendingResolve) {\n const resolve = pendingResolve;\n pendingResolve = null;\n resolve({\n value: undefined as T,\n done: true,\n });\n }\n },\n iterable,\n };\n}\n","export function errorMessage(error: unknown): string {\n if (error instanceof Error && error.message) {\n return error.message;\n }\n return String(error ?? \"Unknown error\");\n}\n\nexport function jsonResponse(body: unknown, status = 200): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n","import type {\n NcpAgentClientEndpoint,\n NcpEndpointEvent,\n NcpStreamRequestPayload,\n} from \"@nextclaw/ncp\";\nimport { matchesScope } from \"./scope.js\";\nimport {\n buildSseResponse,\n createSseEventStream,\n toErrorFrame,\n toNcpEventFrame,\n} from \"./sse-stream.js\";\nimport type {\n EventScope,\n NcpHttpAgentStreamProvider,\n SseEventFrame,\n} from \"./types.js\";\nimport { createAsyncQueue } from \"./async-queue.js\";\nimport { errorMessage } from \"./utils.js\";\n\n/** Options for streaming a live response from the agent (forward path). */\nexport type ForwardResponseOptions = {\n endpoint: NcpAgentClientEndpoint;\n requestEvent: NcpEndpointEvent;\n requestSignal: AbortSignal;\n timeoutMs: number | null;\n scope: EventScope;\n};\n\nexport function createForwardResponse(\n options: ForwardResponseOptions,\n): Response {\n const { requestSignal } = options;\n return buildSseResponse(\n createSseEventStream(createForwardSseEvents(options), requestSignal),\n );\n}\n\nasync function* createForwardSseEvents(\n options: ForwardResponseOptions,\n): AsyncGenerator<SseEventFrame> {\n const { endpoint, requestEvent, requestSignal, timeoutMs, scope } = options;\n const queue = createAsyncQueue<SseEventFrame>();\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let unsubscribe: (() => void) | null = null;\n let stopped = false;\n\n const push = (frame: SseEventFrame) => {\n if (!stopped) {\n queue.push(frame);\n }\n };\n\n const stop = () => {\n if (stopped) {\n return;\n }\n stopped = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n if (unsubscribe) {\n unsubscribe();\n unsubscribe = null;\n }\n requestSignal.removeEventListener(\"abort\", stop);\n queue.close();\n };\n\n requestSignal.addEventListener(\"abort\", stop, { once: true });\n if (timeoutMs !== null) {\n timeoutId = setTimeout(() => {\n push(\n toErrorFrame(\n \"TIMEOUT\",\n \"NCP HTTP stream timed out before terminal event.\",\n ),\n );\n stop();\n }, timeoutMs);\n }\n\n unsubscribe = endpoint.subscribe((event) => {\n if (!matchesScope(scope, event)) {\n return;\n }\n push(toNcpEventFrame(event));\n });\n\n void endpoint\n .emit(requestEvent)\n .catch((error) => {\n push(toErrorFrame(\"EMIT_FAILED\", errorMessage(error)));\n stop();\n })\n .finally(() => {\n if (!requestSignal.aborted) {\n queueMicrotask(stop);\n }\n });\n\n try {\n for await (const frame of queue.iterable) {\n yield frame;\n }\n } finally {\n stop();\n }\n}\n\n/** Live session stream path: read directly from streamProvider, no extra agent call. */\nexport type LiveStreamResponseOptions = {\n streamProvider: NcpHttpAgentStreamProvider;\n payload: NcpStreamRequestPayload;\n signal: AbortSignal;\n};\n\nexport function createLiveStreamResponse(\n options: LiveStreamResponseOptions,\n): Response {\n const { signal } = options;\n return buildSseResponse(\n createSseEventStream(createLiveStreamSseEvents(options), signal),\n );\n}\n\nasync function* createLiveStreamSseEvents(\n options: LiveStreamResponseOptions,\n): AsyncGenerator<SseEventFrame> {\n const { streamProvider, payload, signal } = options;\n try {\n for await (const event of streamProvider.stream({ payload, signal })) {\n if (signal.aborted) {\n break;\n }\n yield toNcpEventFrame(event);\n }\n } catch (error) {\n yield toErrorFrame(\"STREAM_SOURCE_FAILED\", errorMessage(error));\n }\n}\n","import { NcpEventType } from \"@nextclaw/ncp\";\nimport {\n parseAbortPayload,\n parseRequestEnvelope,\n parseStreamPayloadFromUrl,\n} from \"./request-parsers.utils.js\";\nimport {\n createForwardResponse,\n createLiveStreamResponse,\n} from \"./stream-handlers.js\";\nimport { jsonResponse } from \"./utils.js\";\nimport type {\n NcpHttpAgentHandler,\n NcpHttpAgentHandlerOptions,\n} from \"./handler-interface.js\";\n\n/**\n * Framework-agnostic controller for NCP agent HTTP routes.\n * Forwards /send and /stream to agentClientEndpoint; /stream uses streamProvider when set.\n */\nexport class NcpHttpAgentController implements NcpHttpAgentHandler {\n constructor(private readonly options: NcpHttpAgentHandlerOptions) {}\n\n async handleSend(request: Request): Promise<Response> {\n const { agentClientEndpoint } = this.options;\n const envelope = await parseRequestEnvelope(request);\n if (!envelope) {\n return jsonResponse(\n {\n ok: false,\n error: {\n code: \"INVALID_BODY\",\n message: \"Invalid NCP request envelope.\",\n },\n },\n 400,\n );\n }\n\n const handle = await agentClientEndpoint.send(envelope);\n return jsonResponse({ ok: true, data: handle });\n }\n\n async handleStream(request: Request): Promise<Response> {\n const { agentClientEndpoint, streamProvider } = this.options;\n const streamPayload = parseStreamPayloadFromUrl(request.url);\n if (!streamPayload) {\n return jsonResponse(\n {\n ok: false,\n error: { code: \"INVALID_QUERY\", message: \"sessionId is required.\" },\n },\n 400,\n );\n }\n\n if (streamProvider) {\n return createLiveStreamResponse({\n streamProvider,\n payload: streamPayload,\n signal: request.signal,\n });\n }\n\n return createForwardResponse({\n endpoint: agentClientEndpoint,\n requestEvent: {\n occurredAt: new Date().toISOString(),\n type: NcpEventType.MessageStreamRequest,\n payload: streamPayload,\n },\n requestSignal: request.signal,\n timeoutMs: null,\n scope: {\n sessionId: streamPayload.sessionId,\n },\n });\n }\n\n async handleAbort(request: Request): Promise<Response> {\n const { agentClientEndpoint } = this.options;\n const payload = await parseAbortPayload(request);\n if (!payload) {\n return jsonResponse(\n {\n ok: false,\n error: { code: \"INVALID_BODY\", message: \"sessionId is required.\" },\n },\n 400,\n );\n }\n await agentClientEndpoint.abort(payload);\n return jsonResponse({ ok: true });\n }\n}\n","import { Hono } from \"hono\";\nimport { NcpHttpAgentController } from \"./controller.js\";\nimport { normalizeBasePath, sanitizeTimeout } from \"./request-parsers.utils.js\";\nimport type { NcpHttpAgentServerOptions } from \"./types.js\";\n\nexport function createNcpHttpAgentRouter(options: NcpHttpAgentServerOptions): Hono {\n const app = new Hono();\n mountNcpHttpAgentRoutes(app, options);\n return app;\n}\n\nexport function mountNcpHttpAgentRoutes(app: Hono, options: NcpHttpAgentServerOptions): void {\n const { basePath: rawBasePath, agentClientEndpoint, streamProvider, requestTimeoutMs } = options;\n const basePath = normalizeBasePath(rawBasePath);\n const controller = new NcpHttpAgentController({\n agentClientEndpoint,\n streamProvider,\n timeoutMs: sanitizeTimeout(requestTimeoutMs),\n });\n\n app.post(`${basePath}/send`, (c) => controller.handleSend(c.req.raw));\n app.get(`${basePath}/stream`, (c) => controller.handleStream(c.req.raw));\n app.post(`${basePath}/abort`, (c) => controller.handleAbort(c.req.raw));\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/ncp-http-agent-server",
3
- "version": "0.3.48",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "description": "HTTP/SSE server transport adapter for NCP agent endpoints.",
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  ],
17
17
  "dependencies": {
18
18
  "hono": "^4.9.8",
19
- "@nextclaw/ncp": "0.6.6"
19
+ "@nextclaw/ncp": "0.7.1"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^20.17.6",