@ai-matrx/api 0.1.9 → 0.1.10

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 (135) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +1 -1
  3. package/dist/account.d.cts +1 -1
  4. package/dist/account.d.ts +1 -1
  5. package/dist/agents.cjs +12 -12
  6. package/dist/agents.d.cts +1 -1
  7. package/dist/agents.d.ts +1 -1
  8. package/dist/agents.js +2 -2
  9. package/dist/ai.cjs +3 -3
  10. package/dist/ai.d.cts +1 -1
  11. package/dist/ai.d.ts +1 -1
  12. package/dist/ai.js +2 -2
  13. package/dist/apps.cjs +6 -6
  14. package/dist/apps.d.cts +1 -1
  15. package/dist/apps.d.ts +1 -1
  16. package/dist/apps.js +2 -2
  17. package/dist/architecture.cjs +11 -11
  18. package/dist/architecture.d.cts +1 -1
  19. package/dist/architecture.d.ts +1 -1
  20. package/dist/architecture.js +2 -2
  21. package/dist/audio.cjs +5 -5
  22. package/dist/audio.d.cts +1 -1
  23. package/dist/audio.d.ts +1 -1
  24. package/dist/audio.js +2 -2
  25. package/dist/chat.cjs +12 -12
  26. package/dist/chat.d.cts +1 -1
  27. package/dist/chat.d.ts +1 -1
  28. package/dist/chat.js +2 -2
  29. package/dist/{chunk-PIVTHTVR.js → chunk-FLANGLCG.js} +260 -36
  30. package/dist/{chunk-KIEAFMKB.js → chunk-PIPE5OML.js} +100 -46
  31. package/dist/{chunk-2SXAAKGV.cjs → chunk-PKYPPATQ.cjs} +100 -45
  32. package/dist/{chunk-PMGKZ4FT.cjs → chunk-SPASYIUH.cjs} +268 -34
  33. package/dist/code.cjs +7 -7
  34. package/dist/code.d.cts +1 -1
  35. package/dist/code.d.ts +1 -1
  36. package/dist/code.js +2 -2
  37. package/dist/commerce.d.cts +1 -1
  38. package/dist/commerce.d.ts +1 -1
  39. package/dist/communications.cjs +5 -5
  40. package/dist/communications.d.cts +1 -1
  41. package/dist/communications.d.ts +1 -1
  42. package/dist/communications.js +2 -2
  43. package/dist/computer.cjs +4 -4
  44. package/dist/computer.d.cts +1 -1
  45. package/dist/computer.d.ts +1 -1
  46. package/dist/computer.js +2 -2
  47. package/dist/content.cjs +5 -5
  48. package/dist/content.d.cts +1 -1
  49. package/dist/content.d.ts +1 -1
  50. package/dist/content.js +2 -2
  51. package/dist/crm.cjs +3 -3
  52. package/dist/crm.d.cts +1 -1
  53. package/dist/crm.d.ts +1 -1
  54. package/dist/crm.js +2 -2
  55. package/dist/data.d.cts +1 -1
  56. package/dist/data.d.ts +1 -1
  57. package/dist/education.cjs +5 -5
  58. package/dist/education.d.cts +1 -1
  59. package/dist/education.d.ts +1 -1
  60. package/dist/education.js +2 -2
  61. package/dist/files.cjs +21 -21
  62. package/dist/files.d.cts +1 -1
  63. package/dist/files.d.ts +1 -1
  64. package/dist/files.js +2 -2
  65. package/dist/human-resources.d.cts +1 -1
  66. package/dist/human-resources.d.ts +1 -1
  67. package/dist/{index-C3ZlP3BI.d.cts → index-Gj30ybjE.d.cts} +42 -3
  68. package/dist/{index-C3ZlP3BI.d.ts → index-Gj30ybjE.d.ts} +42 -3
  69. package/dist/index.cjs +183 -288
  70. package/dist/index.d.cts +129 -180
  71. package/dist/index.d.ts +129 -180
  72. package/dist/index.js +76 -206
  73. package/dist/integrations.cjs +4 -4
  74. package/dist/integrations.d.cts +1 -1
  75. package/dist/integrations.d.ts +1 -1
  76. package/dist/integrations.js +2 -2
  77. package/dist/intelligence.cjs +10 -8
  78. package/dist/intelligence.d.cts +13 -13
  79. package/dist/intelligence.d.ts +13 -13
  80. package/dist/intelligence.js +5 -3
  81. package/dist/{keys.generated-CK_C5UXG.d.cts → keys.generated-DZUiM-uA.d.cts} +5 -3
  82. package/dist/{keys.generated-CK_C5UXG.d.ts → keys.generated-DZUiM-uA.d.ts} +5 -3
  83. package/dist/knowledge.cjs +43 -43
  84. package/dist/knowledge.d.cts +13 -13
  85. package/dist/knowledge.d.ts +13 -13
  86. package/dist/knowledge.js +2 -2
  87. package/dist/legal.cjs +7 -7
  88. package/dist/legal.d.cts +1 -1
  89. package/dist/legal.d.ts +1 -1
  90. package/dist/legal.js +2 -2
  91. package/dist/marketing.cjs +77 -77
  92. package/dist/marketing.d.cts +27 -27
  93. package/dist/marketing.d.ts +27 -27
  94. package/dist/marketing.js +2 -2
  95. package/dist/masterwork.cjs +33 -33
  96. package/dist/masterwork.d.cts +1 -1
  97. package/dist/masterwork.d.ts +1 -1
  98. package/dist/masterwork.js +2 -2
  99. package/dist/media.cjs +12 -12
  100. package/dist/media.d.cts +1 -1
  101. package/dist/media.d.ts +1 -1
  102. package/dist/media.js +2 -2
  103. package/dist/net.cjs +19 -20
  104. package/dist/net.d.cts +41 -41
  105. package/dist/net.d.ts +41 -41
  106. package/dist/net.js +1 -2
  107. package/dist/platform.cjs +4 -4
  108. package/dist/platform.d.cts +1 -1
  109. package/dist/platform.d.ts +1 -1
  110. package/dist/platform.js +2 -2
  111. package/dist/publish.cjs +8 -8
  112. package/dist/publish.d.cts +1 -1
  113. package/dist/publish.d.ts +1 -1
  114. package/dist/publish.js +2 -2
  115. package/dist/schemas.d.cts +78 -15
  116. package/dist/schemas.d.ts +78 -15
  117. package/dist/stream.cjs +11 -11
  118. package/dist/stream.d.cts +1 -1
  119. package/dist/stream.d.ts +1 -1
  120. package/dist/stream.js +2 -2
  121. package/dist/types.cjs +2 -0
  122. package/dist/types.d.cts +49823 -0
  123. package/dist/types.d.ts +49823 -0
  124. package/dist/types.js +1 -0
  125. package/dist/web.cjs +27 -27
  126. package/dist/web.d.cts +17 -17
  127. package/dist/web.d.ts +17 -17
  128. package/dist/web.js +2 -2
  129. package/dist/workflows.cjs +14 -14
  130. package/dist/workflows.d.cts +23 -26
  131. package/dist/workflows.d.ts +23 -26
  132. package/dist/workflows.js +2 -2
  133. package/package.json +14 -4
  134. package/dist/chunk-FNIYADWI.cjs +0 -59
  135. package/dist/chunk-YTEOFGFC.js +0 -57
