@tanstack/ai-client 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/esm/byok/client.d.ts +52 -0
  2. package/dist/esm/byok/client.js +300 -0
  3. package/dist/esm/byok/client.js.map +1 -0
  4. package/dist/esm/byok/passkey.d.ts +43 -0
  5. package/dist/esm/byok/passkey.js +251 -0
  6. package/dist/esm/byok/passkey.js.map +1 -0
  7. package/dist/esm/byok/resolve.d.ts +8 -0
  8. package/dist/esm/byok/resolve.js +20 -0
  9. package/dist/esm/byok/resolve.js.map +1 -0
  10. package/dist/esm/byok/storage.d.ts +15 -0
  11. package/dist/esm/byok/storage.js +16 -0
  12. package/dist/esm/byok/storage.js.map +1 -0
  13. package/dist/esm/byok.d.ts +8 -0
  14. package/dist/esm/byok.js +5 -0
  15. package/dist/esm/chat-client.d.ts +16 -3
  16. package/dist/esm/chat-client.js +49 -31
  17. package/dist/esm/chat-client.js.map +1 -1
  18. package/dist/esm/connection-adapters.d.ts +2 -0
  19. package/dist/esm/connection-adapters.js +33 -9
  20. package/dist/esm/connection-adapters.js.map +1 -1
  21. package/dist/esm/generation-client.d.ts +3 -1
  22. package/dist/esm/generation-client.js +23 -4
  23. package/dist/esm/generation-client.js.map +1 -1
  24. package/dist/esm/generation-types.d.ts +14 -0
  25. package/dist/esm/generation-types.js.map +1 -1
  26. package/dist/esm/interrupt-manager.d.ts +1 -0
  27. package/dist/esm/interrupt-manager.js +15 -6
  28. package/dist/esm/interrupt-manager.js.map +1 -1
  29. package/dist/esm/sse-parser.js +8 -1
  30. package/dist/esm/sse-parser.js.map +1 -1
  31. package/dist/esm/types.d.ts +29 -3
  32. package/dist/esm/types.js.map +1 -1
  33. package/dist/esm/video-generation-client.d.ts +3 -1
  34. package/dist/esm/video-generation-client.js +25 -6
  35. package/dist/esm/video-generation-client.js.map +1 -1
  36. package/package.json +6 -2
  37. package/src/byok/client.ts +360 -0
  38. package/src/byok/passkey.ts +399 -0
  39. package/src/byok/resolve.ts +30 -0
  40. package/src/byok/storage.ts +29 -0
  41. package/src/byok.ts +20 -0
  42. package/src/chat-client.ts +95 -65
  43. package/src/connection-adapters.ts +41 -12
  44. package/src/generation-client.ts +48 -4
  45. package/src/generation-types.ts +16 -0
  46. package/src/interrupt-manager.ts +20 -6
  47. package/src/sse-parser.ts +10 -0
  48. package/src/types.ts +31 -3
  49. package/src/video-generation-client.ts +45 -4
@@ -94,6 +94,8 @@ export interface RunAgentInputContext {
94
94
  }>;
95
95
  /** Arbitrary user-controlled passthrough data. */
96
96
  forwardedProps?: Record<string, unknown>;
97
+ /** Extra request headers for this run (e.g. BYOK keys). POST only. */
98
+ headers?: Record<string, string>;
97
99
  }
98
100
  export interface ConnectConnectionAdapter {
99
101
  /**
@@ -1,6 +1,7 @@
1
1
  import { createResponseStreamTextDecoder, getResponseStreamReader } from "./response-stream.js";
2
2
  import { parseSseDataLine } from "./sse-utils.js";
3
3
  import { EventType, getChunkRunId, restoreInboundChunk, tanstackMetadata, uiMessagesToWire, withTanstackMetadata } from "@tanstack/ai/client";
4
+ import { ByokMissingError, isByokMissingBody } from "@tanstack/ai/byok";
4
5
  //#region src/connection-adapters.ts
5
6
  /**
6
7
  * Associates connect-wrapped chunks with the run they were produced under.
@@ -287,8 +288,25 @@ async function* linesToNdjsonEvents(lines) {
287
288
  else yield { chunk: restoreInboundUsage(parsed) };
288
289
  }
289
290
  }
290
- function assertResponseOk(response) {
291
- if (!response.ok) throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);
291
+ async function assertResponseOk(response) {
292
+ if (response.ok) return;
293
+ if (response.status === 401) {
294
+ const body = await response.clone().json().catch(() => null);
295
+ if (isByokMissingBody(body)) throw new ByokMissingError(body.error.provider);
296
+ }
297
+ throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);
298
+ }
299
+ function errorFromXhrStatus(xhr) {
300
+ if (xhr.status === 401) {
301
+ let parsed = null;
302
+ try {
303
+ parsed = JSON.parse(xhr.responseText);
304
+ } catch {
305
+ parsed = null;
306
+ }
307
+ if (isByokMissingBody(parsed)) return new ByokMissingError(parsed.error.provider);
308
+ }
309
+ return /* @__PURE__ */ new Error(`XHR error! status: ${xhr.status} ${xhr.statusText}`);
292
310
  }
