@credal/sdk 0.1.9 → 0.1.11

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 (105) hide show
  1. package/dist/cjs/BaseClient.d.ts +4 -0
  2. package/dist/cjs/Client.js +3 -3
  3. package/dist/cjs/api/resources/copilots/client/Client.js +27 -9
  4. package/dist/cjs/api/resources/documentCatalog/client/Client.d.ts +8 -0
  5. package/dist/cjs/api/resources/documentCatalog/client/Client.js +95 -3
  6. package/dist/cjs/api/resources/documentCatalog/client/requests/UploadFileRequest.d.ts +27 -0
  7. package/dist/cjs/api/resources/documentCatalog/client/requests/UploadFileRequest.js +3 -0
  8. package/dist/cjs/api/resources/documentCatalog/client/requests/index.d.ts +1 -0
  9. package/dist/cjs/api/resources/documentCollections/client/Client.js +21 -7
  10. package/dist/cjs/api/resources/search/client/Client.js +3 -1
  11. package/dist/cjs/api/resources/users/client/Client.js +3 -1
  12. package/dist/cjs/core/exports.d.ts +2 -0
  13. package/dist/cjs/core/exports.js +18 -0
  14. package/dist/cjs/core/fetcher/Fetcher.d.ts +4 -1
  15. package/dist/cjs/core/fetcher/Fetcher.js +202 -9
  16. package/dist/cjs/core/fetcher/getRequestBody.d.ts +1 -1
  17. package/dist/cjs/core/fetcher/getRequestBody.js +4 -0
  18. package/dist/cjs/core/fetcher/makeRequest.d.ts +1 -1
  19. package/dist/cjs/core/fetcher/makeRequest.js +0 -2
  20. package/dist/cjs/core/fetcher/requestWithRetries.js +0 -9
  21. package/dist/cjs/core/fetcher/signals.d.ts +0 -6
  22. package/dist/cjs/core/fetcher/signals.js +0 -12
  23. package/dist/cjs/core/file/exports.d.ts +1 -0
  24. package/dist/cjs/core/file/exports.js +2 -0
  25. package/dist/cjs/core/file/file.d.ts +10 -0
  26. package/dist/cjs/core/file/file.js +221 -0
  27. package/dist/cjs/core/file/index.d.ts +2 -0
  28. package/dist/cjs/core/file/index.js +18 -0
  29. package/dist/cjs/core/file/types.d.ts +66 -0
  30. package/dist/cjs/core/file/types.js +2 -0
  31. package/dist/cjs/core/form-data-utils/FormDataWrapper.d.ts +15 -0
  32. package/dist/cjs/core/form-data-utils/FormDataWrapper.js +185 -0
  33. package/dist/cjs/core/form-data-utils/encodeAsFormParameter.d.ts +1 -0
  34. package/dist/cjs/core/form-data-utils/encodeAsFormParameter.js +12 -0
  35. package/dist/cjs/core/form-data-utils/index.d.ts +2 -0
  36. package/dist/cjs/core/form-data-utils/index.js +20 -0
  37. package/dist/cjs/core/headers.js +6 -4
  38. package/dist/cjs/core/index.d.ts +3 -0
  39. package/dist/cjs/core/index.js +4 -1
  40. package/dist/cjs/core/logging/exports.d.ts +18 -0
  41. package/dist/cjs/core/logging/exports.js +45 -0
  42. package/dist/cjs/core/logging/index.d.ts +1 -0
  43. package/dist/cjs/core/logging/index.js +17 -0
  44. package/dist/cjs/core/logging/logger.d.ts +126 -0
  45. package/dist/cjs/core/logging/logger.js +144 -0
  46. package/dist/cjs/core/url/join.js +0 -1
  47. package/dist/cjs/exports.d.ts +1 -0
  48. package/dist/cjs/exports.js +17 -0
  49. package/dist/cjs/index.d.ts +1 -0
  50. package/dist/cjs/index.js +4 -0
  51. package/dist/cjs/version.d.ts +1 -1
  52. package/dist/cjs/version.js +1 -1
  53. package/dist/esm/BaseClient.d.mts +4 -0
  54. package/dist/esm/Client.mjs +3 -3
  55. package/dist/esm/api/resources/copilots/client/Client.mjs +27 -9
  56. package/dist/esm/api/resources/documentCatalog/client/Client.d.mts +8 -0
  57. package/dist/esm/api/resources/documentCatalog/client/Client.mjs +95 -3
  58. package/dist/esm/api/resources/documentCatalog/client/requests/UploadFileRequest.d.mts +27 -0
  59. package/dist/esm/api/resources/documentCatalog/client/requests/UploadFileRequest.mjs +2 -0
  60. package/dist/esm/api/resources/documentCatalog/client/requests/index.d.mts +1 -0
  61. package/dist/esm/api/resources/documentCollections/client/Client.mjs +21 -7
  62. package/dist/esm/api/resources/search/client/Client.mjs +3 -1
  63. package/dist/esm/api/resources/users/client/Client.mjs +3 -1
  64. package/dist/esm/core/exports.d.mts +2 -0
  65. package/dist/esm/core/exports.mjs +2 -0
  66. package/dist/esm/core/fetcher/Fetcher.d.mts +4 -1
  67. package/dist/esm/core/fetcher/Fetcher.mjs +202 -9
  68. package/dist/esm/core/fetcher/getRequestBody.d.mts +1 -1
  69. package/dist/esm/core/fetcher/getRequestBody.mjs +4 -0
  70. package/dist/esm/core/fetcher/makeRequest.d.mts +1 -1
  71. package/dist/esm/core/fetcher/makeRequest.mjs +0 -2
  72. package/dist/esm/core/fetcher/requestWithRetries.mjs +0 -9
  73. package/dist/esm/core/fetcher/signals.d.mts +0 -6
  74. package/dist/esm/core/fetcher/signals.mjs +0 -12
  75. package/dist/esm/core/file/exports.d.mts +1 -0
  76. package/dist/esm/core/file/exports.mjs +1 -0
  77. package/dist/esm/core/file/file.d.mts +10 -0
  78. package/dist/esm/core/file/file.mjs +184 -0
  79. package/dist/esm/core/file/index.d.mts +2 -0
  80. package/dist/esm/core/file/index.mjs +2 -0
  81. package/dist/esm/core/file/types.d.mts +66 -0
  82. package/dist/esm/core/file/types.mjs +1 -0
  83. package/dist/esm/core/form-data-utils/FormDataWrapper.d.mts +15 -0
  84. package/dist/esm/core/form-data-utils/FormDataWrapper.mjs +147 -0
  85. package/dist/esm/core/form-data-utils/encodeAsFormParameter.d.mts +1 -0
  86. package/dist/esm/core/form-data-utils/encodeAsFormParameter.mjs +9 -0
  87. package/dist/esm/core/form-data-utils/index.d.mts +2 -0
  88. package/dist/esm/core/form-data-utils/index.mjs +2 -0
  89. package/dist/esm/core/headers.mjs +6 -4
  90. package/dist/esm/core/index.d.mts +3 -0
  91. package/dist/esm/core/index.mjs +3 -0
  92. package/dist/esm/core/logging/exports.d.mts +18 -0
  93. package/dist/esm/core/logging/exports.mjs +9 -0
  94. package/dist/esm/core/logging/index.d.mts +1 -0
  95. package/dist/esm/core/logging/index.mjs +1 -0
  96. package/dist/esm/core/logging/logger.d.mts +126 -0
  97. package/dist/esm/core/logging/logger.mjs +138 -0
  98. package/dist/esm/core/url/join.mjs +0 -1
  99. package/dist/esm/exports.d.mts +1 -0
  100. package/dist/esm/exports.mjs +1 -0
  101. package/dist/esm/index.d.mts +1 -0
  102. package/dist/esm/index.mjs +1 -0
  103. package/dist/esm/version.d.mts +1 -1
  104. package/dist/esm/version.mjs +1 -1
  105. package/package.json +3 -2