@@ -1,6 +1,89 @@
1
- import { withRetry, isTransportFailure, resilientFetch } from './chunk-KIEAFMKB.js';
1
+ import { resilientFetch, isNetError, withRetry, isTransportFailure, AbortedError } from './chunk-PIPE5OML.js';
2
2
  import { isUuidShape } from '@ai-matrx/kit/uuid';
3
- import { toCredentialsPort, MATRX_HEADERS, credentialToHeaders } from '@ai-matrx/auth/credentials';
3
+ import { credentialToHeaders, toCredentialsPort, MATRX_HEADERS } from '@ai-matrx/auth/credentials';
4
+
5
+ // src/core/protocol.ts
6
+ var MATRX_AI_API_VERSION_DEFAULT = "v2";
7
+ var V2_COVERED_AI_PATH_TEMPLATES = [
8
+ "/ai/manual",
9
+ "/ai/chat",
10
+ "/ai/agents/{agent_id}",
11
+ "/ai/agent/{agent_id}",
12
+ // singular alias — behaves identically
13
+ "/ai/conversations/{conversation_id}",
14
+ "/ai/conversation/{conversation_id}",
15
+ // singular alias
16
+ "/ai/prompts/{prompt_id}",
17
+ // saved-prompt execution
18
+ "/ai/mandates/{mandate_key}"
19
+ // THE MANDATE DOOR — `/v2` sibling exists (routers/v2.py)
20
+ ];
21
+ function toV2Path(path) {
22
+ const withLead = path.startsWith("/") ? path : `/${path}`;
23
+ if (withLead.startsWith("/api/")) {
24
+ const rest = withLead.slice("/api".length);
25
+ return rest.startsWith("/v2/") ? withLead : `/api/v2${rest}`;
26
+ }
27
+ return withLead.startsWith("/v2/") ? withLead : `/v2${withLead}`;
28
+ }
29
+ var COVERED_INTERPOLATED_PATH = [
30
+ /^(?:\/api)?\/ai\/manual$/,
31
+ /^(?:\/api)?\/ai\/chat$/,
32
+ /^(?:\/api)?\/ai\/agents\/[^/]+$/,
33
+ /^(?:\/api)?\/ai\/agent\/[^/]+$/,
34
+ /^(?:\/api)?\/ai\/conversations\/[^/]+$/,
35
+ /^(?:\/api)?\/ai\/conversation\/[^/]+$/,
36
+ /^(?:\/api)?\/ai\/prompts\/[^/]+$/,
37
+ // `/warm` etc. deliberately don't match
38
+ /^(?:\/api)?\/ai\/mandates\/[^/]+$/
39
+ // the mandate door
40
+ ];
41
+ function isCoveredAiPath(path) {
42
+ return COVERED_INTERPOLATED_PATH.some((re) => re.test(path));
43
+ }
44
+ function isV2Path(pathOrUrl) {
45
+ return /\/v2\/ai\//.test(pathOrUrl);
46
+ }
47
+ function toV1FallbackUrl(url) {
48
+ return url.replace(/\/v2\/ai\//, "/ai/");
49
+ }
50
+ function applyAiApiVersion(path, version) {
51
+ if (version !== "v2") return path;
52
+ return isCoveredAiPath(path) ? toV2Path(path) : path;
53
+ }
54
+ async function fetchWithMatrxProtocolFallback(url, init, opts = {}) {
55
+ const { onDowngrade, ...fetchOpts } = opts;
56
+ const logDowngrade = (reason, status2) => {
57
+ console.warn(
58
+ `[matrx] ai_v2_downgrade \u2192 retrying on v1. v2=${url} reason=${reason}`
59
+ );
60
+ onDowngrade?.({ url, reason, ...status2 !== void 0 ? { status: status2 } : {} });
61
+ };
62
+ if (!isV2Path(url)) return resilientFetch(url, init, fetchOpts);
63
+ let result;
64
+ try {
65
+ result = await resilientFetch(url, init, fetchOpts);
66
+ } catch (err) {
67
+ const isAbort = isNetError(err) && err.code === "aborted" || err instanceof Error && err.name === "AbortError";
68
+ if (isAbort) throw err;
69
+ logDowngrade(String(err));
70
+ return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);
71
+ }
72
+ const status = result.response.status;
73
+ if (status === 404 || status === 405 || status >= 500) {
74
+ logDowngrade(`HTTP ${status}`, status);
75
+ return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);
76
+ }
77
+ return result;
78
+ }
79
+ function aiVersionPathOverrides(version) {
80
+ if (version !== "v2") return {};
81
+ const map = {};
82
+ for (const template of V2_COVERED_AI_PATH_TEMPLATES) {
83
+ map[template] = toV2Path(template);
84
+ }
85
+ return map;
86
+ }
4
87
 