293
311
  /**
294
312
  * GET the hydration endpoint for a thread and parse its JSON `{ messages,
@@ -306,7 +324,7 @@ async function fetchThreadHydration(fetchClient, url, headers, credentials, thre
306
324
  },
307
325
  credentials
308
326
  });
309
- assertResponseOk(response);
327
+ await assertResponseOk(response);
310
328
  const data = await response.json();
311
329
  const activeRun = data.activeRun && typeof data.activeRun.runId === "string" ? { runId: data.activeRun.runId } : null;
312
330
  const interrupts = data.interrupts && typeof data.interrupts.runId === "string" && Array.isArray(data.interrupts.pending) && data.interrupts.pending.length > 0 ? {
@@ -335,7 +353,7 @@ async function fetchGenerationHydration(fetchClient, url, headers, credentials,
335
353
  },
336
354
  credentials
337
355
  });
338
- assertResponseOk(response);
356
+ await assertResponseOk(response);
339
357
  const raw = await response.json();
340
358
  if (raw === null) return {
341
359
  resumeSnapshot: null,
@@ -351,12 +369,12 @@ async function fetchGenerationHydration(fetchClient, url, headers, credentials,
351
369
  }
352
370
  /** Yield SSE stream events (chunk + offset) from a fetch Response body. */
353
371
  async function* responseToSSEEvents(response, abortSignal, fallbackIds) {
354
- assertResponseOk(response);
372
+ await assertResponseOk(response);
355
373
  yield* linesToSSEEvents(readStreamLines(getResponseStreamReader(response), abortSignal), fallbackIds);
356
374
  }
357
375
  /** Yield NDJSON stream events (chunk + offset) from a fetch Response body. */
358
376
  async function* responseToNdjsonEvents(response, abortSignal) {
359
- assertResponseOk(response);
377
+ await assertResponseOk(response);
360
378
  yield* linesToNdjsonEvents(readStreamLines(getResponseStreamReader(response), abortSignal));
361
379
  }
362
380
  async function* responseToSSEChunks(response, abortSignal) {
@@ -588,6 +606,7 @@ function fetchServerSentEvents(url, options = {}) {
588
606
  const requestHeaders = {
589
607
  "Content-Type": "application/json",
590
608
  ...mergeHeaders(resolvedOptions.headers),
609
+ ...mergeHeaders(runContext?.headers),
591
610
  ...runIdHeader(runContext?.runId)
592
611
  };
593
612
  const requestBody = buildRunAgentInputBody(messages, data, runContext, resolvedOptions);
@@ -673,6 +692,7 @@ function fetchHttpStream(url, options = {}) {
673
692
  const requestHeaders = {
674
693
  "Content-Type": "application/json",
675
694
  ...mergeHeaders(resolvedOptions.headers),
695
+ ...mergeHeaders(runContext?.headers),
676
696
  ...runIdHeader(runContext?.runId)
677
697
  };
678
698
  const requestBody = buildRunAgentInputBody(messages, data, runContext, resolvedOptions);
@@ -739,7 +759,7 @@ function readXhrLines(xhr, abortSignal) {
739
759
  };
740
760
  const enqueueDelta = () => {
741
761
  if (xhr.status !== 0 && (xhr.status < 200 || xhr.status >= 300)) {
742
- error = /* @__PURE__ */ new Error(`XHR error! status: ${xhr.status} ${xhr.statusText}`);
762
+ error = errorFromXhrStatus(xhr);
743
763
  done = true;
744
764
  return;
745
765
  }
@@ -756,7 +776,7 @@ function readXhrLines(xhr, abortSignal) {
756
776
  };
757
777
  const finish = () => {
758
778
  enqueueDelta();
759
- if (xhr.status !== 0 && (xhr.status < 200 || xhr.status >= 300)) error = /* @__PURE__ */ new Error(`XHR error! status: ${xhr.status} ${xhr.statusText}`);
779
+ if (xhr.status !== 0 && (xhr.status < 200 || xhr.status >= 300)) error = errorFromXhrStatus(xhr);
760
780
  else if (buffer.trim() && !aborted) error = new StreamTruncatedError();
761
781
  done = true;
762
782
  wake();
@@ -813,6 +833,7 @@ function createConfiguredXhrRequest(url, options, messages, data, runContext, me
813
833
  const requestHeaders = {
814
834
  "Content-Type": "application/json",
815
835
  ...mergeHeaders(options.headers),
836
+ ...mergeHeaders(method === "POST" ? runContext?.headers : void 0),
816
837
  ...method === "POST" ? runIdHeader(runContext?.runId) : {},
817
838
  ...extraHeaders
818
839
  };
@@ -1211,7 +1232,10 @@ function fetcherToConnectionAdapter(fetcher) {
1211
1232
  runId: runContext.runId,
1212
1233
  ...runContext.parentRunId !== void 0 ? { parentRunId: runContext.parentRunId } : {},
1213
1234
  ...runContext.resume !== void 0 ? { resume: runContext.resume } : {}
1214
- }, { signal: abortSignal });
1235
+ }, {
1236
+ signal: abortSignal,
1237
+ headers: runContext.headers
1238
+ });
1215
1239
  if (result instanceof Response) yield* responseToSSEChunks(result, abortSignal);
1216
1240
  else yield* abortableIterable(result, abortSignal);
1217
1241
  } };