@anvia/client 1.4.3 → 1.5.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
@@ -47,7 +47,9 @@ server; keep `UIMessage[]` as presentation state in your application.
47
47
  - Typed custom stream data, Agent interactions, and HTTP resume cursors.
48
48
 
49
49
  For React, `@anvia/react` manages this state through `useChat` and `useCompletion`. Generic JSONL/SSE
50
- readers are also available from `@anvia/client/transport` for other event contracts.
50
+ readers are also available from `@anvia/client/transport` for other event contracts. Malformed
51
+ frames are skipped and reported through `onParseError` (or thrown with `strict: true`), and
52
+ `readSseFrames` exposes SSE event names, last event IDs, and retry hints.
51
53
 
52
54
  ## Learn more
53
55
 
@@ -0,0 +1,150 @@
1
+ // src/transport/streams.ts
2
+ var EventStreamParseError = class extends Error {
3
+ format;
4
+ /** The raw JSONL line or joined SSE `data` payload. */
5
+ raw;
6
+ /** 1-based physical line number of the malformed JSONL line. */
7
+ line;
8
+ /** SSE event name of the malformed frame. */
9
+ event;
10
+ /** SSE last event ID in effect when the malformed frame was dispatched. */
11
+ lastEventId;
12
+ constructor(options) {
13
+ super(`Malformed ${options.format === "sse" ? "SSE" : "JSONL"} frame: invalid JSON.`, {
14
+ cause: options.cause
15
+ });
16
+ this.name = "EventStreamParseError";
17
+ this.format = options.format;
18
+ this.raw = options.raw;
19
+ this.line = options.line;
20
+ this.event = options.event;
21
+ this.lastEventId = options.lastEventId;
22
+ }
23
+ };
24
+ async function* readJsonlStream(stream, options = {}) {
25
+ let lineNumber = 0;
26
+ for await (const line of readLines(stream)) {
27
+ lineNumber += 1;
28
+ const raw = line.trim();
29
+ if (raw.length === 0) continue;
30
+ const parsed = parseJson(raw, options, () => ({ format: "jsonl", raw, line: lineNumber }));
31
+ if (parsed.ok) yield parsed.value;
32
+ }
33
+ }
34
+ async function* readSseStream(stream, options = {}) {
35
+ for await (const frame of readSseFrames(stream, options)) yield frame.data;
36
+ }
37
+ async function* readSseFrames(stream, options = {}) {
38
+ let data = [];
39
+ let event = "";
40
+ let lastEventId = "";
41
+ let retry;
42
+ function dispatch() {
43
+ const raw = data.join("\n");
44
+ const name = event === "" ? "message" : event;
45
+ const hasData = data.length > 0;
46
+ data = [];
47
+ event = "";
48
+ if (!hasData || raw.trim().length === 0) return void 0;
49
+ const parsed = parseJson(raw, options, () => ({
50
+ format: "sse",
51
+ raw,
52
+ event: name,
53
+ lastEventId
54
+ }));
55
+ if (!parsed.ok) return void 0;
56
+ const frame2 = { data: parsed.value, event: name, lastEventId };
57
+ if (retry !== void 0) frame2.retry = retry;
58
+ return frame2;
59
+ }
60
+ for await (const line of readLines(stream)) {
61
+ if (line === "") {
62
+ const frame2 = dispatch();
63
+ if (frame2 !== void 0) yield frame2;
64
+ continue;
65
+ }
66
+ if (line.startsWith(":")) continue;
67
+ const separator = line.indexOf(":");
68
+ const field = separator === -1 ? line : line.slice(0, separator);
69
+ let value = separator === -1 ? "" : line.slice(separator + 1);
70
+ if (value.startsWith(" ")) value = value.slice(1);
71
+ if (field === "data") {
72
+ data.push(value);
73
+ } else if (field === "event") {
74
+ event = value;
75
+ } else if (field === "id") {
76
+ if (!value.includes("\0")) lastEventId = value;
77
+ } else if (field === "retry") {
78
+ if (/^\d+$/.test(value)) retry = Number(value);
79
+ }
80
+ }
81
+ const frame = dispatch();
82
+ if (frame !== void 0) yield frame;
83
+ }
84
+ async function* readLines(stream) {
85
+ const reader = stream.getReader();
86
+ const decoder = new TextDecoder();
87
+ let buffer = "";
88
+ let skipLeadingLf = false;
89
+ let completed = false;
90
+ function* split(text) {
91
+ let chunk = text;
92
+ if (skipLeadingLf && chunk.length > 0) {
93
+ skipLeadingLf = false;
94
+ if (chunk.startsWith("\n")) chunk = chunk.slice(1);
95
+ }
96
+ let start = 0;
97
+ let index = buffer.length;
98
+ buffer += chunk;
99
+ for (; index < buffer.length; index += 1) {
100
+ const char = buffer.charCodeAt(index);
101
+ if (char !== 10 && char !== 13) continue;
102
+ yield buffer.slice(start, index);
103
+ if (char === 13) {
104
+ if (index + 1 === buffer.length) skipLeadingLf = true;
105
+ else if (buffer.charCodeAt(index + 1) === 10) index += 1;
106
+ }
107
+ start = index + 1;
108
+ }
109
+ buffer = buffer.slice(start);
110
+ }
111
+ try {
112
+ while (true) {
113
+ const next = await reader.read();
114
+ if (next.done) {
115
+ completed = true;
116
+ break;
117
+ }
118
+ yield* split(decoder.decode(next.value, { stream: true }));
119
+ }
120
+ yield* split(decoder.decode());
121
+ if (buffer.length > 0) yield buffer;
122
+ } finally {
123
+ if (!completed) await cancelReader(reader);
124
+ reader.releaseLock();
125
+ }
126
+ }
127
+ function parseJson(raw, options, details) {
128
+ try {
129
+ return { ok: true, value: JSON.parse(raw) };
130
+ } catch (cause) {
131
+ const error = new EventStreamParseError({ ...details(), cause });
132
+ options.onParseError?.(error);
133
+ if (options.strict === true) throw error;
134
+ return { ok: false };
135
+ }
136
+ }
137
+ async function cancelReader(reader) {
138
+ try {
139
+ await reader.cancel();
140
+ } catch {
141
+ }
142
+ }
143
+
144
+ export {
145
+ EventStreamParseError,
146
+ readJsonlStream,
147
+ readSseStream,
148
+ readSseFrames
149
+ };
150
+ //# sourceMappingURL=chunk-PD72KNCV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/transport/streams.ts"],"sourcesContent":["import type { EventStreamFormat } from \"./types\";\n\n/** A malformed JSONL line or SSE data payload that could not be parsed as JSON. */\nexport class EventStreamParseError extends Error {\n readonly format: EventStreamFormat;\n /** The raw JSONL line or joined SSE `data` payload. */\n readonly raw: string;\n /** 1-based physical line number of the malformed JSONL line. */\n readonly line: number | undefined;\n /** SSE event name of the malformed frame. */\n readonly event: string | undefined;\n /** SSE last event ID in effect when the malformed frame was dispatched. */\n readonly lastEventId: string | undefined;\n\n constructor(options: {\n format: EventStreamFormat;\n raw: string;\n cause: unknown;\n line?: number;\n event?: string;\n lastEventId?: string;\n }) {\n super(`Malformed ${options.format === \"sse\" ? \"SSE\" : \"JSONL\"} frame: invalid JSON.`, {\n cause: options.cause,\n });\n this.name = \"EventStreamParseError\";\n this.format = options.format;\n this.raw = options.raw;\n this.line = options.line;\n this.event = options.event;\n this.lastEventId = options.lastEventId;\n }\n}\n\nexport type EventStreamReadOptions = {\n /**\n * Receives frames whose payload is not valid JSON. Malformed frames are skipped and the\n * stream continues. Throwing from this callback aborts the stream with that error.\n */\n onParseError?: (error: EventStreamParseError) => void;\n /** Throw the parse error instead of skipping malformed frames. */\n strict?: boolean;\n};\n\n/** A dispatched Server-Sent Event with its parsed JSON payload. */\nexport type SseFrame<TEvent> = {\n data: TEvent;\n /** Event name from the `event:` field, `\"message\"` when absent. */\n event: string;\n /** Last event ID set by an `id:` field in this or an earlier frame, `\"\"` when none. */\n lastEventId: string;\n /** Most recent valid `retry:` reconnection time in milliseconds. */\n retry?: number;\n};\n\nexport async function* readJsonlStream<TEvent>(\n stream: ReadableStream<Uint8Array>,\n options: EventStreamReadOptions = {},\n): AsyncIterable<TEvent> {\n let lineNumber = 0;\n for await (const line of readLines(stream)) {\n lineNumber += 1;\n const raw = line.trim();\n if (raw.length === 0) continue;\n const parsed = parseJson(raw, options, () => ({ format: \"jsonl\", raw, line: lineNumber }));\n if (parsed.ok) yield parsed.value as TEvent;\n }\n}\n\nexport async function* readSseStream<TEvent>(\n stream: ReadableStream<Uint8Array>,\n options: EventStreamReadOptions = {},\n): AsyncIterable<TEvent> {\n for await (const frame of readSseFrames<TEvent>(stream, options)) yield frame.data;\n}\n\nexport async function* readSseFrames<TEvent>(\n stream: ReadableStream<Uint8Array>,\n options: EventStreamReadOptions = {},\n): AsyncIterable<SseFrame<TEvent>> {\n let data: string[] = [];\n let event = \"\";\n let lastEventId = \"\";\n let retry: number | undefined;\n\n function dispatch(): SseFrame<TEvent> | undefined {\n const raw = data.join(\"\\n\");\n const name = event === \"\" ? \"message\" : event;\n const hasData = data.length > 0;\n data = [];\n event = \"\";\n // Whitespace-only payloads (for example `data:` heartbeats) carry no JSON event.\n if (!hasData || raw.trim().length === 0) return undefined;\n const parsed = parseJson(raw, options, () => ({\n format: \"sse\",\n raw,\n event: name,\n lastEventId,\n }));\n if (!parsed.ok) return undefined;\n const frame: SseFrame<TEvent> = { data: parsed.value as TEvent, event: name, lastEventId };\n if (retry !== undefined) frame.retry = retry;\n return frame;\n }\n\n for await (const line of readLines(stream)) {\n if (line === \"\") {\n const frame = dispatch();\n if (frame !== undefined) yield frame;\n continue;\n }\n if (line.startsWith(\":\")) continue;\n const separator = line.indexOf(\":\");\n const field = separator === -1 ? line : line.slice(0, separator);\n let value = separator === -1 ? \"\" : line.slice(separator + 1);\n if (value.startsWith(\" \")) value = value.slice(1);\n if (field === \"data\") {\n data.push(value);\n } else if (field === \"event\") {\n event = value;\n } else if (field === \"id\") {\n if (!value.includes(\"\\0\")) lastEventId = value;\n } else if (field === \"retry\") {\n if (/^\\d+$/.test(value)) retry = Number(value);\n }\n }\n // Leniently dispatch a final event that was not followed by a blank line.\n const frame = dispatch();\n if (frame !== undefined) yield frame;\n}\n\n/** Splits a byte stream into lines terminated by CRLF, LF, or a bare CR. */\nasync function* readLines(stream: ReadableStream<Uint8Array>): AsyncIterable<string> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let skipLeadingLf = false;\n let completed = false;\n\n function* split(text: string): Iterable<string> {\n let chunk = text;\n if (skipLeadingLf && chunk.length > 0) {\n skipLeadingLf = false;\n if (chunk.startsWith(\"\\n\")) chunk = chunk.slice(1);\n }\n let start = 0;\n let index = buffer.length;\n buffer += chunk;\n for (; index < buffer.length; index += 1) {\n const char = buffer.charCodeAt(index);\n if (char !== 10 && char !== 13) continue;\n yield buffer.slice(start, index);\n if (char === 13) {\n if (index + 1 === buffer.length) skipLeadingLf = true;\n else if (buffer.charCodeAt(index + 1) === 10) index += 1;\n }\n start = index + 1;\n }\n buffer = buffer.slice(start);\n }\n\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) {\n completed = true;\n break;\n }\n yield* split(decoder.decode(next.value, { stream: true }));\n }\n yield* split(decoder.decode());\n if (buffer.length > 0) yield buffer;\n } finally {\n if (!completed) await cancelReader(reader);\n reader.releaseLock();\n }\n}\n\nfunction parseJson(\n raw: string,\n options: EventStreamReadOptions,\n details: () => Omit<ConstructorParameters<typeof EventStreamParseError>[0], \"cause\">,\n): { ok: true; value: unknown } | { ok: false } {\n try {\n return { ok: true, value: JSON.parse(raw) };\n } catch (cause) {\n const error = new EventStreamParseError({ ...details(), cause });\n options.onParseError?.(error);\n if (options.strict === true) throw error;\n return { ok: false };\n }\n}\n\nasync function cancelReader(reader: ReadableStreamDefaultReader<Uint8Array>): Promise<void> {\n try {\n await reader.cancel();\n } catch {\n // The request may already have been aborted by its owner.\n }\n}\n"],"mappings":";AAGO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EACtC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,SAOT;AACD,UAAM,aAAa,QAAQ,WAAW,QAAQ,QAAQ,OAAO,yBAAyB;AAAA,MACpF,OAAO,QAAQ;AAAA,IACjB,CAAC;AACD,SAAK,OAAO;AACZ,SAAK,SAAS,QAAQ;AACtB,SAAK,MAAM,QAAQ;AACnB,SAAK,OAAO,QAAQ;AACpB,SAAK,QAAQ,QAAQ;AACrB,SAAK,cAAc,QAAQ;AAAA,EAC7B;AACF;AAuBA,gBAAuB,gBACrB,QACA,UAAkC,CAAC,GACZ;AACvB,MAAI,aAAa;AACjB,mBAAiB,QAAQ,UAAU,MAAM,GAAG;AAC1C,kBAAc;AACd,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,IAAI,WAAW,EAAG;AACtB,UAAM,SAAS,UAAU,KAAK,SAAS,OAAO,EAAE,QAAQ,SAAS,KAAK,MAAM,WAAW,EAAE;AACzF,QAAI,OAAO,GAAI,OAAM,OAAO;AAAA,EAC9B;AACF;AAEA,gBAAuB,cACrB,QACA,UAAkC,CAAC,GACZ;AACvB,mBAAiB,SAAS,cAAsB,QAAQ,OAAO,EAAG,OAAM,MAAM;AAChF;AAEA,gBAAuB,cACrB,QACA,UAAkC,CAAC,GACF;AACjC,MAAI,OAAiB,CAAC;AACtB,MAAI,QAAQ;AACZ,MAAI,cAAc;AAClB,MAAI;AAEJ,WAAS,WAAyC;AAChD,UAAM,MAAM,KAAK,KAAK,IAAI;AAC1B,UAAM,OAAO,UAAU,KAAK,YAAY;AACxC,UAAM,UAAU,KAAK,SAAS;AAC9B,WAAO,CAAC;AACR,YAAQ;AAER,QAAI,CAAC,WAAW,IAAI,KAAK,EAAE,WAAW,EAAG,QAAO;AAChD,UAAM,SAAS,UAAU,KAAK,SAAS,OAAO;AAAA,MAC5C,QAAQ;AAAA,MACR;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACF,EAAE;AACF,QAAI,CAAC,OAAO,GAAI,QAAO;AACvB,UAAMA,SAA0B,EAAE,MAAM,OAAO,OAAiB,OAAO,MAAM,YAAY;AACzF,QAAI,UAAU,OAAW,CAAAA,OAAM,QAAQ;AACvC,WAAOA;AAAA,EACT;AAEA,mBAAiB,QAAQ,UAAU,MAAM,GAAG;AAC1C,QAAI,SAAS,IAAI;AACf,YAAMA,SAAQ,SAAS;AACvB,UAAIA,WAAU,OAAW,OAAMA;AAC/B;AAAA,IACF;AACA,QAAI,KAAK,WAAW,GAAG,EAAG;AAC1B,UAAM,YAAY,KAAK,QAAQ,GAAG;AAClC,UAAM,QAAQ,cAAc,KAAK,OAAO,KAAK,MAAM,GAAG,SAAS;AAC/D,QAAI,QAAQ,cAAc,KAAK,KAAK,KAAK,MAAM,YAAY,CAAC;AAC5D,QAAI,MAAM,WAAW,GAAG,EAAG,SAAQ,MAAM,MAAM,CAAC;AAChD,QAAI,UAAU,QAAQ;AACpB,WAAK,KAAK,KAAK;AAAA,IACjB,WAAW,UAAU,SAAS;AAC5B,cAAQ;AAAA,IACV,WAAW,UAAU,MAAM;AACzB,UAAI,CAAC,MAAM,SAAS,IAAI,EAAG,eAAc;AAAA,IAC3C,WAAW,UAAU,SAAS;AAC5B,UAAI,QAAQ,KAAK,KAAK,EAAG,SAAQ,OAAO,KAAK;AAAA,IAC/C;AAAA,EACF;AAEA,QAAM,QAAQ,SAAS;AACvB,MAAI,UAAU,OAAW,OAAM;AACjC;AAGA,gBAAgB,UAAU,QAA2D;AACnF,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AACb,MAAI,gBAAgB;AACpB,MAAI,YAAY;AAEhB,YAAU,MAAM,MAAgC;AAC9C,QAAI,QAAQ;AACZ,QAAI,iBAAiB,MAAM,SAAS,GAAG;AACrC,sBAAgB;AAChB,UAAI,MAAM,WAAW,IAAI,EAAG,SAAQ,MAAM,MAAM,CAAC;AAAA,IACnD;AACA,QAAI,QAAQ;AACZ,QAAI,QAAQ,OAAO;AACnB,cAAU;AACV,WAAO,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACxC,YAAM,OAAO,OAAO,WAAW,KAAK;AACpC,UAAI,SAAS,MAAM,SAAS,GAAI;AAChC,YAAM,OAAO,MAAM,OAAO,KAAK;AAC/B,UAAI,SAAS,IAAI;AACf,YAAI,QAAQ,MAAM,OAAO,OAAQ,iBAAgB;AAAA,iBACxC,OAAO,WAAW,QAAQ,CAAC,MAAM,GAAI,UAAS;AAAA,MACzD;AACA,cAAQ,QAAQ;AAAA,IAClB;AACA,aAAS,OAAO,MAAM,KAAK;AAAA,EAC7B;AAEA,MAAI;AACF,WAAO,MAAM;AACX,YAAM,OAAO,MAAM,OAAO,KAAK;AAC/B,UAAI,KAAK,MAAM;AACb,oBAAY;AACZ;AAAA,MACF;AACA,aAAO,MAAM,QAAQ,OAAO,KAAK,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;AAAA,IAC3D;AACA,WAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,QAAI,OAAO,SAAS,EAAG,OAAM;AAAA,EAC/B,UAAE;AACA,QAAI,CAAC,UAAW,OAAM,aAAa,MAAM;AACzC,WAAO,YAAY;AAAA,EACrB;AACF;AAEA,SAAS,UACP,KACA,SACA,SAC8C;AAC9C,MAAI;AACF,WAAO,EAAE,IAAI,MAAM,OAAO,KAAK,MAAM,GAAG,EAAE;AAAA,EAC5C,SAAS,OAAO;AACd,UAAM,QAAQ,IAAI,sBAAsB,EAAE,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC/D,YAAQ,eAAe,KAAK;AAC5B,QAAI,QAAQ,WAAW,KAAM,OAAM;AACnC,WAAO,EAAE,IAAI,MAAM;AAAA,EACrB;AACF;AAEA,eAAe,aAAa,QAAgE;AAC1F,MAAI;AACF,UAAM,OAAO,OAAO;AAAA,EACtB,QAAQ;AAAA,EAER;AACF;","names":["frame"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  readJsonlStream,
3
3
  readSseStream
