@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.
Files changed (210) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +40 -1774
  3. package/dist/index.d.ts +9 -6
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/adapters/fetch-helpers.d.ts +1 -0
  7. package/dist/lib/adapters/fetch-helpers.d.ts.map +1 -0
  8. package/dist/lib/adapters/fetch.d.ts +1 -0
  9. package/dist/lib/adapters/fetch.d.ts.map +1 -0
  10. package/dist/lib/adapters/fetch.js +23 -3
  11. package/dist/lib/adapters/fetch.js.map +1 -1
  12. package/dist/lib/cancel/CanceledError.d.ts +1 -0
  13. package/dist/lib/cancel/CanceledError.d.ts.map +1 -0
  14. package/dist/lib/cancel/isCancel.d.ts +3 -1
  15. package/dist/lib/cancel/isCancel.d.ts.map +1 -0
  16. package/dist/lib/cancel/isCancel.js +3 -0
  17. package/dist/lib/cancel/isCancel.js.map +1 -1
  18. package/dist/lib/core/Faxios.d.ts +6 -17
  19. package/dist/lib/core/Faxios.d.ts.map +1 -0
  20. package/dist/lib/core/Faxios.js +144 -76
  21. package/dist/lib/core/Faxios.js.map +1 -1
  22. package/dist/lib/core/FaxiosError.d.ts +19 -6
  23. package/dist/lib/core/FaxiosError.d.ts.map +1 -0
  24. package/dist/lib/core/FaxiosError.js +16 -1
  25. package/dist/lib/core/FaxiosError.js.map +1 -1
  26. package/dist/lib/core/FaxiosHeaders.d.ts +12 -8
  27. package/dist/lib/core/FaxiosHeaders.d.ts.map +1 -0
  28. package/dist/lib/core/FaxiosHeaders.js +1 -0
  29. package/dist/lib/core/FaxiosHeaders.js.map +1 -1
  30. package/dist/lib/core/buildFullPath.d.ts +1 -0
  31. package/dist/lib/core/buildFullPath.d.ts.map +1 -0
  32. package/dist/lib/core/define.d.ts +19 -2
  33. package/dist/lib/core/define.d.ts.map +1 -0
  34. package/dist/lib/core/define.js.map +1 -1
  35. package/dist/lib/core/dispatchRequest.d.ts +1 -0
  36. package/dist/lib/core/dispatchRequest.d.ts.map +1 -0
  37. package/dist/lib/core/dispatchRequest.js +4 -0
  38. package/dist/lib/core/dispatchRequest.js.map +1 -1
  39. package/dist/lib/core/mergeConfig.d.ts +1 -0
  40. package/dist/lib/core/mergeConfig.d.ts.map +1 -0
  41. package/dist/lib/core/prepareRequest.d.ts +1 -0
  42. package/dist/lib/core/prepareRequest.d.ts.map +1 -0
  43. package/dist/lib/core/prepareRequest.js +1 -20
  44. package/dist/lib/core/prepareRequest.js.map +1 -1
  45. package/dist/lib/core/route.d.ts +11 -2
  46. package/dist/lib/core/route.d.ts.map +1 -0
  47. package/dist/lib/core/route.js.map +1 -1
  48. package/dist/lib/core/settle.d.ts +1 -0
  49. package/dist/lib/core/settle.d.ts.map +1 -0
  50. package/dist/lib/core/transformData.d.ts +1 -0
  51. package/dist/lib/core/transformData.d.ts.map +1 -0
  52. package/dist/lib/core/validateSchema.d.ts +1 -0
  53. package/dist/lib/core/validateSchema.d.ts.map +1 -0
  54. package/dist/lib/defaults/index.d.ts +1 -0
  55. package/dist/lib/defaults/index.d.ts.map +1 -0
  56. package/dist/lib/defaults/index.js +3 -3
  57. package/dist/lib/defaults/index.js.map +1 -1
  58. package/dist/lib/defaults/transitional.d.ts +1 -1
  59. package/dist/lib/defaults/transitional.d.ts.map +1 -0
  60. package/dist/lib/defaults/transitional.js +0 -1
  61. package/dist/lib/defaults/transitional.js.map +1 -1
  62. package/dist/lib/env/data.d.ts +2 -1
  63. package/dist/lib/env/data.d.ts.map +1 -0
  64. package/dist/lib/env/data.js +1 -1
  65. package/dist/lib/env/data.js.map +1 -1
  66. package/dist/lib/faxios.d.ts +115 -48
  67. package/dist/lib/faxios.d.ts.map +1 -0
  68. package/dist/lib/faxios.js +14 -2
  69. package/dist/lib/faxios.js.map +1 -1
  70. package/dist/lib/helpers/FaxiosURLSearchParams.d.ts +3 -1
  71. package/dist/lib/helpers/FaxiosURLSearchParams.d.ts.map +1 -0
  72. package/dist/lib/helpers/FaxiosURLSearchParams.js.map +1 -1
  73. package/dist/lib/helpers/HttpStatusCode.d.ts +1 -0
  74. package/dist/lib/helpers/HttpStatusCode.d.ts.map +1 -0
  75. package/dist/lib/helpers/buildURL.d.ts +1 -0
  76. package/dist/lib/helpers/buildURL.d.ts.map +1 -0
  77. package/dist/lib/helpers/buildURL.js +7 -1
  78. package/dist/lib/helpers/buildURL.js.map +1 -1
  79. package/dist/lib/helpers/cloneConfig.d.ts +4 -0
  80. package/dist/lib/helpers/cloneConfig.d.ts.map +1 -0
  81. package/dist/lib/helpers/cloneConfig.js +21 -0
  82. package/dist/lib/helpers/cloneConfig.js.map +1 -0
  83. package/dist/lib/helpers/combineURLs.d.ts +1 -0
  84. package/dist/lib/helpers/combineURLs.d.ts.map +1 -0
  85. package/dist/lib/helpers/composeSignals.d.ts +1 -0
  86. package/dist/lib/helpers/composeSignals.d.ts.map +1 -0
  87. package/dist/lib/helpers/composeSignals.js +8 -1
  88. package/dist/lib/helpers/composeSignals.js.map +1 -1
  89. package/dist/lib/helpers/cookies.d.ts +1 -0
  90. package/dist/lib/helpers/cookies.d.ts.map +1 -0
  91. package/dist/lib/helpers/estimateDataURLDecodedBytes.d.ts +1 -0
  92. package/dist/lib/helpers/estimateDataURLDecodedBytes.d.ts.map +1 -0
  93. package/dist/lib/helpers/formDataToJSON.d.ts +1 -0
  94. package/dist/lib/helpers/formDataToJSON.d.ts.map +1 -0
  95. package/dist/lib/helpers/isAbsoluteURL.d.ts +1 -0
  96. package/dist/lib/helpers/isAbsoluteURL.d.ts.map +1 -0
  97. package/dist/lib/helpers/isFaxiosError.d.ts +8 -2
  98. package/dist/lib/helpers/isFaxiosError.d.ts.map +1 -0
  99. package/dist/lib/helpers/isFaxiosError.js +5 -1
  100. package/dist/lib/helpers/isFaxiosError.js.map +1 -1
  101. package/dist/lib/helpers/isURLSameOrigin.d.ts +1 -0
  102. package/dist/lib/helpers/isURLSameOrigin.d.ts.map +1 -0
  103. package/dist/lib/helpers/parseHeaders.d.ts +1 -0
  104. package/dist/lib/helpers/parseHeaders.d.ts.map +1 -0
  105. package/dist/lib/helpers/progressEventReducer.d.ts +1 -0
  106. package/dist/lib/helpers/progressEventReducer.d.ts.map +1 -0
  107. package/dist/lib/helpers/sanitizeHeaderValue.d.ts +1 -0
  108. package/dist/lib/helpers/sanitizeHeaderValue.d.ts.map +1 -0
  109. package/dist/lib/helpers/speedometer.d.ts +1 -0
  110. package/dist/lib/helpers/speedometer.d.ts.map +1 -0
  111. package/dist/lib/helpers/substitutePathParams.d.ts +1 -0
  112. package/dist/lib/helpers/substitutePathParams.d.ts.map +1 -0
  113. package/dist/lib/helpers/throttle.d.ts +1 -0
  114. package/dist/lib/helpers/throttle.d.ts.map +1 -0
  115. package/dist/lib/helpers/toFormData.d.ts +1 -0
  116. package/dist/lib/helpers/toFormData.d.ts.map +1 -0
  117. package/dist/lib/helpers/toURLEncodedForm.d.ts +1 -0
  118. package/dist/lib/helpers/toURLEncodedForm.d.ts.map +1 -0
  119. package/dist/lib/helpers/trackStream.d.ts +1 -0
  120. package/dist/lib/helpers/trackStream.d.ts.map +1 -0
  121. package/dist/lib/helpers/validator.d.ts +1 -0
  122. package/dist/lib/helpers/validator.d.ts.map +1 -0
  123. package/dist/lib/platform.d.ts +2 -1
  124. package/dist/lib/platform.d.ts.map +1 -0
  125. package/dist/lib/plugins/attempt.d.ts +2 -0
  126. package/dist/lib/plugins/attempt.d.ts.map +1 -0
  127. package/dist/lib/plugins/attempt.js +4 -0
  128. package/dist/lib/plugins/attempt.js.map +1 -0
  129. package/dist/lib/plugins/authBearer.d.ts +31 -0
  130. package/dist/lib/plugins/authBearer.d.ts.map +1 -0
  131. package/dist/lib/plugins/authBearer.js +99 -0
  132. package/dist/lib/plugins/authBearer.js.map +1 -0
  133. package/dist/lib/plugins/definePlugin.d.ts +22 -0
  134. package/dist/lib/plugins/definePlugin.d.ts.map +1 -0
  135. package/dist/lib/plugins/definePlugin.js +14 -0
  136. package/dist/lib/plugins/definePlugin.js.map +1 -0
  137. package/dist/lib/plugins/retry.d.ts +66 -0
  138. package/dist/lib/plugins/retry.d.ts.map +1 -0
  139. package/dist/lib/plugins/retry.js +168 -0
  140. package/dist/lib/plugins/retry.js.map +1 -0
  141. package/dist/lib/plugins/timing.d.ts +32 -0
  142. package/dist/lib/plugins/timing.d.ts.map +1 -0
  143. package/dist/lib/plugins/timing.js +53 -0
  144. package/dist/lib/plugins/timing.js.map +1 -0
  145. package/dist/lib/types/standard-schema.d.ts +1 -0
  146. package/dist/lib/types/standard-schema.d.ts.map +1 -0
  147. package/dist/lib/types.d.ts +125 -34
  148. package/dist/lib/types.d.ts.map +1 -0
  149. package/dist/lib/utils.d.ts +1 -0
  150. package/dist/lib/utils.d.ts.map +1 -0
  151. package/package.json +42 -19
  152. package/skills/configure-requests/SKILL.md +380 -0
  153. package/skills/configure-requests/references/axios-differences.md +67 -0
  154. package/skills/configure-requests/references/plugins.md +127 -0
  155. package/src/index.ts +57 -0
  156. package/src/lib/adapters/fetch-helpers.ts +167 -0
  157. package/src/lib/adapters/fetch.ts +810 -0
  158. package/src/lib/cancel/CanceledError.ts +23 -0
  159. package/src/lib/cancel/isCancel.ts +10 -0
  160. package/src/lib/core/Faxios.ts +513 -0
  161. package/src/lib/core/FaxiosError.ts +283 -0
  162. package/src/lib/core/FaxiosHeaders.ts +529 -0
  163. package/src/lib/core/buildFullPath.ts +51 -0
  164. package/src/lib/core/define.ts +127 -0
  165. package/src/lib/core/dispatchRequest.ts +171 -0
  166. package/src/lib/core/mergeConfig.ts +175 -0
  167. package/src/lib/core/prepareRequest.ts +155 -0
  168. package/src/lib/core/route.ts +68 -0
  169. package/src/lib/core/settle.ts +20 -0
  170. package/src/lib/core/transformData.ts +23 -0
  171. package/src/lib/core/validateSchema.ts +53 -0
  172. package/src/lib/defaults/index.ts +221 -0
  173. package/src/lib/defaults/transitional.ts +9 -0
  174. package/src/lib/env/data.ts +1 -0
  175. package/src/lib/faxios.ts +306 -0
  176. package/src/lib/helpers/FaxiosURLSearchParams.ts +52 -0
  177. package/src/lib/helpers/HttpStatusCode.ts +77 -0
  178. package/src/lib/helpers/buildURL.ts +77 -0
  179. package/src/lib/helpers/cloneConfig.ts +23 -0
  180. package/src/lib/helpers/combineURLs.ts +11 -0
  181. package/src/lib/helpers/composeSignals.ts +74 -0
  182. package/src/lib/helpers/cookies.ts +68 -0
  183. package/src/lib/helpers/deprecatedMethod.ts +32 -0
  184. package/src/lib/helpers/estimateDataURLDecodedBytes.ts +95 -0
  185. package/src/lib/helpers/formDataToJSON.ts +122 -0
  186. package/src/lib/helpers/isAbsoluteURL.ts +13 -0
  187. package/src/lib/helpers/isFaxiosError.ts +19 -0
  188. package/src/lib/helpers/isURLSameOrigin.ts +16 -0
  189. package/src/lib/helpers/parseHeaders.ts +76 -0
  190. package/src/lib/helpers/progressEventReducer.ts +57 -0
  191. package/src/lib/helpers/sanitizeHeaderValue.ts +61 -0
  192. package/src/lib/helpers/speedometer.ts +55 -0
  193. package/src/lib/helpers/substitutePathParams.ts +13 -0
  194. package/src/lib/helpers/throttle.ts +45 -0
  195. package/src/lib/helpers/toFormData.ts +296 -0
  196. package/src/lib/helpers/toURLEncodedForm.ts +14 -0
  197. package/src/lib/helpers/trackStream.ts +123 -0
  198. package/src/lib/helpers/validator.ts +114 -0
  199. package/src/lib/platform.ts +44 -0
  200. package/src/lib/plugins/attempt.ts +3 -0
  201. package/src/lib/plugins/authBearer.ts +124 -0
  202. package/src/lib/plugins/definePlugin.ts +34 -0
  203. package/src/lib/plugins/retry.ts +245 -0
  204. package/src/lib/plugins/timing.ts +76 -0
  205. package/src/lib/types/standard-schema.ts +58 -0
  206. package/src/lib/types.ts +496 -0
  207. package/src/lib/utils.ts +932 -0
  208. package/dist/lib/core/InterceptorManager.d.ts +0 -9
  209. package/dist/lib/core/InterceptorManager.js +0 -28
  210. package/dist/lib/core/InterceptorManager.js.map +0 -1
