@zayne-labs/callapi 1.7.5 → 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-G4FFGADM.js';
2
- export { HTTPError, getDefaultOptions } from './chunk-G4FFGADM.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,25 +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 (!responseType) {
304
- return RESPONSE_TYPE_LOOKUP.json();
305
- }
306
- 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)) {
307
314
  throw new Error(`Invalid response type: ${responseType}`);
308
315
  }
309
- const responseData = await RESPONSE_TYPE_LOOKUP[responseType]();
310
- return responseData;
316
+ return RESPONSE_TYPE_LOOKUP[selectedResponseType]();
311
317
  };
312
318
  var resolveSuccessResult = (info) => {
313
319
  const { data, response, resultMode } = info;
@@ -329,37 +335,52 @@ var resolveSuccessResult = (info) => {
329
335
  };
330
336
 
331
337
  // src/retry.ts
332
- 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
+ };
333
343
  var getExponentialDelay = (currentAttemptCount, options) => {
334
- const maxDelay = options.retryMaxDelay ?? 1e4;
335
- 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;
336
348
  return Math.min(exponentialDelay, maxDelay);
337
349
  };
338
350
  var createRetryStrategy = (ctx) => {
339
351
  const { options } = ctx;
340
- const currentRetryCount = options["~retryCount"] ?? 0;
352
+ const currentAttemptCount = options["~retryAttemptCount"] ?? 0;
353
+ const retryStrategy = options.retryStrategy ?? options.retry?.strategy ?? retryDefaults.strategy;
341
354
  const getDelay = () => {
342
- if (options.retryStrategy === "exponential") {
343
- 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
+ }
344
365
  }
345
- return getLinearDelay(options);
346
366
  };
347
367
  const shouldAttemptRetry = async () => {
348
- const customRetryCondition = await options.retryCondition?.(ctx) ?? true;
349
- const maxRetryAttempts = options.retryAttempts ?? 0;
350
- 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;
351
372
  if (ctx.error.name !== "HTTPError") {
352
- return baseRetryCondition;
373
+ return baseShouldRetry;
353
374
  }
354
- const includesMethod = (
355
- // eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
356
- !!ctx.request.method && options.retryMethods?.includes(ctx.request.method)
357
- );
358
- const includesCodes = (
359
- // eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
360
- !!ctx.response?.status && options.retryStatusCodes?.includes(ctx.response.status)
375
+ const retryMethods = new Set(
376
+ options.retryMethods ?? options.retry?.methods ?? retryDefaults.methods
361
377
  );
362
- 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;
363
384
  };
364
385
  const executeRetryHook = async (shouldThrowOnError) => {
365
386
  try {
@@ -452,12 +473,10 @@ var createFetchClient = (initBaseConfig = {}) => {
452
473
  const resolvedBaseConfig = isFunction(initBaseConfig) ? initBaseConfig({ initURL: initURL.toString(), options: extraOptions, request: fetchOptions }) : initBaseConfig;
453
474
  const [baseFetchOptions, baseExtraOptions] = splitBaseConfig(resolvedBaseConfig);
454
475
  const mergedExtraOptions = {
455
- ...defaultExtraOptions,
456
476
  ...baseExtraOptions,
457
477
  ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "options" && extraOptions
458
478
  };
459
479
  const mergedRequestOptions = {
460
- ...defaultRequestOptions,
461
480
  ...baseFetchOptions,
462
481
  ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "request" && fetchOptions
463
482
  };
@@ -470,7 +489,7 @@ var createFetchClient = (initBaseConfig = {}) => {
470
489
  options: mergedExtraOptions,
471
490
  request: mergedRequestOptions
472
491
  });
473
- const fullURL = `${resolvedOptions.baseURL}${mergeUrlWithParamsAndQuery(url, resolvedOptions.params, resolvedOptions.query)}`;
492
+ const fullURL = `${resolvedOptions.baseURL ?? ""}${mergeUrlWithParamsAndQuery(url, resolvedOptions.params, resolvedOptions.query)}`;
474
493
  const options = {
475
494
  ...resolvedOptions,
476
495
  ...resolvedHooks,
@@ -484,9 +503,10 @@ var createFetchClient = (initBaseConfig = {}) => {
484
503
  timeoutSignal,
485
504
  newFetchController.signal
486
505
  );
506
+ const bodySerializer = options.bodySerializer ?? commonDefaults.bodySerializer;
487
507
  const request = {
488
508
  ...resolvedRequestOptions,
489
- body: isSerializable(resolvedRequestOptions.body) ? options.bodySerializer(resolvedRequestOptions.body) : resolvedRequestOptions.body,
509
+ body: isSerializable(resolvedRequestOptions.body) ? bodySerializer(resolvedRequestOptions.body) : resolvedRequestOptions.body,
490
510
  headers: mergeAndResolveHeaders({
491
511
  auth: options.auth,
492
512
  baseHeaders: baseFetchOptions.headers,
@@ -495,7 +515,12 @@ var createFetchClient = (initBaseConfig = {}) => {
495
515
  }),
496
516
  signal: combinedSignal
497
517
  };
498
- const { handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeKeyFromCache } = await createDedupeStrategy({
518
+ const {
519
+ dedupeStrategy,
520
+ handleRequestCancelStrategy,
521
+ handleRequestDeferStrategy,
522
+ removeDedupeKeyFromCache
523
+ } = await createDedupeStrategy({
499
524
  $RequestInfoCache,
500
525
  baseConfig,
501
526
  config,
@@ -512,7 +537,7 @@ var createFetchClient = (initBaseConfig = {}) => {
512
537
  headers: request.headers
513
538
  });
514
539
  const response = await handleRequestDeferStrategy();
515
- const shouldCloneResponse = options.dedupeStrategy === "defer" || options.cloneResponse;
540
+ const shouldCloneResponse = dedupeStrategy === "defer" || options.cloneResponse;
516
541
  const schemas = isFunction(options.schemas) ? options.schemas({ baseSchemas: baseExtraOptions.schemas ?? {} }) : options.schemas;
517
542
  const validators = isFunction(options.validators) ? options.validators({ baseValidators: baseExtraOptions.validators ?? {} }) : options.validators;
518
543
  if (!response.ok) {
@@ -580,7 +605,7 @@ var createFetchClient = (initBaseConfig = {}) => {
580
605
  await waitUntil(delay);
581
606
  const updatedOptions = {
582
607
  ...config,
583
- "~retryCount": (options["~retryCount"] ?? 0) + 1
608
+ "~retryAttemptCount": (options["~retryAttemptCount"] ?? 0) + 1
584
609
  };
585
610
  return callApi2(initURL, updatedOptions);
586
611
  }