4
- } from "./chunk-63JX2QNP.js";
4
+ } from "./chunk-PD72KNCV.js";
5
5
 
6
6
  // src/transport/fetch.ts
7
7
  var EventStreamHttpError = class extends Error {
@@ -22,10 +22,12 @@ async function* fetchEventStream(options) {
22
22
  options.validateResponse?.(response);
23
23
  if (response.body === null) throw new Error("Event stream response does not include a body.");
24
24
  const format = options.format === void 0 || options.format === "auto" ? inferEventStreamFormat(response.headers.get("content-type")) : options.format;
25
+ const readOptions = {};
26
+ if (options.onParseError !== void 0) readOptions.onParseError = options.onParseError;
25
27
  if (format === "sse") {
26
- yield* readSseStream(response.body);
28
+ yield* readSseStream(response.body, readOptions);
27
29
  } else {
28
- yield* readJsonlStream(response.body);
30
+ yield* readJsonlStream(response.body, readOptions);
29
31
  }
30
32
  }
31
33
  function fetchOptions(options) {
@@ -34,6 +36,7 @@ function fetchOptions(options) {
34
36
  format: _format,
35
37
  fetch: _fetch,
36
38
  validateResponse: _validate,
39
+ onParseError: _onParseError,
37
40
  ...init
38
41
  } = options;
39
42
  return init;
@@ -62,6 +65,7 @@ function createFetchEventTransport(options) {
62
65
  if (transportOptions.abortSignal !== void 0) init.signal = transportOptions.abortSignal;
63
66
  if (options.fetch !== void 0) init.fetch = options.fetch;
64
67
  if (options.validateResponse !== void 0) init.validateResponse = options.validateResponse;
68
+ if (options.onParseError !== void 0) init.onParseError = options.onParseError;
65
69
  for await (const event of fetchEventStream(init)) {
66
70
  yield options.mapEvent === void 0 ? event : options.mapEvent(event);
67
71
  }
@@ -120,4 +124,4 @@ export {
120
124
  createFetchEventTransport,
121
125
  createDirectEventTransport
122
126
  };
123
- //# sourceMappingURL=chunk-HZZDET2H.js.map
127
+ //# sourceMappingURL=chunk-RK5U6WVJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/transport/fetch.ts","../src/transport/event-transport.ts"],"sourcesContent":["import { type EventStreamReadOptions, readJsonlStream, readSseStream } from \"./streams\";\nimport type { EventStreamFormat } from \"./types\";\n\nexport type FetchEventStreamOptions = Omit<RequestInit, \"headers\"> & {\n input: string | URL | Request;\n format?: EventStreamFormat | \"auto\";\n fetch?: typeof fetch;\n headers?: HeadersInit;\n validateResponse?: (response: Response) => void;\n onParseError?: EventStreamReadOptions[\"onParseError\"];\n};\n\nexport class EventStreamHttpError extends Error {\n constructor(\n readonly response: Response,\n readonly body: string,\n ) {\n super(`Event stream request failed with status ${response.status}`);\n this.name = \"EventStreamHttpError\";\n }\n}\n\nexport async function* fetchEventStream<TEvent>(\n options: FetchEventStreamOptions,\n): AsyncIterable<TEvent> {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (fetchImpl === undefined) throw new Error(\"fetchEventStream requires a fetch implementation.\");\n\n const response = await fetchImpl(options.input, fetchOptions(options));\n if (!response.ok) throw new EventStreamHttpError(response, await response.text());\n options.validateResponse?.(response);\n if (response.body === null) throw new Error(\"Event stream response does not include a body.\");\n\n const format =\n options.format === undefined || options.format === \"auto\"\n ? inferEventStreamFormat(response.headers.get(\"content-type\"))\n : options.format;\n const readOptions: EventStreamReadOptions = {};\n if (options.onParseError !== undefined) readOptions.onParseError = options.onParseError;\n if (format === \"sse\") {\n yield* readSseStream<TEvent>(response.body, readOptions);\n } else {\n yield* readJsonlStream<TEvent>(response.body, readOptions);\n }\n}\n\nfunction fetchOptions(options: FetchEventStreamOptions): RequestInit {\n const {\n input: _input,\n format: _format,\n fetch: _fetch,\n validateResponse: _validate,\n onParseError: _onParseError,\n ...init\n } = options;\n return init;\n}\n\nfunction inferEventStreamFormat(contentType: string | null): EventStreamFormat {\n return contentType?.toLowerCase().includes(\"text/event-stream\") ? \"sse\" : \"jsonl\";\n}\n","import { type FetchEventStreamOptions, fetchEventStream } from \"./fetch\";\nimport type { EventStreamFormat, EventTransport, EventTransportSendOptions } from \"./types\";\n\nexport type EventTransportContext<TRequest> = EventTransportSendOptions<TRequest>;\n\nexport type EventTransportBodyContext<TRequest> = Omit<\n EventTransportContext<TRequest>,\n \"headers\"\n> & {\n headers: Headers;\n};\n\nexport type CreateFetchEventTransportOptions<TRequest, TEvent> = {\n endpoint: string | URL | ((context: EventTransportContext<TRequest>) => string | URL);\n method?: string;\n format?: EventStreamFormat | \"auto\";\n fetch?: typeof fetch;\n headers?:\n | HeadersInit\n | ((context: EventTransportContext<TRequest>) => HeadersInit | Promise<HeadersInit>);\n body?: (\n context: EventTransportBodyContext<TRequest>,\n ) => BodyInit | null | undefined | Promise<BodyInit | null | undefined>;\n init?: Omit<RequestInit, \"body\" | \"headers\" | \"method\" | \"signal\">;\n mapEvent?: (event: unknown) => TEvent;\n validateResponse?: (response: Response) => void;\n /** Receives malformed frames that were skipped instead of aborting the stream. */\n onParseError?: FetchEventStreamOptions[\"onParseError\"];\n};\n\nexport function createFetchEventTransport<TRequest, TEvent = unknown>(\n options: CreateFetchEventTransportOptions<TRequest, TEvent>,\n): EventTransport<TRequest, TEvent> {\n return {\n async *send(transportOptions) {\n const endpoint =\n typeof options.endpoint === \"function\"\n ? options.endpoint(transportOptions)\n : options.endpoint;\n const requestHeaders = await resolveHeaders(options.headers, transportOptions);\n const headers = mergeHeaders(requestHeaders, transportOptions.headers);\n const method = options.method ?? \"POST\";\n const body = await resolveBody(options.body, transportOptions, headers, method);\n const init: FetchEventStreamOptions = {\n ...options.init,\n input: endpoint,\n method,\n headers,\n format: options.format ?? \"auto\",\n };\n if (body !== undefined) init.body = body;\n if (transportOptions.abortSignal !== undefined) init.signal = transportOptions.abortSignal;\n if (options.fetch !== undefined) init.fetch = options.fetch;\n if (options.validateResponse !== undefined) init.validateResponse = options.validateResponse;\n if (options.onParseError !== undefined) init.onParseError = options.onParseError;\n\n for await (const event of fetchEventStream<unknown>(init)) {\n yield options.mapEvent === undefined ? (event as TEvent) : options.mapEvent(event);\n }\n },\n };\n}\n\nexport function createDirectEventTransport<TRequest, TEvent>(options: {\n handler(context: EventTransportContext<TRequest>): AsyncIterable<TEvent>;\n}): EventTransport<TRequest, TEvent> {\n return {\n async *send(context) {\n const iterator = options.handler(context)[Symbol.asyncIterator]();\n let closePromise: Promise<unknown> | undefined;\n const close = () => {\n closePromise ??= Promise.resolve(iterator.return?.());\n return closePromise;\n };\n const onAbort = () => {\n void close();\n };\n context.abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n try {\n while (!context.abortSignal?.aborted) {\n const next = await iterator.next();\n if (next.done) break;\n yield next.value;\n }\n } finally {\n context.abortSignal?.removeEventListener(\"abort\", onAbort);\n await close();\n }\n },\n };\n}\n\nasync function resolveHeaders<TRequest>(\n headers: CreateFetchEventTransportOptions<TRequest, unknown>[\"headers\"],\n context: EventTransportContext<TRequest>,\n): Promise<HeadersInit | undefined> {\n return typeof headers === \"function\" ? headers(context) : headers;\n}\n\nasync function resolveBody<TRequest>(\n body: CreateFetchEventTransportOptions<TRequest, unknown>[\"body\"],\n context: EventTransportContext<TRequest>,\n headers: Headers,\n method: string,\n): Promise<BodyInit | null | undefined> {\n if (body !== undefined) return body({ ...context, headers });\n if (method.toUpperCase() === \"GET\" || method.toUpperCase() === \"HEAD\") return undefined;\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return JSON.stringify(context.request);\n}\n\nfunction mergeHeaders(...values: Array<HeadersInit | undefined>): Headers {\n const headers = new Headers();\n for (const value of values) {\n if (value === undefined) continue;\n new Headers(value).forEach((headerValue, key) => {\n headers.set(key, headerValue);\n });\n }\n return headers;\n}\n"],"mappings":"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","names":[]}
package/dist/durable.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readSseStream
3
- } from "./chunk-63JX2QNP.js";
3
+ } from "./chunk-PD72KNCV.js";
4
4
 
5
5
  // src/durable.ts
6
6
  import {
@@ -90,7 +90,7 @@ var DurableClient = class {
90
90
  );
91
91
  if (!response.headers.get("content-type")?.startsWith("text/event-stream") || response.body === null)
92
92
  throw new TypeError("Expected a task SSE response.");
93
- for await (const value of readSseStream(response.body)) {
93
+ for await (const value of readSseStream(response.body, { strict: true })) {
94
94
  options.abortSignal?.throwIfAborted();
95
95
  const event = parseTaskEvent(value);
96
96
  if (event.rootId !== snapshot.task.rootId || event.sequence <= cursor)
@@ -137,7 +137,7 @@ var DurableClient = class {
137
137
  );
138
138
  if (!response.headers.get("content-type")?.startsWith("text/event-stream") || response.body === null)
139
139
  throw new TypeError("Expected a graph SSE response.");
140
- for await (const value of readSseStream(response.body)) {
140
+ for await (const value of readSseStream(response.body, { strict: true })) {
141
141
  options.abortSignal?.throwIfAborted();
142
142
  const event = parseDurableGraphEvent(value);
143
143
  if (event.graphId !== graphId || event.sequence <= cursor)
@@ -147,14 +147,12 @@ var DurableClient = class {
147
147
  }
148
148
  }
149
149
  async submit(submission, options = {}) {
150
- return parseDurableSnapshot(
151
- await (await this.request(
152
- "/runs",
153
- "POST",
154
- { ...submission, ...options.enqueue === void 0 ? {} : { enqueue: options.enqueue } },
155
- options
156
- )).json()
157
- );
150
+ const body = { ...submission };
151
+ if (options.enqueue !== void 0) {
152
+ body.enqueue = options.enqueue;
153
+ }
154
+ const response = await this.request("/runs", "POST", body, options);
155
+ return parseDurableSnapshot(await response.json());
158
156
  }
159
157
  async listRuns(filter, options = {}) {
160
158
  const query = new URLSearchParams();
@@ -182,7 +180,7 @@ var DurableClient = class {
182
180
  );
183
181
  if (!response.headers.get("content-type")?.startsWith("text/event-stream") || response.body === null)
184
182
  throw new TypeError("Expected a durable SSE response.");
185
- for await (const value of readSseStream(response.body)) {
183
+ for await (const value of readSseStream(response.body, { strict: true })) {
186
184
  options.abortSignal?.throwIfAborted();
187
185
  const event = parseDurableEvent(value);
188
186
  if (event.runId !== runId || event.sequence <= cursor)
@@ -192,14 +190,13 @@ var DurableClient = class {
192
190
  }
193
191
  }
194
192
  async steer(runId, input, options = {}) {
195
- return parseDurableSteerReceipt(
196
- await (await this.request(
197
- `${this.path(runId)}/steer`,
198
- "POST",
199
- { input, ...options.requestId === void 0 ? {} : { requestId: options.requestId } },
200
- options
201
- )).json()
202
- );
193
+ const path = `${this.path(runId)}/steer`;
194
+ const body = { input };
195
+ if (options.requestId !== void 0) {
196
+ body.requestId = options.requestId;
197
+ }
198
+ const response = await this.request(path, "POST", body, options);
199
+ return parseDurableSteerReceipt(await response.json());
203
200
  }
204
201
  async respond(runId, interactionId, response, options = {}) {
205
202
  await this.request(`${this.path(runId)}/respond`, "POST", { interactionId, response }, options);
@@ -232,13 +229,22 @@ var DurableClient = class {
232
229
  const supplied = typeof this.options.headers === "function" ? await this.options.headers() : this.options.headers;
233
230
  const headers = new Headers(supplied);
234
231
  if (body !== void 0) headers.set("content-type", "application/json");
235
- const response = await (this.options.fetch ?? globalThis.fetch)(`${this.endpoint}${path}`, {
232
+ const fetch = this.options.fetch ?? globalThis.fetch;
233
+ const url = `${this.endpoint}${path}`;
234
+ const init = {
236
235
  method,
237
- headers,
238
- ...body === void 0 ? {} : { body: JSON.stringify(body) },
239
- ...options.abortSignal === void 0 ? {} : { signal: options.abortSignal },
240
- ...this.options.credentials === void 0 ? {} : { credentials: this.options.credentials }
241
- });
236
+ headers
237
+ };
238
+ if (body !== void 0) {
239
+ init.body = JSON.stringify(body);
240
+ }
241
+ if (options.abortSignal !== void 0) {
242
+ init.signal = options.abortSignal;
243
+ }
244
+ if (this.options.credentials !== void 0) {
245
+ init.credentials = this.options.credentials;
246
+ }
247
+ const response = await fetch(url, init);
242
248
  if (!response.ok) {
243
249
  await response.body?.cancel();
244
250
  throw new DurableHttpError(response.status);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/durable.ts"],"sourcesContent":["import {\n parseTaskSnapshot,\n parseTaskGraph,\n parseTaskPage,\n parseTaskEvent,\n type TaskSubmission,\n type TaskSnapshot,\n type TaskGraphSnapshot,\n type TaskPage,\n type TaskListOptions,\n type TaskEvent,\n} from \"@anvia/durable/protocol\";\nimport type { AgentSteerInput, AgentSteerReceipt } from \"@anvia/core/agent\";\nimport type { AgentInteractionResponse } from \"@anvia/core/agent/interactions\";\nimport type { JsonValue, ToolResultOutput } from \"@anvia/core/completion\";\nimport {\n parseDurableEvent,\n parseDurableSteerReceipt,\n type DurableSteerOptions,\n parseDurableGraphSnapshot,\n parseDurableGraphEvent,\n parseDurableGraphPage,\n type DurableGraphSubmission,\n type DurableGraphSnapshot,\n type DurableGraphListOptions,\n type DurableGraphPage,\n type DurableGraphEvent,\n parseDurableRunPage,\n parseDurableSnapshot,\n type DurableEvent,\n type DurableListOptions,\n type DurableRunPage,\n type DurableSnapshot,\n type DurableSubmission,\n type DurableSubmitOptions,\n} from \"@anvia/durable/protocol\";\nimport { readSseStream } from \"./transport/streams\";\n\nexport type DurableRequestOptions = { abortSignal?: AbortSignal };\nexport type DurableClientOptions = {\n /** Absolute HTTP(S) URL matching the server handler's basePath. */\n endpoint: string;\n fetch?: typeof fetch;\n headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n credentials?: RequestCredentials;\n};\nexport class DurableHttpError extends Error {\n constructor(readonly status: number) {\n super(`Durable request failed with HTTP ${status}.`);\n this.name = \"DurableHttpError\";\n }\n}\n\n/** Browser-safe HTTP client. Reconnect explicitly using a snapshot or last applied event cursor. */\nexport class DurableClient {\n private readonly endpoint: string;\n constructor(private readonly options: DurableClientOptions) {\n const endpoint = new URL(options.endpoint);\n if (\n ![\"http:\", \"https:\"].includes(endpoint.protocol) ||\n endpoint.search ||\n endpoint.hash ||\n endpoint.username ||\n endpoint.password\n )\n throw new TypeError(\n \"endpoint must be an HTTP(S) base URL without credentials, query, or fragment.\",\n );\n this.endpoint = endpoint.href.replace(/\\/$/, \"\");\n }\n\n async submitTask(\n /** Trace context is set by the server's `trace` hook. */\n submission: Omit<TaskSubmission, \"trace\">,\n options: DurableRequestOptions = {},\n ): Promise<TaskSnapshot> {\n return parseTaskSnapshot(\n await (await this.request(\"/tasks\", \"POST\", submission, options)).json(),\n );\n }\n async taskSnapshot(id: string, options: DurableRequestOptions = {}): Promise<TaskSnapshot> {\n const snapshot = parseTaskSnapshot(\n await (await this.request(this.taskPath(id), \"GET\", undefined, options)).json(),\n );\n if (snapshot.task.id !== id) throw new TypeError(\"Snapshot belongs to another task.\");\n return snapshot;\n }\n async taskGraph(id: string, options: DurableRequestOptions = {}): Promise<TaskGraphSnapshot> {\n const graph = parseTaskGraph(\n await (await this.request(`${this.taskPath(id)}/graph`, \"GET\", undefined, options)).json(),\n );\n if (!graph.nodes.some((task) => task.id === id))\n throw new TypeError(\"Graph belongs to another task.\");\n return graph;\n }\n async listTasks(\n filter: TaskListOptions & { sessionId: string },\n options: DurableRequestOptions = {},\n ): Promise<TaskPage> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(filter))\n if (value !== undefined) query.set(key, String(value));\n return parseTaskPage(\n await (await this.request(`/tasks?${query}`, \"GET\", undefined, options)).json(),\n );\n }\n async signalTask(\n id: string,\n name: string,\n requestId: string,\n value: JsonValue,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(`${this.taskPath(id)}/signal`, \"POST\", { name, requestId, value }, options);\n }\n async resolveEffect(\n id: string,\n key: string,\n value: JsonValue,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(`${this.taskPath(id)}/resolve-effect`, \"POST\", { key, value }, options);\n }\n async retryTask(id: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.taskPath(id)}/retry`, \"POST\", undefined, options);\n }\n async cancelTask(id: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.taskPath(id)}/cancel`, \"POST\", undefined, options);\n }\n async *streamTask(\n id: string,\n options: DurableRequestOptions & { after?: number } = {},\n ): AsyncIterable<TaskEvent> {\n let cursor = options.after ?? 0;\n if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError(\"Invalid task cursor.\");\n const snapshot = await this.taskSnapshot(id, options);\n const response = await this.request(\n `${this.taskPath(id)}/events?after=${cursor}`,\n \"GET\",\n undefined,\n options,\n );\n if (\n !response.headers.get(\"content-type\")?.startsWith(\"text/event-stream\") ||\n response.body === null\n )\n throw new TypeError(\"Expected a task SSE response.\");\n for await (const value of readSseStream<unknown>(response.body)) {\n options.abortSignal?.throwIfAborted();\n const event = parseTaskEvent(value);\n if (event.rootId !== snapshot.task.rootId || event.sequence <= cursor)\n throw new TypeError(\"Invalid task event order or root ID.\");\n cursor = event.sequence;\n yield event;\n }\n }\n private taskPath(id: string): string {\n if (id.trim().length === 0 || id === \".\" || id === \"..\") throw new TypeError(\"Invalid taskId.\");\n return `/tasks/${encodeURIComponent(id)}`;\n }\n\n async submitGraph(\n submission: DurableGraphSubmission,\n options: DurableRequestOptions = {},\n ): Promise<DurableGraphSnapshot> {\n return parseDurableGraphSnapshot(\n await (await this.request(\"/graphs\", \"POST\", submission, options)).json(),\n );\n }\n async graphSnapshot(\n graphId: string,\n options: DurableRequestOptions = {},\n ): Promise<DurableGraphSnapshot> {\n const snapshot = parseDurableGraphSnapshot(\n await (await this.request(this.graphPath(graphId), \"GET\", undefined, options)).json(),\n );\n if (snapshot.id !== graphId) throw new TypeError(\"Snapshot belongs to another graph.\");\n return snapshot;\n }\n async listGraphs(\n filter: DurableGraphListOptions & { sessionId: string },\n options: DurableRequestOptions = {},\n ): Promise<DurableGraphPage> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(filter))\n if (value !== undefined) query.set(key, String(value));\n return parseDurableGraphPage(\n await (await this.request(`/graphs?${query}`, \"GET\", undefined, options)).json(),\n );\n }\n async cancelGraph(graphId: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.graphPath(graphId)}/cancel`, \"POST\", undefined, options);\n }\n async *streamGraph(\n graphId: string,\n options: DurableRequestOptions & { after?: number } = {},\n ): AsyncIterable<DurableGraphEvent> {\n let cursor = options.after ?? 0;\n if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError(\"Invalid graph cursor.\");\n const response = await this.request(\n `${this.graphPath(graphId)}/events?after=${cursor}`,\n \"GET\",\n undefined,\n options,\n );\n if (\n !response.headers.get(\"content-type\")?.startsWith(\"text/event-stream\") ||\n response.body === null\n )\n throw new TypeError(\"Expected a graph SSE response.\");\n for await (const value of readSseStream<unknown>(response.body)) {\n options.abortSignal?.throwIfAborted();\n const event = parseDurableGraphEvent(value);\n if (event.graphId !== graphId || event.sequence <= cursor)\n throw new TypeError(\"Invalid graph event order or ID.\");\n cursor = event.sequence;\n yield event;\n }\n }\n\n async submit(\n /** Trace context is set by the server's `trace` hook. */\n submission: Omit<DurableSubmission, \"trace\">,\n options: DurableSubmitOptions & DurableRequestOptions = {},\n ): Promise<DurableSnapshot> {\n return parseDurableSnapshot(\n await (\n await this.request(\n \"/runs\",\n \"POST\",\n { ...submission, ...(options.enqueue === undefined ? {} : { enqueue: options.enqueue }) },\n options,\n )\n ).json(),\n );\n }\n async listRuns(\n filter: DurableListOptions & { sessionId: string },\n options: DurableRequestOptions = {},\n ): Promise<DurableRunPage> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(filter))\n if (value !== undefined) query.set(key, String(value));\n return parseDurableRunPage(\n await (await this.request(`/runs?${query}`, \"GET\", undefined, options)).json(),\n );\n }\n async snapshot(runId: string, options: DurableRequestOptions = {}): Promise<DurableSnapshot> {\n const snapshot = parseDurableSnapshot(\n await (await this.request(this.path(runId), \"GET\", undefined, options)).json(),\n );\n if (snapshot.run.id !== runId) throw new TypeError(\"Durable snapshot belongs to another run.\");\n return snapshot;\n }\n async *stream(\n runId: string,\n options: DurableRequestOptions & { after?: number } = {},\n ): AsyncIterable<DurableEvent> {\n let cursor = options.after ?? 0;\n if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError(\"Invalid event cursor.\");\n const response = await this.request(\n `${this.path(runId)}/events?after=${cursor}`,\n \"GET\",\n undefined,\n options,\n );\n if (\n !response.headers.get(\"content-type\")?.startsWith(\"text/event-stream\") ||\n response.body === null\n )\n throw new TypeError(\"Expected a durable SSE response.\");\n for await (const value of readSseStream<unknown>(response.body)) {\n options.abortSignal?.throwIfAborted();\n const event = parseDurableEvent(value);\n if (event.runId !== runId || event.sequence <= cursor)\n throw new TypeError(\"Invalid durable event order or run ID.\");\n cursor = event.sequence;\n yield event;\n }\n }\n async steer(\n runId: string,\n input: AgentSteerInput,\n options: DurableSteerOptions & DurableRequestOptions = {},\n ): Promise<AgentSteerReceipt> {\n return parseDurableSteerReceipt(\n await (\n await this.request(\n `${this.path(runId)}/steer`,\n \"POST\",\n { input, ...(options.requestId === undefined ? {} : { requestId: options.requestId }) },\n options,\n )\n ).json(),\n );\n }\n async respond(\n runId: string,\n interactionId: string,\n response: AgentInteractionResponse,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(`${this.path(runId)}/respond`, \"POST\", { interactionId, response }, options);\n }\n async resolveTool(\n runId: string,\n operationId: string,\n output: ToolResultOutput,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(\n `${this.path(runId)}/resolve-tool`,\n \"POST\",\n { operationId, output },\n options,\n );\n }\n async retry(runId: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.path(runId)}/retry`, \"POST\", undefined, options);\n }\n async cancel(runId: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.path(runId)}/cancel`, \"POST\", undefined, options);\n }\n\n private graphPath(id: string): string {\n if (id.trim().length === 0 || id === \".\" || id === \"..\")\n throw new TypeError(\"Invalid graphId.\");\n return `/graphs/${encodeURIComponent(id)}`;\n }\n private path(id: string): string {\n if (id.trim().length === 0) throw new TypeError(\"runId must not be empty.\");\n return `/runs/${encodeURIComponent(id)}`;\n }\n private async request(\n path: string,\n method: string,\n body: unknown,\n options: DurableRequestOptions,\n ): Promise<Response> {\n options.abortSignal?.throwIfAborted();\n const supplied =\n typeof this.options.headers === \"function\"\n ? await this.options.headers()\n : this.options.headers;\n const headers = new Headers(supplied);\n if (body !== undefined) headers.set(\"content-type\", \"application/json\");\n const response = await (this.options.fetch ?? globalThis.fetch)(`${this.endpoint}${path}`, {\n method,\n headers,\n ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n ...(options.abortSignal === undefined ? {} : { signal: options.abortSignal }),\n ...(this.options.credentials === undefined ? {} : { credentials: this.options.credentials }),\n });\n if (!response.ok) {\n await response.body?.cancel();\n throw new DurableHttpError(response.status);\n }\n return response;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/durable.ts"],"sourcesContent":["import {\n parseTaskSnapshot,\n parseTaskGraph,\n parseTaskPage,\n parseTaskEvent,\n type TaskSubmission,\n type TaskSnapshot,\n type TaskGraphSnapshot,\n type TaskPage,\n type TaskListOptions,\n type TaskEvent,\n} from \"@anvia/durable/protocol\";\nimport type { AgentSteerInput, AgentSteerReceipt } from \"@anvia/core/agent\";\nimport type { AgentInteractionResponse } from \"@anvia/core/agent/interactions\";\nimport type { JsonValue, ToolResultOutput } from \"@anvia/core/completion\";\nimport {\n parseDurableEvent,\n parseDurableSteerReceipt,\n type DurableSteerOptions,\n parseDurableGraphSnapshot,\n parseDurableGraphEvent,\n parseDurableGraphPage,\n type DurableGraphSubmission,\n type DurableGraphSnapshot,\n type DurableGraphListOptions,\n type DurableGraphPage,\n type DurableGraphEvent,\n parseDurableRunPage,\n parseDurableSnapshot,\n type DurableEvent,\n type DurableListOptions,\n type DurableRunPage,\n type DurableSnapshot,\n type DurableSubmission,\n type DurableSubmitOptions,\n} from \"@anvia/durable/protocol\";\nimport { readSseStream } from \"./transport/streams\";\n\nexport type DurableRequestOptions = { abortSignal?: AbortSignal };\nexport type DurableClientOptions = {\n /** Absolute HTTP(S) URL matching the server handler's basePath. */\n endpoint: string;\n fetch?: typeof fetch;\n headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n credentials?: RequestCredentials;\n};\nexport class DurableHttpError extends Error {\n constructor(readonly status: number) {\n super(`Durable request failed with HTTP ${status}.`);\n this.name = \"DurableHttpError\";\n }\n}\n\n/** Browser-safe HTTP client. Reconnect explicitly using a snapshot or last applied event cursor. */\nexport class DurableClient {\n private readonly endpoint: string;\n constructor(private readonly options: DurableClientOptions) {\n const endpoint = new URL(options.endpoint);\n if (\n ![\"http:\", \"https:\"].includes(endpoint.protocol) ||\n endpoint.search ||\n endpoint.hash ||\n endpoint.username ||\n endpoint.password\n )\n throw new TypeError(\n \"endpoint must be an HTTP(S) base URL without credentials, query, or fragment.\",\n );\n this.endpoint = endpoint.href.replace(/\\/$/, \"\");\n }\n\n async submitTask(\n /** Trace context is set by the server's `trace` hook. */\n submission: Omit<TaskSubmission, \"trace\">,\n options: DurableRequestOptions = {},\n ): Promise<TaskSnapshot> {\n return parseTaskSnapshot(\n await (await this.request(\"/tasks\", \"POST\", submission, options)).json(),\n );\n }\n async taskSnapshot(id: string, options: DurableRequestOptions = {}): Promise<TaskSnapshot> {\n const snapshot = parseTaskSnapshot(\n await (await this.request(this.taskPath(id), \"GET\", undefined, options)).json(),\n );\n if (snapshot.task.id !== id) throw new TypeError(\"Snapshot belongs to another task.\");\n return snapshot;\n }\n async taskGraph(id: string, options: DurableRequestOptions = {}): Promise<TaskGraphSnapshot> {\n const graph = parseTaskGraph(\n await (await this.request(`${this.taskPath(id)}/graph`, \"GET\", undefined, options)).json(),\n );\n if (!graph.nodes.some((task) => task.id === id))\n throw new TypeError(\"Graph belongs to another task.\");\n return graph;\n }\n async listTasks(\n filter: TaskListOptions & { sessionId: string },\n options: DurableRequestOptions = {},\n ): Promise<TaskPage> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(filter))\n if (value !== undefined) query.set(key, String(value));\n return parseTaskPage(\n await (await this.request(`/tasks?${query}`, \"GET\", undefined, options)).json(),\n );\n }\n async signalTask(\n id: string,\n name: string,\n requestId: string,\n value: JsonValue,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(`${this.taskPath(id)}/signal`, \"POST\", { name, requestId, value }, options);\n }\n async resolveEffect(\n id: string,\n key: string,\n value: JsonValue,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(`${this.taskPath(id)}/resolve-effect`, \"POST\", { key, value }, options);\n }\n async retryTask(id: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.taskPath(id)}/retry`, \"POST\", undefined, options);\n }\n async cancelTask(id: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.taskPath(id)}/cancel`, \"POST\", undefined, options);\n }\n async *streamTask(\n id: string,\n options: DurableRequestOptions & { after?: number } = {},\n ): AsyncIterable<TaskEvent> {\n let cursor = options.after ?? 0;\n if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError(\"Invalid task cursor.\");\n const snapshot = await this.taskSnapshot(id, options);\n const response = await this.request(\n `${this.taskPath(id)}/events?after=${cursor}`,\n \"GET\",\n undefined,\n options,\n );\n if (\n !response.headers.get(\"content-type\")?.startsWith(\"text/event-stream\") ||\n response.body === null\n )\n throw new TypeError(\"Expected a task SSE response.\");\n for await (const value of readSseStream<unknown>(response.body, { strict: true })) {\n options.abortSignal?.throwIfAborted();\n const event = parseTaskEvent(value);\n if (event.rootId !== snapshot.task.rootId || event.sequence <= cursor)\n throw new TypeError(\"Invalid task event order or root ID.\");\n cursor = event.sequence;\n yield event;\n }\n }\n private taskPath(id: string): string {\n if (id.trim().length === 0 || id === \".\" || id === \"..\") throw new TypeError(\"Invalid taskId.\");\n return `/tasks/${encodeURIComponent(id)}`;\n }\n\n async submitGraph(\n submission: DurableGraphSubmission,\n options: DurableRequestOptions = {},\n ): Promise<DurableGraphSnapshot> {\n return parseDurableGraphSnapshot(\n await (await this.request(\"/graphs\", \"POST\", submission, options)).json(),\n );\n }\n async graphSnapshot(\n graphId: string,\n options: DurableRequestOptions = {},\n ): Promise<DurableGraphSnapshot> {\n const snapshot = parseDurableGraphSnapshot(\n await (await this.request(this.graphPath(graphId), \"GET\", undefined, options)).json(),\n );\n if (snapshot.id !== graphId) throw new TypeError(\"Snapshot belongs to another graph.\");\n return snapshot;\n }\n async listGraphs(\n filter: DurableGraphListOptions & { sessionId: string },\n options: DurableRequestOptions = {},\n ): Promise<DurableGraphPage> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(filter))\n if (value !== undefined) query.set(key, String(value));\n return parseDurableGraphPage(\n await (await this.request(`/graphs?${query}`, \"GET\", undefined, options)).json(),\n );\n }\n async cancelGraph(graphId: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.graphPath(graphId)}/cancel`, \"POST\", undefined, options);\n }\n async *streamGraph(\n graphId: string,\n options: DurableRequestOptions & { after?: number } = {},\n ): AsyncIterable<DurableGraphEvent> {\n let cursor = options.after ?? 0;\n if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError(\"Invalid graph cursor.\");\n const response = await this.request(\n `${this.graphPath(graphId)}/events?after=${cursor}`,\n \"GET\",\n undefined,\n options,\n );\n if (\n !response.headers.get(\"content-type\")?.startsWith(\"text/event-stream\") ||\n response.body === null\n )\n throw new TypeError(\"Expected a graph SSE response.\");\n for await (const value of readSseStream<unknown>(response.body, { strict: true })) {\n options.abortSignal?.throwIfAborted();\n const event = parseDurableGraphEvent(value);\n if (event.graphId !== graphId || event.sequence <= cursor)\n throw new TypeError(\"Invalid graph event order or ID.\");\n cursor = event.sequence;\n yield event;\n }\n }\n\n async submit(\n /** Trace context is set by the server's `trace` hook. */\n submission: Omit<DurableSubmission, \"trace\">,\n options: DurableSubmitOptions & DurableRequestOptions = {},\n ): Promise<DurableSnapshot> {\n const body: Omit<DurableSubmission, \"trace\"> & DurableSubmitOptions = { ...submission };\n\n if (options.enqueue !== undefined) {\n body.enqueue = options.enqueue;\n }\n\n const response = await this.request(\"/runs\", \"POST\", body, options);\n\n return parseDurableSnapshot(await response.json());\n }\n\n async listRuns(\n filter: DurableListOptions & { sessionId: string },\n options: DurableRequestOptions = {},\n ): Promise<DurableRunPage> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(filter))\n if (value !== undefined) query.set(key, String(value));\n return parseDurableRunPage(\n await (await this.request(`/runs?${query}`, \"GET\", undefined, options)).json(),\n );\n }\n async snapshot(runId: string, options: DurableRequestOptions = {}): Promise<DurableSnapshot> {\n const snapshot = parseDurableSnapshot(\n await (await this.request(this.path(runId), \"GET\", undefined, options)).json(),\n );\n if (snapshot.run.id !== runId) throw new TypeError(\"Durable snapshot belongs to another run.\");\n return snapshot;\n }\n async *stream(\n runId: string,\n options: DurableRequestOptions & { after?: number } = {},\n ): AsyncIterable<DurableEvent> {\n let cursor = options.after ?? 0;\n if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError(\"Invalid event cursor.\");\n const response = await this.request(\n `${this.path(runId)}/events?after=${cursor}`,\n \"GET\",\n undefined,\n options,\n );\n if (\n !response.headers.get(\"content-type\")?.startsWith(\"text/event-stream\") ||\n response.body === null\n )\n throw new TypeError(\"Expected a durable SSE response.\");\n for await (const value of readSseStream<unknown>(response.body, { strict: true })) {\n options.abortSignal?.throwIfAborted();\n const event = parseDurableEvent(value);\n if (event.runId !== runId || event.sequence <= cursor)\n throw new TypeError(\"Invalid durable event order or run ID.\");\n cursor = event.sequence;\n yield event;\n }\n }\n async steer(\n runId: string,\n input: AgentSteerInput,\n options: DurableSteerOptions & DurableRequestOptions = {},\n ): Promise<AgentSteerReceipt> {\n const path = `${this.path(runId)}/steer`;\n const body: { input: AgentSteerInput; requestId?: string } = { input };\n\n if (options.requestId !== undefined) {\n body.requestId = options.requestId;\n }\n\n const response = await this.request(path, \"POST\", body, options);\n\n return parseDurableSteerReceipt(await response.json());\n }\n\n async respond(\n runId: string,\n interactionId: string,\n response: AgentInteractionResponse,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(`${this.path(runId)}/respond`, \"POST\", { interactionId, response }, options);\n }\n async resolveTool(\n runId: string,\n operationId: string,\n output: ToolResultOutput,\n options: DurableRequestOptions = {},\n ): Promise<void> {\n await this.request(\n `${this.path(runId)}/resolve-tool`,\n \"POST\",\n { operationId, output },\n options,\n );\n }\n async retry(runId: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.path(runId)}/retry`, \"POST\", undefined, options);\n }\n async cancel(runId: string, options: DurableRequestOptions = {}): Promise<void> {\n await this.request(`${this.path(runId)}/cancel`, \"POST\", undefined, options);\n }\n\n private graphPath(id: string): string {\n if (id.trim().length === 0 || id === \".\" || id === \"..\")\n throw new TypeError(\"Invalid graphId.\");\n return `/graphs/${encodeURIComponent(id)}`;\n }\n private path(id: string): string {\n if (id.trim().length === 0) throw new TypeError(\"runId must not be empty.\");\n return `/runs/${encodeURIComponent(id)}`;\n }\n private async request(\n path: string,\n method: string,\n body: unknown,\n options: DurableRequestOptions,\n ): Promise<Response> {\n options.abortSignal?.throwIfAborted();\n const supplied =\n typeof this.options.headers === \"function\"\n ? await this.options.headers()\n : this.options.headers;\n const headers = new Headers(supplied);\n if (body !== undefined) headers.set(\"content-type\", \"application/json\");\n\n const fetch = this.options.fetch ?? globalThis.fetch;\n const url = `${this.endpoint}${path}`;\n const init: RequestInit = {\n method,\n headers,\n };\n\n if (body !== undefined) {\n init.body = JSON.stringify(body);\n }\n\n if (options.abortSignal !== undefined) {\n init.signal = options.abortSignal;\n }\n\n if (this.options.credentials !== undefined) {\n init.credentials = this.options.credentials;\n }\n\n const response = await fetch(url, init);\n if (!response.ok) {\n await response.body?.cancel();\n throw new DurableHttpError(response.status);\n }\n return response;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { isJsonValue } from '@anvia/core/completion';
4
4
  import { AgentInteractionRequest, AgentInteractionResponse } from '@anvia/core/agent/interactions';
5
5
  import { GuardrailDecisionRecord } from '@anvia/core/guardrails';
6
6
  import { MemoryCompactionInfo } from '@anvia/core/memory';
7
- import { C as CreateFetchEventTransportOptions } from './event-transport-CC5RD-hT.js';
7
+ import { CreateFetchEventTransportOptions } from './transport/index.js';
8
8
 
9
9
  declare const CLIENT_STREAM_PROTOCOL: "anvia.client.v3";
10
10
  type ClientDataMap = Record<string, JsonValue>;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createFetchEventTransport
3
- } from "./chunk-HZZDET2H.js";
4
- import "./chunk-63JX2QNP.js";
3
+ } from "./chunk-RK5U6WVJ.js";
4
+ import "./chunk-PD72KNCV.js";
5
5
 
6
6
  // src/adapters.ts
7
7
  import {
@@ -1,5 +1,55 @@
1
- import { E as EventStreamFormat } from '../event-transport-CC5RD-hT.js';
2
- export { C as CreateFetchEventTransportOptions, a as EventTransport, b as EventTransportSendOptions, c as createDirectEventTransport, d as createFetchEventTransport } from '../event-transport-CC5RD-hT.js';
1
+ type EventStreamFormat = "jsonl" | "sse";
2
+ type EventTransportSendOptions<TRequest> = {
3
+ request: TRequest;
4
+ abortSignal?: AbortSignal;
5
+ headers?: HeadersInit;
6
+ };
7
+ type EventTransport<TRequest, TEvent> = {
8
+ send(options: EventTransportSendOptions<TRequest>): AsyncIterable<TEvent>;
9
+ };
10
+
11
+ /** A malformed JSONL line or SSE data payload that could not be parsed as JSON. */
12
+ declare class EventStreamParseError extends Error {
13
+ readonly format: EventStreamFormat;
14
+ /** The raw JSONL line or joined SSE `data` payload. */
15
+ readonly raw: string;
16
+ /** 1-based physical line number of the malformed JSONL line. */
17
+ readonly line: number | undefined;
18
+ /** SSE event name of the malformed frame. */
19
+ readonly event: string | undefined;
20
+ /** SSE last event ID in effect when the malformed frame was dispatched. */
21
+ readonly lastEventId: string | undefined;
22
+ constructor(options: {
23
+ format: EventStreamFormat;
24
+ raw: string;
25
+ cause: unknown;
26
+ line?: number;
27
+ event?: string;
28
+ lastEventId?: string;
29
+ });
30
+ }
31
+ type EventStreamReadOptions = {
32
+ /**
33
+ * Receives frames whose payload is not valid JSON. Malformed frames are skipped and the
34
+ * stream continues. Throwing from this callback aborts the stream with that error.
35
+ */
36
+ onParseError?: (error: EventStreamParseError) => void;
37
+ /** Throw the parse error instead of skipping malformed frames. */
38
+ strict?: boolean;
39
+ };
40
+ /** A dispatched Server-Sent Event with its parsed JSON payload. */
41
+ type SseFrame<TEvent> = {
42
+ data: TEvent;
43
+ /** Event name from the `event:` field, `"message"` when absent. */
44
+ event: string;
45
+ /** Last event ID set by an `id:` field in this or an earlier frame, `""` when none. */
46
+ lastEventId: string;
47
+ /** Most recent valid `retry:` reconnection time in milliseconds. */
48
+ retry?: number;
49
+ };
50
+ declare function readJsonlStream<TEvent>(stream: ReadableStream<Uint8Array>, options?: EventStreamReadOptions): AsyncIterable<TEvent>;
51
+ declare function readSseStream<TEvent>(stream: ReadableStream<Uint8Array>, options?: EventStreamReadOptions): AsyncIterable<TEvent>;
52
+ declare function readSseFrames<TEvent>(stream: ReadableStream<Uint8Array>, options?: EventStreamReadOptions): AsyncIterable<SseFrame<TEvent>>;
3
53
 
4
54
  type FetchEventStreamOptions = Omit<RequestInit, "headers"> & {
5
55
  input: string | URL | Request;
@@ -7,6 +57,7 @@ type FetchEventStreamOptions = Omit<RequestInit, "headers"> & {
7
57
  fetch?: typeof fetch;
8
58
  headers?: HeadersInit;
9
59
  validateResponse?: (response: Response) => void;
60
+ onParseError?: EventStreamReadOptions["onParseError"];
10
61
  };
11
62
  declare class EventStreamHttpError extends Error {
12
63
  readonly response: Response;
@@ -15,7 +66,26 @@ declare class EventStreamHttpError extends Error {
15
66
  }
16
67
  declare function fetchEventStream<TEvent>(options: FetchEventStreamOptions): AsyncIterable<TEvent>;
17
68
 
18
- declare function readJsonlStream<TEvent>(stream: ReadableStream<Uint8Array>): AsyncIterable<TEvent>;
19
- declare function readSseStream<TEvent>(stream: ReadableStream<Uint8Array>): AsyncIterable<TEvent>;
69
+ type EventTransportContext<TRequest> = EventTransportSendOptions<TRequest>;
70
+ type EventTransportBodyContext<TRequest> = Omit<EventTransportContext<TRequest>, "headers"> & {
71
+ headers: Headers;
72
+ };
73
+ type CreateFetchEventTransportOptions<TRequest, TEvent> = {
74
+ endpoint: string | URL | ((context: EventTransportContext<TRequest>) => string | URL);
75
+ method?: string;
76
+ format?: EventStreamFormat | "auto";
77
+ fetch?: typeof fetch;
78
+ headers?: HeadersInit | ((context: EventTransportContext<TRequest>) => HeadersInit | Promise<HeadersInit>);
79
+ body?: (context: EventTransportBodyContext<TRequest>) => BodyInit | null | undefined | Promise<BodyInit | null | undefined>;
80
+ init?: Omit<RequestInit, "body" | "headers" | "method" | "signal">;
81
+ mapEvent?: (event: unknown) => TEvent;
82
+ validateResponse?: (response: Response) => void;
83
+ /** Receives malformed frames that were skipped instead of aborting the stream. */
84
+ onParseError?: FetchEventStreamOptions["onParseError"];
85
+ };
86
+ declare function createFetchEventTransport<TRequest, TEvent = unknown>(options: CreateFetchEventTransportOptions<TRequest, TEvent>): EventTransport<TRequest, TEvent>;
87
+ declare function createDirectEventTransport<TRequest, TEvent>(options: {
88
+ handler(context: EventTransportContext<TRequest>): AsyncIterable<TEvent>;
89
+ }): EventTransport<TRequest, TEvent>;
20
90
 
21
- export { EventStreamFormat, EventStreamHttpError, type FetchEventStreamOptions, fetchEventStream, readJsonlStream, readSseStream };
91
+ export { type CreateFetchEventTransportOptions, type EventStreamFormat, EventStreamHttpError, EventStreamParseError, type EventStreamReadOptions, type EventTransport, type EventTransportSendOptions, type FetchEventStreamOptions, type SseFrame, createDirectEventTransport, createFetchEventTransport, fetchEventStream, readJsonlStream, readSseFrames, readSseStream };
@@ -3,17 +3,21 @@ import {
3
3
  createDirectEventTransport,
4
4
  createFetchEventTransport,
5
5
  fetchEventStream
6
- } from "../chunk-HZZDET2H.js";
6
+ } from "../chunk-RK5U6WVJ.js";
7
7
  import {
8
+ EventStreamParseError,
8
9
  readJsonlStream,
10
+ readSseFrames,
9
11
  readSseStream
10
- } from "../chunk-63JX2QNP.js";
12
+ } from "../chunk-PD72KNCV.js";
11
13
  export {
12
14
  EventStreamHttpError,
15
+ EventStreamParseError,
13
16
  createDirectEventTransport,
14
17
  createFetchEventTransport,
15
18
  fetchEventStream,
16
19
  readJsonlStream,
20
+ readSseFrames,
17
21
  readSseStream
18
22
  };
19
23
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anvia/client",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Framework-neutral client protocol, transports, and UI message state for Anvia.",
5
5
  "author": "anvia",
6
6
  "license": "MIT",
@@ -37,12 +37,12 @@
37
37
  "tsup": "^8.5.0",
38
38
  "typescript": "^5.9.3",
39
39
  "vitest": "^4.1.11",
40
- "@anvia/core": "1.14.1",
41
- "@anvia/durable": "0.11.0"
40
+ "@anvia/core": "1.16.0",
41
+ "@anvia/durable": "0.12.0"
42
42
  },
43
43
  "peerDependencies": {
44
- "@anvia/durable": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0",
45
- "@anvia/core": "^1.14.1"
44
+ "@anvia/durable": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0",
45
+ "@anvia/core": "^1.16.0"
46
46
  },
47
47
  "peerDependenciesMeta": {
48
48
  "@anvia/durable": {
@@ -1,86 +0,0 @@
1
- // src/transport/streams.ts
2
- async function* readJsonlStream(stream) {
3
- const reader = stream.getReader();
4
- const decoder = new TextDecoder();
5
- let buffer = "";
6
- let completed = false;
7
- try {
8
- while (true) {
9
- const next = await reader.read();
10
- if (next.done) {
11
- completed = true;
12
- break;
13
- }
14
- buffer += decoder.decode(next.value, { stream: true });
15
- const lines = buffer.split(/\r?\n/);
16
- buffer = lines.pop() ?? "";
17
- for (const line of lines) {
18
- const value2 = line.trim();
19
- if (value2.length > 0) yield JSON.parse(value2);
20
- }
21
- }
22
- buffer += decoder.decode();
23
- const value = buffer.trim();
24
- if (value.length > 0) yield JSON.parse(value);
25
- } finally {
26
- if (!completed) await cancelReader(reader);
27
- reader.releaseLock();
28
- }
29
- }
30
- async function* readSseStream(stream) {
31
- const reader = stream.getReader();
32
- const decoder = new TextDecoder();
33
- let buffer = "";
34
- let data = [];
35
- let completed = false;
36
- function parseLine(line) {
37
- if (line === "") {
38
- const complete = data.length === 0 ? void 0 : data.join("\n");
39
- data = [];
40
- return complete;
41
- }
42
- if (line.startsWith(":")) return void 0;
43
- const separator = line.indexOf(":");
44
- const field = separator === -1 ? line : line.slice(0, separator);
45
- const value = separator === -1 ? "" : line.slice(separator + 1).replace(/^ /, "");
46
- if (field === "data") data.push(value);
47
- return void 0;
48
- }
49
- try {
50
- while (true) {
51
- const next = await reader.read();
52
- if (next.done) {
53
- completed = true;
54
- break;
55
- }
56
- buffer += decoder.decode(next.value, { stream: true });
57
- const lines = buffer.split(/\r?\n/);
58
- buffer = lines.pop() ?? "";
59
- for (const line of lines) {
60
- const complete = parseLine(line);
61
- if (complete !== void 0) yield JSON.parse(complete);
62
- }
63
- }
64
- buffer += decoder.decode();
65
- if (buffer.length > 0) {
66
- const complete = parseLine(buffer);
67
- if (complete !== void 0) yield JSON.parse(complete);
68
- }
69
- if (data.length > 0) yield JSON.parse(data.join("\n"));
70
- } finally {
71
- if (!completed) await cancelReader(reader);
72
- reader.releaseLock();
73
- }
74
- }
75
- async function cancelReader(reader) {
76
- try {
77
- await reader.cancel();
78
- } catch {
79
- }
80
- }
81
-
82
- export {
83
- readJsonlStream,
84
- readSseStream
85
- };
86
- //# sourceMappingURL=chunk-63JX2QNP.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/transport/streams.ts"],"sourcesContent":["export async function* readJsonlStream<TEvent>(\n stream: ReadableStream<Uint8Array>,\n): AsyncIterable<TEvent> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let completed = false;\n\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) {\n completed = true;\n break;\n }\n buffer += decoder.decode(next.value, { stream: true });\n const lines = buffer.split(/\\r?\\n/);\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n const value = line.trim();\n if (value.length > 0) yield JSON.parse(value) as TEvent;\n }\n }\n buffer += decoder.decode();\n const value = buffer.trim();\n if (value.length > 0) yield JSON.parse(value) as TEvent;\n } finally {\n if (!completed) await cancelReader(reader);\n reader.releaseLock();\n }\n}\n\nexport async function* readSseStream<TEvent>(\n stream: ReadableStream<Uint8Array>,\n): AsyncIterable<TEvent> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let data: string[] = [];\n let completed = false;\n\n function parseLine(line: string): string | undefined {\n if (line === \"\") {\n const complete = data.length === 0 ? undefined : data.join(\"\\n\");\n data = [];\n return complete;\n }\n if (line.startsWith(\":\")) return undefined;\n const separator = line.indexOf(\":\");\n const field = separator === -1 ? line : line.slice(0, separator);\n const value = separator === -1 ? \"\" : line.slice(separator + 1).replace(/^ /, \"\");\n if (field === \"data\") data.push(value);\n return undefined;\n }\n\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) {\n completed = true;\n break;\n }\n buffer += decoder.decode(next.value, { stream: true });\n const lines = buffer.split(/\\r?\\n/);\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n const complete = parseLine(line);\n if (complete !== undefined) yield JSON.parse(complete) as TEvent;\n }\n }\n buffer += decoder.decode();\n if (buffer.length > 0) {\n const complete = parseLine(buffer);\n if (complete !== undefined) yield JSON.parse(complete) as TEvent;\n }\n if (data.length > 0) yield JSON.parse(data.join(\"\\n\")) as TEvent;\n } finally {\n if (!completed) await cancelReader(reader);\n reader.releaseLock();\n }\n}\n\nasync function cancelReader(reader: ReadableStreamDefaultReader<Uint8Array>): Promise<void> {\n try {\n await reader.cancel();\n } catch {\n // The request may already have been aborted by its owner.\n }\n}\n"],"mappings":";AAAA,gBAAuB,gBACrB,QACuB;AACvB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AACb,MAAI,YAAY;AAEhB,MAAI;AACF,WAAO,MAAM;AACX,YAAM,OAAO,MAAM,OAAO,KAAK;AAC/B,UAAI,KAAK,MAAM;AACb,oBAAY;AACZ;AAAA,MACF;AACA,gBAAU,QAAQ,OAAO,KAAK,OAAO,EAAE,QAAQ,KAAK,CAAC;AACrD,YAAM,QAAQ,OAAO,MAAM,OAAO;AAClC,eAAS,MAAM,IAAI,KAAK;AACxB,iBAAW,QAAQ,OAAO;AACxB,cAAMA,SAAQ,KAAK,KAAK;AACxB,YAAIA,OAAM,SAAS,EAAG,OAAM,KAAK,MAAMA,MAAK;AAAA,MAC9C;AAAA,IACF;AACA,cAAU,QAAQ,OAAO;AACzB,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,MAAM,SAAS,EAAG,OAAM,KAAK,MAAM,KAAK;AAAA,EAC9C,UAAE;AACA,QAAI,CAAC,UAAW,OAAM,aAAa,MAAM;AACzC,WAAO,YAAY;AAAA,EACrB;AACF;AAEA,gBAAuB,cACrB,QACuB;AACvB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AACb,MAAI,OAAiB,CAAC;AACtB,MAAI,YAAY;AAEhB,WAAS,UAAU,MAAkC;AACnD,QAAI,SAAS,IAAI;AACf,YAAM,WAAW,KAAK,WAAW,IAAI,SAAY,KAAK,KAAK,IAAI;AAC/D,aAAO,CAAC;AACR,aAAO;AAAA,IACT;AACA,QAAI,KAAK,WAAW,GAAG,EAAG,QAAO;AACjC,UAAM,YAAY,KAAK,QAAQ,GAAG;AAClC,UAAM,QAAQ,cAAc,KAAK,OAAO,KAAK,MAAM,GAAG,SAAS;AAC/D,UAAM,QAAQ,cAAc,KAAK,KAAK,KAAK,MAAM,YAAY,CAAC,EAAE,QAAQ,MAAM,EAAE;AAChF,QAAI,UAAU,OAAQ,MAAK,KAAK,KAAK;AACrC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,MAAM;AACX,YAAM,OAAO,MAAM,OAAO,KAAK;AAC/B,UAAI,KAAK,MAAM;AACb,oBAAY;AACZ;AAAA,MACF;AACA,gBAAU,QAAQ,OAAO,KAAK,OAAO,EAAE,QAAQ,KAAK,CAAC;AACrD,YAAM,QAAQ,OAAO,MAAM,OAAO;AAClC,eAAS,MAAM,IAAI,KAAK;AACxB,iBAAW,QAAQ,OAAO;AACxB,cAAM,WAAW,UAAU,IAAI;AAC/B,YAAI,aAAa,OAAW,OAAM,KAAK,MAAM,QAAQ;AAAA,MACvD;AAAA,IACF;AACA,cAAU,QAAQ,OAAO;AACzB,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,WAAW,UAAU,MAAM;AACjC,UAAI,aAAa,OAAW,OAAM,KAAK,MAAM,QAAQ;AAAA,IACvD;AACA,QAAI,KAAK,SAAS,EAAG,OAAM,KAAK,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,EACvD,UAAE;AACA,QAAI,CAAC,UAAW,OAAM,aAAa,MAAM;AACzC,WAAO,YAAY;AAAA,EACrB;AACF;AAEA,eAAe,aAAa,QAAgE;AAC1F,MAAI;AACF,UAAM,OAAO,OAAO;AAAA,EACtB,QAAQ;AAAA,EAER;AACF;","names":["value"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/transport/fetch.ts","../src/transport/event-transport.ts"],"sourcesContent":["import { readJsonlStream, readSseStream } from \"./streams\";\nimport type { EventStreamFormat } from \"./types\";\n\nexport type FetchEventStreamOptions = Omit<RequestInit, \"headers\"> & {\n input: string | URL | Request;\n format?: EventStreamFormat | \"auto\";\n fetch?: typeof fetch;\n headers?: HeadersInit;\n validateResponse?: (response: Response) => void;\n};\n\nexport class EventStreamHttpError extends Error {\n constructor(\n readonly response: Response,\n readonly body: string,\n ) {\n super(`Event stream request failed with status ${response.status}`);\n this.name = \"EventStreamHttpError\";\n }\n}\n\nexport async function* fetchEventStream<TEvent>(\n options: FetchEventStreamOptions,\n): AsyncIterable<TEvent> {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (fetchImpl === undefined) throw new Error(\"fetchEventStream requires a fetch implementation.\");\n\n const response = await fetchImpl(options.input, fetchOptions(options));\n if (!response.ok) throw new EventStreamHttpError(response, await response.text());\n options.validateResponse?.(response);\n if (response.body === null) throw new Error(\"Event stream response does not include a body.\");\n\n const format =\n options.format === undefined || options.format === \"auto\"\n ? inferEventStreamFormat(response.headers.get(\"content-type\"))\n : options.format;\n if (format === \"sse\") {\n yield* readSseStream<TEvent>(response.body);\n } else {\n yield* readJsonlStream<TEvent>(response.body);\n }\n}\n\nfunction fetchOptions(options: FetchEventStreamOptions): RequestInit {\n const {\n input: _input,\n format: _format,\n fetch: _fetch,\n validateResponse: _validate,\n ...init\n } = options;\n return init;\n}\n\nfunction inferEventStreamFormat(contentType: string | null): EventStreamFormat {\n return contentType?.toLowerCase().includes(\"text/event-stream\") ? \"sse\" : \"jsonl\";\n}\n","import { type FetchEventStreamOptions, fetchEventStream } from \"./fetch\";\nimport type { EventStreamFormat, EventTransport, EventTransportSendOptions } from \"./types\";\n\nexport type EventTransportContext<TRequest> = EventTransportSendOptions<TRequest>;\n\nexport type EventTransportBodyContext<TRequest> = Omit<\n EventTransportContext<TRequest>,\n \"headers\"\n> & {\n headers: Headers;\n};\n\nexport type CreateFetchEventTransportOptions<TRequest, TEvent> = {\n endpoint: string | URL | ((context: EventTransportContext<TRequest>) => string | URL);\n method?: string;\n format?: EventStreamFormat | \"auto\";\n fetch?: typeof fetch;\n headers?:\n | HeadersInit\n | ((context: EventTransportContext<TRequest>) => HeadersInit | Promise<HeadersInit>);\n body?: (\n context: EventTransportBodyContext<TRequest>,\n ) => BodyInit | null | undefined | Promise<BodyInit | null | undefined>;\n init?: Omit<RequestInit, \"body\" | \"headers\" | \"method\" | \"signal\">;\n mapEvent?: (event: unknown) => TEvent;\n validateResponse?: (response: Response) => void;\n};\n\nexport function createFetchEventTransport<TRequest, TEvent = unknown>(\n options: CreateFetchEventTransportOptions<TRequest, TEvent>,\n): EventTransport<TRequest, TEvent> {\n return {\n async *send(transportOptions) {\n const endpoint =\n typeof options.endpoint === \"function\"\n ? options.endpoint(transportOptions)\n : options.endpoint;\n const requestHeaders = await resolveHeaders(options.headers, transportOptions);\n const headers = mergeHeaders(requestHeaders, transportOptions.headers);\n const method = options.method ?? \"POST\";\n const body = await resolveBody(options.body, transportOptions, headers, method);\n const init: FetchEventStreamOptions = {\n ...options.init,\n input: endpoint,\n method,\n headers,\n format: options.format ?? \"auto\",\n };\n if (body !== undefined) init.body = body;\n if (transportOptions.abortSignal !== undefined) init.signal = transportOptions.abortSignal;\n if (options.fetch !== undefined) init.fetch = options.fetch;\n if (options.validateResponse !== undefined) init.validateResponse = options.validateResponse;\n\n for await (const event of fetchEventStream<unknown>(init)) {\n yield options.mapEvent === undefined ? (event as TEvent) : options.mapEvent(event);\n }\n },\n };\n}\n\nexport function createDirectEventTransport<TRequest, TEvent>(options: {\n handler(context: EventTransportContext<TRequest>): AsyncIterable<TEvent>;\n}): EventTransport<TRequest, TEvent> {\n return {\n async *send(context) {\n const iterator = options.handler(context)[Symbol.asyncIterator]();\n let closePromise: Promise<unknown> | undefined;\n const close = () => {\n closePromise ??= Promise.resolve(iterator.return?.());\n return closePromise;\n };\n const onAbort = () => {\n void close();\n };\n context.abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n try {\n while (!context.abortSignal?.aborted) {\n const next = await iterator.next();\n if (next.done) break;\n yield next.value;\n }\n } finally {\n context.abortSignal?.removeEventListener(\"abort\", onAbort);\n await close();\n }\n },\n };\n}\n\nasync function resolveHeaders<TRequest>(\n headers: CreateFetchEventTransportOptions<TRequest, unknown>[\"headers\"],\n context: EventTransportContext<TRequest>,\n): Promise<HeadersInit | undefined> {\n return typeof headers === \"function\" ? headers(context) : headers;\n}\n\nasync function resolveBody<TRequest>(\n body: CreateFetchEventTransportOptions<TRequest, unknown>[\"body\"],\n context: EventTransportContext<TRequest>,\n headers: Headers,\n method: string,\n): Promise<BodyInit | null | undefined> {\n if (body !== undefined) return body({ ...context, headers });\n if (method.toUpperCase() === \"GET\" || method.toUpperCase() === \"HEAD\") return undefined;\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n return JSON.stringify(context.request);\n}\n\nfunction mergeHeaders(...values: Array<HeadersInit | undefined>): Headers {\n const headers = new Headers();\n for (const value of values) {\n if (value === undefined) continue;\n new Headers(value).forEach((headerValue, key) => {\n headers.set(key, headerValue);\n });\n }\n return headers;\n}\n"],"mappings":"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","names":[]}
@@ -1,31 +0,0 @@
1
- type EventStreamFormat = "jsonl" | "sse";
2
- type EventTransportSendOptions<TRequest> = {
3
- request: TRequest;
4
- abortSignal?: AbortSignal;
5
- headers?: HeadersInit;
6
- };
7
- type EventTransport<TRequest, TEvent> = {
8
- send(options: EventTransportSendOptions<TRequest>): AsyncIterable<TEvent>;
9
- };
10
-
11
- type EventTransportContext<TRequest> = EventTransportSendOptions<TRequest>;
12
- type EventTransportBodyContext<TRequest> = Omit<EventTransportContext<TRequest>, "headers"> & {
13
- headers: Headers;
14
- };
15
- type CreateFetchEventTransportOptions<TRequest, TEvent> = {
16
- endpoint: string | URL | ((context: EventTransportContext<TRequest>) => string | URL);
17
- method?: string;
18
- format?: EventStreamFormat | "auto";
19
- fetch?: typeof fetch;
20
- headers?: HeadersInit | ((context: EventTransportContext<TRequest>) => HeadersInit | Promise<HeadersInit>);
21
- body?: (context: EventTransportBodyContext<TRequest>) => BodyInit | null | undefined | Promise<BodyInit | null | undefined>;
22
- init?: Omit<RequestInit, "body" | "headers" | "method" | "signal">;
23
- mapEvent?: (event: unknown) => TEvent;
24
- validateResponse?: (response: Response) => void;
25
- };
26
- declare function createFetchEventTransport<TRequest, TEvent = unknown>(options: CreateFetchEventTransportOptions<TRequest, TEvent>): EventTransport<TRequest, TEvent>;
27
- declare function createDirectEventTransport<TRequest, TEvent>(options: {
28
- handler(context: EventTransportContext<TRequest>): AsyncIterable<TEvent>;
29
- }): EventTransport<TRequest, TEvent>;
30
-
31
- export { type CreateFetchEventTransportOptions as C, type EventStreamFormat as E, type EventTransport as a, type EventTransportSendOptions as b, createDirectEventTransport as c, createFetchEventTransport as d };