@gcmdev/faxios 0.1.0 → 0.2.1
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/LICENSE +1 -0
- package/README.md +40 -1774
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/adapters/fetch-helpers.d.ts +1 -0
- package/dist/lib/adapters/fetch-helpers.d.ts.map +1 -0
- package/dist/lib/adapters/fetch.d.ts +1 -0
- package/dist/lib/adapters/fetch.d.ts.map +1 -0
- package/dist/lib/adapters/fetch.js +23 -3
- package/dist/lib/adapters/fetch.js.map +1 -1
- package/dist/lib/cancel/CanceledError.d.ts +1 -0
- package/dist/lib/cancel/CanceledError.d.ts.map +1 -0
- package/dist/lib/cancel/isCancel.d.ts +3 -1
- package/dist/lib/cancel/isCancel.d.ts.map +1 -0
- package/dist/lib/cancel/isCancel.js +3 -0
- package/dist/lib/cancel/isCancel.js.map +1 -1
- package/dist/lib/core/Faxios.d.ts +6 -17
- package/dist/lib/core/Faxios.d.ts.map +1 -0
- package/dist/lib/core/Faxios.js +144 -76
- package/dist/lib/core/Faxios.js.map +1 -1
- package/dist/lib/core/FaxiosError.d.ts +19 -6
- package/dist/lib/core/FaxiosError.d.ts.map +1 -0
- package/dist/lib/core/FaxiosError.js +16 -1
- package/dist/lib/core/FaxiosError.js.map +1 -1
- package/dist/lib/core/FaxiosHeaders.d.ts +12 -8
- package/dist/lib/core/FaxiosHeaders.d.ts.map +1 -0
- package/dist/lib/core/FaxiosHeaders.js +1 -0
- package/dist/lib/core/FaxiosHeaders.js.map +1 -1
- package/dist/lib/core/buildFullPath.d.ts +1 -0
- package/dist/lib/core/buildFullPath.d.ts.map +1 -0
- package/dist/lib/core/define.d.ts +19 -2
- package/dist/lib/core/define.d.ts.map +1 -0
- package/dist/lib/core/define.js.map +1 -1
- package/dist/lib/core/dispatchRequest.d.ts +1 -0
- package/dist/lib/core/dispatchRequest.d.ts.map +1 -0
- package/dist/lib/core/dispatchRequest.js +4 -0
- package/dist/lib/core/dispatchRequest.js.map +1 -1
- package/dist/lib/core/mergeConfig.d.ts +1 -0
- package/dist/lib/core/mergeConfig.d.ts.map +1 -0
- package/dist/lib/core/prepareRequest.d.ts +1 -0
- package/dist/lib/core/prepareRequest.d.ts.map +1 -0
- package/dist/lib/core/prepareRequest.js +1 -20
- package/dist/lib/core/prepareRequest.js.map +1 -1
- package/dist/lib/core/route.d.ts +11 -2
- package/dist/lib/core/route.d.ts.map +1 -0
- package/dist/lib/core/route.js.map +1 -1
- package/dist/lib/core/settle.d.ts +1 -0
- package/dist/lib/core/settle.d.ts.map +1 -0
- package/dist/lib/core/transformData.d.ts +1 -0
- package/dist/lib/core/transformData.d.ts.map +1 -0
- package/dist/lib/core/validateSchema.d.ts +1 -0
- package/dist/lib/core/validateSchema.d.ts.map +1 -0
- package/dist/lib/defaults/index.d.ts +1 -0
- package/dist/lib/defaults/index.d.ts.map +1 -0
- package/dist/lib/defaults/index.js +3 -3
- package/dist/lib/defaults/index.js.map +1 -1
- package/dist/lib/defaults/transitional.d.ts +1 -1
- package/dist/lib/defaults/transitional.d.ts.map +1 -0
- package/dist/lib/defaults/transitional.js +0 -1
- package/dist/lib/defaults/transitional.js.map +1 -1
- package/dist/lib/env/data.d.ts +2 -1
- package/dist/lib/env/data.d.ts.map +1 -0
- package/dist/lib/env/data.js +1 -1
- package/dist/lib/env/data.js.map +1 -1
- package/dist/lib/faxios.d.ts +115 -48
- package/dist/lib/faxios.d.ts.map +1 -0
- package/dist/lib/faxios.js +14 -2
- package/dist/lib/faxios.js.map +1 -1
- package/dist/lib/helpers/FaxiosURLSearchParams.d.ts +3 -1
- package/dist/lib/helpers/FaxiosURLSearchParams.d.ts.map +1 -0
- package/dist/lib/helpers/FaxiosURLSearchParams.js.map +1 -1
- package/dist/lib/helpers/HttpStatusCode.d.ts +1 -0
- package/dist/lib/helpers/HttpStatusCode.d.ts.map +1 -0
- package/dist/lib/helpers/buildURL.d.ts +1 -0
- package/dist/lib/helpers/buildURL.d.ts.map +1 -0
- package/dist/lib/helpers/buildURL.js +7 -1
- package/dist/lib/helpers/buildURL.js.map +1 -1
- package/dist/lib/helpers/cloneConfig.d.ts +4 -0
- package/dist/lib/helpers/cloneConfig.d.ts.map +1 -0
- package/dist/lib/helpers/cloneConfig.js +21 -0
- package/dist/lib/helpers/cloneConfig.js.map +1 -0
- package/dist/lib/helpers/combineURLs.d.ts +1 -0
- package/dist/lib/helpers/combineURLs.d.ts.map +1 -0
- package/dist/lib/helpers/composeSignals.d.ts +1 -0
- package/dist/lib/helpers/composeSignals.d.ts.map +1 -0
- package/dist/lib/helpers/composeSignals.js +8 -1
- package/dist/lib/helpers/composeSignals.js.map +1 -1
- package/dist/lib/helpers/cookies.d.ts +1 -0
- package/dist/lib/helpers/cookies.d.ts.map +1 -0
- package/dist/lib/helpers/estimateDataURLDecodedBytes.d.ts +1 -0
- package/dist/lib/helpers/estimateDataURLDecodedBytes.d.ts.map +1 -0
- package/dist/lib/helpers/formDataToJSON.d.ts +1 -0
- package/dist/lib/helpers/formDataToJSON.d.ts.map +1 -0
- package/dist/lib/helpers/isAbsoluteURL.d.ts +1 -0
- package/dist/lib/helpers/isAbsoluteURL.d.ts.map +1 -0
- package/dist/lib/helpers/isFaxiosError.d.ts +8 -2
- package/dist/lib/helpers/isFaxiosError.d.ts.map +1 -0
- package/dist/lib/helpers/isFaxiosError.js +5 -1
- package/dist/lib/helpers/isFaxiosError.js.map +1 -1
- package/dist/lib/helpers/isURLSameOrigin.d.ts +1 -0
- package/dist/lib/helpers/isURLSameOrigin.d.ts.map +1 -0
- package/dist/lib/helpers/parseHeaders.d.ts +1 -0
- package/dist/lib/helpers/parseHeaders.d.ts.map +1 -0
- package/dist/lib/helpers/progressEventReducer.d.ts +1 -0
- package/dist/lib/helpers/progressEventReducer.d.ts.map +1 -0
- package/dist/lib/helpers/sanitizeHeaderValue.d.ts +1 -0
- package/dist/lib/helpers/sanitizeHeaderValue.d.ts.map +1 -0
- package/dist/lib/helpers/speedometer.d.ts +1 -0
- package/dist/lib/helpers/speedometer.d.ts.map +1 -0
- package/dist/lib/helpers/substitutePathParams.d.ts +1 -0
- package/dist/lib/helpers/substitutePathParams.d.ts.map +1 -0
- package/dist/lib/helpers/throttle.d.ts +1 -0
- package/dist/lib/helpers/throttle.d.ts.map +1 -0
- package/dist/lib/helpers/toFormData.d.ts +1 -0
- package/dist/lib/helpers/toFormData.d.ts.map +1 -0
- package/dist/lib/helpers/toURLEncodedForm.d.ts +1 -0
- package/dist/lib/helpers/toURLEncodedForm.d.ts.map +1 -0
- package/dist/lib/helpers/trackStream.d.ts +1 -0
- package/dist/lib/helpers/trackStream.d.ts.map +1 -0
- package/dist/lib/helpers/validator.d.ts +1 -0
- package/dist/lib/helpers/validator.d.ts.map +1 -0
- package/dist/lib/platform.d.ts +2 -1
- package/dist/lib/platform.d.ts.map +1 -0
- package/dist/lib/plugins/attempt.d.ts +2 -0
- package/dist/lib/plugins/attempt.d.ts.map +1 -0
- package/dist/lib/plugins/attempt.js +4 -0
- package/dist/lib/plugins/attempt.js.map +1 -0
- package/dist/lib/plugins/authBearer.d.ts +31 -0
- package/dist/lib/plugins/authBearer.d.ts.map +1 -0
- package/dist/lib/plugins/authBearer.js +99 -0
- package/dist/lib/plugins/authBearer.js.map +1 -0
- package/dist/lib/plugins/definePlugin.d.ts +22 -0
- package/dist/lib/plugins/definePlugin.d.ts.map +1 -0
- package/dist/lib/plugins/definePlugin.js +14 -0
- package/dist/lib/plugins/definePlugin.js.map +1 -0
- package/dist/lib/plugins/retry.d.ts +66 -0
- package/dist/lib/plugins/retry.d.ts.map +1 -0
- package/dist/lib/plugins/retry.js +168 -0
- package/dist/lib/plugins/retry.js.map +1 -0
- package/dist/lib/plugins/timing.d.ts +32 -0
- package/dist/lib/plugins/timing.d.ts.map +1 -0
- package/dist/lib/plugins/timing.js +53 -0
- package/dist/lib/plugins/timing.js.map +1 -0
- package/dist/lib/types/standard-schema.d.ts +1 -0
- package/dist/lib/types/standard-schema.d.ts.map +1 -0
- package/dist/lib/types.d.ts +125 -34
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/package.json +42 -19
- package/skills/configure-requests/SKILL.md +380 -0
- package/skills/configure-requests/references/axios-differences.md +67 -0
- package/skills/configure-requests/references/plugins.md +127 -0
- package/src/index.ts +57 -0
- package/src/lib/adapters/fetch-helpers.ts +167 -0
- package/src/lib/adapters/fetch.ts +810 -0
- package/src/lib/cancel/CanceledError.ts +23 -0
- package/src/lib/cancel/isCancel.ts +10 -0
- package/src/lib/core/Faxios.ts +513 -0
- package/src/lib/core/FaxiosError.ts +283 -0
- package/src/lib/core/FaxiosHeaders.ts +529 -0
- package/src/lib/core/buildFullPath.ts +51 -0
- package/src/lib/core/define.ts +127 -0
- package/src/lib/core/dispatchRequest.ts +171 -0
- package/src/lib/core/mergeConfig.ts +175 -0
- package/src/lib/core/prepareRequest.ts +155 -0
- package/src/lib/core/route.ts +68 -0
- package/src/lib/core/settle.ts +20 -0
- package/src/lib/core/transformData.ts +23 -0
- package/src/lib/core/validateSchema.ts +53 -0
- package/src/lib/defaults/index.ts +221 -0
- package/src/lib/defaults/transitional.ts +9 -0
- package/src/lib/env/data.ts +1 -0
- package/src/lib/faxios.ts +306 -0
- package/src/lib/helpers/FaxiosURLSearchParams.ts +52 -0
- package/src/lib/helpers/HttpStatusCode.ts +77 -0
- package/src/lib/helpers/buildURL.ts +77 -0
- package/src/lib/helpers/cloneConfig.ts +23 -0
- package/src/lib/helpers/combineURLs.ts +11 -0
- package/src/lib/helpers/composeSignals.ts +74 -0
- package/src/lib/helpers/cookies.ts +68 -0
- package/src/lib/helpers/deprecatedMethod.ts +32 -0
- package/src/lib/helpers/estimateDataURLDecodedBytes.ts +95 -0
- package/src/lib/helpers/formDataToJSON.ts +122 -0
- package/src/lib/helpers/isAbsoluteURL.ts +13 -0
- package/src/lib/helpers/isFaxiosError.ts +19 -0
- package/src/lib/helpers/isURLSameOrigin.ts +16 -0
- package/src/lib/helpers/parseHeaders.ts +76 -0
- package/src/lib/helpers/progressEventReducer.ts +57 -0
- package/src/lib/helpers/sanitizeHeaderValue.ts +61 -0
- package/src/lib/helpers/speedometer.ts +55 -0
- package/src/lib/helpers/substitutePathParams.ts +13 -0
- package/src/lib/helpers/throttle.ts +45 -0
- package/src/lib/helpers/toFormData.ts +296 -0
- package/src/lib/helpers/toURLEncodedForm.ts +14 -0
- package/src/lib/helpers/trackStream.ts +123 -0
- package/src/lib/helpers/validator.ts +114 -0
- package/src/lib/platform.ts +44 -0
- package/src/lib/plugins/attempt.ts +3 -0
- package/src/lib/plugins/authBearer.ts +124 -0
- package/src/lib/plugins/definePlugin.ts +34 -0
- package/src/lib/plugins/retry.ts +245 -0
- package/src/lib/plugins/timing.ts +76 -0
- package/src/lib/types/standard-schema.ts +58 -0
- package/src/lib/types.ts +496 -0
- package/src/lib/utils.ts +932 -0
- package/dist/lib/core/InterceptorManager.d.ts +0 -9
- package/dist/lib/core/InterceptorManager.js +0 -28
- package/dist/lib/core/InterceptorManager.js.map +0 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import FaxiosError from "../core/FaxiosError.js";
|
|
4
|
+
import type { FaxiosRequestConfig, InternalFaxiosRequestConfig } from "../types.js";
|
|
5
|
+
|
|
6
|
+
class CanceledError extends FaxiosError {
|
|
7
|
+
/**
|
|
8
|
+
* A `CanceledError` is an object that is thrown when an operation is canceled.
|
|
9
|
+
*
|
|
10
|
+
* @param {string=} message The message.
|
|
11
|
+
* @param {Object=} config The config.
|
|
12
|
+
* @param {Object=} request The request.
|
|
13
|
+
*
|
|
14
|
+
* @returns {CanceledError} The created error.
|
|
15
|
+
*/
|
|
16
|
+
constructor(message?: string | null, config?: FaxiosRequestConfig, request?: unknown) {
|
|
17
|
+
super(message == null ? "canceled" : message, FaxiosError.ERR_CANCELED, config as InternalFaxiosRequestConfig, request);
|
|
18
|
+
this.name = "CanceledError";
|
|
19
|
+
(this as unknown as Record<string, unknown>)["__CANCEL__"] = true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default CanceledError;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import type CanceledError from "./CanceledError.js";
|
|
4
|
+
|
|
5
|
+
// Checks the `__CANCEL__` flag CanceledError sets, not `instanceof`, so
|
|
6
|
+
// cancellations from another copy of faxios still match. The flag is a plain
|
|
7
|
+
// writable property, so any object carrying it is narrowed.
|
|
8
|
+
export default function isCancel(value: unknown): value is CanceledError {
|
|
9
|
+
return !!(value && (value as Record<string, unknown>).__CANCEL__);
|
|
10
|
+
}
|
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import CanceledError from "../cancel/CanceledError.js";
|
|
4
|
+
import buildURL from "../helpers/buildURL.js";
|
|
5
|
+
import cloneConfig, { DANGEROUS_KEYS } from "../helpers/cloneConfig.js";
|
|
6
|
+
import validator from "../helpers/validator.js";
|
|
7
|
+
import type { ValidatorFn } from "../helpers/validator.js";
|
|
8
|
+
import type { StandardSchemaV1 } from "../types/standard-schema.js";
|
|
9
|
+
import type {
|
|
10
|
+
FaxiosContext,
|
|
11
|
+
FaxiosMiddleware,
|
|
12
|
+
FaxiosNext,
|
|
13
|
+
FaxiosPluginArgument,
|
|
14
|
+
FaxiosRequestConfig,
|
|
15
|
+
FaxiosRequestHeaders,
|
|
16
|
+
FaxiosResponse,
|
|
17
|
+
GenericAbortSignal,
|
|
18
|
+
HeadersDefaults,
|
|
19
|
+
InternalFaxiosRequestConfig,
|
|
20
|
+
Method,
|
|
21
|
+
SchemaConfig,
|
|
22
|
+
StringLiteralsOrString
|
|
23
|
+
} from "../types.js";
|
|
24
|
+
import utils from "../utils.js";
|
|
25
|
+
import buildFullPath from "./buildFullPath.js";
|
|
26
|
+
import { createDefinedEndpoint } from "./define.js";
|
|
27
|
+
import type { DefineConfig, DefinedEndpoint } from "./define.js";
|
|
28
|
+
import dispatchRequest from "./dispatchRequest.js";
|
|
29
|
+
import FaxiosError from "./FaxiosError.js";
|
|
30
|
+
import FaxiosHeaders from "./FaxiosHeaders.js";
|
|
31
|
+
import mergeConfig from "./mergeConfig.js";
|
|
32
|
+
import type { RouteConfig, RouteBuilder } from "./route.js";
|
|
33
|
+
import { createRouteBuilder } from "./route.js";
|
|
34
|
+
|
|
35
|
+
type TransitionalFn = (
|
|
36
|
+
validator: ValidatorFn | false | undefined,
|
|
37
|
+
version?: string,
|
|
38
|
+
message?: string
|
|
39
|
+
) => ValidatorFn;
|
|
40
|
+
type SpellingFn = (correctSpelling: string) => ValidatorFn;
|
|
41
|
+
const validators = validator.validators as Record<
|
|
42
|
+
string,
|
|
43
|
+
ValidatorFn | undefined
|
|
44
|
+
> & {
|
|
45
|
+
transitional?: TransitionalFn;
|
|
46
|
+
spelling?: SpellingFn;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Every method header group declared on HeadersDefaults. `satisfies` keeps this
|
|
50
|
+
// list exhaustive, so a group the types accept can never reach the wire.
|
|
51
|
+
const METHOD_HEADER_GROUPS = Object.keys({
|
|
52
|
+
common: true,
|
|
53
|
+
delete: true,
|
|
54
|
+
get: true,
|
|
55
|
+
head: true,
|
|
56
|
+
options: true,
|
|
57
|
+
post: true,
|
|
58
|
+
put: true,
|
|
59
|
+
patch: true,
|
|
60
|
+
purge: true,
|
|
61
|
+
link: true,
|
|
62
|
+
unlink: true,
|
|
63
|
+
query: true,
|
|
64
|
+
} satisfies Record<keyof HeadersDefaults, true>) as Array<keyof HeadersDefaults>;
|
|
65
|
+
|
|
66
|
+
function patchErrorStack(err: Error): void {
|
|
67
|
+
let dummy: { stack?: string; } = {};
|
|
68
|
+
// captureStackTrace is V8-only (Node, Chromium); fall back elsewhere.
|
|
69
|
+
const captureStackTrace = (Error as { captureStackTrace?: (target: object) => void; }).captureStackTrace;
|
|
70
|
+
if (captureStackTrace) {
|
|
71
|
+
captureStackTrace(dummy);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
dummy = new Error();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const rawStack = dummy.stack ?? "";
|
|
78
|
+
const firstNewline = rawStack.indexOf("\n");
|
|
79
|
+
// slice off the Error: ... line
|
|
80
|
+
const stack = firstNewline === -1 ? "" : rawStack.slice(firstNewline + 1);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
if (!err.stack) {
|
|
84
|
+
err.stack = stack;
|
|
85
|
+
// match without the 2 top stack lines
|
|
86
|
+
}
|
|
87
|
+
else if (stack) {
|
|
88
|
+
const firstNewlineIndex = stack.indexOf("\n");
|
|
89
|
+
const secondNewlineIndex =
|
|
90
|
+
firstNewlineIndex === -1
|
|
91
|
+
? -1
|
|
92
|
+
: stack.indexOf("\n", firstNewlineIndex + 1);
|
|
93
|
+
const stackWithoutTwoTopLines =
|
|
94
|
+
secondNewlineIndex === -1
|
|
95
|
+
? ""
|
|
96
|
+
: stack.slice(secondNewlineIndex + 1);
|
|
97
|
+
|
|
98
|
+
if (!String(err.stack).endsWith(stackWithoutTwoTopLines)) {
|
|
99
|
+
err.stack += "\n" + stack;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// ignore the case where "stack" is an un-writable property
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function normalizeParamsSerializer(config: FaxiosRequestConfig): void {
|
|
109
|
+
const { paramsSerializer } = config;
|
|
110
|
+
if (paramsSerializer == null) return;
|
|
111
|
+
|
|
112
|
+
if (utils.isFunction(paramsSerializer)) {
|
|
113
|
+
config.paramsSerializer = {
|
|
114
|
+
serialize: paramsSerializer as (
|
|
115
|
+
params: Record<string, unknown>
|
|
116
|
+
) => string,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
validator.assertOptions(
|
|
121
|
+
paramsSerializer,
|
|
122
|
+
{
|
|
123
|
+
encode: validators.function!,
|
|
124
|
+
serialize: validators.function!,
|
|
125
|
+
},
|
|
126
|
+
true
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function resolveAllowAbsoluteUrls(
|
|
132
|
+
config: FaxiosRequestConfig,
|
|
133
|
+
defaults: FaxiosRequestConfig
|
|
134
|
+
): void {
|
|
135
|
+
if (config.allowAbsoluteUrls === undefined) {
|
|
136
|
+
config.allowAbsoluteUrls = defaults.allowAbsoluteUrls ?? !defaults.baseURL;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// The registry is untyped: each entry was checked against its instance's options and capabilities
|
|
141
|
+
// when use() accepted it, and the runtime only forwards contexts between entries.
|
|
142
|
+
type AnyContextMiddleware = FaxiosMiddleware<unknown, unknown>;
|
|
143
|
+
type AnyContextNext = FaxiosNext<unknown, unknown>;
|
|
144
|
+
|
|
145
|
+
type MiddlewareEntry = {
|
|
146
|
+
// The value passed to use(), kept only for eject()'s identity check.
|
|
147
|
+
ref: unknown;
|
|
148
|
+
run: AnyContextMiddleware;
|
|
149
|
+
provided: Array<string>;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
function composeMiddleware(entries: ReadonlyArray<MiddlewareEntry>, dispatch: AnyContextNext): AnyContextNext {
|
|
153
|
+
// Plain closures, no async wrapper: a middleware that calls next() before awaiting reaches the
|
|
154
|
+
// adapter in the same tick, exactly as a request without middleware does.
|
|
155
|
+
return entries.reduceRight<AnyContextNext>((next, entry) => ctx => entry.run(ctx, next), dispatch);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Each dispatch works on its own copy, so dispatch's in-place writes (path-param substitution,
|
|
159
|
+
// transformRequest, schema output, header normalization) never reach ctx.config, and a middleware
|
|
160
|
+
// that calls next() again starts from the same input.
|
|
161
|
+
function copyForDispatch(config: InternalFaxiosRequestConfig): InternalFaxiosRequestConfig {
|
|
162
|
+
const copy = cloneConfig(config);
|
|
163
|
+
copy.headers = new FaxiosHeaders(config.headers) as unknown as FaxiosRequestHeaders;
|
|
164
|
+
return copy;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Middleware is caller code that may await anything, so the caller's abort settles the request
|
|
168
|
+
// right away instead of waiting for it. Dispatch still checks the signal before the adapter call,
|
|
169
|
+
// so nothing is sent after an abort either way. An already-aborted request runs no middleware.
|
|
170
|
+
function settleOnAbort(
|
|
171
|
+
run: () => Promise<FaxiosResponse>,
|
|
172
|
+
signal: AbortSignal | GenericAbortSignal,
|
|
173
|
+
config: InternalFaxiosRequestConfig
|
|
174
|
+
): Promise<FaxiosResponse> {
|
|
175
|
+
if (signal.aborted) return Promise.reject(new CanceledError(null, config));
|
|
176
|
+
const { addEventListener: add, removeEventListener: remove } = signal;
|
|
177
|
+
if (typeof add !== "function") return run();
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
const stop = () => remove?.call(signal, "abort", onAbort);
|
|
180
|
+
function onAbort() {
|
|
181
|
+
stop();
|
|
182
|
+
reject(new CanceledError(null, config));
|
|
183
|
+
}
|
|
184
|
+
// Listen before running: middleware may abort the signal before its first await.
|
|
185
|
+
add.call(signal, "abort", onAbort);
|
|
186
|
+
// The executor calls run() right away and turns a synchronous throw into a rejection, which
|
|
187
|
+
// Promise.resolve(run()) wouldn't, and .then(run) would delay dispatch by a tick.
|
|
188
|
+
// eslint-disable-next-line sonarjs/prefer-promise-shorthand -- see above
|
|
189
|
+
const pending = new Promise<FaxiosResponse>(_resolve => {
|
|
190
|
+
_resolve(run());
|
|
191
|
+
});
|
|
192
|
+
// Once the abort has settled the request, this result has nowhere to go; the handlers below
|
|
193
|
+
// still consume it, so it never becomes an unhandled rejection.
|
|
194
|
+
pending.finally(stop).then(resolve)
|
|
195
|
+
.catch(reject);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Middleware registration isn't a Faxios member: the callable instance from create() reaches it
|
|
200
|
+
// through these, and its FaxiosInstance["use"] is the one place plugins are typed and checked.
|
|
201
|
+
// The registry itself is untyped, so the class has nothing to type-check against.
|
|
202
|
+
let useMiddleware!: (faxios: Faxios, middleware: AnyContextMiddleware | FaxiosPluginArgument) => void;
|
|
203
|
+
let ejectMiddleware!: (faxios: Faxios, middleware: unknown) => void;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Create a new instance of Faxios
|
|
207
|
+
*
|
|
208
|
+
* @param {Object} instanceConfig The default config for the instance
|
|
209
|
+
*
|
|
210
|
+
* @return {Faxios} A new instance of Faxios
|
|
211
|
+
*/
|
|
212
|
+
class Faxios {
|
|
213
|
+
defaults: FaxiosRequestConfig;
|
|
214
|
+
#middleware: ReadonlyArray<MiddlewareEntry> = [];
|
|
215
|
+
// Middleware and capabilities are replaced, never mutated, on use()/eject(): a request keeps the
|
|
216
|
+
// snapshot it started with, and composes nothing per call.
|
|
217
|
+
#composed: AnyContextNext | null = null;
|
|
218
|
+
#capabilities: Record<string, unknown> = Object.create(null);
|
|
219
|
+
|
|
220
|
+
constructor(instanceConfig?: FaxiosRequestConfig) {
|
|
221
|
+
this.defaults = instanceConfig || {};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
static {
|
|
225
|
+
useMiddleware = (faxios, middleware) => {
|
|
226
|
+
faxios.#use(middleware);
|
|
227
|
+
};
|
|
228
|
+
ejectMiddleware = (faxios, middleware) => {
|
|
229
|
+
faxios.#eject(middleware);
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Middleware runs in registration order before dispatch and in reverse order after it.
|
|
234
|
+
#use(middleware: AnyContextMiddleware | FaxiosPluginArgument): void {
|
|
235
|
+
const plugin = typeof middleware === "function" ? null : middleware;
|
|
236
|
+
// Plugins are caller objects: only their own fields count, so a polluted Object.prototype
|
|
237
|
+
// can't supply middleware or capabilities (THREATMODEL T-R4b).
|
|
238
|
+
const own = <K extends keyof FaxiosPluginArgument>(key: K) =>
|
|
239
|
+
(plugin && utils.hasOwnProp(plugin, key) ? plugin[key] : undefined);
|
|
240
|
+
const run = plugin ? own("middleware") : middleware;
|
|
241
|
+
if (typeof run !== "function") {
|
|
242
|
+
throw new FaxiosError("use() expects a middleware function or a plugin with a middleware function", FaxiosError.ERR_BAD_OPTION_VALUE);
|
|
243
|
+
}
|
|
244
|
+
const name = own("name");
|
|
245
|
+
if (plugin && (typeof name !== "string" || name === "")) {
|
|
246
|
+
throw new FaxiosError("use() expects a plugin's own name to be a non-empty string", FaxiosError.ERR_BAD_OPTION_VALUE);
|
|
247
|
+
}
|
|
248
|
+
const provides = own("provides");
|
|
249
|
+
const provided = provides == null ? [] : this.#addCapabilities(String(name), provides);
|
|
250
|
+
this.#setMiddleware([ ...this.#middleware, { ref: middleware, run, provided }]);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Removes middleware or a plugin registered with use(), by reference. In-flight requests keep
|
|
254
|
+
// the snapshot they started with.
|
|
255
|
+
#eject(middleware: unknown): void {
|
|
256
|
+
const index = this.#middleware.findIndex(entry => entry.ref === middleware);
|
|
257
|
+
if (index === -1) return;
|
|
258
|
+
const capabilities = Object.assign(Object.create(null) as Record<string, unknown>, this.#capabilities);
|
|
259
|
+
for (const key of this.#middleware[index]!.provided) {
|
|
260
|
+
delete capabilities[key];
|
|
261
|
+
}
|
|
262
|
+
this.#capabilities = capabilities;
|
|
263
|
+
this.#setMiddleware(this.#middleware.filter((_, i) => i !== index));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
#setMiddleware(entries: ReadonlyArray<MiddlewareEntry>): void {
|
|
267
|
+
this.#middleware = entries;
|
|
268
|
+
this.#composed = entries.length === 0
|
|
269
|
+
? null
|
|
270
|
+
: composeMiddleware(entries, ctx => dispatchRequest(copyForDispatch(ctx.config)));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
#addCapabilities(pluginName: string, provides: unknown): Array<string> {
|
|
274
|
+
const source = provides as Record<string, unknown>;
|
|
275
|
+
const keys = Object.keys(source).filter(key => !DANGEROUS_KEYS.has(key));
|
|
276
|
+
for (const key of keys) {
|
|
277
|
+
if (utils.hasOwnProp(this.#capabilities, key)) {
|
|
278
|
+
throw new FaxiosError(`Plugin "${pluginName}" provides capability "${key}", which another plugin already provides`, FaxiosError.ERR_BAD_OPTION);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
this.#capabilities = Object.assign(Object.create(null) as Record<string, unknown>, this.#capabilities);
|
|
282
|
+
for (const key of keys) {
|
|
283
|
+
this.#capabilities[key] = source[key];
|
|
284
|
+
}
|
|
285
|
+
return keys;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Dispatch a request
|
|
290
|
+
*
|
|
291
|
+
* @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)
|
|
292
|
+
* @param {?Object} config
|
|
293
|
+
*
|
|
294
|
+
* @returns {Promise} The Promise to be fulfilled
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
async request<O, D = unknown>(config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
298
|
+
async request<T = unknown, R = FaxiosResponse<T>, D = unknown>(configOrUrl: string | FaxiosRequestConfig<D>, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
299
|
+
async request(
|
|
300
|
+
configOrUrl: string | FaxiosRequestConfig,
|
|
301
|
+
config?: FaxiosRequestConfig
|
|
302
|
+
) {
|
|
303
|
+
try {
|
|
304
|
+
return await this.#request(configOrUrl, config);
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
if (err instanceof Error) {
|
|
308
|
+
patchErrorStack(err);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async #request(
|
|
316
|
+
configOrUrl: string | FaxiosRequestConfig,
|
|
317
|
+
config?: FaxiosRequestConfig
|
|
318
|
+
): Promise<unknown> {
|
|
319
|
+
/*eslint no-param-reassign:0*/
|
|
320
|
+
// Allow for faxios('example/url'[, config]) a la fetch API
|
|
321
|
+
if (typeof configOrUrl === "string") {
|
|
322
|
+
config = config || {};
|
|
323
|
+
config.url = configOrUrl;
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
config = configOrUrl;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
config = mergeConfig(this.defaults, config);
|
|
330
|
+
|
|
331
|
+
const { transitional, headers } = config;
|
|
332
|
+
|
|
333
|
+
if (transitional !== undefined) {
|
|
334
|
+
validator.assertOptions(
|
|
335
|
+
transitional,
|
|
336
|
+
{
|
|
337
|
+
silentJSONParsing: validators.transitional!(validators.boolean),
|
|
338
|
+
forcedJSONParsing: validators.transitional!(validators.boolean),
|
|
339
|
+
clarifyTimeoutError: validators.transitional!(validators.boolean),
|
|
340
|
+
advertiseZstdAcceptEncoding: validators.transitional!(
|
|
341
|
+
validators.boolean
|
|
342
|
+
),
|
|
343
|
+
validateStatusUndefinedResolves: validators.transitional!(
|
|
344
|
+
validators.boolean
|
|
345
|
+
),
|
|
346
|
+
},
|
|
347
|
+
false
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
normalizeParamsSerializer(config);
|
|
352
|
+
resolveAllowAbsoluteUrls(config, this.defaults);
|
|
353
|
+
|
|
354
|
+
validator.assertOptions(
|
|
355
|
+
config,
|
|
356
|
+
{
|
|
357
|
+
baseUrl: validators.spelling!("baseURL"),
|
|
358
|
+
withXsrfToken: validators.spelling!("withXSRFToken"),
|
|
359
|
+
},
|
|
360
|
+
true
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
// Set config.method
|
|
364
|
+
config.method = (
|
|
365
|
+
(config.method || this.defaults.method || "get") as string
|
|
366
|
+
).toLowerCase();
|
|
367
|
+
|
|
368
|
+
// Flatten headers
|
|
369
|
+
// Every FaxiosConfigHeaders member is a string-keyed object, so this is a
|
|
370
|
+
// checked widening, not an assertion: mergeConfig spreads a top-level
|
|
371
|
+
// FaxiosHeaders, and method header groups are typed as plain header bags.
|
|
372
|
+
const h: Record<string, unknown> | undefined = headers;
|
|
373
|
+
let contextHeaders = h && utils.merge(h.common, h[config.method]);
|
|
374
|
+
|
|
375
|
+
if (h) {
|
|
376
|
+
for (const group of METHOD_HEADER_GROUPS) {
|
|
377
|
+
delete h[group];
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
config.headers = FaxiosHeaders.concat(
|
|
382
|
+
contextHeaders,
|
|
383
|
+
...(h ? [ h as unknown as null ] : [])
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
const composed = this.#composed;
|
|
387
|
+
if (!composed) return dispatchRequest(config as InternalFaxiosRequestConfig);
|
|
388
|
+
|
|
389
|
+
const ctx: FaxiosContext = {
|
|
390
|
+
config: config as InternalFaxiosRequestConfig,
|
|
391
|
+
state: Object.create(null),
|
|
392
|
+
capabilities: this.#capabilities,
|
|
393
|
+
};
|
|
394
|
+
const signal = utils.hasOwnProp(config, "signal") ? config.signal : undefined;
|
|
395
|
+
return signal ? settleOnAbort(() => composed(ctx), signal, ctx.config) : composed(ctx);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
get<O, D = unknown>(url: string, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
399
|
+
get<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
400
|
+
get(url: string, config?: FaxiosRequestConfig) {
|
|
401
|
+
return this.request(mergeConfig(config || {}, {
|
|
402
|
+
method: "get",
|
|
403
|
+
url,
|
|
404
|
+
data: config && utils.hasOwnProp(config, "data") ? config.data : undefined,
|
|
405
|
+
}));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
delete<O, D = unknown>(url: string, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
409
|
+
delete<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
410
|
+
delete(url: string, config?: FaxiosRequestConfig) {
|
|
411
|
+
return this.request(mergeConfig(config || {}, {
|
|
412
|
+
method: "delete",
|
|
413
|
+
url,
|
|
414
|
+
data: config && utils.hasOwnProp(config, "data") ? config.data : undefined,
|
|
415
|
+
}));
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
head<O, D = unknown>(url: string, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
419
|
+
head<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
420
|
+
head(url: string, config?: FaxiosRequestConfig) {
|
|
421
|
+
return this.request(mergeConfig(config || {}, {
|
|
422
|
+
method: "head",
|
|
423
|
+
url,
|
|
424
|
+
data: config && utils.hasOwnProp(config, "data") ? config.data : undefined,
|
|
425
|
+
}));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
options<O, D = unknown>(url: string, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
429
|
+
options<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
430
|
+
options(url: string, config?: FaxiosRequestConfig) {
|
|
431
|
+
return this.request(mergeConfig(config || {}, {
|
|
432
|
+
method: "options",
|
|
433
|
+
url,
|
|
434
|
+
data: config && utils.hasOwnProp(config, "data") ? config.data : undefined,
|
|
435
|
+
}));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
post<O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
439
|
+
post<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
440
|
+
post(url: string, data?: unknown, config?: FaxiosRequestConfig) {
|
|
441
|
+
return this.request(mergeConfig(config || {}, { method: "post", headers: {}, url, data }));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
postForm<O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
445
|
+
postForm<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
446
|
+
postForm(url: string, data?: unknown, config?: FaxiosRequestConfig) {
|
|
447
|
+
return this.request(mergeConfig(config || {}, { method: "post", headers: { "Content-Type": "multipart/form-data" }, url, data }));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
put<O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
451
|
+
put<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
452
|
+
put(url: string, data?: unknown, config?: FaxiosRequestConfig) {
|
|
453
|
+
return this.request(mergeConfig(config || {}, { method: "put", headers: {}, url, data }));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
putForm<O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
457
|
+
putForm<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
458
|
+
putForm(url: string, data?: unknown, config?: FaxiosRequestConfig) {
|
|
459
|
+
return this.request(mergeConfig(config || {}, { method: "put", headers: { "Content-Type": "multipart/form-data" }, url, data }));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
patch<O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
463
|
+
patch<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
464
|
+
patch(url: string, data?: unknown, config?: FaxiosRequestConfig) {
|
|
465
|
+
return this.request(mergeConfig(config || {}, { method: "patch", headers: {}, url, data }));
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
patchForm<O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
469
|
+
patchForm<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
470
|
+
patchForm(url: string, data?: unknown, config?: FaxiosRequestConfig) {
|
|
471
|
+
return this.request(mergeConfig(config || {}, { method: "patch", headers: { "Content-Type": "multipart/form-data" }, url, data }));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
query<O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
|
|
475
|
+
query<T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D>): Promise<R>;
|
|
476
|
+
query(url: string, data?: unknown, config?: FaxiosRequestConfig) {
|
|
477
|
+
return this.request(mergeConfig(config || {}, { method: "query", headers: {}, url, data }));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
getUri(config?: FaxiosRequestConfig) {
|
|
481
|
+
config = mergeConfig(this.defaults, config);
|
|
482
|
+
const fullPath = buildFullPath(
|
|
483
|
+
config.baseURL,
|
|
484
|
+
config.url,
|
|
485
|
+
config.allowAbsoluteUrls,
|
|
486
|
+
config
|
|
487
|
+
);
|
|
488
|
+
return buildURL(fullPath, config.params, config.paramsSerializer);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
define<
|
|
492
|
+
PP extends StandardSchemaV1<unknown, Record<string, unknown>> | undefined = undefined,
|
|
493
|
+
P extends StandardSchemaV1 | undefined = undefined,
|
|
494
|
+
D extends StandardSchemaV1 | undefined = undefined,
|
|
495
|
+
R extends StandardSchemaV1 | undefined = undefined
|
|
496
|
+
>(
|
|
497
|
+
method: StringLiteralsOrString<Method>,
|
|
498
|
+
url: string,
|
|
499
|
+
config?: DefineConfig<PP, P, D, R>
|
|
500
|
+
): DefinedEndpoint<PP, P, D, R> {
|
|
501
|
+
return createDefinedEndpoint(this, method, url, config);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
route<PP extends StandardSchemaV1<unknown, Record<string, unknown>> | undefined = undefined>(
|
|
505
|
+
url: string,
|
|
506
|
+
config?: RouteConfig<PP>
|
|
507
|
+
): RouteBuilder<PP> {
|
|
508
|
+
return createRouteBuilder(this, url, config);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
export { ejectMiddleware, useMiddleware };
|
|
513
|
+
export default Faxios;
|