@@ -12,21 +12,153 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.fetcher = void 0;
13
13
  exports.fetcherImpl = fetcherImpl;
14
14
  const json_js_1 = require("../json.js");
15
+ const logger_js_1 = require("../logging/logger.js");
15
16
  const createRequestUrl_js_1 = require("./createRequestUrl.js");
16
17
  const EndpointSupplier_js_1 = require("./EndpointSupplier.js");
17
18
  const getErrorResponseBody_js_1 = require("./getErrorResponseBody.js");
18
19
  const getFetchFn_js_1 = require("./getFetchFn.js");
19
20
  const getRequestBody_js_1 = require("./getRequestBody.js");
20
21
  const getResponseBody_js_1 = require("./getResponseBody.js");
22
+ const Headers_js_1 = require("./Headers.js");
21
23
  const makeRequest_js_1 = require("./makeRequest.js");
22
24
  const RawResponse_js_1 = require("./RawResponse.js");
23
25
  const requestWithRetries_js_1 = require("./requestWithRetries.js");
26
+ const SENSITIVE_HEADERS = new Set([
27
+ "authorization",
28
+ "www-authenticate",
29
+ "x-api-key",
30
+ "api-key",
31
+ "apikey",
32
+ "x-api-token",
33
+ "x-auth-token",
34
+ "auth-token",
35
+ "cookie",
36
+ "set-cookie",
37
+ "proxy-authorization",
38
+ "proxy-authenticate",
39
+ "x-csrf-token",
40
+ "x-xsrf-token",
41
+ "x-session-token",
42
+ "x-access-token",
43
+ ]);
44
+ function redactHeaders(headers) {
45
+ const filtered = {};
46
+ for (const [key, value] of headers instanceof Headers_js_1.Headers ? headers.entries() : Object.entries(headers)) {
47
+ if (SENSITIVE_HEADERS.has(key.toLowerCase())) {
48
+ filtered[key] = "[REDACTED]";
49
+ }
50
+ else {
51
+ filtered[key] = value;
52
+ }
53
+ }
54
+ return filtered;
55
+ }
56
+ const SENSITIVE_QUERY_PARAMS = new Set([
57
+ "api_key",
58
+ "api-key",
59
+ "apikey",
60
+ "token",
61
+ "access_token",
62
+ "access-token",
63
+ "auth_token",
64
+ "auth-token",
65
+ "password",
66
+ "passwd",
67
+ "secret",
68
+ "api_secret",
69
+ "api-secret",
70
+ "apisecret",
71
+ "key",
72
+ "session",
73
+ "session_id",
74
+ "session-id",
75
+ ]);
76
+ function redactQueryParameters(queryParameters) {
77
+ if (queryParameters == null) {
78
+ return queryParameters;
79
+ }
80
+ const redacted = {};
81
+ for (const [key, value] of Object.entries(queryParameters)) {
82
+ if (SENSITIVE_QUERY_PARAMS.has(key.toLowerCase())) {
83
+ redacted[key] = "[REDACTED]";
84
+ }
85
+ else {
86
+ redacted[key] = value;
87
+ }
88
+ }
89
+ return redacted;
90
+ }
91
+ function redactUrl(url) {
92
+ const protocolIndex = url.indexOf("://");
93
+ if (protocolIndex === -1)
94
+ return url;
95
+ const afterProtocol = protocolIndex + 3;
96
+ // Find the first delimiter that marks the end of the authority section
97
+ const pathStart = url.indexOf("/", afterProtocol);
98
+ let queryStart = url.indexOf("?", afterProtocol);
99
+ let fragmentStart = url.indexOf("#", afterProtocol);
100
+ const firstDelimiter = Math.min(pathStart === -1 ? url.length : pathStart, queryStart === -1 ? url.length : queryStart, fragmentStart === -1 ? url.length : fragmentStart);
101
+ // Find the LAST @ before the delimiter (handles multiple @ in credentials)
102
+ let atIndex = -1;
103
+ for (let i = afterProtocol; i < firstDelimiter; i++) {
104
+ if (url[i] === "@") {
105
+ atIndex = i;
106
+ }
107
+ }
108
+ if (atIndex !== -1) {
109
+ url = `${url.slice(0, afterProtocol)}[REDACTED]@${url.slice(atIndex + 1)}`;
110
+ }
111
+ // Recalculate queryStart since url might have changed
112
+ queryStart = url.indexOf("?");
113
+ if (queryStart === -1)
114
+ return url;
115
+ fragmentStart = url.indexOf("#", queryStart);
116
+ const queryEnd = fragmentStart !== -1 ? fragmentStart : url.length;
117
+ const queryString = url.slice(queryStart + 1, queryEnd);
118
+ if (queryString.length === 0)
119
+ return url;
120
+ // FAST PATH: Quick check if any sensitive keywords present
121
+ // Using indexOf is faster than regex for simple substring matching
122
+ const lower = queryString.toLowerCase();
123
+ const hasSensitive = lower.includes("token") ||
124
+ lower.includes("key") ||
125
+ lower.includes("password") ||
126
+ lower.includes("passwd") ||
127
+ lower.includes("secret") ||
128
+ lower.includes("session") ||
129
+ lower.includes("auth");
130
+ if (!hasSensitive) {
131
+ return url;
132
+ }
133
+ // SLOW PATH: Parse and redact
134
+ const redactedParams = [];
135
+ const params = queryString.split("&");
136
+ for (const param of params) {
137
+ const equalIndex = param.indexOf("=");
138
+ if (equalIndex === -1) {
139
+ redactedParams.push(param);
140
+ continue;
141
+ }
142
+ const key = param.slice(0, equalIndex);
143
+ let shouldRedact = SENSITIVE_QUERY_PARAMS.has(key.toLowerCase());
144
+ if (!shouldRedact && key.includes("%")) {
145
+ try {
146
+ const decodedKey = decodeURIComponent(key);
147
+ shouldRedact = SENSITIVE_QUERY_PARAMS.has(decodedKey.toLowerCase());
148
+ }
149
+ catch (_a) { }
150
+ }
151
+ redactedParams.push(shouldRedact ? `${key}=[REDACTED]` : param);
152
+ }
153
+ return url.slice(0, queryStart + 1) + redactedParams.join("&") + url.slice(queryEnd);
154
+ }
24
155
  function getHeaders(args) {
25
156
  return __awaiter(this, void 0, void 0, function* () {
26
157
  var _a;
27
- const newHeaders = {};
158
+ const newHeaders = new Headers_js_1.Headers();
159
+ newHeaders.set("Accept", args.responseType === "json" ? "application/json" : args.responseType === "text" ? "text/plain" : "*/*");
28
160
  if (args.body !== undefined && args.contentType != null) {
29
- newHeaders["Content-Type"] = args.contentType;
161
+ newHeaders.set("Content-Type", args.contentType);
30
162
  }
31
163
  if (args.headers == null) {
32
164
  return newHeaders;
@@ -34,31 +166,52 @@ function getHeaders(args) {
34
166
  for (const [key, value] of Object.entries(args.headers)) {
35
167
  const result = yield EndpointSupplier_js_1.EndpointSupplier.get(value, { endpointMetadata: (_a = args.endpointMetadata) !== null && _a !== void 0 ? _a : {} });
36
168
  if (typeof result === "string") {
37
- newHeaders[key] = result;
169
+ newHeaders.set(key, result);
38
170
  continue;
39
171
  }
40
172
  if (result == null) {
41
173
  continue;
42
174
  }
43
- newHeaders[key] = `${result}`;
175
+ newHeaders.set(key, `${result}`);
44
176
  }
45
177
  return newHeaders;
46
178
  });
47
179
  }
48
180
  function fetcherImpl(args) {
49
181
  return __awaiter(this, void 0, void 0, function* () {
50
- var _a;
182
+ var _a, _b, _c;
51
183
  const url = (0, createRequestUrl_js_1.createRequestUrl)(args.url, args.queryParameters);
52
184
  const requestBody = yield (0, getRequestBody_js_1.getRequestBody)({
53
185
  body: args.body,
54
- type: args.requestType === "json" ? "json" : "other",
186
+ type: (_a = args.requestType) !== null && _a !== void 0 ? _a : "other",
55
187
  });
56
- const fetchFn = yield (0, getFetchFn_js_1.getFetchFn)();
188
+ const fetchFn = (_b = args.fetchFn) !== null && _b !== void 0 ? _b : (yield (0, getFetchFn_js_1.getFetchFn)());
189
+ const headers = yield getHeaders(args);
190
+ const logger = (0, logger_js_1.createLogger)(args.logging);
191
+ if (logger.isDebug()) {
192
+ const metadata = {
193
+ method: args.method,
194
+ url: redactUrl(url),
195
+ headers: redactHeaders(headers),
196
+ queryParameters: redactQueryParameters(args.queryParameters),
197
+ hasBody: requestBody != null,
198
+ };
199
+ logger.debug("Making HTTP request", metadata);
200
+ }
57
201
  try {
58
202
  const response = yield (0, requestWithRetries_js_1.requestWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
59
- return (0, makeRequest_js_1.makeRequest)(fetchFn, url, args.method, yield getHeaders(args), requestBody, args.timeoutMs, args.abortSignal, args.withCredentials, args.duplex);
203
+ return (0, makeRequest_js_1.makeRequest)(fetchFn, url, args.method, headers, requestBody, args.timeoutMs, args.abortSignal, args.withCredentials, args.duplex);
60
204
  }), args.maxRetries);
61
205
  if (response.status >= 200 && response.status < 400) {
206
+ if (logger.isDebug()) {
207
+ const metadata = {
208
+ method: args.method,
209
+ url: redactUrl(url),
210
+ statusCode: response.status,
211
+ responseHeaders: redactHeaders(response.headers),
212
+ };
213
+ logger.debug("HTTP request succeeded", metadata);
214
+ }
62
215
  return {
63
216
  ok: true,
64
217
  body: (yield (0, getResponseBody_js_1.getResponseBody)(response, args.responseType)),
@@ -67,6 +220,15 @@ function fetcherImpl(args) {
67
220
  };
68
221
  }
69
222
  else {
223
+ if (logger.isError()) {
224
+ const metadata = {
225
+ method: args.method,
226
+ url: redactUrl(url),
227
+ statusCode: response.status,
228
+ responseHeaders: redactHeaders(Object.fromEntries(response.headers.entries())),
229
+ };
230
+ logger.error("HTTP request failed with error status", metadata);
231
+ }
70
232
  return {
71
233
  ok: false,
72
234
  error: {
@@ -79,7 +241,14 @@ function fetcherImpl(args) {
79
241
  }
80
242
  }
81
243
  catch (error) {
82
- if ((_a = args.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
244
+ if ((_c = args.abortSignal) === null || _c === void 0 ? void 0 : _c.aborted) {
245
+ if (logger.isError()) {
246
+ const metadata = {
247
+ method: args.method,
248
+ url: redactUrl(url),
249
+ };
250
+ logger.error("HTTP request was aborted", metadata);
251
+ }
83
252
  return {
84
253
  ok: false,
85
254
  error: {
@@ -90,6 +259,14 @@ function fetcherImpl(args) {
90
259
  };
91
260
  }
92
261
  else if (error instanceof Error && error.name === "AbortError") {
262
+ if (logger.isError()) {
263
+ const metadata = {
264
+ method: args.method,
265
+ url: redactUrl(url),
266
+ timeoutMs: args.timeoutMs,
267
+ };
268
+ logger.error("HTTP request timed out", metadata);
269
+ }
93
270
  return {
94
271
  ok: false,
95
272
  error: {
@@ -99,6 +276,14 @@ function fetcherImpl(args) {
99
276
  };
100
277
  }
101
278
  else if (error instanceof Error) {
279
+ if (logger.isError()) {
280
+ const metadata = {
281
+ method: args.method,
282
+ url: redactUrl(url),
283
+ errorMessage: error.message,
284
+ };
285
+ logger.error("HTTP request failed with error", metadata);
286
+ }
102
287
  return {
103
288
  ok: false,
104
289
  error: {
@@ -108,6 +293,14 @@ function fetcherImpl(args) {
108
293
  rawResponse: RawResponse_js_1.unknownRawResponse,
109
294
  };
110
295
  }
296
+ if (logger.isError()) {
297
+ const metadata = {
298
+ method: args.method,
299
+ url: redactUrl(url),
300
+ error: (0, json_js_1.toJson)(error),
301
+ };
302
+ logger.error("HTTP request failed with unknown error", metadata);
303
+ }
111
304
  return {
112
305
  ok: false,
113
306
  error: {
@@ -1,7 +1,7 @@
1
1
  export declare namespace GetRequestBody {
2
2
  interface Args {
3
3
  body: unknown;
4
- type: "json" | "file" | "bytes" | "other";
4
+ type: "json" | "file" | "bytes" | "form" | "other";
5
5
  }
6
6
  }
7
7
  export declare function getRequestBody({ body, type }: GetRequestBody.Args): Promise<BodyInit | undefined>;
@@ -11,8 +11,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getRequestBody = getRequestBody;
13
13
  const json_js_1 = require("../json.js");
14
+ const qs_js_1 = require("../url/qs.js");
14
15
  function getRequestBody(_a) {
15
16
  return __awaiter(this, arguments, void 0, function* ({ body, type }) {
17
+ if (type === "form") {
18
+ return (0, qs_js_1.toQueryString)(body, { arrayFormat: "repeat", encode: true });
19
+ }
16
20
  if (type.includes("json")) {
17
21
  return (0, json_js_1.toJson)(body);
18
22
  }
@@ -1 +1 @@
1
- export declare const makeRequest: (fetchFn: (url: string, init: RequestInit) => Promise<Response>, url: string, method: string, headers: Record<string, string>, requestBody: BodyInit | undefined, timeoutMs?: number, abortSignal?: AbortSignal, withCredentials?: boolean, duplex?: "half") => Promise<Response>;
1
+ export declare const makeRequest: (fetchFn: (url: string, init: RequestInit) => Promise<Response>, url: string, method: string, headers: Headers | Record<string, string>, requestBody: BodyInit | undefined, timeoutMs?: number, abortSignal?: AbortSignal, withCredentials?: boolean, duplex?: "half") => Promise<Response>;
@@ -13,14 +13,12 @@ exports.makeRequest = void 0;
13
13
  const signals_js_1 = require("./signals.js");
14
14
  const makeRequest = (fetchFn, url, method, headers, requestBody, timeoutMs, abortSignal, withCredentials, duplex) => __awaiter(void 0, void 0, void 0, function* () {
15
15
  const signals = [];
16
- // Add timeout signal
17
16
  let timeoutAbortId;
18
17
  if (timeoutMs != null) {
19
18
  const { signal, abortId } = (0, signals_js_1.getTimeoutSignal)(timeoutMs);
20
19
  timeoutAbortId = abortId;
21
20
  signals.push(signal);
22
21
  }
23
- // Add arbitrary signal
24
22
  if (abortSignal != null) {
25
23
  signals.push(abortSignal);
26
24
  }
@@ -15,25 +15,20 @@ const MAX_RETRY_DELAY = 60000; // in milliseconds
15
15
  const DEFAULT_MAX_RETRIES = 2;
16
16
  const JITTER_FACTOR = 0.2; // 20% random jitter
17
17
  function addPositiveJitter(delay) {
18
- // Generate a random value between 0 and +JITTER_FACTOR
19
18
  const jitterMultiplier = 1 + Math.random() * JITTER_FACTOR;
20
19
  return delay * jitterMultiplier;
21
20
  }
22
21
  function addSymmetricJitter(delay) {
23
- // Generate a random value in a JITTER_FACTOR-sized percentage range around delay
24
22
  const jitterMultiplier = 1 + (Math.random() - 0.5) * JITTER_FACTOR;
25
23
  return delay * jitterMultiplier;
26
24
  }
27
25
  function getRetryDelayFromHeaders(response, retryAttempt) {
28
- // Check for Retry-After header first (RFC 7231), with no jitter
29
26
  const retryAfter = response.headers.get("Retry-After");
30
27
  if (retryAfter) {
31
- // Parse as number of seconds...
32
28
  const retryAfterSeconds = parseInt(retryAfter, 10);
33
29
  if (!Number.isNaN(retryAfterSeconds) && retryAfterSeconds > 0) {
34
30
  return Math.min(retryAfterSeconds * 1000, MAX_RETRY_DELAY);
35
31
  }
36
- // ...or as an HTTP date; both are valid
37
32
  const retryAfterDate = new Date(retryAfter);
38
33
  if (!Number.isNaN(retryAfterDate.getTime())) {
39
34
  const delay = retryAfterDate.getTime() - Date.now();
@@ -42,19 +37,16 @@ function getRetryDelayFromHeaders(response, retryAttempt) {
42
37
  }
43
38
  }
44
39
  }
45
- // Then check for industry-standard X-RateLimit-Reset header, with positive jitter
46
40
  const rateLimitReset = response.headers.get("X-RateLimit-Reset");
47
41
  if (rateLimitReset) {
48
42
  const resetTime = parseInt(rateLimitReset, 10);
49
43
  if (!Number.isNaN(resetTime)) {
50
- // Assume Unix timestamp in epoch seconds
51
44
  const delay = resetTime * 1000 - Date.now();
52
45
  if (delay > 0) {
53
46
  return addPositiveJitter(Math.min(delay, MAX_RETRY_DELAY));
54
47
  }
55
48
  }
56
49
  }
57
- // Fall back to exponential backoff, with symmetric jitter
58
50
  return addSymmetricJitter(Math.min(INITIAL_RETRY_DELAY * Math.pow(2, retryAttempt), MAX_RETRY_DELAY));
59
51
  }
60
52
  function requestWithRetries(requestFn_1) {
@@ -62,7 +54,6 @@ function requestWithRetries(requestFn_1) {
62
54
  let response = yield requestFn();
63
55
  for (let i = 0; i < maxRetries; ++i) {
64
56
  if ([408, 429].includes(response.status) || response.status >= 500) {
65
- // Get delay with appropriate jitter applied
66
57
  const delay = getRetryDelayFromHeaders(response, i);
67
58
  yield new Promise((resolve) => setTimeout(resolve, delay));
68
59
  response = yield requestFn();
@@ -2,10 +2,4 @@ export declare function getTimeoutSignal(timeoutMs: number): {
2
2
  signal: AbortSignal;
3
3
  abortId: NodeJS.Timeout;
4
4
  };
5
- /**
6
- * Returns an abort signal that is getting aborted when
7
- * at least one of the specified abort signals is aborted.
8
- *
9
- * Requires at least node.js 18.
10
- */
11
5
  export declare function anySignal(...args: AbortSignal[] | [AbortSignal[]]): AbortSignal;
@@ -8,26 +8,14 @@ function getTimeoutSignal(timeoutMs) {
8
8
  const abortId = setTimeout(() => controller.abort(TIMEOUT), timeoutMs);
9
9
  return { signal: controller.signal, abortId };
10
10
  }
11
- /**
12
- * Returns an abort signal that is getting aborted when
13
- * at least one of the specified abort signals is aborted.
14
- *
15
- * Requires at least node.js 18.
16
- */
17
11
  function anySignal(...args) {
18
- // Allowing signals to be passed either as array
19
- // of signals or as multiple arguments.
20
12
  const signals = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args);
21
13
  const controller = new AbortController();
22
14
  for (const signal of signals) {
23
15
  if (signal.aborted) {
24
- // Exiting early if one of the signals
25
- // is already aborted.
26
16
  controller.abort(signal === null || signal === void 0 ? void 0 : signal.reason);
27
17
  break;
28
18
  }
29
- // Listening for signals and removing the listeners
30
- // when at least one symbol is aborted.
31
19
  signal.addEventListener("abort", () => controller.abort(signal === null || signal === void 0 ? void 0 : signal.reason), {
32
20
  signal: controller.signal,
33
21
  });
@@ -0,0 +1 @@
1
+ export type { Uploadable } from "./types.js";
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ import type { Uploadable } from "./types.js";
2
+ export declare function toBinaryUploadRequest(file: Uploadable): Promise<{
3
+ body: Uploadable.FileLike;
4
+ headers?: Record<string, string>;
5
+ }>;
6
+ export declare function toMultipartDataPart(file: Uploadable): Promise<{
7
+ data: Uploadable.FileLike;
8
+ filename?: string;
9
+ contentType?: string;
10
+ }>;
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.toBinaryUploadRequest = toBinaryUploadRequest;
46
+ exports.toMultipartDataPart = toMultipartDataPart;
47
+ function toBinaryUploadRequest(file) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ const { data, filename, contentLength, contentType } = yield getFileWithMetadata(file);
50
+ const request = {
51
+ body: data,
52
+ headers: {},
53
+ };
54
+ if (filename) {
55
+ request.headers["Content-Disposition"] = `attachment; filename="${filename}"`;
56
+ }
57
+ if (contentType) {
58
+ request.headers["Content-Type"] = contentType;
59
+ }
60
+ if (contentLength != null) {
61
+ request.headers["Content-Length"] = contentLength.toString();
62
+ }
63
+ return request;
64
+ });
65
+ }
66
+ function toMultipartDataPart(file) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ const { data, filename, contentType } = yield getFileWithMetadata(file, {
69
+ noSniffFileSize: true,
70
+ });
71
+ return {
72
+ data,
73
+ filename,
74
+ contentType,
75
+ };
76
+ });
77
+ }
78
+ function getFileWithMetadata(file_1) {
79
+ return __awaiter(this, arguments, void 0, function* (file, { noSniffFileSize } = {}) {
80
+ var _a, _b, _c, _d, _e;
81
+ if (isFileLike(file)) {
82
+ return getFileWithMetadata({
83
+ data: file,
84
+ }, { noSniffFileSize });
85
+ }
86
+ if ("path" in file) {
87
+ const fs = yield Promise.resolve().then(() => __importStar(require("fs")));
88
+ if (!fs || !fs.createReadStream) {
89
+ throw new Error("File path uploads are not supported in this environment.");
90
+ }
91
+ const data = fs.createReadStream(file.path);
92
+ const contentLength = (_a = file.contentLength) !== null && _a !== void 0 ? _a : (noSniffFileSize === true ? undefined : yield tryGetFileSizeFromPath(file.path));
93
+ const filename = (_b = file.filename) !== null && _b !== void 0 ? _b : getNameFromPath(file.path);
94
+ return {
95
+ data,
96
+ filename,
97
+ contentType: file.contentType,
98
+ contentLength,
99
+ };
100
+ }
101
+ if ("data" in file) {
102
+ const data = file.data;
103
+ const contentLength = (_c = file.contentLength) !== null && _c !== void 0 ? _c : (yield tryGetContentLengthFromFileLike(data, {
104
+ noSniffFileSize,
105
+ }));
106
+ const filename = (_d = file.filename) !== null && _d !== void 0 ? _d : tryGetNameFromFileLike(data);
107
+ return {
108
+ data,
109
+ filename,
110
+ contentType: (_e = file.contentType) !== null && _e !== void 0 ? _e : tryGetContentTypeFromFileLike(data),
111
+ contentLength,
112
+ };
113
+ }
114
+ throw new Error(`Invalid FileUpload of type ${typeof file}: ${JSON.stringify(file)}`);
115
+ });
116
+ }
117
+ function isFileLike(value) {
118
+ return (isBuffer(value) ||
119
+ isArrayBufferView(value) ||
120
+ isArrayBuffer(value) ||
121
+ isUint8Array(value) ||
122
+ isBlob(value) ||
123
+ isFile(value) ||
124
+ isStreamLike(value) ||
125
+ isReadableStream(value));
126
+ }
127
+ function tryGetFileSizeFromPath(path) {
128
+ return __awaiter(this, void 0, void 0, function* () {
129
+ try {
130
+ const fs = yield Promise.resolve().then(() => __importStar(require("fs")));
131
+ if (!fs || !fs.promises || !fs.promises.stat) {
132
+ return undefined;
133
+ }
134
+ const fileStat = yield fs.promises.stat(path);
135
+ return fileStat.size;
136
+ }
137
+ catch (_fallbackError) {
138
+ return undefined;
139
+ }
140
+ });
141
+ }
142
+ function tryGetNameFromFileLike(data) {
143
+ if (isNamedValue(data)) {
144
+ return data.name;
145
+ }
146
+ if (isPathedValue(data)) {
147
+ return getNameFromPath(data.path.toString());
148
+ }
149
+ return undefined;
150
+ }
151
+ function tryGetContentLengthFromFileLike(data_1) {
152
+ return __awaiter(this, arguments, void 0, function* (data, { noSniffFileSize } = {}) {
153
+ if (isBuffer(data)) {
154
+ return data.length;
155
+ }
156
+ if (isArrayBufferView(data)) {
157
+ return data.byteLength;
158
+ }
159
+ if (isArrayBuffer(data)) {
160
+ return data.byteLength;
161
+ }
162
+ if (isBlob(data)) {
163
+ return data.size;
164
+ }
165
+ if (isFile(data)) {
166
+ return data.size;
167
+ }
168
+ if (noSniffFileSize === true) {
169
+ return undefined;
170
+ }
171
+ if (isPathedValue(data)) {
172
+ return yield tryGetFileSizeFromPath(data.path.toString());
173
+ }
174
+ return undefined;
175
+ });
176
+ }
177
+ function tryGetContentTypeFromFileLike(data) {
178
+ if (isBlob(data)) {
179
+ return data.type;
180
+ }
181
+ if (isFile(data)) {
182
+ return data.type;
183
+ }
184
+ return undefined;
185
+ }
186
+ function getNameFromPath(path) {
187
+ const lastForwardSlash = path.lastIndexOf("/");
188
+ const lastBackSlash = path.lastIndexOf("\\");
189
+ const lastSlashIndex = Math.max(lastForwardSlash, lastBackSlash);
190
+ return lastSlashIndex >= 0 ? path.substring(lastSlashIndex + 1) : path;
191
+ }
192
+ function isNamedValue(value) {
193
+ return typeof value === "object" && value != null && "name" in value;
194
+ }
195
+ function isPathedValue(value) {
196
+ return typeof value === "object" && value != null && "path" in value;
197
+ }
198
+ function isStreamLike(value) {
199
+ return typeof value === "object" && value != null && ("read" in value || "pipe" in value);
200
+ }
201
+ function isReadableStream(value) {
202
+ return typeof value === "object" && value != null && "getReader" in value;
203
+ }
204
+ function isBuffer(value) {
205
+ return typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(value);
206
+ }
207
+ function isArrayBufferView(value) {
208
+ return typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(value);
209
+ }
210
+ function isArrayBuffer(value) {
211
+ return typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer;
212
+ }
213
+ function isUint8Array(value) {
214
+ return typeof Uint8Array !== "undefined" && value instanceof Uint8Array;
215
+ }
216
+ function isBlob(value) {
217
+ return typeof Blob !== "undefined" && value instanceof Blob;
218
+ }
219
+ function isFile(value) {
220
+ return typeof File !== "undefined" && value instanceof File;
221
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./file.js";
2
+ export * from "./types.js";