@zayne-labs/callapi 1.7.4 → 1.7.6

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/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { splitConfig, isFunction, splitBaseConfig, defaultExtraOptions, defaultRequestOptions, createTimeoutSignal, createCombinedSignal, mergeAndResolveHeaders, isSerializable, HTTPError, resolveErrorResult, isHTTPErrorInstance, waitUntil, omitKeys, isPlainObject, isString, isArray, toQueryString, getFetchImpl, isReadableStream, isObject } from './chunk-FE6ZVVZS.js';
2
- export { HTTPError, getDefaultOptions } from './chunk-FE6ZVVZS.js';
1
+ import { splitConfig, isFunction, splitBaseConfig, createTimeoutSignal, createCombinedSignal, commonDefaults, mergeAndResolveHeaders, isSerializable, HTTPError, resolveErrorResult, isHTTPErrorInstance, waitUntil, hookDefaults, dedupeDefaults, responseDefaults, omitKeys, retryDefaults, isArray, isPlainObject, isString, toQueryString, getFetchImpl, isReadableStream, isObject, requestOptionDefaults } from './chunk-UVFIGKZS.js';
2
+ export { HTTPError } from './chunk-UVFIGKZS.js';
3
3
 
4
4
  // src/hooks.ts
5
5
  var hookRegistries = {
@@ -142,23 +142,24 @@ var toStreamableResponse = async (context) => {
142
142
  };
143
143
 
144
144
  // src/dedupe.ts
145
- var generateDedupeKey = (options, request) => {
146
- const shouldHaveDedupeKey = options.dedupeStrategy === "cancel" || options.dedupeStrategy === "defer";
147
- if (!shouldHaveDedupeKey) {
148
- return null;
149
- }
150
- return `${options.fullURL}-${JSON.stringify({ options, request })}`;
151
- };
152
145
  var createDedupeStrategy = async (context) => {
153
146
  const { $RequestInfoCache, baseConfig, config, newFetchController, options, request } = context;
154
- const dedupeKey = options.dedupeKey ?? generateDedupeKey(options, request);
147
+ const dedupeStrategy = options.dedupeStrategy ?? dedupeDefaults.dedupeStrategy;
148
+ const generateDedupeKey = () => {
149
+ const shouldHaveDedupeKey = dedupeStrategy === "cancel" || dedupeStrategy === "defer";
150
+ if (!shouldHaveDedupeKey) {
151
+ return null;
152
+ }
153
+ return `${options.fullURL}-${JSON.stringify({ options, request })}`;
154
+ };
155
+ const dedupeKey = options.dedupeKey ?? generateDedupeKey();
155
156
  const $RequestInfoCacheOrNull = dedupeKey !== null ? $RequestInfoCache : null;
156
157
  if (dedupeKey !== null) {
157
158
  await waitUntil(0.1);
158
159
  }
159
160
  const prevRequestInfo = $RequestInfoCacheOrNull?.get(dedupeKey);
160
161
  const handleRequestCancelStrategy = () => {
161
- const shouldCancelRequest = prevRequestInfo && options.dedupeStrategy === "cancel";
162
+ const shouldCancelRequest = prevRequestInfo && dedupeStrategy === "cancel";
162
163
  if (!shouldCancelRequest) return;
163
164
  const message = options.dedupeKey ? `Duplicate request detected - Aborting previous request with key '${options.dedupeKey}' as a new request was initiated` : `Duplicate request detected - Aborting previous request to '${options.fullURL}' as a new request with identical options was initiated`;
164
165
  const reason = new DOMException(message, "AbortError");
@@ -167,7 +168,7 @@ var createDedupeStrategy = async (context) => {
167
168
  };
168
169
  const handleRequestDeferStrategy = async () => {
169
170
  const fetchApi = getFetchImpl(options.customFetchImpl);
170
- const shouldUsePromiseFromCache = prevRequestInfo && options.dedupeStrategy === "defer";
171
+ const shouldUsePromiseFromCache = prevRequestInfo && dedupeStrategy === "defer";
171
172
  const requestInstance = new Request(
172
173
  options.fullURL,
173
174
  isReadableStream(request.body) && !request.duplex ? { ...request, duplex: "half" } : request
@@ -183,7 +184,9 @@ var createDedupeStrategy = async (context) => {
183
184
  if (isReadableStream(request.body)) {
184
185
  return fetchApi(requestInstance.clone());
185
186
  }
186
- return fetchApi(options.fullURL, request);
187
+ const method = request.method ?? requestOptionDefaults.method;
188
+ const modifiedRequest = { ...request, method };
189
+ return fetchApi(options.fullURL, modifiedRequest);
187
190
  };
188
191
  const responsePromise = shouldUsePromiseFromCache ? prevRequestInfo.responsePromise : getFetchApiPromise();
189
192
  $RequestInfoCacheOrNull?.set(dedupeKey, { controller: newFetchController, responsePromise });
@@ -200,6 +203,7 @@ var createDedupeStrategy = async (context) => {
200
203
  $RequestInfoCacheOrNull?.delete(dedupeKey);
201
204
  };
202
205
  return {
206
+ dedupeStrategy,
203
207
  handleRequestCancelStrategy,
204
208
  handleRequestDeferStrategy,
205
209
  removeDedupeKeyFromCache
@@ -224,17 +228,23 @@ var initializePlugins = async (context) => {
224
228
  const clonedHookRegistries = structuredClone(hookRegistries);
225
229
  const addMainHooks = () => {
226
230
  for (const key of Object.keys(clonedHookRegistries)) {
227
- const mainHook = options[key];
231
+ const baseHook = baseConfig[key];
232
+ const instanceHook = config[key];
233
+ const overriddenHook = options[key];
234
+ const mainHook = isArray(baseHook) && Boolean(instanceHook) ? [baseHook, instanceHook].flat() : overriddenHook;
235
+ if (!mainHook) continue;
228
236
  clonedHookRegistries[key].add(mainHook);
229
237
  }
230
238
  };
231
239
  const addPluginHooks = (pluginHooks) => {
232
240
  for (const key of Object.keys(clonedHookRegistries)) {
233
241
  const pluginHook = pluginHooks[key];
242
+ if (!pluginHook) continue;
234
243
  clonedHookRegistries[key].add(pluginHook);
235
244
  }
236
245
  };
237
- if (options.mergedHooksExecutionOrder === "mainHooksBeforePlugins") {
246
+ const mergedHooksExecutionOrder = options.mergedHooksExecutionOrder ?? hookDefaults.mergedHooksExecutionOrder;
247
+ if (mergedHooksExecutionOrder === "mainHooksBeforePlugins") {
238
248
  addMainHooks();
239
249
  }
240
250
  const resolvedPlugins = resolvePluginArray(options.plugins, baseConfig.plugins);
@@ -266,13 +276,14 @@ var initializePlugins = async (context) => {
266
276
  if (!plugin.hooks) continue;
267
277
  addPluginHooks(plugin.hooks);
268
278
  }
269
- if (!options.mergedHooksExecutionOrder || options.mergedHooksExecutionOrder === "mainHooksAfterPlugins") {
279
+ if (mergedHooksExecutionOrder === "mainHooksAfterPlugins") {
270
280
  addMainHooks();
271
281
  }
272
282
  const resolvedHooks = {};
273
283
  for (const [key, hookRegistry] of Object.entries(clonedHookRegistries)) {
274
- const flattenedHookArray = [...hookRegistry].flat().filter(Boolean);
275
- const composedHook = composeTwoHooks(flattenedHookArray, options.mergedHooksExecutionMode);
284
+ const flattenedHookArray = [...hookRegistry].flat();
285
+ const mergedHooksExecutionMode = options.mergedHooksExecutionMode ?? hookDefaults.mergedHooksExecutionMode;
286
+ const composedHook = composeTwoHooks(flattenedHookArray, mergedHooksExecutionMode);
276
287
  resolvedHooks[key] = composedHook;
277
288
  }
278
289
  return {
@@ -289,22 +300,20 @@ var getResponseType = (response, parser) => ({
289
300
  blob: () => response.blob(),
290
301
  formData: () => response.formData(),
291
302
  json: async () => {
292
- if (parser) {
293
- const text = await response.text();
294
- return parser(text);
295
- }
296
- return response.json();
303
+ const text = await response.text();
304
+ return parser(text);
297
305
  },
298
306
  stream: () => response.body,
299
307
  text: () => response.text()
300
308
  });
301
- var resolveResponseData = async (response, responseType, parser) => {
302
- const RESPONSE_TYPE_LOOKUP = getResponseType(response, parser);
303
- if (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {
309
+ var resolveResponseData = (response, responseType, parser) => {
310
+ const selectedParser = parser ?? responseDefaults.responseParser;
311
+ const selectedResponseType = responseType ?? responseDefaults.responseType;
312
+ const RESPONSE_TYPE_LOOKUP = getResponseType(response, selectedParser);
313
+ if (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, selectedResponseType)) {
304
314
  throw new Error(`Invalid response type: ${responseType}`);
305
315
  }
306
- const responseData = await RESPONSE_TYPE_LOOKUP[responseType]();
307
- return responseData;
316
+ return RESPONSE_TYPE_LOOKUP[selectedResponseType]();
308
317
  };
309
318
  var resolveSuccessResult = (info) => {
310
319
  const { data, response, resultMode } = info;
@@ -326,37 +335,52 @@ var resolveSuccessResult = (info) => {
326
335
  };
327
336
 
328
337
  // src/retry.ts
329
- var getLinearDelay = (options) => options.retryDelay ?? 1e3;
338
+ var getLinearDelay = (currentAttemptCount, options) => {
339
+ const retryDelay = options.retryDelay ?? options.retry?.delay;
340
+ const resolveRetryDelay = (isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay) ?? retryDefaults.delay;
341
+ return resolveRetryDelay;
342
+ };
330
343
  var getExponentialDelay = (currentAttemptCount, options) => {
331
- const maxDelay = options.retryMaxDelay ?? 1e4;
332
- const exponentialDelay = (options.retryDelay ?? 1e3) * 2 ** currentAttemptCount;
344
+ const retryDelay = options.retryDelay ?? options.retry?.delay ?? retryDefaults.delay;
345
+ const resolveRetryDelay = Number(isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay);
346
+ const maxDelay = Number(options.retryMaxDelay ?? options.retry?.maxDelay ?? retryDefaults.maxDelay);
347
+ const exponentialDelay = resolveRetryDelay * 2 ** currentAttemptCount;
333
348
  return Math.min(exponentialDelay, maxDelay);
334
349
  };
335
350
  var createRetryStrategy = (ctx) => {
336
351
  const { options } = ctx;
337
- const currentRetryCount = options["~retryCount"] ?? 0;
352
+ const currentAttemptCount = options["~retryAttemptCount"] ?? 0;
353
+ const retryStrategy = options.retryStrategy ?? options.retry?.strategy ?? retryDefaults.strategy;
338
354
  const getDelay = () => {
339
- if (options.retryStrategy === "exponential") {
340
- return getExponentialDelay(currentRetryCount, options);
355
+ switch (retryStrategy) {
356
+ case "exponential": {
357
+ return getExponentialDelay(currentAttemptCount, options);
358
+ }
359
+ case "linear": {
360
+ return getLinearDelay(currentAttemptCount, options);
361
+ }
362
+ default: {
363
+ throw new Error(`Invalid retry strategy: ${retryStrategy}`);
364
+ }
341
365
  }
342
- return getLinearDelay(options);
343
366
  };
344
367
  const shouldAttemptRetry = async () => {
345
- const customRetryCondition = await options.retryCondition?.(ctx) ?? true;
346
- const maxRetryAttempts = options.retryAttempts ?? 0;
347
- const baseRetryCondition = maxRetryAttempts > currentRetryCount && customRetryCondition;
368
+ const retryCondition = options.retryCondition ?? options.retry?.condition ?? retryDefaults.condition;
369
+ const maxRetryAttempts = options.retryAttempts ?? options.retry?.attempts ?? retryDefaults.attempts;
370
+ const customRetryCondition = await retryCondition(ctx);
371
+ const baseShouldRetry = maxRetryAttempts > currentAttemptCount && customRetryCondition;
348
372
  if (ctx.error.name !== "HTTPError") {
349
- return baseRetryCondition;
373
+ return baseShouldRetry;
350
374
  }
351
- const includesMethod = (
352
- // eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
353
- !!ctx.request.method && options.retryMethods?.includes(ctx.request.method)
354
- );
355
- const includesCodes = (
356
- // eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
357
- !!ctx.response?.status && options.retryStatusCodes?.includes(ctx.response.status)
375
+ const retryMethods = new Set(
376
+ options.retryMethods ?? options.retry?.methods ?? retryDefaults.methods
358
377
  );
359
- return includesCodes && includesMethod && baseRetryCondition;
378
+ const selectedStatusCodeArray = options.retryStatusCodes ?? options.retry?.statusCodes;
379
+ const retryStatusCodes = selectedStatusCodeArray ? new Set(selectedStatusCodeArray) : null;
380
+ const includesMethod = Boolean(ctx.request.method) && retryMethods.has(ctx.request.method);
381
+ const includesStatusCodes = Boolean(ctx.response?.status) && (retryStatusCodes?.has(ctx.response.status) ?? true);
382
+ const shouldRetry = baseShouldRetry && includesMethod && includesStatusCodes;
383
+ return shouldRetry;
360
384
  };
361
385
  const executeRetryHook = async (shouldThrowOnError) => {
362
386
  try {
@@ -449,12 +473,10 @@ var createFetchClient = (initBaseConfig = {}) => {
449
473
  const resolvedBaseConfig = isFunction(initBaseConfig) ? initBaseConfig({ initURL: initURL.toString(), options: extraOptions, request: fetchOptions }) : initBaseConfig;
450
474
  const [baseFetchOptions, baseExtraOptions] = splitBaseConfig(resolvedBaseConfig);
451
475
  const mergedExtraOptions = {
452
- ...defaultExtraOptions,
453
476
  ...baseExtraOptions,
454
477
  ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "options" && extraOptions
455
478
  };
456
479
  const mergedRequestOptions = {
457
- ...defaultRequestOptions,
458
480
  ...baseFetchOptions,
459
481
  ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "request" && fetchOptions
460
482
  };
@@ -467,7 +489,7 @@ var createFetchClient = (initBaseConfig = {}) => {
467
489
  options: mergedExtraOptions,
468
490
  request: mergedRequestOptions
469
491
  });
470
- const fullURL = `${resolvedOptions.baseURL}${mergeUrlWithParamsAndQuery(url, resolvedOptions.params, resolvedOptions.query)}`;
492
+ const fullURL = `${resolvedOptions.baseURL ?? ""}${mergeUrlWithParamsAndQuery(url, resolvedOptions.params, resolvedOptions.query)}`;
471
493
  const options = {
472
494
  ...resolvedOptions,
473
495
  ...resolvedHooks,
@@ -481,9 +503,10 @@ var createFetchClient = (initBaseConfig = {}) => {
481
503
  timeoutSignal,
482
504
  newFetchController.signal
483
505
  );
506
+ const bodySerializer = options.bodySerializer ?? commonDefaults.bodySerializer;
484
507
  const request = {
485
508
  ...resolvedRequestOptions,
486
- body: isSerializable(resolvedRequestOptions.body) ? options.bodySerializer(resolvedRequestOptions.body) : resolvedRequestOptions.body,
509
+ body: isSerializable(resolvedRequestOptions.body) ? bodySerializer(resolvedRequestOptions.body) : resolvedRequestOptions.body,
487
510
  headers: mergeAndResolveHeaders({
488
511
  auth: options.auth,
489
512
  baseHeaders: baseFetchOptions.headers,
@@ -492,7 +515,12 @@ var createFetchClient = (initBaseConfig = {}) => {
492
515
  }),
493
516
  signal: combinedSignal
494
517
  };
495
- const { handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeKeyFromCache } = await createDedupeStrategy({
518
+ const {
519
+ dedupeStrategy,
520
+ handleRequestCancelStrategy,
521
+ handleRequestDeferStrategy,
522
+ removeDedupeKeyFromCache
523
+ } = await createDedupeStrategy({
496
524
  $RequestInfoCache,
497
525
  baseConfig,
498
526
  config,
@@ -509,7 +537,7 @@ var createFetchClient = (initBaseConfig = {}) => {
509
537
  headers: request.headers
510
538
  });
511
539
  const response = await handleRequestDeferStrategy();
512
- const shouldCloneResponse = options.dedupeStrategy === "defer" || options.cloneResponse;
540
+ const shouldCloneResponse = dedupeStrategy === "defer" || options.cloneResponse;
513
541
  const schemas = isFunction(options.schemas) ? options.schemas({ baseSchemas: baseExtraOptions.schemas ?? {} }) : options.schemas;
514
542
  const validators = isFunction(options.validators) ? options.validators({ baseValidators: baseExtraOptions.validators ?? {} }) : options.validators;
515
543
  if (!response.ok) {
@@ -577,7 +605,7 @@ var createFetchClient = (initBaseConfig = {}) => {
577
605
  await waitUntil(delay);
578
606
  const updatedOptions = {
579
607
  ...config,
580
- "~retryCount": (options["~retryCount"] ?? 0) + 1
608
+ "~retryAttemptCount": (options["~retryAttemptCount"] ?? 0) + 1
581
609
  };
582
610
  return callApi2(initURL, updatedOptions);
583
611
  }