@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,171 @@
1
+ "use strict";
2
+
3
+ import { getFetch } from "../adapters/fetch.js";
4
+ import CanceledError from "../cancel/CanceledError.js";
5
+ import isCancel from "../cancel/isCancel.js";
6
+ import FaxiosError from "../core/FaxiosError.js";
7
+ import FaxiosHeaders from "../core/FaxiosHeaders.js";
8
+ import { validateSchema } from "../core/validateSchema.js";
9
+ import { substitutePathParams } from "../helpers/substitutePathParams.js";
10
+ import type { InternalFaxiosRequestConfig, FaxiosResponse } from "../types.js";
11
+ import utils from "../utils.js";
12
+ import transformData from "./transformData.js";
13
+
14
+ function throwIfCancellationRequested(config: InternalFaxiosRequestConfig): void {
15
+ if (config.signal && config.signal.aborted) {
16
+ throw new CanceledError(undefined, config);
17
+ }
18
+ }
19
+
20
+ async function validateAndSubstitutePathParams(config: InternalFaxiosRequestConfig): Promise<void> {
21
+ if (config.pathParamsSchema) {
22
+ const validated = await validateSchema(
23
+ config.pathParamsSchema, config.pathParams,
24
+ FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA, config
25
+ );
26
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard: schema can return { value: null }
27
+ if (validated == null) {
28
+ throw new FaxiosError(
29
+ "pathParamsSchema returned null/undefined",
30
+ FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA, config
31
+ );
32
+ }
33
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, sonarjs/different-types-comparison -- runtime guard: schema may transform to non-Record
34
+ if (typeof validated !== "object" || validated === null || Array.isArray(validated)) {
35
+ throw new FaxiosError(
36
+ "pathParamsSchema must return a plain object",
37
+ FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA, config
38
+ );
39
+ }
40
+ config.pathParams = validated;
41
+ }
42
+ const params = config.pathParams ?? {};
43
+ try {
44
+ config.url = substitutePathParams(config.url ?? "", params);
45
+ }
46
+ catch (err) {
47
+ throw FaxiosError.from(
48
+ err instanceof Error ? err : new Error(String(err)),
49
+ FaxiosError.ERR_BAD_OPTION_VALUE, config
50
+ );
51
+ }
52
+ }
53
+
54
+ // Intentional mutation: config is the internal merged copy (post-mergeConfig), not the user's original.
55
+ // Validation order (pathParams → params → data) is a fail-fast guarantee — do not reorder.
56
+ // DO NOT make this function async. Returning undefined (not a Promise) on the fast path is a
57
+ // microtask-ordering contract: dispatchRequest must reach the adapter in the same microtask so
58
+ // that a synchronous controller.abort() after request creation is processed by the adapter's
59
+ // signal listener, not before it registers. An async function always returns a Promise, inserting
60
+ // a microtask boundary that breaks abort timing in fetch adapter tests and real-world usage.
61
+ function validatePreFlight(config: InternalFaxiosRequestConfig): Promise<void> | undefined {
62
+ if (config.pathParamsSchema && config.pathParams === undefined) {
63
+ throw new FaxiosError(
64
+ "pathParams is required when pathParamsSchema is configured",
65
+ FaxiosError.ERR_BAD_OPTION_VALUE, config
66
+ );
67
+ }
68
+
69
+ const hasSchemas = config.pathParamsSchema || config.paramsSchema || config.requestSchema;
70
+ if (!hasSchemas && config.pathParams === undefined) return undefined;
71
+
72
+ // pathParams present but no schemas — substitute synchronously, no microtask boundary needed.
73
+ if (!hasSchemas) {
74
+ const params = config.pathParams ?? {};
75
+ try { config.url = substitutePathParams(config.url ?? "", params); }
76
+ catch (err) { throw FaxiosError.from(err instanceof Error ? err : new Error(String(err)), FaxiosError.ERR_BAD_OPTION_VALUE, config); }
77
+ return undefined;
78
+ }
79
+
80
+ return (async () => {
81
+ if (config.pathParams !== undefined) {
82
+ await validateAndSubstitutePathParams(config);
83
+ }
84
+
85
+ if (config.paramsSchema) {
86
+ throwIfCancellationRequested(config);
87
+ config.params = await validateSchema(config.paramsSchema, config.params, FaxiosError.ERR_BAD_PARAMS_SCHEMA, config) as typeof config.params;
88
+ }
89
+
90
+ if (config.requestSchema) {
91
+ throwIfCancellationRequested(config);
92
+ config.data = await validateSchema(config.requestSchema, config.data, FaxiosError.ERR_BAD_REQUEST_SCHEMA, config);
93
+ }
94
+ })();
95
+ }
96
+
97
+ export default async function dispatchRequest(this: unknown, config: InternalFaxiosRequestConfig): Promise<FaxiosResponse> {
98
+ throwIfCancellationRequested(config);
99
+
100
+ const preFlight = validatePreFlight(config);
101
+ if (preFlight) await preFlight;
102
+
103
+ config.headers = FaxiosHeaders.from(config.headers) as unknown as typeof config.headers;
104
+
105
+ config.data = transformData.call(config, config.transformRequest);
106
+
107
+ if (config.data != null && !utils.isFormData(config.data) && [ "post", "put", "patch" ].indexOf(config.method as string) !== -1) {
108
+ (config.headers as unknown as { setContentType: (v: string, r: boolean) => void; }).setContentType("application/x-www-form-urlencoded", false);
109
+ }
110
+
111
+ // Last cancellation check: nothing between here and the adapter call may await. An abort that
112
+ // lands during pre-flight validation must not reach the adapter, which only listens for future
113
+ // abort events.
114
+ throwIfCancellationRequested(config);
115
+
116
+ const _adapter = getFetch(config);
117
+ if (!_adapter) {
118
+ throw new FaxiosError(
119
+ "Fetch API is not supported in this environment",
120
+ FaxiosError.ERR_NOT_SUPPORT,
121
+ config
122
+ );
123
+ }
124
+ const adapter = _adapter as (config: InternalFaxiosRequestConfig) => Promise<FaxiosResponse>;
125
+
126
+ /* eslint-disable promise/always-return */
127
+ return (adapter(config))
128
+ .then(
129
+
130
+ function onAdapterResolution(response: FaxiosResponse) {
131
+ throwIfCancellationRequested(config);
132
+
133
+ (config as unknown as Record<string, unknown>)["response"] = response;
134
+
135
+ try {
136
+ response.data = transformData.call(config, config.transformResponse, response);
137
+ response.headers = FaxiosHeaders.from(response.headers);
138
+ }
139
+ finally {
140
+ delete (config as unknown as Record<string, unknown>)["response"];
141
+ }
142
+
143
+ if (config.responseSchema) {
144
+ return validateSchema(config.responseSchema, response.data, FaxiosError.ERR_BAD_RESPONSE_SCHEMA, config, response)
145
+ .then(data => { response.data = data; throwIfCancellationRequested(config); return response; });
146
+ }
147
+
148
+ return response;
149
+ },
150
+ function onAdapterRejection(reason: unknown) {
151
+ if (!isCancel(reason)) {
152
+ throwIfCancellationRequested(config);
153
+
154
+ const r = reason as { response?: { data?: unknown; headers?: unknown; status?: number; [k: string]: unknown; }; } | null;
155
+ if (r?.response) {
156
+ (config as unknown as Record<string, unknown>)["response"] = r.response;
157
+ try {
158
+ r.response.data = transformData.call(config, config.transformResponse, r.response);
159
+ }
160
+ finally {
161
+ delete (config as unknown as Record<string, unknown>)["response"];
162
+ }
163
+ r.response.headers = FaxiosHeaders.from(r.response.headers as Record<string, unknown>);
164
+ }
165
+ }
166
+
167
+ throw reason;
168
+ }
169
+ );
170
+ /* eslint-enable promise/always-return */
171
+ }
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+
3
+ import type { FaxiosRequestConfig, FaxiosDefaults } from "../types.js";
4
+ import utils from "../utils.js";
5
+ import FaxiosHeaders from "./FaxiosHeaders.js";
6
+
7
+ const headersToObject = (thing: unknown) => (thing instanceof FaxiosHeaders ? { ...thing } : thing);
8
+
9
+ /**
10
+ * Config-specific merge-function which creates a new config-object
11
+ * by merging two configuration objects together.
12
+ *
13
+ * @param {Object} config1
14
+ * @param {Object} config2
15
+ *
16
+ * @returns {Object} New object resulting from merging config2 to config1
17
+ */
18
+ export default function mergeConfig(config1: FaxiosRequestConfig | FaxiosDefaults | Record<string, unknown>, config2?: FaxiosRequestConfig | FaxiosDefaults | Record<string, unknown>): FaxiosRequestConfig & Record<string, unknown> {
19
+
20
+ config2 = config2 || {};
21
+
22
+ // Use a null-prototype object so that downstream reads such as `config.auth`
23
+ // or `config.baseURL` cannot inherit polluted values from Object.prototype.
24
+ // `hasOwnProperty` is restored as a non-enumerable own slot to preserve
25
+ // ergonomics for user code that relies on it.
26
+ const config = Object.create(null);
27
+ Object.defineProperty(config, "hasOwnProperty",
28
+ // Null-proto descriptor so a polluted Object.prototype.get cannot turn
29
+ // this data descriptor into an accessor descriptor on the way in.
30
+ Object.assign(Object.create(null) as PropertyDescriptor, {
31
+ value: Object.prototype.hasOwnProperty,
32
+ enumerable: false,
33
+ writable: true,
34
+ configurable: true,
35
+ })
36
+ );
37
+
38
+ function getMergedValue(target: unknown, source: unknown, _prop?: unknown, caseless?: unknown): unknown {
39
+ if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
40
+ return utils.merge.call({ caseless }, target, source);
41
+ }
42
+ else if (utils.isPlainObject(source)) {
43
+ return utils.merge({}, source);
44
+ }
45
+ else if (utils.isArray(source)) {
46
+ return source.slice();
47
+ }
48
+ return source;
49
+ }
50
+
51
+ function mergeDeepProperties(a: unknown, b: unknown, prop?: unknown, caseless?: unknown): unknown {
52
+ if (!utils.isUndefined(b)) {
53
+ return getMergedValue(a, b, prop, caseless);
54
+ }
55
+ else if (!utils.isUndefined(a)) {
56
+ return getMergedValue(undefined, a, prop, caseless);
57
+ }
58
+ return undefined;
59
+ }
60
+
61
+ function valueFromConfig2(_a: unknown, b: unknown): unknown {
62
+ if (!utils.isUndefined(b)) {
63
+ return getMergedValue(undefined, b);
64
+ }
65
+ return undefined;
66
+ }
67
+
68
+ function defaultToConfig2(a: unknown, b: unknown, prop?: unknown): unknown {
69
+ if (!utils.isUndefined(b)) {
70
+ return getMergedValue(undefined, b);
71
+ }
72
+ // ponytail: explicit undefined in config2 (e.g. xsrfCookieName: undefined) must win over config1's default
73
+ else if (utils.hasOwnProp(config2, prop as string)) {
74
+ return undefined;
75
+ }
76
+ else if (!utils.isUndefined(a)) {
77
+ return getMergedValue(undefined, a);
78
+ }
79
+ return undefined;
80
+ }
81
+
82
+ function getMergedTransitionalOption(prop: string): unknown {
83
+ const c2 = config2 as Record<string, unknown>;
84
+ const c1 = config1 as Record<string, unknown>;
85
+ const transitional2 = utils.hasOwnProp(config2, "transitional") ? c2["transitional"] : undefined;
86
+
87
+ if (!utils.isUndefined(transitional2)) {
88
+ if (utils.isPlainObject(transitional2)) {
89
+ if (utils.hasOwnProp(transitional2, prop)) {
90
+ return (transitional2 as Record<string, unknown>)[prop];
91
+ }
92
+ }
93
+ else {
94
+ return undefined;
95
+ }
96
+ }
97
+
98
+ const transitional1 = utils.hasOwnProp(config1, "transitional") ? c1["transitional"] : undefined;
99
+
100
+ if (utils.isPlainObject(transitional1) && utils.hasOwnProp(transitional1, prop)) {
101
+ return (transitional1 as Record<string, unknown>)[prop];
102
+ }
103
+
104
+ return undefined;
105
+ }
106
+
107
+ function mergeDirectKeys(a: unknown, b: unknown, prop?: unknown): unknown {
108
+ if (utils.hasOwnProp(config2, prop as string)) {
109
+ return getMergedValue(a, b);
110
+ }
111
+ else if (utils.hasOwnProp(config1, prop as string)) {
112
+ return getMergedValue(undefined, a);
113
+ }
114
+ return undefined;
115
+ }
116
+
117
+ const mergeMap = {
118
+ url: valueFromConfig2,
119
+ method: valueFromConfig2,
120
+ data: valueFromConfig2,
121
+ baseURL: defaultToConfig2,
122
+ transformRequest: defaultToConfig2,
123
+ transformResponse: defaultToConfig2,
124
+ paramsSerializer: defaultToConfig2,
125
+ timeout: defaultToConfig2,
126
+ timeoutMessage: defaultToConfig2,
127
+ withCredentials: defaultToConfig2,
128
+ withXSRFToken: defaultToConfig2,
129
+ responseType: defaultToConfig2,
130
+ xsrfCookieName: defaultToConfig2,
131
+ xsrfHeaderName: defaultToConfig2,
132
+ onUploadProgress: defaultToConfig2,
133
+ onDownloadProgress: defaultToConfig2,
134
+ maxContentLength: defaultToConfig2,
135
+ maxBodyLength: defaultToConfig2,
136
+ responseEncoding: defaultToConfig2,
137
+ responseSchema: defaultToConfig2,
138
+ requestSchema: defaultToConfig2,
139
+ paramsSchema: defaultToConfig2,
140
+ pathParams: defaultToConfig2,
141
+ pathParamsSchema: defaultToConfig2,
142
+ validateStatus: mergeDirectKeys,
143
+ headers: (a: unknown, b: unknown, prop?: unknown) =>
144
+ mergeDeepProperties(headersToObject(a), headersToObject(b), prop, true),
145
+ };
146
+
147
+ const c1 = config1 as Record<string, unknown>;
148
+ const c2 = config2 as Record<string, unknown>;
149
+ const out = config as Record<string, unknown>;
150
+
151
+ utils.forEach(Object.keys({ ...config1, ...config2 }), function computeConfigValue(_value: unknown, _prop: unknown) {
152
+ const key = _value as string;
153
+ if (key === "__proto__" || key === "constructor" || key === "prototype") return;
154
+ const mergeFn = (utils.hasOwnProp(mergeMap, key) ? (mergeMap as Record<string, typeof mergeDeepProperties>)[key] : mergeDeepProperties)!;
155
+ const a = utils.hasOwnProp(config1, key) ? c1[key] : undefined;
156
+ const b = utils.hasOwnProp(config2, key) ? c2[key] : undefined;
157
+ const configValue = mergeFn(a, b, key);
158
+ (utils.isUndefined(configValue) && mergeFn !== mergeDirectKeys) || (out[key] = configValue);
159
+ });
160
+
161
+ if (
162
+ utils.hasOwnProp(config2, "validateStatus") &&
163
+ utils.isUndefined((config2).validateStatus) &&
164
+ getMergedTransitionalOption("validateStatusUndefinedResolves") === false
165
+ ) {
166
+ if (utils.hasOwnProp(config1, "validateStatus")) {
167
+ out["validateStatus"] = getMergedValue(undefined, (config1).validateStatus);
168
+ }
169
+ else {
170
+ delete out["validateStatus"];
171
+ }
172
+ }
173
+
174
+ return config;
175
+ }
@@ -0,0 +1,155 @@
1
+ import buildFullPath from "../core/buildFullPath.js";
2
+ import FaxiosHeaders from "../core/FaxiosHeaders.js";
3
+ import buildURL from "../helpers/buildURL.js";
4
+ import cloneConfig from "../helpers/cloneConfig.js";
5
+ import cookies from "../helpers/cookies.js";
6
+ import isURLSameOrigin from "../helpers/isURLSameOrigin.js";
7
+ import platform from "../platform.js";
8
+ import type { FaxiosRequestConfig } from "../types.js";
9
+ import utils from "../utils.js";
10
+
11
+ const FORM_DATA_CONTENT_HEADERS = [ "content-type", "content-length" ];
12
+
13
+ function setFormDataHeaders(
14
+ headers: FaxiosHeaders,
15
+ formHeaders: Record<string, unknown>,
16
+ policy: unknown
17
+ ): void {
18
+ if (policy !== "content-only") {
19
+ headers.set(formHeaders);
20
+ return;
21
+ }
22
+ /* eslint-disable big-o/no-array-lookup-in-loop -- 2-element constant array */
23
+ Object.entries(formHeaders).forEach(([ key, val ]) => {
24
+ if (FORM_DATA_CONTENT_HEADERS.includes(key.toLowerCase())) {
25
+ headers.set(key, val);
26
+ }
27
+ });
28
+ /* eslint-enable big-o/no-array-lookup-in-loop */
29
+ }
30
+
31
+ /**
32
+ * Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
33
+ * This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
34
+ *
35
+ * @param {string} str The string to encode
36
+ *
37
+ * @returns {string} UTF-8 bytes as a Latin-1 string
38
+ */
39
+ const encodeUTF8 = (str: string): string =>
40
+ encodeURIComponent(str).replace(
41
+ /%([0-9A-F]{2})/gi,
42
+ (_: string, hex: string) => String.fromCharCode(parseInt(hex, 16))
43
+ );
44
+
45
+ function applyXSRFToken(
46
+ headers: FaxiosHeaders,
47
+ withXSRFToken: ((cfg: unknown) => unknown) | boolean | null | undefined,
48
+ xsrfHeaderName: string | undefined,
49
+ xsrfCookieName: string | undefined,
50
+ config: FaxiosRequestConfig
51
+ ): void {
52
+ if (utils.isFunction(withXSRFToken)) {
53
+ withXSRFToken = (withXSRFToken as (cfg: unknown) => unknown)(
54
+ config
55
+ ) as boolean | null | undefined;
56
+ }
57
+
58
+ // Strict boolean check — prevents proto-pollution gadgets (e.g. Object.prototype.withXSRFToken = 1)
59
+ // and misconfigurations (e.g. "false") from short-circuiting the same-origin check and leaking
60
+ // the XSRF token cross-origin.
61
+ const shouldSendXSRF =
62
+ withXSRFToken === true ||
63
+ (withXSRFToken == null && isURLSameOrigin(config.url ?? ""));
64
+
65
+ if (shouldSendXSRF) {
66
+ const xsrfValue =
67
+ xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName);
68
+
69
+ if (xsrfValue) {
70
+ headers.set(xsrfHeaderName, xsrfValue);
71
+ }
72
+ }
73
+ }
74
+
75
+ function prepareRequest(config: FaxiosRequestConfig): FaxiosRequestConfig {
76
+ const newConfig = cloneConfig(config);
77
+
78
+ // Read only own properties to prevent prototype pollution gadgets
79
+ // (e.g. Object.prototype.baseURL = 'https://evil.com').
80
+ const own = (key: string) =>
81
+ utils.hasOwnProp(newConfig, key)
82
+ ? (newConfig as Record<string, unknown>)[key]
83
+ : undefined;
84
+
85
+ const data = own("data");
86
+ let withXSRFToken = own("withXSRFToken") as
87
+ | ((cfg: unknown) => unknown)
88
+ | boolean
89
+ | null
90
+ | undefined;
91
+ const xsrfHeaderName = own("xsrfHeaderName") as string | undefined;
92
+ const xsrfCookieName = own("xsrfCookieName") as string | undefined;
93
+ const auth = own("auth");
94
+ const baseURL = own("baseURL");
95
+ const allowAbsoluteUrls = own("allowAbsoluteUrls");
96
+ const url = own("url");
97
+
98
+ const headers: FaxiosHeaders = FaxiosHeaders.from(
99
+ own("headers") as Record<string, unknown> | null | undefined
100
+ );
101
+ newConfig.headers = headers;
102
+
103
+ newConfig.url = buildURL(
104
+ buildFullPath(baseURL, url, allowAbsoluteUrls, newConfig),
105
+ own("params"),
106
+ own("paramsSerializer")
107
+ );
108
+
109
+ // HTTP basic authentication
110
+ if (auth) {
111
+ const username = String(utils.getSafeProp(auth, "username") || "");
112
+ const password = String(utils.getSafeProp(auth, "password") || "");
113
+
114
+ headers.set(
115
+ "Authorization",
116
+ "Basic " +
117
+ (
118
+ (globalThis as Record<string, unknown>)["btoa"] as (
119
+ s: string
120
+ ) => string
121
+ )(username + ":" + (password ? encodeUTF8(password) : ""))
122
+ );
123
+ }
124
+
125
+ if (utils.isFormData(data)) {
126
+ if (
127
+ platform.hasStandardBrowserEnv ||
128
+ platform.hasStandardBrowserWebWorkerEnv ||
129
+ utils.isReactNative(data)
130
+ ) {
131
+ (headers.setContentType as (v: unknown) => unknown)(undefined); // browser/web worker/RN handles it
132
+ }
133
+ else if (
134
+ utils.isFunction((data as Record<string, unknown>)["getHeaders"])
135
+ ) {
136
+ // Node.js FormData (like form-data package)
137
+ setFormDataHeaders(
138
+ headers,
139
+ (data as { getHeaders: () => Record<string, unknown>; }).getHeaders(),
140
+ own("formDataHeaderPolicy")
141
+ );
142
+ }
143
+ }
144
+
145
+ // Add xsrf header
146
+ // This is only done if running in a standard browser environment.
147
+ // Specifically not if we're in a web worker, or react-native.
148
+ if (platform.hasStandardBrowserEnv) {
149
+ applyXSRFToken(headers, withXSRFToken, xsrfHeaderName, xsrfCookieName, newConfig);
150
+ }
151
+
152
+ return newConfig;
153
+ }
154
+
155
+ export default prepareRequest;
@@ -0,0 +1,68 @@
1
+ // @ts-self-types="./route.d.ts" — required for Deno: maps built .js to adjacent .d.ts in dist/
2
+
3
+ import type { StandardSchemaV1 } from "../types/standard-schema.js";
4
+ import type { BasePerCallConfig, DefineConfig, DefinedEndpoint, FaxiosLike } from "./define.js";
5
+ import { createDefinedEndpoint } from "./define.js";
6
+
7
+ /** Config for `route()`: request defaults shared by every method, plus an optional `pathParamsSchema`. */
8
+ export type RouteConfig<PP extends StandardSchemaV1<unknown, Record<string, unknown>> | undefined = undefined> =
9
+ BasePerCallConfig & {
10
+ /**
11
+ * Standard Schema that validates `pathParams` on every call of every method's endpoint; its
12
+ * output fills the `{key}` placeholders. Makes `pathParams` required per call, and a method's
13
+ * config can't replace it. A failure rejects with `ERR_BAD_PATH_PARAMS_SCHEMA`.
14
+ */
15
+ pathParamsSchema?: PP;
16
+ };
17
+
18
+ /** Config for one method of a route; merged over the route config. */
19
+ export type RouteMethodConfig<
20
+ P extends StandardSchemaV1 | undefined = undefined,
21
+ D extends StandardSchemaV1 | undefined = undefined,
22
+ R extends StandardSchemaV1 | undefined = undefined
23
+ > = BasePerCallConfig & {
24
+ paramsSchema?: P;
25
+ requestSchema?: D;
26
+ responseSchema?: R;
27
+ };
28
+
29
+ /** The object `route()` returns: one endpoint factory per HTTP method (no `query`). */
30
+ export type RouteBuilder<PP extends StandardSchemaV1<unknown, Record<string, unknown>> | undefined, TOpts = unknown> = {
31
+ [M in "get" | "post" | "put" | "patch" | "delete" | "head" | "options"]: <
32
+ P extends StandardSchemaV1 | undefined = undefined,
33
+ D extends StandardSchemaV1 | undefined = undefined,
34
+ R extends StandardSchemaV1 | undefined = undefined
35
+ >(config?: RouteMethodConfig<P, D, R> & TOpts) => DefinedEndpoint<PP, P, D, R, TOpts>;
36
+ };
37
+
38
+ // ponytail: `query` excluded — non-standard HTTP method alias, not useful in route definitions
39
+ const methods = [ "get", "post", "put", "patch", "delete", "head", "options" ] as const satisfies ReadonlyArray<keyof RouteBuilder<undefined>>;
40
+
41
+ export function createRouteBuilder<PP extends StandardSchemaV1<unknown, Record<string, unknown>> | undefined>(
42
+ instance: FaxiosLike,
43
+ url: string,
44
+ routeConfig?: RouteConfig<PP>
45
+ ): RouteBuilder<PP> {
46
+ const raw = Object.assign(Object.create(null), routeConfig ?? {});
47
+ delete raw.__proto__;
48
+ delete raw.constructor;
49
+ delete raw.prototype;
50
+ const { pathParamsSchema, ...routeDefaults } = raw;
51
+
52
+ const builder = {} as RouteBuilder<PP>;
53
+ for (const method of methods) {
54
+ (builder as Record<string, unknown>)[method] = <
55
+ P extends StandardSchemaV1 | undefined,
56
+ D extends StandardSchemaV1 | undefined,
57
+ R extends StandardSchemaV1 | undefined
58
+ >(methodConfig?: RouteMethodConfig<P, D, R>) => {
59
+ const defineConf = {
60
+ ...routeDefaults,
61
+ ...(methodConfig ?? {}),
62
+ ...(pathParamsSchema !== undefined ? { pathParamsSchema } : {}),
63
+ } as DefineConfig<PP, P, D, R>;
64
+ return createDefinedEndpoint<PP, P, D, R>(instance, method, url, defineConf);
65
+ };
66
+ }
67
+ return builder;
68
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ import type { FaxiosResponse } from "../types.js";
4
+ import FaxiosError from "./FaxiosError.js";
5
+
6
+ export function settle(resolve: (value: FaxiosResponse) => void, reject: (reason: unknown) => void, response: FaxiosResponse): void {
7
+ const validateStatus = response.config.validateStatus;
8
+ if (!response.status || !validateStatus || validateStatus(response.status)) {
9
+ resolve(response);
10
+ }
11
+ else {
12
+ reject(new FaxiosError(
13
+ "Request failed with status code " + response.status,
14
+ response.status >= 400 && response.status < 500 ? FaxiosError.ERR_BAD_REQUEST : FaxiosError.ERR_BAD_RESPONSE,
15
+ response.config,
16
+ response.request,
17
+ response
18
+ ));
19
+ }
20
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ import FaxiosHeaders from "../core/FaxiosHeaders.js";
4
+ import defaults from "../defaults/index.js";
5
+ import type { InternalFaxiosRequestConfig, FaxiosRequestHeaders, FaxiosRequestTransformer, FaxiosResponseTransformer } from "../types.js";
6
+ import utils from "../utils.js";
7
+
8
+ type TransformFn = FaxiosRequestTransformer | FaxiosResponseTransformer;
9
+
10
+ export default function transformData(this: unknown, fns: TransformFn | Array<TransformFn> | undefined, response?: { data?: unknown; headers?: unknown; status?: number; } | null): unknown {
11
+ const config = (this || defaults) as InternalFaxiosRequestConfig;
12
+ const context = response || config;
13
+ const headers = FaxiosHeaders.from(context.headers as Record<string, unknown> | undefined);
14
+ let data: unknown = (context as { data?: unknown; }).data;
15
+
16
+ utils.forEach(fns, function transform(fn: unknown) {
17
+ data = (fn as TransformFn).call(config, data, headers as unknown as FaxiosRequestHeaders, response?.status);
18
+ });
19
+
20
+ headers.normalize(false);
21
+
22
+ return data;
23
+ }
@@ -0,0 +1,53 @@
1
+ import isCancel from "../cancel/isCancel.js";
2
+ import type { StandardSchemaV1 } from "../types/standard-schema.js";
3
+ import type { InternalFaxiosRequestConfig, FaxiosResponse } from "../types.js";
4
+ import FaxiosError from "./FaxiosError.js";
5
+
6
+ type SchemaErrorCode =
7
+ | typeof FaxiosError.ERR_BAD_RESPONSE_SCHEMA
8
+ | typeof FaxiosError.ERR_BAD_REQUEST_SCHEMA
9
+ | typeof FaxiosError.ERR_BAD_PARAMS_SCHEMA
10
+ | typeof FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA;
11
+
12
+ export async function validateSchema<S extends StandardSchemaV1>(
13
+ schema: S,
14
+ value: unknown,
15
+ errorCode: SchemaErrorCode,
16
+ config: InternalFaxiosRequestConfig,
17
+ response?: FaxiosResponse
18
+ ): Promise<StandardSchemaV1.InferOutput<S>> {
19
+ let result: StandardSchemaV1.Result<unknown> | undefined;
20
+ try {
21
+ const raw = schema["~standard"].validate(value);
22
+ result = raw instanceof Promise ? await raw : raw;
23
+ }
24
+ catch (err) {
25
+ if (isCancel(err)) throw err;
26
+ const cause = err instanceof Error ? err : new Error(String(err), { cause: err });
27
+ const wrapped = FaxiosError.from(
28
+ cause, errorCode, config, undefined, response
29
+ );
30
+ wrapped.issues = [{ message: wrapped.message }];
31
+ throw wrapped;
32
+ }
33
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
34
+ if (!result) {
35
+ const error = new FaxiosError(
36
+ `schema['~standard'].validate() returned a non-Result value`,
37
+ errorCode, config, undefined, response
38
+ );
39
+ error.issues = [];
40
+ throw error;
41
+ }
42
+ if (result.issues !== undefined) {
43
+ const error = new FaxiosError(
44
+ "Schema validation failed",
45
+ errorCode, config, undefined, response
46
+ );
47
+ // Strip to spec-only fields — runtime libs may attach sensitive data
48
+ error.issues = result.issues.map(({ message, path }) => path ? { message, path } : { message });
49
+ throw error;
50
+ }
51
+ // Standard Schema spec guarantees Result.value aligns with InferOutput
52
+ return result.value;
53
+ }