@zayne-labs/callapi 1.7.2 → 1.7.4

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,35 @@
1
- import { splitConfig, isFunction, splitBaseConfig, combineHooks, defaultExtraOptions, defaultRequestOptions, mergeAndResolveHeaders, isSerializable, executeHooks, HTTPError, resolveErrorResult, isHTTPErrorInstance, waitUntil, omitKeys, isPlainObject, isString, isArray, toQueryString, getFetchImpl, isReadableStream, isObject } from './chunk-IAT2JZPC.js';
2
- export { HTTPError, getDefaultOptions } from './chunk-IAT2JZPC.js';
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';
3
+
4
+ // src/hooks.ts
5
+ var hookRegistries = {
6
+ onError: /* @__PURE__ */ new Set(),
7
+ onRequest: /* @__PURE__ */ new Set(),
8
+ onRequestError: /* @__PURE__ */ new Set(),
9
+ onRequestStream: /* @__PURE__ */ new Set(),
10
+ onResponse: /* @__PURE__ */ new Set(),
11
+ onResponseError: /* @__PURE__ */ new Set(),
12
+ onResponseStream: /* @__PURE__ */ new Set(),
13
+ onRetry: /* @__PURE__ */ new Set(),
14
+ onSuccess: /* @__PURE__ */ new Set()
15
+ };
16
+ var composeTwoHooks = (hooks, mergedHooksExecutionMode) => {
17
+ if (hooks.length === 0) return;
18
+ const mergedHook = async (ctx) => {
19
+ if (mergedHooksExecutionMode === "sequential") {
20
+ for (const hook of hooks) {
21
+ await hook?.(ctx);
22
+ }
23
+ return;
24
+ }
25
+ if (mergedHooksExecutionMode === "parallel") {
26
+ const hookArray = [...hooks];
27
+ await Promise.all(hookArray.map((uniqueHook) => uniqueHook?.(ctx)));
28
+ }
29
+ };
30
+ return mergedHook;
31
+ };
32
+ var executeHooks = (...hooks) => Promise.all(hooks);
3
33
 
4
34
  // src/stream.ts