5
88
  // src/core/backend-errors.ts
6
89
  var BackendApiError = class extends Error {
@@ -822,7 +905,167 @@ var DEPLOYMENTS = {
822
905
  }
823
906
  };
824
907
  var DOMAINS = ["account", "agents", "ai", "apps", "architecture", "audio", "chat", "code", "commerce", "communications", "computer", "content", "crm", "data", "education", "files", "human-resources", "integrations", "intelligence", "knowledge", "legal", "marketing", "masterwork", "media", "platform", "publish", "web", "workflows"];
908
+ var SESSION_READY_TIMEOUT_MS = 3e3;
825
909
  var DEFAULT_CONNECT_TIMEOUT_MS = 15e3;
910
+ function isBodyInit(body) {
911
+ return typeof body === "string" || typeof Blob !== "undefined" && body instanceof Blob || typeof FormData !== "undefined" && body instanceof FormData || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || body instanceof ArrayBuffer || ArrayBuffer.isView(body) || typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
912
+ }
913
+ async function waitForSessionReady(credentials, timeoutMs = SESSION_READY_TIMEOUT_MS) {
914
+ const ready = credentials?.ready;
915
+ if (!ready) return;
916
+ let timer;
917
+ try {
918
+ await Promise.race([
919
+ ready.call(credentials).catch(() => void 0),
920
+ new Promise((resolve) => {
921
+ timer = setTimeout(resolve, Math.max(0, timeoutMs));
922
+ })
923
+ ]);
924
+ } finally {
925
+ if (timer !== void 0) clearTimeout(timer);
926
+ }
927
+ }
928
+ function headerBag(headers) {
929
+ return { ...headers ?? {} };
930
+ }
931
+ function hasHeader(headers, name) {
932
+ const lower = name.toLowerCase();
933
+ return Object.keys(headers).some((key) => key.toLowerCase() === lower);
934
+ }
935
+ function encodeBody(method, body, headers) {
936
+ const upper = method.toUpperCase();
937
+ if (body === void 0 || upper === "GET" || upper === "HEAD") return void 0;
938
+ if (isBodyInit(body)) return body;
939
+ if (!hasHeader(headers, "content-type")) headers["Content-Type"] = "application/json";
940
+ return JSON.stringify(body);
941
+ }
942
+ function bodySize(body) {
943
+ if (body === void 0) return 0;
944
+ if (typeof body === "string") return new TextEncoder().encode(body).byteLength;
945
+ if (typeof Blob !== "undefined" && body instanceof Blob) return body.size;
946
+ if (body instanceof ArrayBuffer) return body.byteLength;
947
+ if (ArrayBuffer.isView(body)) return body.byteLength;
948
+ return 0;
949
+ }
950
+ function parseXhrHeaders(raw) {
951
+ const headers = new Headers();
952
+ for (const line of raw.trim().split(/[\r\n]+/)) {
953
+ const index = line.indexOf(":");
954
+ if (index <= 0) continue;
955
+ try {
956
+ headers.append(line.slice(0, index).trim(), line.slice(index + 1).trim());
957
+ } catch {
958
+ }
959
+ }
960
+ return headers;
961
+ }
962
+ function sendWithXhr(url, init, signal, totalTimeoutMs, onUploadProgress) {
963
+ const controller = new AbortController();
964
+ return new Promise((resolve, reject) => {
965
+ const xhr = new XMLHttpRequest();
966
+ xhr.open(init.method, url, true);
967
+ xhr.responseType = "arraybuffer";
968
+ for (const [name, value] of Object.entries(init.headers)) xhr.setRequestHeader(name, value);
969
+ if (totalTimeoutMs !== null && totalTimeoutMs > 0) xhr.timeout = totalTimeoutMs;
970
+ let lastLoaded = 0;
971
+ xhr.upload.onprogress = (event) => {
972
+ const loaded = Math.max(lastLoaded, event.loaded);
973
+ lastLoaded = loaded;
974
+ onUploadProgress({ loaded, total: event.lengthComputable ? event.total : 0 });
975
+ };
976
+ const onAbort = () => xhr.abort();
977
+ signal?.addEventListener("abort", onAbort, { once: true });
978
+ controller.signal.addEventListener("abort", onAbort, { once: true });
979
+ const cleanup = () => signal?.removeEventListener("abort", onAbort);
980
+ xhr.onload = () => {
981
+ cleanup();
982
+ const status = xhr.status === 0 ? 200 : xhr.status;
983
+ const nullBody = status === 204 || status === 205 || status === 304;
984
+ const response = new Response(nullBody ? null : xhr.response, {
985
+ status,
986
+ statusText: xhr.statusText,
987
+ headers: parseXhrHeaders(xhr.getAllResponseHeaders())
988
+ });
989
+ resolve({ response, controller });
990
+ };
991
+ xhr.onerror = () => {
992
+ cleanup();
993
+ reject(new TypeError(`Network failure uploading to ${url}`));
994
+ };
995
+ xhr.ontimeout = () => {
996
+ cleanup();
997
+ reject(new DOMException(`Upload to ${url} exceeded ${totalTimeoutMs}ms`, "TimeoutError"));
998
+ };
999
+ xhr.onabort = () => {
1000
+ cleanup();
1001
+ reject(new DOMException("The upload was cancelled.", "AbortError"));
1002
+ };
1003
+ if (signal?.aborted) {
1004
+ xhr.abort();
1005
+ return;
1006
+ }
1007
+ xhr.send(init.body ?? null);
1008
+ });
1009
+ }
1010
+ async function sendOnWire(request, auth = {}) {
1011
+ const method = request.method.toUpperCase();
1012
+ const headers = headerBag(request.headers);
1013
+ const body = encodeBody(method, request.body, headers);
1014
+ await waitForSessionReady(auth.credentials, auth.readyTimeoutMs);
1015
+ const credentialHeaders = auth.credentials ? credentialToHeaders(await auth.credentials.get()) : {};
1016
+ const attempt = (sendHeaders) => {
1017
+ if (request.signal?.aborted) return Promise.reject(new AbortedError(request.signal.reason));
1018
+ const merged = { ...sendHeaders };
1019
+ if (request.onUploadProgress && body !== void 0) {
1020
+ if (typeof XMLHttpRequest !== "undefined" && !(typeof ReadableStream !== "undefined" && body instanceof ReadableStream)) {
1021
+ return sendWithXhr(
1022
+ request.url,
1023
+ { method, headers: merged, body },
1024
+ request.signal,
1025
+ request.totalTimeoutMs ?? null,
1026
+ request.onUploadProgress
1027
+ );
1028
+ }
1029
+ }
1030
+ return fetchWithMatrxProtocolFallback(
1031
+ request.url,
1032
+ { method, headers: merged, ...body !== void 0 ? { body } : {} },
1033
+ {
1034
+ ...request.signal ? { signal: request.signal } : {},
1035
+ connectTimeoutMs: request.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,
1036
+ totalTimeoutMs: request.totalTimeoutMs !== void 0 ? request.totalTimeoutMs : null,
1037
+ throwOnHttpError: false,
1038
+ ...request.onProtocolDowngrade ? { onDowngrade: request.onProtocolDowngrade } : {}
1039
+ }
1040
+ ).then((result) => {
1041
+ if (request.onUploadProgress && body !== void 0) {
1042
+ const total = bodySize(body);
1043
+ request.onUploadProgress({ loaded: total, total });
1044
+ }
1045
+ return result;
1046
+ });
1047
+ };
1048
+ const over = Object.fromEntries(
1049
+ Object.entries(request.overHeaders ?? {}).filter(([name]) => name.toLowerCase() !== "content-type")
1050
+ );
1051
+ const firstHeaders = { ...headers, ...credentialHeaders, ...over };
1052
+ const idempotent = method === "GET" || method === "HEAD";
1053
+ const attempts = Math.max(1, request.retryAttempts ?? 1);
1054
+ const first = idempotent && attempts > 1 && !request.stream ? await withRetry(() => attempt(firstHeaders), {
1055
+ attempts,
1056
+ retryOn: isTransportFailure,
1057
+ ...request.signal ? { signal: request.signal } : {}
1058
+ }) : await attempt(firstHeaders);
1059
+ if (first.response.status !== 401 || !auth.refreshCredentials) return first;
1060
+ if (!await auth.refreshCredentials()) return first;
1061
+ await first.response.body?.cancel().catch(() => void 0);
1062
+ const retryHeaders = { ...headers };
1063
+ Object.assign(retryHeaders, auth.credentials ? credentialToHeaders(await auth.credentials.get()) : {}, over);
1064
+ return attempt(retryHeaders);
1065
+ }
1066
+
1067
+ // src/api.ts
1068
+ var DEFAULT_CONNECT_TIMEOUT_MS2 = 15e3;
826
1069
  function defaultRequestId() {
827
1070
  const c = globalThis.crypto;
828
1071
  if (c?.randomUUID) return c.randomUUID();
@@ -851,9 +1094,6 @@ function queryString(query) {
851
1094
  }
852
1095
  return parts.length ? `?${parts.join("&")}` : "";
853
1096
  }
