@anvia/client 1.2.1 → 1.3.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
@@ -54,3 +54,22 @@ readers are also available from `@anvia/client/transport` for other event contra
54
54
  - [Client protocol guide](https://github.com/anvia-hq/anvia/blob/main/docs/packages/client.md)
55
55
  - [Server response helpers](https://github.com/anvia-hq/anvia/tree/main/packages/server#readme)
56
56
  - [React hooks](https://github.com/anvia-hq/anvia/tree/main/packages/react#readme)
57
+
58
+ ## Durable HTTP client
59
+
60
+ The optional `@anvia/client/durable` entrypoint exports `DurableClient` and
61
+ `DurableHttpError`. Install `@anvia/durable` to use it. It supports submit, list, snapshot,
62
+ SSE observation, approval responses, retry, cancellation, and tool reconciliation.
63
+
64
+ Construct it with an absolute `endpoint`, optional `fetch`, `credentials`, and static or
65
+ per-request `headers`. Restore UI state from `snapshot(runId)`, then observe
66
+ `stream(runId, { after: snapshot.cursor })`. Incoming records and event ordering are
67
+ validated. Reconnection is explicit; aborting observation does not cancel execution.
68
+ These committed progress events are separate from token-delta chat streams.
69
+
70
+ See the [durable HTTP guide](../../docs/packages/durable.md#http-server-and-client).
71
+
72
+ `DurableClient` also exposes `submitGraph`, `listGraphs`, `graphSnapshot`, `streamGraph`, and
73
+ `cancelGraph`. Graph snapshots contain renderable nodes/edges and explicit waiting reasons.
74
+ Use each node's `runId` with the existing response/retry/reconciliation methods. Graph streams
75
+ carry `graphId` and `taskId`; refresh the snapshot to obtain the latest graph-wide state.
@@ -0,0 +1,86 @@
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
@@ -0,0 +1 @@
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,83 +1,7 @@
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
- }
1
+ import {
2
+ readJsonlStream,
3
+ readSseStream
4
+ } from "./chunk-63JX2QNP.js";
81
5
 
82
6
  // src/transport/fetch.ts
83
7
  var EventStreamHttpError = class extends Error {
@@ -191,11 +115,9 @@ function mergeHeaders(...values) {
191
115
  }
192
116
 
193
117
  export {
194
- readJsonlStream,
195
- readSseStream,
196
118
  EventStreamHttpError,
197
119
  fetchEventStream,
198
120
  createFetchEventTransport,
199
121
  createDirectEventTransport
200
122
  };
201
- //# sourceMappingURL=chunk-2KGXQZWA.js.map
123
+ //# sourceMappingURL=chunk-HZZDET2H.js.map
@@ -0,0 +1 @@
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":[]}
@@ -0,0 +1,64 @@
1
+ import { TaskSubmission, TaskSnapshot, TaskGraphSnapshot, TaskListOptions, TaskPage, TaskEvent, DurableGraphSubmission, DurableGraphSnapshot, DurableGraphListOptions, DurableGraphPage, DurableGraphEvent, DurableSubmission, DurableSubmitOptions, DurableSnapshot, DurableListOptions, DurableRunPage, DurableEvent } from '@anvia/durable/protocol';
2
+ import { AgentInteractionResponse } from '@anvia/core/agent/interactions';
3
+ import { JsonValue, ToolResultOutput } from '@anvia/core/completion';
4
+
5
+ type DurableRequestOptions = {
6
+ abortSignal?: AbortSignal;
7
+ };
8
+ type DurableClientOptions = {
9
+ /** Absolute HTTP(S) URL matching the server handler's basePath. */
10
+ endpoint: string;
11
+ fetch?: typeof fetch;
12
+ headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
13
+ credentials?: RequestCredentials;
14
+ };
15
+ declare class DurableHttpError extends Error {
16
+ readonly status: number;
17
+ constructor(status: number);
18
+ }
19
+ /** Browser-safe HTTP client. Reconnect explicitly using a snapshot or last applied event cursor. */
20
+ declare class DurableClient {
21
+ private readonly options;
22
+ private readonly endpoint;
23
+ constructor(options: DurableClientOptions);
24
+ submitTask(submission: TaskSubmission, options?: DurableRequestOptions): Promise<TaskSnapshot>;
25
+ taskSnapshot(id: string, options?: DurableRequestOptions): Promise<TaskSnapshot>;
26
+ taskGraph(id: string, options?: DurableRequestOptions): Promise<TaskGraphSnapshot>;
27
+ listTasks(filter: TaskListOptions & {
28
+ sessionId: string;
29
+ }, options?: DurableRequestOptions): Promise<TaskPage>;
30
+ signalTask(id: string, name: string, requestId: string, value: JsonValue, options?: DurableRequestOptions): Promise<void>;
31
+ resolveEffect(id: string, key: string, value: JsonValue, options?: DurableRequestOptions): Promise<void>;
32
+ retryTask(id: string, options?: DurableRequestOptions): Promise<void>;
33
+ cancelTask(id: string, options?: DurableRequestOptions): Promise<void>;
34
+ streamTask(id: string, options?: DurableRequestOptions & {
35
+ after?: number;
36
+ }): AsyncIterable<TaskEvent>;
37
+ private taskPath;
38
+ submitGraph(submission: DurableGraphSubmission, options?: DurableRequestOptions): Promise<DurableGraphSnapshot>;
39
+ graphSnapshot(graphId: string, options?: DurableRequestOptions): Promise<DurableGraphSnapshot>;
40
+ listGraphs(filter: DurableGraphListOptions & {
41
+ sessionId: string;
42
+ }, options?: DurableRequestOptions): Promise<DurableGraphPage>;
43
+ cancelGraph(graphId: string, options?: DurableRequestOptions): Promise<void>;
44
+ streamGraph(graphId: string, options?: DurableRequestOptions & {
45
+ after?: number;
46
+ }): AsyncIterable<DurableGraphEvent>;
47
+ submit(submission: DurableSubmission, options?: DurableSubmitOptions & DurableRequestOptions): Promise<DurableSnapshot>;
48
+ listRuns(filter: DurableListOptions & {
49
+ sessionId: string;
50
+ }, options?: DurableRequestOptions): Promise<DurableRunPage>;
51
+ snapshot(runId: string, options?: DurableRequestOptions): Promise<DurableSnapshot>;
52
+ stream(runId: string, options?: DurableRequestOptions & {
53
+ after?: number;
54
+ }): AsyncIterable<DurableEvent>;
55
+ respond(runId: string, interactionId: string, response: AgentInteractionResponse, options?: DurableRequestOptions): Promise<void>;
56
+ resolveTool(runId: string, operationId: string, output: ToolResultOutput, options?: DurableRequestOptions): Promise<void>;
57
+ retry(runId: string, options?: DurableRequestOptions): Promise<void>;
58
+ cancel(runId: string, options?: DurableRequestOptions): Promise<void>;
59
+ private graphPath;
60
+ private path;
61
+ private request;
62
+ }
63
+
64
+ export { DurableClient, type DurableClientOptions, DurableHttpError, type DurableRequestOptions };
@@ -0,0 +1,242 @@
1
+ import {
2
+ readSseStream
3
+ } from "./chunk-63JX2QNP.js";
4
+
5
+ // src/durable.ts
6
+ import {
7
+ parseTaskSnapshot,
8
+ parseTaskGraph,
9
+ parseTaskPage,
10
+ parseTaskEvent
11
+ } from "@anvia/durable/protocol";
12
+ import {
13
+ parseDurableEvent,
14
+ parseDurableGraphSnapshot,
15
+ parseDurableGraphEvent,
16
+ parseDurableGraphPage,
17
+ parseDurableRunPage,
18
+ parseDurableSnapshot
19
+ } from "@anvia/durable/protocol";
20
+ var DurableHttpError = class extends Error {
21
+ constructor(status) {
22
+ super(`Durable request failed with HTTP ${status}.`);
23
+ this.status = status;
24
+ this.name = "DurableHttpError";
25
+ }
26
+ status;
27
+ };
28
+ var DurableClient = class {
29
+ constructor(options) {
30
+ this.options = options;
31
+ const endpoint = new URL(options.endpoint);
32
+ if (!["http:", "https:"].includes(endpoint.protocol) || endpoint.search || endpoint.hash || endpoint.username || endpoint.password)
33
+ throw new TypeError(
34
+ "endpoint must be an HTTP(S) base URL without credentials, query, or fragment."
35
+ );
36
+ this.endpoint = endpoint.href.replace(/\/$/, "");
37
+ }
38
+ options;
39
+ endpoint;
40
+ async submitTask(submission, options = {}) {
41
+ return parseTaskSnapshot(
42
+ await (await this.request("/tasks", "POST", submission, options)).json()
43
+ );
44
+ }
45
+ async taskSnapshot(id, options = {}) {
46
+ const snapshot = parseTaskSnapshot(
47
+ await (await this.request(this.taskPath(id), "GET", void 0, options)).json()
48
+ );
49
+ if (snapshot.task.id !== id) throw new TypeError("Snapshot belongs to another task.");
50
+ return snapshot;
51
+ }
52
+ async taskGraph(id, options = {}) {
53
+ const graph = parseTaskGraph(
54
+ await (await this.request(`${this.taskPath(id)}/graph`, "GET", void 0, options)).json()
55
+ );
56
+ if (!graph.nodes.some((task) => task.id === id))
57
+ throw new TypeError("Graph belongs to another task.");
58
+ return graph;
59
+ }
60
+ async listTasks(filter, options = {}) {
61
+ const query = new URLSearchParams();
62
+ for (const [key, value] of Object.entries(filter))
63
+ if (value !== void 0) query.set(key, String(value));
64
+ return parseTaskPage(
65
+ await (await this.request(`/tasks?${query}`, "GET", void 0, options)).json()
66
+ );
67
+ }
68
+ async signalTask(id, name, requestId, value, options = {}) {
69
+ await this.request(`${this.taskPath(id)}/signal`, "POST", { name, requestId, value }, options);
70
+ }
71
+ async resolveEffect(id, key, value, options = {}) {
72
+ await this.request(`${this.taskPath(id)}/resolve-effect`, "POST", { key, value }, options);
73
+ }
74
+ async retryTask(id, options = {}) {
75
+ await this.request(`${this.taskPath(id)}/retry`, "POST", void 0, options);
76
+ }
77
+ async cancelTask(id, options = {}) {
78
+ await this.request(`${this.taskPath(id)}/cancel`, "POST", void 0, options);
79
+ }
80
+ async *streamTask(id, options = {}) {
81
+ let cursor = options.after ?? 0;
82
+ if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError("Invalid task cursor.");
83
+ const snapshot = await this.taskSnapshot(id, options);
84
+ const response = await this.request(
85
+ `${this.taskPath(id)}/events?after=${cursor}`,
86
+ "GET",
87
+ void 0,
88
+ options
89
+ );
90
+ if (!response.headers.get("content-type")?.startsWith("text/event-stream") || response.body === null)
91
+ throw new TypeError("Expected a task SSE response.");
92
+ for await (const value of readSseStream(response.body)) {
93
+ options.abortSignal?.throwIfAborted();
94
+ const event = parseTaskEvent(value);
95
+ if (event.rootId !== snapshot.task.rootId || event.sequence <= cursor)
96
+ throw new TypeError("Invalid task event order or root ID.");
97
+ cursor = event.sequence;
98
+ yield event;
99
+ }
100
+ }
101
+ taskPath(id) {
102
+ if (id.trim().length === 0 || id === "." || id === "..") throw new TypeError("Invalid taskId.");
103
+ return `/tasks/${encodeURIComponent(id)}`;
104
+ }
105
+ async submitGraph(submission, options = {}) {
106
+ return parseDurableGraphSnapshot(
107
+ await (await this.request("/graphs", "POST", submission, options)).json()
108
+ );
109
+ }
110
+ async graphSnapshot(graphId, options = {}) {
111
+ const snapshot = parseDurableGraphSnapshot(
112
+ await (await this.request(this.graphPath(graphId), "GET", void 0, options)).json()
113
+ );
114
+ if (snapshot.id !== graphId) throw new TypeError("Snapshot belongs to another graph.");
115
+ return snapshot;
116
+ }
117
+ async listGraphs(filter, options = {}) {
118
+ const query = new URLSearchParams();
119
+ for (const [key, value] of Object.entries(filter))
120
+ if (value !== void 0) query.set(key, String(value));
121
+ return parseDurableGraphPage(
122
+ await (await this.request(`/graphs?${query}`, "GET", void 0, options)).json()
123
+ );
124
+ }
125
+ async cancelGraph(graphId, options = {}) {
126
+ await this.request(`${this.graphPath(graphId)}/cancel`, "POST", void 0, options);
127
+ }
128
+ async *streamGraph(graphId, options = {}) {
129
+ let cursor = options.after ?? 0;
130
+ if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError("Invalid graph cursor.");
131
+ const response = await this.request(
132
+ `${this.graphPath(graphId)}/events?after=${cursor}`,
133
+ "GET",
134
+ void 0,
135
+ options
136
+ );
137
+ if (!response.headers.get("content-type")?.startsWith("text/event-stream") || response.body === null)
138
+ throw new TypeError("Expected a graph SSE response.");
139
+ for await (const value of readSseStream(response.body)) {
140
+ options.abortSignal?.throwIfAborted();
141
+ const event = parseDurableGraphEvent(value);
142
+ if (event.graphId !== graphId || event.sequence <= cursor)
143
+ throw new TypeError("Invalid graph event order or ID.");
144
+ cursor = event.sequence;
145
+ yield event;
146
+ }
147
+ }
148
+ async submit(submission, options = {}) {
149
+ return parseDurableSnapshot(
150
+ await (await this.request(
151
+ "/runs",
152
+ "POST",
153
+ { ...submission, ...options.enqueue === void 0 ? {} : { enqueue: options.enqueue } },
154
+ options
155
+ )).json()
156
+ );
157
+ }
158
+ async listRuns(filter, options = {}) {
159
+ const query = new URLSearchParams();
160
+ for (const [key, value] of Object.entries(filter))
161
+ if (value !== void 0) query.set(key, String(value));
162
+ return parseDurableRunPage(
163
+ await (await this.request(`/runs?${query}`, "GET", void 0, options)).json()
164
+ );
165
+ }
166
+ async snapshot(runId, options = {}) {
167
+ const snapshot = parseDurableSnapshot(
168
+ await (await this.request(this.path(runId), "GET", void 0, options)).json()
169
+ );
170
+ if (snapshot.run.id !== runId) throw new TypeError("Durable snapshot belongs to another run.");
171
+ return snapshot;
172
+ }
173
+ async *stream(runId, options = {}) {
174
+ let cursor = options.after ?? 0;
175
+ if (!Number.isSafeInteger(cursor) || cursor < 0) throw new TypeError("Invalid event cursor.");
176
+ const response = await this.request(
177
+ `${this.path(runId)}/events?after=${cursor}`,
178
+ "GET",
179
+ void 0,
180
+ options
181
+ );
182
+ if (!response.headers.get("content-type")?.startsWith("text/event-stream") || response.body === null)
183
+ throw new TypeError("Expected a durable SSE response.");
184
+ for await (const value of readSseStream(response.body)) {
185
+ options.abortSignal?.throwIfAborted();
186
+ const event = parseDurableEvent(value);
187
+ if (event.runId !== runId || event.sequence <= cursor)
188
+ throw new TypeError("Invalid durable event order or run ID.");
189
+ cursor = event.sequence;
190
+ yield event;
191
+ }
192
+ }
193
+ async respond(runId, interactionId, response, options = {}) {
194
+ await this.request(`${this.path(runId)}/respond`, "POST", { interactionId, response }, options);
195
+ }
196
+ async resolveTool(runId, operationId, output, options = {}) {
197
+ await this.request(
198
+ `${this.path(runId)}/resolve-tool`,
199
+ "POST",
200
+ { operationId, output },
201
+ options
202
+ );
203
+ }
204
+ async retry(runId, options = {}) {
205
+ await this.request(`${this.path(runId)}/retry`, "POST", void 0, options);
206
+ }
207
+ async cancel(runId, options = {}) {
208
+ await this.request(`${this.path(runId)}/cancel`, "POST", void 0, options);
209
+ }
210
+ graphPath(id) {
211
+ if (id.trim().length === 0 || id === "." || id === "..")
212
+ throw new TypeError("Invalid graphId.");
213
+ return `/graphs/${encodeURIComponent(id)}`;
214
+ }
215
+ path(id) {
216
+ if (id.trim().length === 0) throw new TypeError("runId must not be empty.");
217
+ return `/runs/${encodeURIComponent(id)}`;
218
+ }
219
+ async request(path, method, body, options) {
220
+ options.abortSignal?.throwIfAborted();
221
+ const supplied = typeof this.options.headers === "function" ? await this.options.headers() : this.options.headers;
222
+ const headers = new Headers(supplied);
223
+ if (body !== void 0) headers.set("content-type", "application/json");
224
+ const response = await (this.options.fetch ?? globalThis.fetch)(`${this.endpoint}${path}`, {
225
+ method,
226
+ headers,
227
+ ...body === void 0 ? {} : { body: JSON.stringify(body) },
228
+ ...options.abortSignal === void 0 ? {} : { signal: options.abortSignal },
229
+ ...this.options.credentials === void 0 ? {} : { credentials: this.options.credentials }
230
+ });
231
+ if (!response.ok) {
232
+ await response.body?.cancel();
233
+ throw new DurableHttpError(response.status);
234
+ }
235
+ return response;
236
+ }
237
+ };
238
+ export {
239
+ DurableClient,
240
+ DurableHttpError
241
+ };
242
+ //# sourceMappingURL=durable.js.map
@@ -0,0 +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 { AgentInteractionResponse } from \"@anvia/core/agent/interactions\";\nimport type { JsonValue, ToolResultOutput } from \"@anvia/core/completion\";\nimport {\n parseDurableEvent,\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 submission: TaskSubmission,\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 submission: DurableSubmission,\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 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":[]}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  createFetchEventTransport
3
- } from "./chunk-2KGXQZWA.js";
3
+ } from "./chunk-HZZDET2H.js";
4
+ import "./chunk-63JX2QNP.js";
4
5
 
5
6
  // src/adapters.ts
6
7
  import {