5
35
  var createProgressEvent = (options) => {
@@ -22,17 +52,19 @@ var calculateTotalBytesFromBody = async (requestBody, existingTotalBytes) => {
22
52
  return totalBytes;
23
53
  };
24
54
  var toStreamableRequest = async (context) => {
25
- const { options, request, requestInstance } = context;
55
+ const { baseConfig, config, options, request, requestInstance } = context;
26
56
  if (!options.onRequestStream || !requestInstance.body) return;
27
57
  const contentLength = requestInstance.headers.get("content-length") ?? new Headers(request.headers).get("content-length") ?? request.body?.size;
28
58
  let totalBytes = Number(contentLength ?? 0);
29
- const shouldForceContentLengthCalc = isObject(options.forceStreamSizeCalc) ? options.forceStreamSizeCalc.request : options.forceStreamSizeCalc;
59
+ const shouldForceContentLengthCalc = isObject(options.forceCalculateStreamSize) ? options.forceCalculateStreamSize.request : options.forceCalculateStreamSize;
30
60
  if (!contentLength && shouldForceContentLengthCalc) {
31
61
  totalBytes = await calculateTotalBytesFromBody(requestInstance.clone().body, totalBytes);
32
62
  }
33
63
  let transferredBytes = 0;
34
64
  await executeHooks(
35
65
  options.onRequestStream({
66
+ baseConfig,
67
+ config,
36
68
  event: createProgressEvent({ chunk: new Uint8Array(), totalBytes, transferredBytes }),
37
69
  options,
38
70
  request,
@@ -48,6 +80,8 @@ var toStreamableRequest = async (context) => {
48
80
  totalBytes = Math.max(totalBytes, transferredBytes);
49
81
  await executeHooks(
50
82
  options.onRequestStream?.({
83
+ baseConfig,
84
+ config,
51
85
  event: createProgressEvent({ chunk, totalBytes, transferredBytes }),
52
86
  options,
53
87
  request,
@@ -61,19 +95,21 @@ var toStreamableRequest = async (context) => {
61
95
  });
62
96
  };
63
97
  var toStreamableResponse = async (context) => {
64
- const { options, request, response } = context;
98
+ const { baseConfig, config, options, request, response } = context;
65
99
  if (!options.onResponseStream || !response.body) {
66
100
  return response;
67
101
  }
68
102
  const contentLength = response.headers.get("content-length");
69
103
  let totalBytes = Number(contentLength ?? 0);
70
- const shouldForceContentLengthCalc = isObject(options.forceStreamSizeCalc) ? options.forceStreamSizeCalc.response : options.forceStreamSizeCalc;
104
+ const shouldForceContentLengthCalc = isObject(options.forceCalculateStreamSize) ? options.forceCalculateStreamSize.response : options.forceCalculateStreamSize;
71
105
  if (!contentLength && shouldForceContentLengthCalc) {
72
106
  totalBytes = await calculateTotalBytesFromBody(response.clone().body, totalBytes);
73
107
  }
74
108
  let transferredBytes = 0;
75
109
  await executeHooks(
76
110
  options.onResponseStream({
111
+ baseConfig,
112
+ config,
77
113
  event: createProgressEvent({ chunk: new Uint8Array(), totalBytes, transferredBytes }),
78
114
  options,
79
115
  request,
@@ -89,6 +125,8 @@ var toStreamableResponse = async (context) => {
89
125
  totalBytes = Math.max(totalBytes, transferredBytes);
90
126
  await executeHooks(
91
127
  options.onResponseStream?.({
128
+ baseConfig,
129
+ config,
92
130
  event: createProgressEvent({ chunk, totalBytes, transferredBytes }),
93
131
  options,
94
132
  request,
@@ -104,16 +142,16 @@ var toStreamableResponse = async (context) => {
104
142
  };
105
143
 
106
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
+ };
107
152
  var createDedupeStrategy = async (context) => {
108
- const { $RequestInfoCache, newFetchController, options, request } = context;
109
- const generateDedupeKey = () => {
110
- const shouldHaveDedupeKey = options.dedupeStrategy === "cancel" || options.dedupeStrategy === "defer";
111
- if (!shouldHaveDedupeKey) {
112
- return null;
113
- }
114
- return `${options.fullURL}-${JSON.stringify({ options, request })}`;
115
- };
116
- const dedupeKey = options.dedupeKey ?? generateDedupeKey();
153
+ const { $RequestInfoCache, baseConfig, config, newFetchController, options, request } = context;
154
+ const dedupeKey = options.dedupeKey ?? generateDedupeKey(options, request);
117
155
  const $RequestInfoCacheOrNull = dedupeKey !== null ? $RequestInfoCache : null;
118
156
  if (dedupeKey !== null) {
119
157
  await waitUntil(0.1);
@@ -134,24 +172,33 @@ var createDedupeStrategy = async (context) => {
134
172
  options.fullURL,
135
173
  isReadableStream(request.body) && !request.duplex ? { ...request, duplex: "half" } : request
136
174
  );
137
- void toStreamableRequest({
175
+ await toStreamableRequest({
176
+ baseConfig,
177
+ config,
138
178
  options,
139
179
  request,
140
180
  requestInstance: requestInstance.clone()
141
181
  });
142
- const responsePromise = shouldUsePromiseFromCache ? prevRequestInfo.responsePromise : (
143
- // eslint-disable-next-line unicorn/no-nested-ternary -- Allow
144
- isReadableStream(request.body) ? fetchApi(requestInstance.clone()) : fetchApi(options.fullURL, request)
145
- );
182
+ const getFetchApiPromise = () => {
183
+ if (isReadableStream(request.body)) {
184
+ return fetchApi(requestInstance.clone());
185
+ }
186
+ return fetchApi(options.fullURL, request);
187
+ };
188
+ const responsePromise = shouldUsePromiseFromCache ? prevRequestInfo.responsePromise : getFetchApiPromise();
146
189
  $RequestInfoCacheOrNull?.set(dedupeKey, { controller: newFetchController, responsePromise });
147
190
  const streamableResponse = toStreamableResponse({
191
+ baseConfig,
192
+ config,
148
193
  options,
149
194
  request,
150
195
  response: await responsePromise
151
196
  });
152
197
  return streamableResponse;
153
198
  };
154
- const removeDedupeKeyFromCache = () => $RequestInfoCacheOrNull?.delete(dedupeKey);
199
+ const removeDedupeKeyFromCache = () => {
200
+ $RequestInfoCacheOrNull?.delete(dedupeKey);
201
+ };
155
202
  return {
156
203
  handleRequestCancelStrategy,
157
204
  handleRequestDeferStrategy,
@@ -163,61 +210,34 @@ var createDedupeStrategy = async (context) => {
163
210
  var definePlugin = (plugin) => {
164
211
  return plugin;
165
212
  };
166
- var createMergedHook = (hooks, mergedHooksExecutionMode) => {
167
- if (hooks.length === 0) return;
168
- const mergedHook = async (ctx) => {
169
- if (mergedHooksExecutionMode === "sequential") {
170
- for (const hook of hooks) {
171
- await hook?.(ctx);
172
- }
173
- return;
174
- }
175
- if (mergedHooksExecutionMode === "parallel") {
176
- const hookArray = [...hooks];
177
- await Promise.all(hookArray.map((uniqueHook) => uniqueHook?.(ctx)));
178
- }
179
- };
180
- return mergedHook;
181
- };
182
- var hooksEnum = {
183
- onError: /* @__PURE__ */ new Set(),
184
- onRequest: /* @__PURE__ */ new Set(),
185
- onRequestError: /* @__PURE__ */ new Set(),
186
- onRequestStream: /* @__PURE__ */ new Set(),
187
- onResponse: /* @__PURE__ */ new Set(),
188
- onResponseError: /* @__PURE__ */ new Set(),
189
- onResponseStream: /* @__PURE__ */ new Set(),
190
- onRetry: /* @__PURE__ */ new Set(),
191
- onSuccess: /* @__PURE__ */ new Set()
192
- };
193
- var getPluginArray = (plugins) => {
213
+ var resolvePluginArray = (plugins, basePlugins) => {
194
214
  if (!plugins) {
195
215
  return [];
196
216
  }
217
+ if (isFunction(plugins)) {
218
+ return plugins({ basePlugins: basePlugins ?? [] });
219
+ }
197
220
  return plugins;
198
221
  };
199
222
  var initializePlugins = async (context) => {
200
223
  const { baseConfig, config, initURL, options, request } = context;
201
- const hookRegistries = structuredClone(hooksEnum);
224
+ const clonedHookRegistries = structuredClone(hookRegistries);
202
225
  const addMainHooks = () => {
203
- for (const key of Object.keys(hooksEnum)) {
226
+ for (const key of Object.keys(clonedHookRegistries)) {
204
227
  const mainHook = options[key];
205
- hookRegistries[key].add(mainHook);
228
+ clonedHookRegistries[key].add(mainHook);
206
229
  }
207
230
  };
208
231
  const addPluginHooks = (pluginHooks) => {
209
- for (const key of Object.keys(hooksEnum)) {
232
+ for (const key of Object.keys(clonedHookRegistries)) {
210
233
  const pluginHook = pluginHooks[key];
211
- hookRegistries[key].add(pluginHook);
234
+ clonedHookRegistries[key].add(pluginHook);
212
235
  }
213
236
  };
214
237
  if (options.mergedHooksExecutionOrder === "mainHooksBeforePlugins") {
215
238
  addMainHooks();
216
239
  }
217
- const resolvedPlugins = [
218
- ...getPluginArray(options.plugins),
219
- ...getPluginArray(options.extend?.plugins)
220
- ];
240
+ const resolvedPlugins = resolvePluginArray(options.plugins, baseConfig.plugins);
221
241
  let resolvedUrl = initURL;
222
242
  let resolvedOptions = options;
223
243
  let resolvedRequestOptions = request;
@@ -250,10 +270,10 @@ var initializePlugins = async (context) => {
250
270
  addMainHooks();
251
271
  }
252
272
  const resolvedHooks = {};
253
- for (const [key, hookRegistry] of Object.entries(hookRegistries)) {
273
+ for (const [key, hookRegistry] of Object.entries(clonedHookRegistries)) {
254
274
  const flattenedHookArray = [...hookRegistry].flat().filter(Boolean);
255
- const mergedHook = createMergedHook(flattenedHookArray, options.mergedHooksExecutionMode);
256
- resolvedHooks[key] = mergedHook;
275
+ const composedHook = composeTwoHooks(flattenedHookArray, options.mergedHooksExecutionMode);
276
+ resolvedHooks[key] = composedHook;
257
277
  }
258
278
  return {
259
279
  resolvedHooks,
@@ -406,10 +426,6 @@ var mergeUrlWithParamsAndQuery = (url, params, query) => {
406
426
  return mergeUrlWithQuery(urlWithMergedParams, query);
407
427
  };
408
428
 
409
- // src/utils/polyfills.ts
410
- var createCombinedSignal = (...signals) => AbortSignal.any(signals.filter(Boolean));
411
- var createTimeoutSignal = (milliseconds) => AbortSignal.timeout(milliseconds);
412
-
413
429
  // src/validation.ts
414
430
  var standardSchemaParser = async (schema, inputData) => {
415
431
  const result = await schema["~standard"].validate(inputData);
@@ -418,11 +434,6 @@ var standardSchemaParser = async (schema, inputData) => {
418
434
  }
419
435
  return result.value;
420
436
  };
421
- var createExtensibleSchemasAndValidators = (options) => {
422
- const schemas = options.schemas && { ...options.schemas, ...options.extend?.schemas };
423
- const validators = options.validators && { ...options.validators, ...options.extend?.validators };
424
- return { schemas, validators };
425
- };
426
437
  var handleValidation = async (responseData, schema, validator) => {
427
438
  const validResponseData = validator ? validator(responseData) : responseData;
428
439
  const schemaValidResponseData = schema ? await standardSchemaParser(schema, validResponseData) : validResponseData;
@@ -430,35 +441,27 @@ var handleValidation = async (responseData, schema, validator) => {
430
441
  };
431
442
 
432
443
  // src/createFetchClient.ts
433
- var createFetchClient = (baseConfig = {}) => {
444
+ var createFetchClient = (initBaseConfig = {}) => {
434
445
  const $RequestInfoCache = /* @__PURE__ */ new Map();
435
446
  const callApi2 = async (...parameters) => {
436
- const [initURL, config = {}] = parameters;
437
- const [fetchOptions, extraOptions] = splitConfig(config);
438
- const resolvedBaseConfig = isFunction(baseConfig) ? baseConfig({
439
- initURL: initURL.toString(),
440
- options: extraOptions,
441
- request: fetchOptions
442
- }) : baseConfig;
447
+ const [initURL, initConfig = {}] = parameters;
448
+ const [fetchOptions, extraOptions] = splitConfig(initConfig);
449
+ const resolvedBaseConfig = isFunction(initBaseConfig) ? initBaseConfig({ initURL: initURL.toString(), options: extraOptions, request: fetchOptions }) : initBaseConfig;
443
450
  const [baseFetchOptions, baseExtraOptions] = splitBaseConfig(resolvedBaseConfig);
444
- for (const key of Object.keys(hooksEnum)) {
445
- combineHooks(
446
- baseExtraOptions[key],
447
- extraOptions[key]
448
- );
449
- }
450
451
  const mergedExtraOptions = {
451
452
  ...defaultExtraOptions,
452
453
  ...baseExtraOptions,
453
- ...!baseExtraOptions.mergeMainOptionsManuallyFromBase && extraOptions
454
+ ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "options" && extraOptions
454
455
  };
455
456
  const mergedRequestOptions = {
456
457
  ...defaultRequestOptions,
457
458
  ...baseFetchOptions,
458
- ...fetchOptions
459
+ ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "request" && fetchOptions
459
460
  };
461
+ const baseConfig = resolvedBaseConfig;
462
+ const config = initConfig;
460
463
  const { resolvedHooks, resolvedOptions, resolvedRequestOptions, url } = await initializePlugins({
461
- baseConfig: resolvedBaseConfig,
464
+ baseConfig,
462
465
  config,
463
466
  initURL,
464
467
  options: mergedExtraOptions,
@@ -489,18 +492,26 @@ var createFetchClient = (baseConfig = {}) => {
489
492
  }),
490
493
  signal: combinedSignal
491
494
  };
492
- const { handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeKeyFromCache } = await createDedupeStrategy({ $RequestInfoCache, newFetchController, options, request });
495
+ const { handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeKeyFromCache } = await createDedupeStrategy({
496
+ $RequestInfoCache,
497
+ baseConfig,
498
+ config,
499
+ newFetchController,
500
+ options,
501
+ request
502
+ });
493
503
  await handleRequestCancelStrategy();
494
504
  try {
495
- await executeHooks(options.onRequest?.({ options, request }));
505
+ await executeHooks(options.onRequest?.({ baseConfig, config, options, request }));
496
506
  request.headers = mergeAndResolveHeaders({
497
507
  auth: options.auth,
498
508
  body: request.body,
499
509
  headers: request.headers
500
510
  });
501
511
  const response = await handleRequestDeferStrategy();
502
- const { schemas, validators } = createExtensibleSchemasAndValidators(options);
503
512
  const shouldCloneResponse = options.dedupeStrategy === "defer" || options.cloneResponse;
513
+ const schemas = isFunction(options.schemas) ? options.schemas({ baseSchemas: baseExtraOptions.schemas ?? {} }) : options.schemas;
514
+ const validators = isFunction(options.validators) ? options.validators({ baseValidators: baseExtraOptions.validators ?? {} }) : options.validators;
504
515
  if (!response.ok) {
505
516
  const errorData = await resolveResponseData(
506
517
  shouldCloneResponse ? response.clone() : response,
@@ -525,6 +536,8 @@ var createFetchClient = (baseConfig = {}) => {
525
536
  );
526
537
  const validSuccessData = await handleValidation(successData, schemas?.data, validators?.data);
527
538
  const successContext = {
539
+ baseConfig,
540
+ config,
528
541
  data: validSuccessData,
529
542
  options,
530
543
  request,
@@ -547,6 +560,8 @@ var createFetchClient = (baseConfig = {}) => {
547
560
  resultMode: options.resultMode
548
561
  });
549
562
  const errorContext = {
563
+ baseConfig,
564
+ config,
550
565
  error: apiDetails.error,
551
566
  options,
552
567
  request,
@@ -590,9 +605,9 @@ var createFetchClient = (baseConfig = {}) => {
590
605
  return await handleRetryOrGetResult({ message });
591
606
  }
592
607
  await executeHooks(
593
- // == At this point only the request errors exist, so the request error interceptor is called
608
+ // == At this point only the request errors exist, so the request error hook is called
594
609
  options.onRequestError?.(errorContext),
595
- // == Also call the onError interceptor
610
+ // == Also call the onError hook
596
611
  options.onError?.(errorContext)
597
612
  );
598
613
  return await handleRetryOrGetResult();