854
- function isBodyInit(body) {
855
- return typeof body === "string" || typeof Blob !== "undefined" && body instanceof Blob || typeof FormData !== "undefined" && body instanceof FormData || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || body instanceof ArrayBuffer || ArrayBuffer.isView(body) || typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
856
- }
857
1097
  function acceptFor(stream) {
858
1098
  switch (stream) {
859
1099
  case "ndjson":
@@ -919,43 +1159,27 @@ function createApi(options = {}) {
919
1159
  Accept: acceptFor(op.s),
920
1160
  [MATRX_HEADERS.requestId]: requestId
921
1161
  };
922
- let body;
923
- if (args?.body !== void 0 && op.m !== "GET" && op.m !== "HEAD") {
924
- if (isBodyInit(args.body)) {
925
- body = args.body;
926
- } else {
927
- body = JSON.stringify(args.body);
928
- headers["Content-Type"] = "application/json";
929
- }
930
- }
931
- const credentialHeaders = credentialToHeaders(await credentials.get());
932
- Object.assign(headers, credentialHeaders);
933
1162
  if (orgId !== null) headers[MATRX_HEADERS.organization] = orgId;
934
1163
  options.onRequest?.({ operation: op.n, method: op.m, url, requestId, deployment: op.d });
935
- const attempt = (sendHeaders = headers) => resilientFetch(
936
- url,
937
- { method: op.m, headers: sendHeaders, ...body !== void 0 ? { body } : {} },
1164
+ const { response, controller } = await sendOnWire(
938
1165
  {
1166
+ url,
1167
+ method: op.m,
1168
+ headers,
1169
+ body: args?.body,
939
1170
  ...call?.signal ? { signal: call.signal } : {},
940
- connectTimeoutMs: call?.connectTimeoutMs ?? options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,
1171
+ connectTimeoutMs: call?.connectTimeoutMs ?? options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS2,
941
1172
  totalTimeoutMs: call?.totalTimeoutMs !== void 0 ? call.totalTimeoutMs : options.totalTimeoutMs ?? null,
942
- throwOnHttpError: false
1173
+ stream: Boolean(op.s),
1174
+ retryAttempts,
1175
+ ...call?.onUploadProgress ? { onUploadProgress: call.onUploadProgress } : {}
1176
+ },
1177
+ {
1178
+ credentials,
1179
+ ...options.readyTimeoutMs !== void 0 ? { readyTimeoutMs: options.readyTimeoutMs } : {},
1180
+ ...options.refreshCredentials ? { refreshCredentials: options.refreshCredentials } : {}
943
1181
  }
944
1182
  );
945
- const idempotent = op.m === "GET" || op.m === "HEAD";
946
- const { response, controller } = idempotent && retryAttempts > 1 && !op.s ? await withRetry(() => attempt(), {
947
- attempts: retryAttempts,
948
- retryOn: isTransportFailure,
949
- ...call?.signal ? { signal: call.signal } : {}
950
- }) : await attempt();
951
- if (response.status === 401 && options.refreshCredentials && await options.refreshCredentials()) {
952
- const retryHeaders = { ...headers };
953
- for (const name of Object.keys(credentialHeaders)) delete retryHeaders[name];
954
- Object.assign(retryHeaders, credentialToHeaders(await credentials.get()));
955
- const retried = await attempt(retryHeaders);
956
- if (!retried.response.ok) throw await errorFrom(retried.response, interpolate(op.p, args?.path));
957
- return { response: retried.response, requestId, controller: retried.controller };
958
- }
959
1183
  if (!response.ok) throw await errorFrom(response, interpolate(op.p, args?.path));
960
1184
  return { response, requestId, controller };
961
1185
  };
@@ -1022,4 +1246,4 @@ async function openJsonOrStream(api, op, args, options) {
1022
1246
  return { kind: "stream", stream: toStream(op, response, requestId, controller) };
1023
1247
  }
1024
1248
 
1025
- export { BackendApiError, CONTRACT_SHA256, DEFAULT_MATRX_NDJSON_READ_AHEAD, DEPLOYMENTS, DOMAINS, MatrxApiError, OrganizationContextError, StreamTransportError, applyOrganizationContextHeader, assertOrganizationMatchesOperation, assertQueryOrganizationMatchesContext, createApi, createMatrxNdjsonFramer, createMatrxSseFramer, createOrganizationOperation, describeBackendFailure, extractMatrxErrorCode, extractMatrxErrorMessage, getUserMessage, isGenericUserMessage, isStreamTransportLost, normalizeMatrxStreamEnvelope, openJsonOrStream, openStream, parseCallApiError, parseHttpError, parseHttpErrorBody, parseMatrxSseFrame, parsePersistedBackendError, parseStreamError, readMatrxNdjsonStream, readMatrxSseStream, requireOrganizationContext, unwrapUpstreamError };
1249
+ export { BackendApiError, CONTRACT_SHA256, DEFAULT_MATRX_NDJSON_READ_AHEAD, DEPLOYMENTS, DOMAINS, MATRX_AI_API_VERSION_DEFAULT, MatrxApiError, OrganizationContextError, StreamTransportError, V2_COVERED_AI_PATH_TEMPLATES, aiVersionPathOverrides, applyAiApiVersion, applyOrganizationContextHeader, assertOrganizationMatchesOperation, assertQueryOrganizationMatchesContext, createApi, createMatrxNdjsonFramer, createMatrxSseFramer, createOrganizationOperation, describeBackendFailure, extractMatrxErrorCode, extractMatrxErrorMessage, fetchWithMatrxProtocolFallback, getUserMessage, isCoveredAiPath, isGenericUserMessage, isStreamTransportLost, isV2Path, normalizeMatrxStreamEnvelope, openJsonOrStream, openStream, parseCallApiError, parseHttpError, parseHttpErrorBody, parseMatrxSseFrame, parsePersistedBackendError, parseStreamError, readMatrxNdjsonStream, readMatrxSseStream, requireOrganizationContext, sendOnWire, toV1FallbackUrl, toV2Path, unwrapUpstreamError };
@@ -141,6 +141,58 @@ function toNetError(err) {
141
141
  );
142
142
  }
143
143
 
144
+ // src/net/retry.ts
145
+ function defaultRetryOn(err) {
146
+ return isNetError(err) && err.retryable;
147
+ }
148
+ function sleep(ms, signal) {
149
+ return new Promise((resolve, reject) => {
150
+ const timer = setTimeout(() => {
151
+ resolve();
152
+ if (signal) signal.removeEventListener("abort", onAbort);
153
+ }, ms);
154
+ const onAbort = () => {
155
+ clearTimeout(timer);
156
+ reject(signal?.reason ?? new Error("Aborted"));
157
+ };
158
+ if (signal) {
159
+ if (signal.aborted) {
160
+ clearTimeout(timer);
161
+ reject(signal.reason);
162
+ } else {
163
+ signal.addEventListener("abort", onAbort, { once: true });
164
+ }
165
+ }
166
+ });
167
+ }
168
+ async function withRetry(fn, opts = {}) {
169
+ const attempts = Math.max(1, opts.attempts ?? 3);
170
+ const initialDelayMs = opts.initialDelayMs ?? 250;
171
+ const maxDelayMs = opts.maxDelayMs ?? 4e3;
172
+ const factor = opts.backoffFactor ?? 2;
173
+ const jitter = Math.max(0, Math.min(1, opts.jitter ?? 0.25));
174
+ const retryOn = opts.retryOn ?? defaultRetryOn;
175
+ let lastErr;
176
+ for (let attempt = 1; attempt <= attempts; attempt++) {
177
+ if (opts.signal?.aborted) throw opts.signal.reason;
178
+ try {
179
+ return await fn(attempt);
180
+ } catch (err) {
181
+ lastErr = err;
182
+ if (attempt === attempts || !retryOn(err)) throw err;
183
+ const base = Math.min(
184
+ maxDelayMs,
185
+ initialDelayMs * Math.pow(factor, attempt - 1)
186
+ );
187
+ const jitterAmount = base * jitter * (Math.random() * 2 - 1);
188
+ const delayMs = Math.max(0, Math.round(base + jitterAmount));
189
+ opts.onRetry?.(attempt, err, delayMs);
190
+ await sleep(delayMs, opts.signal);
191
+ }
192
+ }
193
+ throw lastErr;
194
+ }
195
+
144
196
  // src/net/resilient-fetch.ts
145
197
  var DEFAULTS = {
146
198
  connectTimeoutMs: 15e3,
@@ -209,56 +261,58 @@ async function resilientFetch(url, init = {}, opts = {}) {
209
261
  }
210
262
  }
211
263
 
212
- // src/net/retry.ts
213
- function defaultRetryOn(err) {
214
- return isNetError(err) && err.retryable;
215
- }
216
- function sleep(ms, signal) {
217
- return new Promise((resolve, reject) => {
218
- const timer = setTimeout(() => {
219
- resolve();
220
- if (signal) signal.removeEventListener("abort", onAbort);
221
- }, ms);
222
- const onAbort = () => {
223
- clearTimeout(timer);
224
- reject(signal?.reason ?? new Error("Aborted"));
225
- };
226
- if (signal) {
227
- if (signal.aborted) {
228
- clearTimeout(timer);
229
- reject(signal.reason);
230
- } else {
231
- signal.addEventListener("abort", onAbort, { once: true });
232
- }
264
+ // src/net/stream-monitor.ts
265
+ var DEFAULTS2 = {
266
+ heartbeatTimeoutMs: 3e4,
267
+ maxLifetimeMs: 6e5
268
+ };
269
+ async function* monitorStream(source, opts = {}) {
270
+ const heartbeatTimeoutMs = opts.heartbeatTimeoutMs ?? DEFAULTS2.heartbeatTimeoutMs;
271
+ const maxLifetimeMs = opts.maxLifetimeMs ?? DEFAULTS2.maxLifetimeMs;
272
+ const abort = opts.abortController;
273
+ const startedAt = Date.now();
274
+ const iter = source[Symbol.asyncIterator]();
275
+ while (true) {
276
+ const elapsed = Date.now() - startedAt;
277
+ const remainingLifetime = maxLifetimeMs - elapsed;
278
+ if (remainingLifetime <= 0) {
279
+ abort?.abort("total-timeout");
280
+ throw new TotalTimeoutError(maxLifetimeMs);
233
281
  }
234
- });
235
- }
236
- async function withRetry(fn, opts = {}) {
237
- const attempts = Math.max(1, opts.attempts ?? 3);
238
- const initialDelayMs = opts.initialDelayMs ?? 250;
239
- const maxDelayMs = opts.maxDelayMs ?? 4e3;
240
- const factor = opts.backoffFactor ?? 2;
241
- const jitter = Math.max(0, Math.min(1, opts.jitter ?? 0.25));
242
- const retryOn = opts.retryOn ?? defaultRetryOn;
243
- let lastErr;
244
- for (let attempt = 1; attempt <= attempts; attempt++) {
245
- if (opts.signal?.aborted) throw opts.signal.reason;
282
+ const deadline = Math.min(heartbeatTimeoutMs, remainingLifetime);
283
+ let timer = null;
284
+ let timedOutKind = null;
285
+ const timeoutPromise = new Promise((_, reject) => {
286
+ timer = setTimeout(() => {
287
+ timedOutKind = deadline === remainingLifetime ? "total" : "heartbeat";
288
+ abort?.abort(
289
+ timedOutKind === "total" ? "total-timeout" : "heartbeat-timeout"
290
+ );
291
+ reject(
292
+ timedOutKind === "total" ? new TotalTimeoutError(maxLifetimeMs) : new HeartbeatTimeoutError(heartbeatTimeoutMs)
293
+ );
294
+ }, deadline);
295
+ });
296
+ let result;
246
297
  try {
247
- return await fn(attempt);
298
+ result = await Promise.race([iter.next(), timeoutPromise]);
248
299
  } catch (err) {
249
- lastErr = err;
250
- if (attempt === attempts || !retryOn(err)) throw err;
251
- const base = Math.min(
252
- maxDelayMs,
253
- initialDelayMs * Math.pow(factor, attempt - 1)
254
- );
255
- const jitterAmount = base * jitter * (Math.random() * 2 - 1);
256
- const delayMs = Math.max(0, Math.round(base + jitterAmount));
257
- opts.onRetry?.(attempt, err, delayMs);
258
- await sleep(delayMs, opts.signal);
300
+ if (timer !== null) clearTimeout(timer);
301
+ try {
302
+ const cleanup = iter.return?.(void 0);
303
+ if (cleanup) {
304
+ void Promise.resolve(cleanup).catch(() => {
305
+ });
306
+ }
307
+ } catch {
308
+ }
309
+ throw err;
259
310
  }
311
+ if (timer !== null) clearTimeout(timer);
312
+ if (result.done) return;
313
+ opts.onHeartbeat?.(Date.now());
314
+ yield result.value;
260
315
  }
261
- throw lastErr;
262
316
  }
263
317
 
264
- export { AbortedError, ConnectTimeoutError, HeartbeatTimeoutError, HttpError, NetError, NetworkError, OfflineError, TotalTimeoutError, extractErrorMessage, isNetError, isTransportFailure, resilientFetch, toNetError, withRetry };
318
+ export { AbortedError, ConnectTimeoutError, HeartbeatTimeoutError, HttpError, NetError, NetworkError, OfflineError, TotalTimeoutError, extractErrorMessage, isNetError, isTransportFailure, monitorStream, resilientFetch, toNetError, withRetry };
@@ -143,6 +143,58 @@ function toNetError(err) {
143
143
  );
144
144
  }
145
145
 
146
+ // src/net/retry.ts
147
+ function defaultRetryOn(err) {
148
+ return isNetError(err) && err.retryable;
149
+ }
150
+ function sleep(ms, signal) {
151
+ return new Promise((resolve, reject) => {
152
+ const timer = setTimeout(() => {
153
+ resolve();
154
+ if (signal) signal.removeEventListener("abort", onAbort);
155
+ }, ms);
156
+ const onAbort = () => {
157
+ clearTimeout(timer);
158
+ reject(signal?.reason ?? new Error("Aborted"));
159
+ };
160
+ if (signal) {
161
+ if (signal.aborted) {
162
+ clearTimeout(timer);
163
+ reject(signal.reason);
164
+ } else {
165
+ signal.addEventListener("abort", onAbort, { once: true });
166
+ }
167
+ }
168
+ });
169
+ }
170
+ async function withRetry(fn, opts = {}) {
171
+ const attempts = Math.max(1, opts.attempts ?? 3);
172
+ const initialDelayMs = opts.initialDelayMs ?? 250;
173
+ const maxDelayMs = opts.maxDelayMs ?? 4e3;
174
+ const factor = opts.backoffFactor ?? 2;
175
+ const jitter = Math.max(0, Math.min(1, opts.jitter ?? 0.25));
176
+ const retryOn = opts.retryOn ?? defaultRetryOn;
177
+ let lastErr;
178
+ for (let attempt = 1; attempt <= attempts; attempt++) {
179
+ if (opts.signal?.aborted) throw opts.signal.reason;
180
+ try {
181
+ return await fn(attempt);
182
+ } catch (err) {
183
+ lastErr = err;
184
+ if (attempt === attempts || !retryOn(err)) throw err;
185
+ const base = Math.min(
186
+ maxDelayMs,
187
+ initialDelayMs * Math.pow(factor, attempt - 1)
188
+ );
189
+ const jitterAmount = base * jitter * (Math.random() * 2 - 1);
190
+ const delayMs = Math.max(0, Math.round(base + jitterAmount));
191
+ opts.onRetry?.(attempt, err, delayMs);
192
+ await sleep(delayMs, opts.signal);
193
+ }
194
+ }
195
+ throw lastErr;
196
+ }
197
+
146
198
  // src/net/resilient-fetch.ts
147
199
  var DEFAULTS = {
148
200
  connectTimeoutMs: 15e3,
@@ -211,56 +263,58 @@ async function resilientFetch(url, init = {}, opts = {}) {
211
263
  }
212
264
  }
213
265
 
214
- // src/net/retry.ts
215
- function defaultRetryOn(err) {
216
- return isNetError(err) && err.retryable;
217
- }
218
- function sleep(ms, signal) {
219
- return new Promise((resolve, reject) => {
220
- const timer = setTimeout(() => {
221
- resolve();
222
- if (signal) signal.removeEventListener("abort", onAbort);
223
- }, ms);
224
- const onAbort = () => {
225
- clearTimeout(timer);
226
- reject(signal?.reason ?? new Error("Aborted"));
227
- };
228
- if (signal) {
229
- if (signal.aborted) {
230
- clearTimeout(timer);
231
- reject(signal.reason);
232
- } else {
233
- signal.addEventListener("abort", onAbort, { once: true });
234
- }
266
+ // src/net/stream-monitor.ts
267
+ var DEFAULTS2 = {
268
+ heartbeatTimeoutMs: 3e4,
269
+ maxLifetimeMs: 6e5
270
+ };
271
+ async function* monitorStream(source, opts = {}) {
272
+ const heartbeatTimeoutMs = opts.heartbeatTimeoutMs ?? DEFAULTS2.heartbeatTimeoutMs;
273
+ const maxLifetimeMs = opts.maxLifetimeMs ?? DEFAULTS2.maxLifetimeMs;
274
+ const abort = opts.abortController;
275
+ const startedAt = Date.now();
276
+ const iter = source[Symbol.asyncIterator]();
277
+ while (true) {
278
+ const elapsed = Date.now() - startedAt;
279
+ const remainingLifetime = maxLifetimeMs - elapsed;
280
+ if (remainingLifetime <= 0) {
281
+ abort?.abort("total-timeout");
282
+ throw new TotalTimeoutError(maxLifetimeMs);
235
283
  }
236
- });
237
- }
238
- async function withRetry(fn, opts = {}) {
239
- const attempts = Math.max(1, opts.attempts ?? 3);
240
- const initialDelayMs = opts.initialDelayMs ?? 250;
241
- const maxDelayMs = opts.maxDelayMs ?? 4e3;
242
- const factor = opts.backoffFactor ?? 2;
243
- const jitter = Math.max(0, Math.min(1, opts.jitter ?? 0.25));
244
- const retryOn = opts.retryOn ?? defaultRetryOn;
245
- let lastErr;
246
- for (let attempt = 1; attempt <= attempts; attempt++) {
247
- if (opts.signal?.aborted) throw opts.signal.reason;
284
+ const deadline = Math.min(heartbeatTimeoutMs, remainingLifetime);
285
+ let timer = null;
286
+ let timedOutKind = null;
287
+ const timeoutPromise = new Promise((_, reject) => {
288
+ timer = setTimeout(() => {
289
+ timedOutKind = deadline === remainingLifetime ? "total" : "heartbeat";
290
+ abort?.abort(
291
+ timedOutKind === "total" ? "total-timeout" : "heartbeat-timeout"
292
+ );
293
+ reject(
294
+ timedOutKind === "total" ? new TotalTimeoutError(maxLifetimeMs) : new HeartbeatTimeoutError(heartbeatTimeoutMs)
295
+ );
296
+ }, deadline);
297
+ });
298
+ let result;
248
299
  try {
249
- return await fn(attempt);
300
+ result = await Promise.race([iter.next(), timeoutPromise]);
250
301
  } catch (err) {
251
- lastErr = err;
252
- if (attempt === attempts || !retryOn(err)) throw err;
253
- const base = Math.min(
254
- maxDelayMs,
255
- initialDelayMs * Math.pow(factor, attempt - 1)
256
- );
257
- const jitterAmount = base * jitter * (Math.random() * 2 - 1);
258
- const delayMs = Math.max(0, Math.round(base + jitterAmount));
259
- opts.onRetry?.(attempt, err, delayMs);
260
- await sleep(delayMs, opts.signal);
302
+ if (timer !== null) clearTimeout(timer);
303
+ try {
304
+ const cleanup = iter.return?.(void 0);
305
+ if (cleanup) {
306
+ void Promise.resolve(cleanup).catch(() => {
307
+ });
308
+ }
309
+ } catch {
310
+ }
311
+ throw err;
261
312
  }
313
+ if (timer !== null) clearTimeout(timer);
314
+ if (result.done) return;
315
+ opts.onHeartbeat?.(Date.now());
316
+ yield result.value;
262
317
  }
263
- throw lastErr;
264
318
  }
265
319
 
266
320
  exports.AbortedError = AbortedError;
@@ -274,6 +328,7 @@ exports.TotalTimeoutError = TotalTimeoutError;
274
328
  exports.extractErrorMessage = extractErrorMessage;
275
329
  exports.isNetError = isNetError;
276
330
  exports.isTransportFailure = isTransportFailure;
331
+ exports.monitorStream = monitorStream;
277
332
  exports.resilientFetch = resilientFetch;
278
333
  exports.toNetError = toNetError;
279
334
  exports.withRetry = withRetry;