@zayne-labs/callapi 1.11.5 → 1.11.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/README.md +5 -5
- package/dist/esm/{common-NVdD93VW.d.ts → common-ClytspsT.d.ts} +36 -36
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +427 -7
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/index.d.ts +57 -6
- package/dist/esm/utils/index.js +2 -2
- package/dist/esm/utils-DOVvfarH.js +225 -0
- package/dist/esm/utils-DOVvfarH.js.map +1 -0
- package/package.json +11 -11
- package/dist/esm/common-CfCB_X1k.js +0 -580
- package/dist/esm/common-CfCB_X1k.js.map +0 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as defineEnum, S as requestOptionDefaults, a as isFunction, b as ValidationError, d as isPromise, f as isQueryString, g as isValidJsonString, h as isString, i as isBoolean, l as isObject, m as isSerializable, n as toQueryString, p as isReadableStream, r as isArray, s as isHTTPErrorInstance, u as isPlainObject, v as isValidationErrorInstance, x as extraOptionDefaults, y as HTTPError } from "./utils-DOVvfarH.js";
|
|
2
2
|
|
|
3
3
|
//#region src/result.ts
|
|
4
4
|
const getResponseType = (response, parser) => ({
|
|
@@ -262,6 +262,427 @@ const toStreamableResponse = async (context) => {
|
|
|
262
262
|
return new Response(stream, response);
|
|
263
263
|
};
|
|
264
264
|
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/auth.ts
|
|
267
|
+
const resolveAuthValue = (value) => isFunction(value) ? value() : value;
|
|
268
|
+
const getAuthHeader = async (auth) => {
|
|
269
|
+
if (auth === void 0) return;
|
|
270
|
+
if (isPromise(auth) || isFunction(auth) || !isObject(auth)) {
|
|
271
|
+
const authValue = await resolveAuthValue(auth);
|
|
272
|
+
if (authValue === void 0) return;
|
|
273
|
+
return { Authorization: `Bearer ${authValue}` };
|
|
274
|
+
}
|
|
275
|
+
switch (auth.type) {
|
|
276
|
+
case "Basic": {
|
|
277
|
+
const [username, password] = await Promise.all([resolveAuthValue(auth.username), resolveAuthValue(auth.password)]);
|
|
278
|
+
if (username === void 0 || password === void 0) return;
|
|
279
|
+
return { Authorization: `Basic ${globalThis.btoa(`${username}:${password}`)}` };
|
|
280
|
+
}
|
|
281
|
+
case "Custom": {
|
|
282
|
+
const [prefix, value] = await Promise.all([resolveAuthValue(auth.prefix), resolveAuthValue(auth.value)]);
|
|
283
|
+
if (value === void 0) return;
|
|
284
|
+
return { Authorization: `${prefix} ${value}` };
|
|
285
|
+
}
|
|
286
|
+
default: {
|
|
287
|
+
const [bearer, token] = await Promise.all([resolveAuthValue(auth.bearer), resolveAuthValue(auth.token)]);
|
|
288
|
+
if (bearer !== void 0) return { Authorization: `Bearer ${bearer}` };
|
|
289
|
+
if (token === void 0) return;
|
|
290
|
+
return { Authorization: `Token ${token}` };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
//#endregion
|
|
296
|
+
//#region src/constants/common.ts
|
|
297
|
+
const fetchSpecificKeys = defineEnum([
|
|
298
|
+
"body",
|
|
299
|
+
"integrity",
|
|
300
|
+
"duplex",
|
|
301
|
+
"method",
|
|
302
|
+
"headers",
|
|
303
|
+
"signal",
|
|
304
|
+
"cache",
|
|
305
|
+
"redirect",
|
|
306
|
+
"window",
|
|
307
|
+
"credentials",
|
|
308
|
+
"keepalive",
|
|
309
|
+
"referrer",
|
|
310
|
+
"priority",
|
|
311
|
+
"mode",
|
|
312
|
+
"referrerPolicy"
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/validation.ts
|
|
317
|
+
const handleValidatorFunction = async (validator, inputData) => {
|
|
318
|
+
try {
|
|
319
|
+
return {
|
|
320
|
+
issues: void 0,
|
|
321
|
+
value: await validator(inputData)
|
|
322
|
+
};
|
|
323
|
+
} catch (error) {
|
|
324
|
+
return {
|
|
325
|
+
issues: toArray(error),
|
|
326
|
+
value: void 0
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
const standardSchemaParser = async (fullSchema, schemaName, inputData, response) => {
|
|
331
|
+
const schema = fullSchema?.[schemaName];
|
|
332
|
+
if (!schema) return inputData;
|
|
333
|
+
const result = isFunction(schema) ? await handleValidatorFunction(schema, inputData) : await schema["~standard"].validate(inputData);
|
|
334
|
+
if (result.issues) throw new ValidationError({
|
|
335
|
+
issueCause: schemaName,
|
|
336
|
+
issues: result.issues,
|
|
337
|
+
response: response ?? null
|
|
338
|
+
});
|
|
339
|
+
return result.value;
|
|
340
|
+
};
|
|
341
|
+
const routeKeyMethods = defineEnum([
|
|
342
|
+
"delete",
|
|
343
|
+
"get",
|
|
344
|
+
"patch",
|
|
345
|
+
"post",
|
|
346
|
+
"put"
|
|
347
|
+
]);
|
|
348
|
+
const handleSchemaValidation = async (fullSchema, schemaName, validationOptions) => {
|
|
349
|
+
const { inputValue, response, schemaConfig } = validationOptions;
|
|
350
|
+
if (schemaConfig?.disableRuntimeValidation) return inputValue;
|
|
351
|
+
return await standardSchemaParser(fullSchema, schemaName, inputValue, response);
|
|
352
|
+
};
|
|
353
|
+
const extraOptionsToBeValidated = [
|
|
354
|
+
"meta",
|
|
355
|
+
"params",
|
|
356
|
+
"query"
|
|
357
|
+
];
|
|
358
|
+
const handleExtraOptionsValidation = async (validationOptions) => {
|
|
359
|
+
const { options, schema, schemaConfig } = validationOptions;
|
|
360
|
+
const validationResultArray = await Promise.all(extraOptionsToBeValidated.map((schemaName) => handleSchemaValidation(schema, schemaName, {
|
|
361
|
+
inputValue: options[schemaName],
|
|
362
|
+
schemaConfig
|
|
363
|
+
})));
|
|
364
|
+
const validatedResultObject = {};
|
|
365
|
+
for (const [index, schemaName] of extraOptionsToBeValidated.entries()) {
|
|
366
|
+
const validationResult = validationResultArray[index];
|
|
367
|
+
if (validationResult === void 0) continue;
|
|
368
|
+
validatedResultObject[schemaName] = validationResult;
|
|
369
|
+
}
|
|
370
|
+
return validatedResultObject;
|
|
371
|
+
};
|
|
372
|
+
const requestOptionsToBeValidated = [
|
|
373
|
+
"body",
|
|
374
|
+
"headers",
|
|
375
|
+
"method"
|
|
376
|
+
];
|
|
377
|
+
const handleRequestOptionsValidation = async (validationOptions) => {
|
|
378
|
+
const { requestOptions, schema, schemaConfig } = validationOptions;
|
|
379
|
+
const validationResultArray = await Promise.all(requestOptionsToBeValidated.map((schemaName) => handleSchemaValidation(schema, schemaName, {
|
|
380
|
+
inputValue: requestOptions[schemaName],
|
|
381
|
+
schemaConfig
|
|
382
|
+
})));
|
|
383
|
+
const validatedResultObject = {};
|
|
384
|
+
for (const [index, propertyKey] of requestOptionsToBeValidated.entries()) {
|
|
385
|
+
const validationResult = validationResultArray[index];
|
|
386
|
+
if (validationResult === void 0) continue;
|
|
387
|
+
validatedResultObject[propertyKey] = validationResult;
|
|
388
|
+
}
|
|
389
|
+
return validatedResultObject;
|
|
390
|
+
};
|
|
391
|
+
const handleConfigValidation = async (validationOptions) => {
|
|
392
|
+
const { baseExtraOptions, currentRouteSchemaKey, extraOptions, options, requestOptions } = validationOptions;
|
|
393
|
+
const { currentRouteSchema, resolvedSchema } = getResolvedSchema({
|
|
394
|
+
baseExtraOptions,
|
|
395
|
+
currentRouteSchemaKey,
|
|
396
|
+
extraOptions
|
|
397
|
+
});
|
|
398
|
+
const resolvedSchemaConfig = getResolvedSchemaConfig({
|
|
399
|
+
baseExtraOptions,
|
|
400
|
+
extraOptions
|
|
401
|
+
});
|
|
402
|
+
if (resolvedSchemaConfig?.strict === true && !currentRouteSchema) throw new ValidationError({
|
|
403
|
+
issueCause: "schemaConfig-(strict)",
|
|
404
|
+
issues: [{ message: `Strict Mode - No schema found for route '${currentRouteSchemaKey}' ` }],
|
|
405
|
+
response: null
|
|
406
|
+
});
|
|
407
|
+
if (resolvedSchemaConfig?.disableRuntimeValidation) return {
|
|
408
|
+
extraOptionsValidationResult: null,
|
|
409
|
+
requestOptionsValidationResult: null,
|
|
410
|
+
resolvedSchema,
|
|
411
|
+
resolvedSchemaConfig,
|
|
412
|
+
shouldApplySchemaOutput: false
|
|
413
|
+
};
|
|
414
|
+
const [extraOptionsValidationResult, requestOptionsValidationResult] = await Promise.all([handleExtraOptionsValidation({
|
|
415
|
+
options,
|
|
416
|
+
schema: resolvedSchema,
|
|
417
|
+
schemaConfig: resolvedSchemaConfig
|
|
418
|
+
}), handleRequestOptionsValidation({
|
|
419
|
+
requestOptions,
|
|
420
|
+
schema: resolvedSchema,
|
|
421
|
+
schemaConfig: resolvedSchemaConfig
|
|
422
|
+
})]);
|
|
423
|
+
return {
|
|
424
|
+
extraOptionsValidationResult,
|
|
425
|
+
requestOptionsValidationResult,
|
|
426
|
+
resolvedSchema,
|
|
427
|
+
resolvedSchemaConfig,
|
|
428
|
+
shouldApplySchemaOutput: (Boolean(extraOptionsValidationResult) || Boolean(requestOptionsValidationResult)) && !resolvedSchemaConfig?.disableValidationOutputApplication
|
|
429
|
+
};
|
|
430
|
+
};
|
|
431
|
+
const fallBackRouteSchemaKey = ".";
|
|
432
|
+
const getResolvedSchema = (context) => {
|
|
433
|
+
const { baseExtraOptions, currentRouteSchemaKey, extraOptions } = context;
|
|
434
|
+
const fallbackRouteSchema = baseExtraOptions.schema?.routes[fallBackRouteSchemaKey];
|
|
435
|
+
const currentRouteSchema = baseExtraOptions.schema?.routes[currentRouteSchemaKey];
|
|
436
|
+
const resolvedRouteSchema = {
|
|
437
|
+
...fallbackRouteSchema,
|
|
438
|
+
...currentRouteSchema
|
|
439
|
+
};
|
|
440
|
+
return {
|
|
441
|
+
currentRouteSchema,
|
|
442
|
+
resolvedSchema: isFunction(extraOptions.schema) ? extraOptions.schema({
|
|
443
|
+
baseSchemaRoutes: baseExtraOptions.schema?.routes ?? {},
|
|
444
|
+
currentRouteSchema: resolvedRouteSchema ?? {}
|
|
445
|
+
}) : extraOptions.schema ?? resolvedRouteSchema
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
const getResolvedSchemaConfig = (context) => {
|
|
449
|
+
const { baseExtraOptions, extraOptions } = context;
|
|
450
|
+
return isFunction(extraOptions.schemaConfig) ? extraOptions.schemaConfig({ baseSchemaConfig: baseExtraOptions.schema?.config ?? {} }) : extraOptions.schemaConfig ?? baseExtraOptions.schema?.config;
|
|
451
|
+
};
|
|
452
|
+
const getCurrentRouteSchemaKeyAndMainInitURL = (context) => {
|
|
453
|
+
const { baseExtraOptions, extraOptions, initURL } = context;
|
|
454
|
+
const schemaConfig = getResolvedSchemaConfig({
|
|
455
|
+
baseExtraOptions,
|
|
456
|
+
extraOptions
|
|
457
|
+
});
|
|
458
|
+
let currentRouteSchemaKey = initURL;
|
|
459
|
+
let mainInitURL = initURL;
|
|
460
|
+
if (schemaConfig?.prefix && currentRouteSchemaKey.startsWith(schemaConfig.prefix)) {
|
|
461
|
+
currentRouteSchemaKey = currentRouteSchemaKey.replace(schemaConfig.prefix, "");
|
|
462
|
+
mainInitURL = mainInitURL.replace(schemaConfig.prefix, schemaConfig.baseURL ?? "");
|
|
463
|
+
}
|
|
464
|
+
if (schemaConfig?.baseURL && currentRouteSchemaKey.startsWith(schemaConfig.baseURL)) currentRouteSchemaKey = currentRouteSchemaKey.replace(schemaConfig.baseURL, "");
|
|
465
|
+
return {
|
|
466
|
+
currentRouteSchemaKey,
|
|
467
|
+
mainInitURL
|
|
468
|
+
};
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
//#endregion
|
|
472
|
+
//#region src/url.ts
|
|
473
|
+
const slash = "/";
|
|
474
|
+
const colon = ":";
|
|
475
|
+
const openBrace = "{";
|
|
476
|
+
const closeBrace = "}";
|
|
477
|
+
const mergeUrlWithParams = (url, params) => {
|
|
478
|
+
if (!params) return url;
|
|
479
|
+
let newUrl = url;
|
|
480
|
+
if (isArray(params)) {
|
|
481
|
+
const matchedParamsArray = newUrl.split(slash).filter((part) => part.startsWith(colon) || part.startsWith(openBrace) && part.endsWith(closeBrace));
|
|
482
|
+
for (const [paramIndex, matchedParam] of matchedParamsArray.entries()) {
|
|
483
|
+
const stringParamValue = String(params[paramIndex]);
|
|
484
|
+
newUrl = newUrl.replace(matchedParam, stringParamValue);
|
|
485
|
+
}
|
|
486
|
+
return newUrl;
|
|
487
|
+
}
|
|
488
|
+
for (const [paramKey, paramValue] of Object.entries(params)) {
|
|
489
|
+
const colonPattern = `${colon}${paramKey}`;
|
|
490
|
+
const bracePattern = `${openBrace}${paramKey}${closeBrace}`;
|
|
491
|
+
const stringValue = String(paramValue);
|
|
492
|
+
newUrl = newUrl.replace(colonPattern, stringValue);
|
|
493
|
+
newUrl = newUrl.replace(bracePattern, stringValue);
|
|
494
|
+
}
|
|
495
|
+
return newUrl;
|
|
496
|
+
};
|
|
497
|
+
const questionMark = "?";
|
|
498
|
+
const ampersand = "&";
|
|
499
|
+
const mergeUrlWithQuery = (url, query) => {
|
|
500
|
+
if (!query) return url;
|
|
501
|
+
const queryString = toQueryString(query);
|
|
502
|
+
if (queryString?.length === 0) return url;
|
|
503
|
+
if (url.endsWith(questionMark)) return `${url}${queryString}`;
|
|
504
|
+
if (url.includes(questionMark)) return `${url}${ampersand}${queryString}`;
|
|
505
|
+
return `${url}${questionMark}${queryString}`;
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* @description Extracts the HTTP method from method-prefixed route patterns.
|
|
509
|
+
*
|
|
510
|
+
* Analyzes URLs that start with method modifiers (e.g., "@get/", "@post/") and extracts
|
|
511
|
+
* the HTTP method for use in API requests. This enables method specification directly
|
|
512
|
+
* in route definitions.
|
|
513
|
+
*
|
|
514
|
+
* @param initURL - The URL string to analyze for method modifiers
|
|
515
|
+
* @returns The extracted HTTP method (lowercase) if found, otherwise undefined
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* ```typescript
|
|
519
|
+
* // Method extraction from prefixed routes
|
|
520
|
+
* extractMethodFromURL("@get/users"); // Returns: "get"
|
|
521
|
+
* extractMethodFromURL("@post/users"); // Returns: "post"
|
|
522
|
+
* extractMethodFromURL("@put/users/:id"); // Returns: "put"
|
|
523
|
+
* extractMethodFromURL("@delete/users/:id"); // Returns: "delete"
|
|
524
|
+
* extractMethodFromURL("@patch/users/:id"); // Returns: "patch"
|
|
525
|
+
*
|
|
526
|
+
* // No method modifier
|
|
527
|
+
* extractMethodFromURL("/users"); // Returns: undefined
|
|
528
|
+
* extractMethodFromURL("users"); // Returns: undefined
|
|
529
|
+
*
|
|
530
|
+
* // Invalid or unsupported methods
|
|
531
|
+
* extractMethodFromURL("@invalid/users"); // Returns: undefined
|
|
532
|
+
* extractMethodFromURL("@/users"); // Returns: undefined
|
|
533
|
+
*
|
|
534
|
+
* // Edge cases
|
|
535
|
+
* extractMethodFromURL(undefined); // Returns: undefined
|
|
536
|
+
* extractMethodFromURL(""); // Returns: undefined
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
const extractMethodFromURL = (initURL) => {
|
|
540
|
+
if (!initURL?.startsWith("@")) return;
|
|
541
|
+
const method = initURL.split("@")[1]?.split("/")[0];
|
|
542
|
+
if (!method || !routeKeyMethods.includes(method)) return;
|
|
543
|
+
return method;
|
|
544
|
+
};
|
|
545
|
+
const normalizeURL = (initURL) => {
|
|
546
|
+
const methodFromURL = extractMethodFromURL(initURL);
|
|
547
|
+
if (!methodFromURL) return initURL;
|
|
548
|
+
return initURL.replace(`@${methodFromURL}/`, "/");
|
|
549
|
+
};
|
|
550
|
+
const getFullAndNormalizedURL = (options) => {
|
|
551
|
+
const { baseURL, initURL, params, query } = options;
|
|
552
|
+
const normalizedInitURL = normalizeURL(initURL);
|
|
553
|
+
const urlWithMergedQueryAndParams = mergeUrlWithQuery(mergeUrlWithParams(normalizedInitURL, params), query);
|
|
554
|
+
return {
|
|
555
|
+
fullURL: !urlWithMergedQueryAndParams.startsWith("http") && baseURL ? `${baseURL}${urlWithMergedQueryAndParams}` : urlWithMergedQueryAndParams,
|
|
556
|
+
normalizedInitURL
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
//#endregion
|
|
561
|
+
//#region src/utils/polyfills/combinedSignal.ts
|
|
562
|
+
const createCombinedSignalPolyfill = (signals) => {
|
|
563
|
+
const controller = new AbortController();
|
|
564
|
+
const handleAbort = (actualSignal) => {
|
|
565
|
+
if (controller.signal.aborted) return;
|
|
566
|
+
controller.abort(actualSignal.reason);
|
|
567
|
+
};
|
|
568
|
+
for (const actualSignal of signals) {
|
|
569
|
+
if (actualSignal.aborted) {
|
|
570
|
+
handleAbort(actualSignal);
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
actualSignal.addEventListener("abort", () => handleAbort(actualSignal), { signal: controller.signal });
|
|
574
|
+
}
|
|
575
|
+
return controller.signal;
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
//#endregion
|
|
579
|
+
//#region src/utils/polyfills/timeoutSignal.ts
|
|
580
|
+
const createTimeoutSignalPolyfill = (milliseconds) => {
|
|
581
|
+
const controller = new AbortController();
|
|
582
|
+
const reason = new DOMException("Request timed out", "TimeoutError");
|
|
583
|
+
const timeout = setTimeout(() => controller.abort(reason), milliseconds);
|
|
584
|
+
controller.signal.addEventListener("abort", () => clearTimeout(timeout));
|
|
585
|
+
return controller.signal;
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
//#endregion
|
|
589
|
+
//#region src/utils/common.ts
|
|
590
|
+
const omitKeys = (initialObject, keysToOmit) => {
|
|
591
|
+
const updatedObject = {};
|
|
592
|
+
const keysToOmitSet = new Set(keysToOmit);
|
|
593
|
+
for (const [key, value] of Object.entries(initialObject)) if (!keysToOmitSet.has(key)) updatedObject[key] = value;
|
|
594
|
+
return updatedObject;
|
|
595
|
+
};
|
|
596
|
+
const pickKeys = (initialObject, keysToPick) => {
|
|
597
|
+
const updatedObject = {};
|
|
598
|
+
const keysToPickSet = new Set(keysToPick);
|
|
599
|
+
for (const [key, value] of Object.entries(initialObject)) if (keysToPickSet.has(key)) updatedObject[key] = value;
|
|
600
|
+
return updatedObject;
|
|
601
|
+
};
|
|
602
|
+
const splitBaseConfig = (baseConfig) => [pickKeys(baseConfig, fetchSpecificKeys), omitKeys(baseConfig, fetchSpecificKeys)];
|
|
603
|
+
const splitConfig = (config) => [pickKeys(config, fetchSpecificKeys), omitKeys(config, fetchSpecificKeys)];
|
|
604
|
+
const objectifyHeaders = (headers) => {
|
|
605
|
+
if (!headers || isPlainObject(headers)) return headers;
|
|
606
|
+
return Object.fromEntries(headers);
|
|
607
|
+
};
|
|
608
|
+
const getHeaders = async (options) => {
|
|
609
|
+
const { auth, body, headers } = options;
|
|
610
|
+
if (!(Boolean(headers) || Boolean(body) || Boolean(auth))) return;
|
|
611
|
+
const headersObject = {
|
|
612
|
+
...await getAuthHeader(auth),
|
|
613
|
+
...objectifyHeaders(headers)
|
|
614
|
+
};
|
|
615
|
+
if (isQueryString(body)) {
|
|
616
|
+
headersObject["Content-Type"] = "application/x-www-form-urlencoded";
|
|
617
|
+
return headersObject;
|
|
618
|
+
}
|
|
619
|
+
if (isSerializable(body) || isValidJsonString(body)) {
|
|
620
|
+
headersObject["Content-Type"] = "application/json";
|
|
621
|
+
headersObject.Accept = "application/json";
|
|
622
|
+
}
|
|
623
|
+
return headersObject;
|
|
624
|
+
};
|
|
625
|
+
const getMethod = (ctx) => {
|
|
626
|
+
const { initURL, method } = ctx;
|
|
627
|
+
return method?.toUpperCase() ?? extractMethodFromURL(initURL)?.toUpperCase() ?? requestOptionDefaults.method;
|
|
628
|
+
};
|
|
629
|
+
const getBody = (options) => {
|
|
630
|
+
const { body, bodySerializer } = options;
|
|
631
|
+
if (isSerializable(body)) return (bodySerializer ?? extraOptionDefaults.bodySerializer)(body);
|
|
632
|
+
return body;
|
|
633
|
+
};
|
|
634
|
+
const getInitFetchImpl = (customFetchImpl) => {
|
|
635
|
+
if (customFetchImpl) return customFetchImpl;
|
|
636
|
+
if (typeof globalThis !== "undefined" && isFunction(globalThis.fetch)) return globalThis.fetch;
|
|
637
|
+
throw new Error("No fetch implementation found");
|
|
638
|
+
};
|
|
639
|
+
const getFetchImpl = (context) => {
|
|
640
|
+
const { customFetchImpl, fetchMiddleware, requestContext } = context;
|
|
641
|
+
const initFetchImpl = getInitFetchImpl(customFetchImpl);
|
|
642
|
+
return fetchMiddleware ? fetchMiddleware({
|
|
643
|
+
...requestContext,
|
|
644
|
+
fetchImpl: initFetchImpl
|
|
645
|
+
}) : initFetchImpl;
|
|
646
|
+
};
|
|
647
|
+
const PromiseWithResolvers = () => {
|
|
648
|
+
let reject;
|
|
649
|
+
let resolve;
|
|
650
|
+
return {
|
|
651
|
+
promise: new Promise((res, rej) => {
|
|
652
|
+
resolve = res;
|
|
653
|
+
reject = rej;
|
|
654
|
+
}),
|
|
655
|
+
reject,
|
|
656
|
+
resolve
|
|
657
|
+
};
|
|
658
|
+
};
|
|
659
|
+
const waitFor = (delay) => {
|
|
660
|
+
if (delay === 0) return;
|
|
661
|
+
const { promise, resolve } = PromiseWithResolvers();
|
|
662
|
+
setTimeout(resolve, delay);
|
|
663
|
+
return promise;
|
|
664
|
+
};
|
|
665
|
+
const createCombinedSignal = (...signals) => {
|
|
666
|
+
const cleanedSignals = signals.filter((signal) => signal != null);
|
|
667
|
+
if (!("any" in AbortSignal)) return createCombinedSignalPolyfill(cleanedSignals);
|
|
668
|
+
return AbortSignal.any(cleanedSignals);
|
|
669
|
+
};
|
|
670
|
+
const createTimeoutSignal = (milliseconds) => {
|
|
671
|
+
if (milliseconds == null) return null;
|
|
672
|
+
if (!("timeout" in AbortSignal)) return createTimeoutSignalPolyfill(milliseconds);
|
|
673
|
+
return AbortSignal.timeout(milliseconds);
|
|
674
|
+
};
|
|
675
|
+
const deterministicHashFn = (value) => {
|
|
676
|
+
return JSON.stringify(value, (_, val) => {
|
|
677
|
+
if (!isPlainObject(val)) return val;
|
|
678
|
+
const sortedKeys = Object.keys(val).toSorted();
|
|
679
|
+
const result = {};
|
|
680
|
+
for (const key of sortedKeys) result[key] = val[key];
|
|
681
|
+
return result;
|
|
682
|
+
});
|
|
683
|
+
};
|
|
684
|
+
const toArray = (value) => isArray(value) ? value : [value];
|
|
685
|
+
|
|
265
686
|
//#endregion
|
|
266
687
|
//#region src/dedupe.ts
|
|
267
688
|
const createDedupeStrategy = async (context) => {
|
|
@@ -272,16 +693,16 @@ const createDedupeStrategy = async (context) => {
|
|
|
272
693
|
if (!(resolvedDedupeStrategy === "cancel" || resolvedDedupeStrategy === "defer")) return null;
|
|
273
694
|
const dedupeKey$1 = globalOptions.dedupeKey ?? globalOptions.dedupe?.key;
|
|
274
695
|
const resolvedDedupeKey = isFunction(dedupeKey$1) ? dedupeKey$1(context) : dedupeKey$1;
|
|
275
|
-
if (resolvedDedupeKey
|
|
276
|
-
return `${globalOptions.fullURL}-${deterministicHashFn({
|
|
696
|
+
if (resolvedDedupeKey === void 0) return `${globalOptions.fullURL}-${deterministicHashFn({
|
|
277
697
|
options: globalOptions,
|
|
278
698
|
request: globalRequest
|
|
279
699
|
})}`;
|
|
700
|
+
return resolvedDedupeKey;
|
|
280
701
|
};
|
|
281
702
|
const getDedupeCacheScopeKey = () => {
|
|
282
|
-
const dedupeCacheScopeKey$1 = globalOptions.dedupeCacheScopeKey ?? globalOptions.dedupe?.cacheScopeKey
|
|
703
|
+
const dedupeCacheScopeKey$1 = globalOptions.dedupeCacheScopeKey ?? globalOptions.dedupe?.cacheScopeKey;
|
|
283
704
|
const resolvedDedupeCacheScopeKey = isFunction(dedupeCacheScopeKey$1) ? dedupeCacheScopeKey$1(context) : dedupeCacheScopeKey$1;
|
|
284
|
-
if (resolvedDedupeCacheScopeKey
|
|
705
|
+
if (resolvedDedupeCacheScopeKey === void 0) return extraOptionDefaults.dedupeCacheScopeKey;
|
|
285
706
|
return resolvedDedupeCacheScopeKey;
|
|
286
707
|
};
|
|
287
708
|
const dedupeKey = getDedupeKey();
|
|
@@ -595,8 +1016,7 @@ const createFetchClient = (initBaseConfig = {}) => {
|
|
|
595
1016
|
initURLNormalized: normalizedInitURL
|
|
596
1017
|
};
|
|
597
1018
|
const newFetchController = new AbortController();
|
|
598
|
-
const
|
|
599
|
-
const combinedSignal = createCombinedSignal(resolvedRequestOptions.signal, timeoutSignal, newFetchController.signal);
|
|
1019
|
+
const combinedSignal = createCombinedSignal(createTimeoutSignal(options.timeout), resolvedRequestOptions.signal, newFetchController.signal);
|
|
600
1020
|
const initMethod = getMethod({
|
|
601
1021
|
initURL: resolvedInitURL,
|
|
602
1022
|
method: resolvedRequestOptions.method
|