@@ -0,0 +1,810 @@
1
+ import FaxiosError from "../core/FaxiosError.js";
2
+ import FaxiosHeaders from "../core/FaxiosHeaders.js";
3
+ import prepareRequest from "../core/prepareRequest.js";
4
+ import { settle } from "../core/settle.js";
5
+ import { VERSION } from "../env/data.js";
6
+ import composeSignals from "../helpers/composeSignals.js";
7
+ import estimateDataURLDecodedBytes from "../helpers/estimateDataURLDecodedBytes.js";
8
+ import {
9
+ progressEventReducer,
10
+ progressEventDecorator,
11
+ asyncDecorator
12
+ } from "../helpers/progressEventReducer.js";
13
+ import { toByteStringHeaderObject } from "../helpers/sanitizeHeaderValue.js";
14
+ import { trackStream } from "../helpers/trackStream.js";
15
+ import platform from "../platform.js";
16
+ import type {
17
+ InternalFaxiosRequestConfig,
18
+ FaxiosRequestHeaders
19
+ } from "../types.js";
20
+ import utils from "../utils.js";
21
+ import { checkDeclaredContentLength, checkMaterializedSize, handleFetchCaughtError, cleanFormDataContentType, encodeBodyIfNeeded } from "./fetch-helpers.js";
22
+ import type { ComposedSignal, PendingBodyErrorRef } from "./fetch-helpers.js";
23
+
24
+ // btoa is a global in Node 16+ and browsers; accessed via globalThis for no-DOM lib compat
25
+ const _btoa: (data: string) => string = (
26
+ globalThis as unknown as Record<string, unknown>
27
+ )["btoa"] as (data: string) => string;
28
+ type AnyConstructor = new (...args: Array<unknown>) => unknown;
29
+ type FetchFn = (input: unknown, init?: unknown) => Promise<AnyResponse>;
30
+ type AnyResponse = {
31
+ body: unknown;
32
+ headers: {
33
+ has: (name: string) => boolean;
34
+ get: (name: string) => string | null;
35
+ [key: string]: unknown;
36
+ };
37
+ status: number;
38
+ statusText: string;
39
+ arrayBuffer: () => Promise<ArrayBuffer>;
40
+ [key: string]: unknown;
41
+ };
42
+ type AnyRequest = {
43
+ headers: {
44
+ has: (name: string) => boolean;
45
+ get: (name: string) => string | null;
46
+ };
47
+ body: { cancel: () => Promise<void>; } | null;
48
+ arrayBuffer: () => Promise<ArrayBuffer>;
49
+ [key: string]: unknown;
50
+ };
51
+ type AnyReadableStream = {
52
+ cancel: () => Promise<void>;
53
+ [key: string]: unknown;
54
+ };
55
+ type AnyTextEncoder = { encode: (str: string) => Uint8Array; };
56
+
57
+ const DEFAULT_CHUNK_SIZE = 64 * 1024;
58
+
59
+ const { isFunction } = utils;
60
+
61
+ // Server runtimes default User-Agent to their own (e.g. "node"), so name faxios there.
62
+ // Browsers send their own User-Agent; setting one makes every cross-origin request
63
+ // need a CORS preflight that most APIs don't allow.
64
+ const setsUserAgent = !platform.hasStandardBrowserEnv && !platform.hasStandardBrowserWebWorkerEnv;
65
+ const applyDefaultUserAgent = (headers: FaxiosRequestHeaders): void => {
66
+ if (setsUserAgent) headers.set("User-Agent", "faxios/" + VERSION, false);
67
+ };
68
+
69
+ /**
70
+ * Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
71
+ * This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
72
+ *
73
+ * @param {string} str The string to encode
74
+ *
75
+ * @returns {string} UTF-8 bytes as a Latin-1 string
76
+ */
77
+ const encodeUTF8 = (str: string): string =>
78
+ encodeURIComponent(str).replace(
79
+ /%([0-9A-F]{2})/gi,
80
+ (_: string, hex: string) => String.fromCharCode(parseInt(hex, 16))
81
+ );
82
+
83
+ // Node's WHATWG URL parser returns `username` and `password` percent-encoded.
84
+ // Decode before composing the `auth` option so credentials such as
85
+ // `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
86
+ // original value for malformed input so a bad encoding never throws.
87
+ const decodeURIComponentSafe = (value: unknown): unknown => {
88
+ if (!utils.isString(value)) {
89
+ return value;
90
+ }
91
+
92
+ try {
93
+ return decodeURIComponent(value as string);
94
+ }
95
+ catch {
96
+ return value;
97
+ }
98
+ };
99
+
100
+ const test = (
101
+ fn: (...args: Array<unknown>) => unknown,
102
+ ...args: Array<unknown>
103
+ ): boolean => {
104
+ try {
105
+ return !!fn(...args);
106
+ }
107
+ catch {
108
+ return false;
109
+ }
110
+ };
111
+
112
+ const maybeWithAuthCredentials = (url: string): boolean => {
113
+ const protocolIndex = url.indexOf("://");
114
+ const urlToCheck = protocolIndex !== -1 ? url.slice(protocolIndex + 3) : url;
115
+ // Only `@` indicates credentials in the authority; `:` alone is a port separator.
116
+ return urlToCheck.includes("@");
117
+ };
118
+
119
+ // eslint-disable-next-line sonarjs/function-return-type
120
+ const factory = (env: Record<string, unknown>) => {
121
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
122
+ const globalObject: Record<string, unknown> = utils.global ?? globalThis;
123
+ const ReadableStream = globalObject["ReadableStream"] as
124
+ | (AnyConstructor & { prototype: AnyReadableStream; })
125
+ | undefined;
126
+ const TextEncoder = globalObject["TextEncoder"] as
127
+ | (new () => AnyTextEncoder)
128
+ | undefined;
129
+
130
+ env = utils.merge.call(
131
+ {
132
+ skipUndefined: true,
133
+ },
134
+ {
135
+ Request: globalObject["Request"],
136
+ Response: globalObject["Response"],
137
+ },
138
+ env
139
+ );
140
+
141
+ const {
142
+ fetch: envFetch,
143
+ Request,
144
+ Response,
145
+ } = env as {
146
+ fetch?: FetchFn;
147
+ Request?: AnyConstructor;
148
+ Response?: AnyConstructor;
149
+ };
150
+ const _globalFetch = (globalThis as unknown as Record<string, unknown>)[
151
+ "fetch"
152
+ ];
153
+ const isFetchSupported = envFetch
154
+ ? isFunction(envFetch)
155
+ : isFunction(_globalFetch);
156
+ const isRequestSupported = isFunction(Request);
157
+ const isResponseSupported = isFunction(Response);
158
+
159
+ if (!isFetchSupported) {
160
+ return false;
161
+ }
162
+
163
+ const isReadableStreamSupported = isFunction(ReadableStream);
164
+
165
+ const encodeText: (str: string) => Promise<Uint8Array> | Uint8Array =
166
+ typeof TextEncoder === "function"
167
+ ? (
168
+ (encoder: AnyTextEncoder) => (str: string) =>
169
+ encoder.encode(str)
170
+ )(new TextEncoder())
171
+ : async (str: string) =>
172
+ new Uint8Array(
173
+ await (
174
+ new (Request as AnyConstructor)(str) as AnyRequest
175
+ ).arrayBuffer()
176
+ );
177
+
178
+ // A Node stream body reaches fetch twice: once in `new Request(url, init)` and again in
179
+ // `fetch(request, init)`. undici (Node 26.11+) starts reading an async iterable in both,
180
+ // so the first chunk goes to the discarded copy. One web stream is read only once.
181
+ // Web stream bodies must yield bytes, so string chunks (e.g. `Readable.from(["a"])`) are encoded.
182
+ const from = (ReadableStream as { from?: (source: unknown) => unknown; } | undefined)?.from;
183
+ const streamFrom = typeof from === "function" ? from.bind(ReadableStream) : undefined;
184
+ async function* toByteChunks(source: AsyncIterable<unknown>) {
185
+ for await (const chunk of source) yield typeof chunk === "string" ? await encodeText(chunk) : chunk;
186
+ }
187
+ const toWebStream = (body: unknown): unknown =>
188
+ (streamFrom && utils.isStream(body) && !utils.isFormData(body)
189
+ ? streamFrom(toByteChunks(body as AsyncIterable<unknown>))
190
+ : body);
191
+
192
+ const supportsRequestStream =
193
+ isRequestSupported &&
194
+ isReadableStreamSupported &&
195
+ test(() => {
196
+ let duplexAccessed = false;
197
+
198
+ const request = new (Request as AnyConstructor)(platform.origin, {
199
+ body: new (ReadableStream as AnyConstructor)(),
200
+ method: "POST",
201
+ get duplex() {
202
+ duplexAccessed = true;
203
+ return "half";
204
+ },
205
+ }) as AnyRequest;
206
+
207
+ const hasContentType = request.headers.has("Content-Type");
208
+
209
+ if (request.body != null) {
210
+ request.body.cancel().catch(() => {});
211
+ }
212
+
213
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
214
+ return duplexAccessed && !hasContentType;
215
+ });
216
+
217
+ const supportsResponseStream =
218
+ isResponseSupported &&
219
+ isReadableStreamSupported &&
220
+ test(() =>
221
+ utils.isReadableStream!(
222
+ (new (Response as AnyConstructor)("") as AnyResponse).body
223
+ )
224
+ );
225
+
226
+ const resolvers: Record<
227
+ string,
228
+ ((res: AnyResponse, config?: unknown) => unknown) | false
229
+ > = {
230
+ stream: supportsResponseStream && ((res: AnyResponse) => res.body),
231
+ };
232
+
233
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
234
+ isFetchSupported &&
235
+ (() => {
236
+ [ "text", "arrayBuffer", "blob", "formData", "stream" ].forEach(type => {
237
+ !resolvers[type] &&
238
+ (resolvers[type] = (res: AnyResponse, config?: unknown) => {
239
+ const method = (res as Record<string, unknown>)[type];
240
+
241
+ if (method) {
242
+ return (method as (this: AnyResponse) => unknown).call(res);
243
+ }
244
+
245
+ throw new FaxiosError(
246
+ `Response type '${type}' is not supported`,
247
+ FaxiosError.ERR_NOT_SUPPORT,
248
+ config as InternalFaxiosRequestConfig
249
+ );
250
+ });
251
+ });
252
+ })();
253
+
254
+ const getBodyLength = async (body: unknown): Promise<number | undefined> => {
255
+ if (body == null) {
256
+ return 0;
257
+ }
258
+
259
+ if (utils.isBlob(body)) {
260
+ return (body as { size: number; }).size;
261
+ }
262
+
263
+ if (utils.isSpecCompliantForm(body)) {
264
+ const _request = new (Request as AnyConstructor)(platform.origin, {
265
+ method: "POST",
266
+ body,
267
+ }) as AnyRequest;
268
+ return (await _request.arrayBuffer()).byteLength;
269
+ }
270
+
271
+ if (utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) {
272
+ return (body as ArrayBufferView | ArrayBuffer).byteLength;
273
+ }
274
+
275
+ if (utils.isURLSearchParams(body)) {
276
+ body = body + "";
277
+ }
278
+
279
+ if (utils.isString(body)) {
280
+ return (await encodeText(body as string)).byteLength;
281
+ }
282
+ return undefined;
283
+ };
284
+
285
+ const resolveBodyLength = async (
286
+ headers: FaxiosRequestHeaders,
287
+ body: unknown
288
+ ): Promise<number | undefined> => {
289
+ const length = utils.toFiniteNumber(headers.getContentLength());
290
+
291
+ return length == null ? getBodyLength(body) : length;
292
+ };
293
+
294
+ const normalizeCredentials = (wc: string | boolean): string => {
295
+ if (utils.isString(wc)) return wc as string;
296
+ return wc ? "include" : "omit";
297
+ };
298
+
299
+ // HTTP basic authentication: extract auth from config or URL, set Authorization header,
300
+ // strip credentials from URL. Returns the (possibly updated) URL.
301
+ const applyAuthToRequest = (
302
+ url: string,
303
+ headers: FaxiosRequestHeaders,
304
+ own: (key: string) => unknown
305
+ ): string => {
306
+ let auth: { username: unknown; password: unknown; } | undefined;
307
+ const configAuth = own("auth");
308
+ if (configAuth) {
309
+ auth = {
310
+ username: utils.getSafeProp(configAuth, "username") || "",
311
+ password: utils.getSafeProp(configAuth, "password") || "",
312
+ };
313
+ }
314
+ if (maybeWithAuthCredentials(url)) {
315
+ const parsedURL = new URL(url, platform.origin);
316
+ if (!auth && (parsedURL.username || parsedURL.password)) {
317
+ auth = {
318
+ username: decodeURIComponentSafe(parsedURL.username),
319
+ password: decodeURIComponentSafe(parsedURL.password),
320
+ };
321
+ }
322
+ if (parsedURL.username || parsedURL.password) {
323
+ parsedURL.username = "";
324
+ parsedURL.password = "";
325
+ url = parsedURL.href;
326
+ }
327
+ }
328
+ if (auth) {
329
+ headers.delete("authorization");
330
+ headers.set(
331
+ "Authorization",
332
+ "Basic " +
333
+ _btoa(
334
+ encodeUTF8(
335
+ String(auth.username || "") + ":" + String(auth.password || "")
336
+ )
337
+ )
338
+ );
339
+ }
340
+ return url;
341
+ };
342
+
343
+ // Pre-flight size checks: data: URL content-length and known-size body maxBodyLength.
344
+ // Returns requestContentLength if computed, else undefined.
345
+ const checkPreflightLimits = async (
346
+ url: string,
347
+ data: unknown,
348
+ method: string,
349
+ hasMaxContentLength: boolean,
350
+ maxContentLength: number,
351
+ hasMaxBodyLength: boolean,
352
+ maxBodyLength: number,
353
+ config: InternalFaxiosRequestConfig,
354
+ request: unknown
355
+ ): Promise<number | undefined> => {
356
+ // Enforce maxContentLength for data: URLs up-front so we never materialize
357
+ // an oversized payload. The HTTP adapter applies the same check.
358
+ if (
359
+ hasMaxContentLength &&
360
+ typeof url === "string" &&
361
+ url.startsWith("data:")
362
+ ) {
363
+ const estimated = estimateDataURLDecodedBytes(url);
364
+ if (estimated > maxContentLength) {
365
+ throw new FaxiosError(
366
+ "maxContentLength size of " + maxContentLength + " exceeded",
367
+ FaxiosError.ERR_BAD_RESPONSE,
368
+ config,
369
+ request
370
+ );
371
+ }
372
+ }
373
+ // Enforce maxBodyLength against known-size bodies before dispatch using
374
+ // the body's actual size — never a caller-declared Content-Length.
375
+ if (hasMaxBodyLength && method !== "get" && method !== "head") {
376
+ const outboundLength = await getBodyLength(data);
377
+ if (typeof outboundLength === "number" && isFinite(outboundLength)) {
378
+ if (outboundLength > maxBodyLength) {
379
+ throw new FaxiosError(
380
+ "Request body larger than maxBodyLength limit",
381
+ FaxiosError.ERR_BAD_REQUEST,
382
+ config,
383
+ request
384
+ );
385
+ }
386
+ return outboundLength;
387
+ }
388
+ }
389
+ return undefined;
390
+ };
391
+
392
+ // Wrap a Request body with upload progress tracking and optional maxBodyLength enforcement.
393
+ const applyUploadProgress = (
394
+ _request: AnyRequest,
395
+ data: unknown,
396
+ headers: FaxiosRequestHeaders,
397
+ requestContentLength: number | undefined,
398
+ onUploadProgress: unknown,
399
+ _trackStream: (stream: unknown, onProgress?: (bytes: number) => void, flush?: () => void) => unknown
400
+ ): unknown => {
401
+ let contentTypeHeader: string | null;
402
+ if (
403
+ utils.isFormData(data) &&
404
+ (contentTypeHeader = _request.headers.get("content-type"))
405
+ ) {
406
+ headers.setContentType(contentTypeHeader);
407
+ }
408
+ if (_request.body) {
409
+ const [ onProgress, flush ] = onUploadProgress
410
+ ? progressEventDecorator(
411
+ requestContentLength,
412
+ progressEventReducer(
413
+ asyncDecorator(
414
+ onUploadProgress as (...args: Array<unknown>) => unknown
415
+ ),
416
+ false
417
+ )
418
+ )
419
+ : [];
420
+ return _trackStream(_request.body, onProgress, flush);
421
+ }
422
+ return data;
423
+ };
424
+
425
+ // Set up request body streaming with upload progress and/or maxBodyLength enforcement.
426
+ const buildUploadStream = async (
427
+ data: unknown,
428
+ url: string,
429
+ method: string,
430
+ headers: FaxiosRequestHeaders,
431
+ onUploadProgress: unknown,
432
+ mustEnforceStreamBody: boolean,
433
+ requestContentLength: number | undefined,
434
+ hasMaxBodyLength: boolean,
435
+ maxBodyLength: number,
436
+ config: InternalFaxiosRequestConfig,
437
+ request: unknown,
438
+ pendingBodyErrorRef: PendingBodyErrorRef
439
+ ): Promise<{ data: unknown; requestContentLength: number | undefined; }> => {
440
+ const _makeBodyLengthError = () =>
441
+ new FaxiosError(
442
+ "Request body larger than maxBodyLength limit",
443
+ FaxiosError.ERR_BAD_REQUEST,
444
+ config,
445
+ request
446
+ );
447
+
448
+ const _trackStream = (
449
+ stream: unknown,
450
+ onProgress?: (bytes: number) => void,
451
+ flush?: () => void
452
+ ) =>
453
+ trackStream(
454
+ stream,
455
+ DEFAULT_CHUNK_SIZE,
456
+ (loadedBytes: number) => {
457
+ if (hasMaxBodyLength && loadedBytes > maxBodyLength) {
458
+ pendingBodyErrorRef.value = _makeBodyLengthError();
459
+ throw pendingBodyErrorRef.value;
460
+ }
461
+ onProgress && onProgress(loadedBytes);
462
+ },
463
+ flush
464
+ );
465
+
466
+ if (
467
+ supportsRequestStream &&
468
+ method !== "get" &&
469
+ method !== "head" &&
470
+ (onUploadProgress || mustEnforceStreamBody)
471
+ ) {
472
+ requestContentLength =
473
+ requestContentLength == null
474
+ ? await resolveBodyLength(headers, data)
475
+ : requestContentLength;
476
+
477
+ // A declared length of 0 is only trusted to skip the wrap when we are
478
+ // not enforcing a stream limit (which must not rely on that header).
479
+ if (requestContentLength !== 0 || mustEnforceStreamBody) {
480
+ const _request = new (Request as AnyConstructor)(url, {
481
+ method: "POST",
482
+ body: data,
483
+ duplex: "half",
484
+ }) as AnyRequest;
485
+ data = applyUploadProgress(_request, data, headers, requestContentLength, onUploadProgress, _trackStream);
486
+ }
487
+ }
488
+ else if (
489
+ mustEnforceStreamBody &&
490
+ !isRequestSupported &&
491
+ isReadableStreamSupported &&
492
+ method !== "get" &&
493
+ method !== "head"
494
+ ) {
495
+ data = _trackStream(data);
496
+ }
497
+ else if (
498
+ mustEnforceStreamBody &&
499
+ isRequestSupported &&
500
+ !supportsRequestStream &&
501
+ method !== "get" &&
502
+ method !== "head"
503
+ ) {
504
+ throw new FaxiosError(
505
+ "Stream request bodies are not supported by the current fetch implementation",
506
+ FaxiosError.ERR_NOT_SUPPORT,
507
+ config,
508
+ request
509
+ );
510
+ }
511
+
512
+ return { data, requestContentLength };
513
+ };
514
+
515
+ // Wrap the response body stream with download progress tracking and maxContentLength enforcement.
516
+ const buildDownloadStream = (
517
+ response: AnyResponse,
518
+ responseHeaders: FaxiosHeaders,
519
+ onDownloadProgress: unknown,
520
+ hasMaxContentLength: boolean,
521
+ maxContentLength: number,
522
+ isStreamResponse: boolean,
523
+ unsubscribe: (() => void) | false | undefined,
524
+ config: InternalFaxiosRequestConfig,
525
+ request: unknown
526
+ ): AnyResponse => {
527
+ const needsWrapping = onDownloadProgress || hasMaxContentLength || (isStreamResponse && unsubscribe);
528
+ if (!supportsResponseStream || !response.body || !needsWrapping) {
529
+ return response;
530
+ }
531
+
532
+ const options: Record<string, unknown> = {};
533
+ [ "status", "statusText", "headers" ].forEach(prop => {
534
+ options[prop] = response[prop];
535
+ });
536
+
537
+ const responseContentLength = utils.toFiniteNumber(
538
+ (responseHeaders.getContentLength as () => unknown)()
539
+ );
540
+
541
+ const [ onProgress, flush ] = onDownloadProgress
542
+ ? progressEventDecorator(
543
+ responseContentLength,
544
+ progressEventReducer(
545
+ asyncDecorator(
546
+ onDownloadProgress as (...args: Array<unknown>) => unknown
547
+ ),
548
+ true
549
+ )
550
+ )
551
+ : [];
552
+
553
+ let bytesRead = 0;
554
+ const onChunkProgress = (loadedBytes: number): void => {
555
+ if (hasMaxContentLength) {
556
+ bytesRead = loadedBytes;
557
+ if (bytesRead > maxContentLength) {
558
+ throw new FaxiosError(
559
+ "maxContentLength size of " + maxContentLength + " exceeded",
560
+ FaxiosError.ERR_BAD_RESPONSE,
561
+ config,
562
+ request
563
+ );
564
+ }
565
+ }
566
+ onProgress && onProgress(loadedBytes);
567
+ };
568
+
569
+ return new (Response as AnyConstructor)(
570
+ trackStream(
571
+ response.body,
572
+ DEFAULT_CHUNK_SIZE,
573
+ onChunkProgress,
574
+ () => {
575
+ flush && flush();
576
+ unsubscribe && unsubscribe();
577
+ }
578
+ ),
579
+ options
580
+ ) as AnyResponse;
581
+ };
582
+
583
+ const unsubscribeOnComplete = (isStreamResponse: boolean, unsubscribe: (() => void) | undefined) => {
584
+ if (!isStreamResponse) unsubscribe?.();
585
+ };
586
+
587
+ return async (config: InternalFaxiosRequestConfig) => {
588
+ const _resolved = prepareRequest(config) as InternalFaxiosRequestConfig & {
589
+ fetchOptions?: Record<string, unknown>;
590
+ withCredentials?: string | boolean;
591
+ };
592
+ let {
593
+ url,
594
+ method,
595
+ data,
596
+ signal,
597
+ timeout,
598
+ timeoutErrorMessage,
599
+ onDownloadProgress,
600
+ onUploadProgress,
601
+ responseType,
602
+ fetchOptions,
603
+ maxContentLength,
604
+ maxBodyLength,
605
+ } = _resolved;
606
+ let headers = _resolved.headers;
607
+ let withCredentials: string | boolean =
608
+ _resolved.withCredentials ?? "same-origin";
609
+
610
+ const hasMaxContentLength =
611
+ utils.isNumber(maxContentLength) && maxContentLength! > -1;
612
+ const hasMaxBodyLength =
613
+ utils.isNumber(maxBodyLength) && maxBodyLength! > -1;
614
+ const own = (key: string): unknown =>
615
+ utils.hasOwnProp(config, key)
616
+ ? (config as unknown as Record<string, unknown>)[key]
617
+ : undefined;
618
+
619
+ const _fetch: FetchFn = (envFetch || (globalThis as unknown as Record<string, unknown>)["fetch"]) as FetchFn;
620
+
621
+ if (timeout != null && !Number.isFinite(Number(timeout))) {
622
+ throw new FaxiosError(
623
+ "error trying to parse `config.timeout` to int",
624
+ FaxiosError.ERR_BAD_OPTION_VALUE,
625
+ config
626
+ );
627
+ }
628
+
629
+ responseType = (
630
+ responseType ? (responseType + "").toLowerCase() : "text"
631
+ ) as typeof responseType;
632
+
633
+ const composedSignal = composeSignals(
634
+ [ signal ],
635
+ timeout,
636
+ timeoutErrorMessage
637
+ ) as ComposedSignal | undefined;
638
+
639
+ const unsubscribe = composedSignal?.unsubscribe?.bind(composedSignal);
640
+
641
+ let request: Request | null = null;
642
+ const pendingBodyErrorRef: PendingBodyErrorRef = { value: null };
643
+
644
+ try {
645
+ url = applyAuthToRequest(url!, headers, own);
646
+
647
+ const preflightContentLength = await checkPreflightLimits(
648
+ url,
649
+ data,
650
+ method!,
651
+ hasMaxContentLength,
652
+ maxContentLength!,
653
+ hasMaxBodyLength,
654
+ maxBodyLength!,
655
+ config,
656
+ request
657
+ );
658
+
659
+ // A streamed body under maxBodyLength must be counted as fetch consumes
660
+ // it; its size is never trusted from a caller-declared Content-Length.
661
+ const isStreamLike = utils.isReadableStream!(data) || utils.isStream(data);
662
+ const mustEnforceStreamBody = hasMaxBodyLength && isStreamLike;
663
+
664
+ ({ data } = await buildUploadStream(
665
+ data,
666
+ url,
667
+ method!,
668
+ headers,
669
+ onUploadProgress,
670
+ mustEnforceStreamBody,
671
+ preflightContentLength,
672
+ hasMaxBodyLength,
673
+ maxBodyLength!,
674
+ config,
675
+ request,
676
+ pendingBodyErrorRef
677
+ ));
678
+
679
+ withCredentials = normalizeCredentials(withCredentials);
680
+
681
+ // Cloudflare Workers throws when credentials are defined
682
+ // see https://github.com/cloudflare/workerd/issues/902
683
+ const isCredentialsSupported =
684
+ isRequestSupported &&
685
+ Request != null &&
686
+ "credentials" in (Request.prototype as object);
687
+
688
+ cleanFormDataContentType(data, headers);
689
+
690
+ applyDefaultUserAgent(headers);
691
+
692
+ const serializedHeaders = toByteStringHeaderObject(headers.normalize(false));
693
+
694
+ // Browsers auto-add "text/plain;charset=UTF-8" for string bodies when no Content-Type is set.
695
+ // Encoding as Uint8Array prevents the browser from injecting a content-type.
696
+ // Case-insensitive check: toByteStringHeaderObject may normalize to lowercase.
697
+ data = toWebStream(await encodeBodyIfNeeded(data, serializedHeaders, encodeText));
698
+
699
+ const resolvedOptions = {
700
+ ...fetchOptions,
701
+ signal: composedSignal,
702
+ method: (method as string).toUpperCase(),
703
+ headers: serializedHeaders,
704
+ body: data,
705
+ duplex: "half",
706
+ credentials: isCredentialsSupported ? withCredentials : undefined,
707
+ };
708
+
709
+ request = isRequestSupported
710
+ ? new (Request as AnyConstructor)(url, resolvedOptions) as Request
711
+ : null;
712
+
713
+ // Pass resolvedOptions (all own-properties) as the fetch init even when a
714
+ // Request object is supplied: undici re-reads RequestInit fields (method,
715
+ // headers, body, credentials) off Object.prototype when init is absent,
716
+ // so a polluted Object.prototype.method would override the Request's verb.
717
+ // An explicit own-property init neutralizes every such gadget.
718
+ let response = await (isRequestSupported
719
+ ? _fetch(request, resolvedOptions)
720
+ : _fetch(url, resolvedOptions));
721
+
722
+ const responseHeaders = FaxiosHeaders.from(response.headers);
723
+
724
+ checkDeclaredContentLength(responseHeaders, hasMaxContentLength, maxContentLength!, config, request);
725
+
726
+ const isStreamResponse =
727
+ supportsResponseStream &&
728
+ (responseType === "stream" || responseType === "response");
729
+
730
+ response = buildDownloadStream(
731
+ response,
732
+ responseHeaders,
733
+ onDownloadProgress,
734
+ hasMaxContentLength,
735
+ maxContentLength!,
736
+ isStreamResponse,
737
+ unsubscribe,
738
+ config,
739
+ request
740
+ );
741
+
742
+ responseType = responseType || "text";
743
+
744
+ const resolverKey = utils.findKey(resolvers, responseType) || "text";
745
+ const resolver = resolvers[resolverKey];
746
+ const responseData = await (resolver && resolver(response, config));
747
+
748
+ checkMaterializedSize(
749
+ responseData,
750
+ hasMaxContentLength,
751
+ maxContentLength!,
752
+ isStreamResponse,
753
+ supportsResponseStream,
754
+ config,
755
+ request
756
+ );
757
+
758
+ unsubscribeOnComplete(isStreamResponse, unsubscribe);
759
+
760
+ return await new Promise((resolve, reject) => {
761
+ settle(resolve, reject, {
762
+ data: responseData,
763
+ headers: FaxiosHeaders.from(response.headers),
764
+ status: response.status,
765
+ statusText: response.statusText,
766
+ config,
767
+ request,
768
+ });
769
+ });
770
+ }
771
+ catch (err) {
772
+ unsubscribe && unsubscribe();
773
+ throw handleFetchCaughtError(err, composedSignal, pendingBodyErrorRef, config, request);
774
+ }
775
+ };
776
+ };
777
+
778
+ const seedCache = new Map<unknown, unknown>();
779
+
780
+ export const getFetch = (config?: { env?: Record<string, unknown>; }) => {
781
+ const env: Record<string, unknown> = (config && config.env) || {};
782
+ const { fetch, Request, Response } = env as {
783
+ fetch?: unknown;
784
+ Request?: unknown;
785
+ Response?: unknown;
786
+ };
787
+ const seeds: Array<unknown> = [ Request, Response, fetch ];
788
+
789
+ const len = seeds.length;
790
+ let i = len;
791
+ let seed: unknown;
792
+ let target: unknown;
793
+ let map: Map<unknown, unknown> = seedCache;
794
+
795
+ while (i--) {
796
+ seed = seeds[i];
797
+ target = map.get(seed);
798
+
799
+ if (target === undefined) {
800
+ target = i ? new Map<unknown, unknown>() : factory(env);
801
+ map.set(seed, target);
802
+ }
803
+
804
+ map = target as Map<unknown, unknown>;
805
+ }
806
+
807
+ return target;
808
+ };
809
+
810
+ getFetch();