@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,61 @@
1
+ "use strict";
2
+
3
+ import utils from "../utils.js";
4
+
5
+ function trimSPorHTAB(str: string): string {
6
+ let start = 0;
7
+ let end = str.length;
8
+
9
+ while (start < end) {
10
+ const code = str.charCodeAt(start);
11
+
12
+ if (code !== 0x09 && code !== 0x20) {
13
+ break;
14
+ }
15
+
16
+ start += 1;
17
+ }
18
+
19
+ while (end > start) {
20
+ const code = str.charCodeAt(end - 1);
21
+
22
+ if (code !== 0x09 && code !== 0x20) {
23
+ break;
24
+ }
25
+
26
+ end -= 1;
27
+ }
28
+
29
+ return start === 0 && end === str.length ? str : str.slice(start, end);
30
+ }
31
+
32
+ // The control-code ranges are intentional: header sanitization strips C0/DEL bytes.
33
+ // eslint-disable-next-line no-control-regex
34
+ const INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp("[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+", "g");
35
+ // eslint-disable-next-line no-control-regex, sonarjs/no-control-regex
36
+ const INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+", "g");
37
+
38
+ // eslint-disable-next-line sonarjs/function-return-type
39
+ function sanitizeValue(value: unknown, invalidChars: RegExp): string | Array<string> {
40
+ if (utils.isArray(value)) {
41
+ return (value as Array<unknown>).map(item => sanitizeValue(item, invalidChars) as string);
42
+ }
43
+
44
+ return trimSPorHTAB(String(value).replace(invalidChars, ""));
45
+ }
46
+
47
+ export const sanitizeHeaderValue = (value: unknown) =>
48
+ sanitizeValue(value, INVALID_UNICODE_HEADER_VALUE_CHARS);
49
+
50
+ const sanitizeByteStringHeaderValue = (value: unknown) =>
51
+ sanitizeValue(value, INVALID_BYTE_STRING_HEADER_VALUE_CHARS);
52
+
53
+ export function toByteStringHeaderObject(headers: { toJSON: () => Record<string, unknown>; }) {
54
+ const byteStringHeaders: Record<string, unknown> = Object.create(null);
55
+
56
+ utils.forEach(headers.toJSON(), (value: unknown, header: unknown) => {
57
+ byteStringHeaders[String(header)] = sanitizeByteStringHeaderValue(value);
58
+ });
59
+
60
+ return byteStringHeaders;
61
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Calculate data maxRate
5
+ * @param {Number} [samplesCount= 10]
6
+ * @param {Number} [min= 1000]
7
+ * @returns {Function}
8
+ */
9
+ function speedometer(samplesCount?: number, min?: number): (chunkLength: number) => number | undefined {
10
+ samplesCount = samplesCount || 10;
11
+ const bytes: Array<number> = new Array(samplesCount);
12
+ const timestamps: Array<number> = new Array(samplesCount);
13
+ let head = 0;
14
+ let tail = 0;
15
+ let firstSampleTS: number | undefined;
16
+
17
+ min = min !== undefined ? min : 1000;
18
+
19
+ return function push(chunkLength: number): number | undefined {
20
+ const now = Date.now();
21
+
22
+ const startedAt = timestamps[tail];
23
+
24
+ if (!firstSampleTS) {
25
+ firstSampleTS = now;
26
+ }
27
+
28
+ bytes[head] = chunkLength;
29
+ timestamps[head] = now;
30
+
31
+ let i = tail;
32
+ let bytesCount = 0;
33
+
34
+ while (i !== head) {
35
+ bytesCount += bytes[i++]!;
36
+ i = i % samplesCount;
37
+ }
38
+
39
+ head = (head + 1) % samplesCount;
40
+
41
+ if (head === tail) {
42
+ tail = (tail + 1) % samplesCount;
43
+ }
44
+
45
+ if (now - firstSampleTS < min) {
46
+ return;
47
+ }
48
+
49
+ const passed = startedAt && now - startedAt;
50
+
51
+ return passed ? Math.round((bytesCount * 1000) / passed) : undefined;
52
+ };
53
+ }
54
+
55
+ export default speedometer;
@@ -0,0 +1,13 @@
1
+ /** Expects raw (unencoded) param values — applies encodeURIComponent here. */
2
+ export function substitutePathParams(url: string, params: Record<string, unknown>): string {
3
+ return url.replace(/\{([^{}]+)\}/g, (_match, key: string) => {
4
+ if (!Object.prototype.hasOwnProperty.call(params, key)) {
5
+ throw new Error(`Path param "${key}" not found in pathParams`);
6
+ }
7
+ const val = params[key];
8
+ if (val == null) {
9
+ throw new Error(`Path param "${key}" is null or undefined`);
10
+ }
11
+ return encodeURIComponent(String(val));
12
+ });
13
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Throttle decorator
3
+ * @param {Function} fn
4
+ * @param {Number} freq
5
+ * @return {Function}
6
+ */
7
+ function throttle(fn: (...args: Array<unknown>) => void, freq: number): [(...args: Array<unknown>) => void, () => void] {
8
+ let timestamp = 0;
9
+ const threshold = 1000 / freq;
10
+ let lastArgs: Array<unknown> | null = null;
11
+ let timer: ReturnType<typeof setTimeout> | null = null;
12
+
13
+ const invoke = (args: Array<unknown>, now: number = Date.now()) => {
14
+ timestamp = now;
15
+ lastArgs = null;
16
+ if (timer) {
17
+ clearTimeout(timer);
18
+ timer = null;
19
+ }
20
+ fn(...args);
21
+ };
22
+
23
+ const throttled = (...args: Array<unknown>) => {
24
+ const now = Date.now();
25
+ const passed = now - timestamp;
26
+ if (passed >= threshold) {
27
+ invoke(args, now);
28
+ }
29
+ else {
30
+ lastArgs = args;
31
+ if (!timer) {
32
+ timer = setTimeout(() => {
33
+ timer = null;
34
+ invoke(lastArgs!);
35
+ }, threshold - passed);
36
+ }
37
+ }
38
+ };
39
+
40
+ const flush = () => { if (lastArgs) invoke(lastArgs); };
41
+
42
+ return [ throttled, flush ];
43
+ }
44
+
45
+ export default throttle;
@@ -0,0 +1,296 @@
1
+ "use strict";
2
+
3
+ import FaxiosError from "../core/FaxiosError.js";
4
+ // temporary hotfix to avoid circular references until FaxiosURLSearchParams is refactored
5
+ import type { GenericFormData, SerializerVisitor, FormDataVisitorHelpers } from "../types.js";
6
+ import utils from "../utils.js";
7
+
8
+ // Default nesting limit shared with the inverse transform (formDataToJSON) so
9
+ // the FormData <-> JSON round-trip stays symmetric.
10
+ export const DEFAULT_FORM_DATA_MAX_DEPTH = 100;
11
+
12
+ /**
13
+ * Determines if the given thing is a array or js object.
14
+ *
15
+ * @param {string} thing - The object or array to be visited.
16
+ *
17
+ * @returns {boolean}
18
+ */
19
+ function isVisitable(thing: unknown): boolean {
20
+ return utils.isPlainObject(thing) || utils.isArray(thing);
21
+ }
22
+
23
+ /**
24
+ * It removes the brackets from the end of a string
25
+ *
26
+ * @param {string} key - The key of the parameter.
27
+ *
28
+ * @returns {string} the key without the brackets.
29
+ */
30
+ function removeBrackets(key: string): string {
31
+ return key.endsWith("[]") ? key.slice(0, -2) : key;
32
+ }
33
+
34
+ /**
35
+ * It takes a path, a key, and a boolean, and returns a string
36
+ *
37
+ * @param {string} path - The path to the current key.
38
+ * @param {string} key - The key of the current object being iterated over.
39
+ * @param {string} dots - If true, the key will be rendered with dots instead of brackets.
40
+ *
41
+ * @returns {string} The path to the current key.
42
+ */
43
+ function renderKey(path: Array<string | number> | null | undefined, key: string | number, dots: unknown): string {
44
+ if (!path) return String(key);
45
+ return path
46
+ .concat(key)
47
+ .map(function each(token: string | number, i: number) {
48
+ token = removeBrackets(String(token));
49
+ return !dots && i ? "[" + token + "]" : token;
50
+ })
51
+ .join(dots ? "." : "");
52
+ }
53
+
54
+ /**
55
+ * If the array is an array and none of its elements are visitable, then it's a flat array.
56
+ *
57
+ * @param {Array<any>} arr - The array to check
58
+ *
59
+ * @returns {boolean}
60
+ */
61
+ function isFlatArray(arr: unknown): boolean {
62
+ return utils.isArray(arr) && !(arr as Array<unknown>).some(isVisitable);
63
+ }
64
+
65
+ const predicates = utils.toFlatObject(utils, {}, null as unknown as false, function filter(prop: string) {
66
+ return /^is[A-Z]/.test(prop);
67
+ });
68
+
69
+ /**
70
+ * Convert a data object to FormData
71
+ *
72
+ * @param {Object} obj
73
+ * @param {?Object} [formData]
74
+ * @param {?Object} [options]
75
+ * @param {Function} [options.visitor]
76
+ * @param {Boolean} [options.metaTokens = true]
77
+ * @param {Boolean} [options.dots = false]
78
+ * @param {?Boolean} [options.indexes = false]
79
+ *
80
+ * @returns {Object}
81
+ **/
82
+
83
+ /**
84
+ * It converts an object into a FormData object
85
+ *
86
+ * @param {Object<any, any>} obj - The object to convert to form data.
87
+ * @param {string} formData - The FormData object to append to.
88
+ * @param {Object<string, any>} options
89
+ *
90
+ * @returns
91
+ */
92
+ function toFormData(obj: unknown, formData?: GenericFormData | null, options?: Record<string, unknown>): GenericFormData {
93
+ if (!utils.isObject(obj)) {
94
+ throw new TypeError("target must be an object");
95
+ }
96
+
97
+ const FormDataCtor = (globalThis as Record<string, unknown>)["FormData"] as (new () => GenericFormData) | undefined;
98
+ if (!formData) {
99
+ if (!FormDataCtor) throw new FaxiosError("FormData is not available in this environment", FaxiosError.ERR_NOT_SUPPORT);
100
+ formData = new FormDataCtor();
101
+ }
102
+
103
+ options = utils.toFlatObject(
104
+ options,
105
+ {
106
+ metaTokens: true,
107
+ dots: false,
108
+ indexes: false,
109
+ },
110
+ false,
111
+ function defined(option: string, source: unknown) {
112
+ return !utils.isUndefined((source as Record<string, unknown>)[option]);
113
+ }
114
+ );
115
+
116
+ const metaTokens = options["metaTokens"];
117
+
118
+ const visitor = (options["visitor"] || defaultVisitor) as SerializerVisitor;
119
+ const dots = options["dots"];
120
+ const indexes = options["indexes"];
121
+ const _Blob = options["Blob"] || (typeof (globalThis as Record<string, unknown>)["Blob"] !== "undefined" && (globalThis as Record<string, unknown>)["Blob"]);
122
+ const maxDepth =
123
+ options["maxDepth"] === undefined
124
+ ? DEFAULT_FORM_DATA_MAX_DEPTH
125
+ : (options["maxDepth"] as number);
126
+ const useBlob = _Blob && utils.isSpecCompliantForm(formData);
127
+ const stack: Array<unknown> = [];
128
+
129
+ if (!utils.isFunction(visitor)) {
130
+ throw new TypeError("visitor must be a function");
131
+ }
132
+
133
+ function convertValue(value: unknown): unknown {
134
+ if (value === null) return "";
135
+
136
+ if (utils.isDate(value)) {
137
+ return (value as Date).toISOString();
138
+ }
139
+
140
+ if (utils.isBoolean(value)) {
141
+ return String(value);
142
+ }
143
+
144
+ if (!useBlob && utils.isBlob(value)) {
145
+ throw new FaxiosError("Blob is not supported. Use a Buffer instead.");
146
+ }
147
+
148
+ if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
149
+ const BlobCtor = (globalThis as Record<string, unknown>)["Blob"] as (new (parts: Array<unknown>) => unknown) | undefined;
150
+ if (useBlob && typeof BlobCtor === "function") {
151
+ return new BlobCtor([ value ]);
152
+ }
153
+ throw new FaxiosError("Blob is required for binary FormData values in this environment", FaxiosError.ERR_NOT_SUPPORT);
154
+ }
155
+
156
+ return value;
157
+ }
158
+
159
+ function throwIfMaxDepthExceeded(depth: number): void {
160
+ if (depth > (maxDepth)) {
161
+ throw new FaxiosError(
162
+ "Object is too deeply nested (" +
163
+ depth +
164
+ " levels). Max depth: " +
165
+ maxDepth,
166
+ FaxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED
167
+ );
168
+ }
169
+ }
170
+
171
+ function stringifyWithDepthLimit(value: unknown, depth: number): string {
172
+ if (maxDepth === Infinity) {
173
+ return JSON.stringify(value);
174
+ }
175
+
176
+ const ancestors: Array<unknown> = [];
177
+
178
+ return JSON.stringify(value, function limitDepth(this: unknown, _key: string, currentValue: unknown): unknown {
179
+ if (!utils.isObject(currentValue)) {
180
+ return currentValue;
181
+ }
182
+
183
+ while (ancestors.length && ancestors[ancestors.length - 1] !== this) {
184
+ ancestors.pop();
185
+ }
186
+
187
+ ancestors.push(currentValue);
188
+ throwIfMaxDepthExceeded(depth + ancestors.length - 1);
189
+
190
+ return currentValue;
191
+ });
192
+ }
193
+
194
+ /**
195
+ * Default visitor.
196
+ *
197
+ * @param {*} value
198
+ * @param {String|Number} key
199
+ * @param {Array<String|Number>} path
200
+ * @this {FormData}
201
+ *
202
+ * @returns {boolean} return true to visit the each prop of the value recursively
203
+ */
204
+ function defaultVisitor(this: GenericFormData, value: unknown, key: string | number, path: null | Array<string | number>, _helpers?: FormDataVisitorHelpers): boolean {
205
+ let arr: unknown = value;
206
+
207
+ if (utils.isReactNative(formData) && utils.isReactNativeBlob(value)) {
208
+ (formData as GenericFormData).append(renderKey(path, key, dots), convertValue(value));
209
+ return false;
210
+ }
211
+
212
+ if (value && !path && typeof value === "object") {
213
+ if (String(key).endsWith("{}")) {
214
+ key = metaTokens ? key : String(key).slice(0, -2);
215
+
216
+ value = stringifyWithDepthLimit(value, 1);
217
+ }
218
+ else if (
219
+ (utils.isArray(value) && isFlatArray(value)) ||
220
+ ((utils.isFileList(value) || String(key).endsWith("[]")) &&
221
+ (arr = utils.toArray(value)))
222
+ ) {
223
+ key = removeBrackets(String(key));
224
+
225
+ (arr as Array<unknown>).forEach(function each(el: unknown, index: number) {
226
+ !utils.isUndefined(el) && el !== null &&
227
+ (formData as GenericFormData).append(
228
+ /* eslint-disable sonarjs/no-nested-conditional */
229
+ indexes === true
230
+ ? renderKey([ String(key) ], index, dots)
231
+ : indexes === null
232
+ ? String(key)
233
+ : String(key) + "[]",
234
+ /* eslint-enable sonarjs/no-nested-conditional */
235
+ convertValue(el)
236
+ );
237
+ });
238
+ return false;
239
+ }
240
+ }
241
+
242
+ if (isVisitable(value)) {
243
+ return true;
244
+ }
245
+
246
+ (formData as GenericFormData).append(renderKey(path, key, dots), convertValue(value));
247
+
248
+ return false;
249
+ }
250
+
251
+ const exposedHelpers: FormDataVisitorHelpers = Object.assign(predicates, {
252
+ defaultVisitor: defaultVisitor,
253
+ convertValue,
254
+ isVisitable,
255
+ });
256
+
257
+ function build(value: unknown, path?: Array<string | number>, depth = 0): void {
258
+ if (utils.isUndefined(value)) return;
259
+
260
+ throwIfMaxDepthExceeded(depth);
261
+
262
+ if (stack.indexOf(value) !== -1) {
263
+ throw new Error("Circular reference detected in " + (path ?? []).join("."));
264
+ }
265
+
266
+ stack.push(value);
267
+
268
+ utils.forEach(value, function each(el: unknown, key: unknown) {
269
+ const result =
270
+ !utils.isUndefined(el) && el !== null &&
271
+ visitor.call(
272
+ formData as GenericFormData,
273
+ el,
274
+ utils.isString(key) ? (key as string).trim() : key as string | number,
275
+ path ?? null,
276
+ exposedHelpers
277
+ );
278
+
279
+ if (result === true) {
280
+ build(el, path ? path.concat(key as string | number) : [ key as string | number ], depth + 1);
281
+ }
282
+ });
283
+
284
+ stack.pop();
285
+ }
286
+
287
+ if (!utils.isObject(obj)) {
288
+ throw new TypeError("data must be an object");
289
+ }
290
+
291
+ build(obj);
292
+
293
+ return formData;
294
+ }
295
+
296
+ export default toFormData;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ import platform from "../platform.js";
4
+ import type { GenericFormData } from "../types.js";
5
+ import toFormData from "./toFormData.js";
6
+
7
+ export default function toURLEncodedForm(data: unknown, options?: Record<string, unknown>) {
8
+ // ponytail: web-standard platform always provides global URLSearchParams
9
+ return toFormData(
10
+ data,
11
+ new (platform.classes.URLSearchParams as new () => object)() as unknown as GenericFormData,
12
+ { ...options }
13
+ );
14
+ }
@@ -0,0 +1,123 @@
1
+ type ReadableStreamController = {
2
+ enqueue: (chunk: Uint8Array) => void;
3
+ close: () => void;
4
+ };
5
+
6
+ type ReadableStreamSource = {
7
+ pull?: (controller: ReadableStreamController) => Promise<void>;
8
+ cancel?: (reason?: unknown) => Promise<unknown>;
9
+ };
10
+
11
+ type ReadableStreamInit = {
12
+ highWaterMark?: number;
13
+ };
14
+
15
+ type ReadableStreamCtor = new (source: ReadableStreamSource, init?: ReadableStreamInit) => unknown;
16
+
17
+ const ReadableStreamGlobal = (globalThis as Record<string, unknown>)["ReadableStream"] as ReadableStreamCtor | undefined;
18
+
19
+ type ByteChunk = { byteLength: number; slice: (start: number, end?: number) => ByteChunk; };
20
+
21
+ const streamChunk = function* (chunk: ByteChunk, chunkSize?: number): Generator<ByteChunk> {
22
+ const len = chunk.byteLength;
23
+
24
+ if (!chunkSize || len < chunkSize) {
25
+ yield chunk;
26
+ return;
27
+ }
28
+
29
+ let pos = 0;
30
+ let end: number;
31
+
32
+ while (pos < len) {
33
+ end = pos + chunkSize;
34
+ yield chunk.slice(pos, end);
35
+ pos = end;
36
+ }
37
+ };
38
+
39
+ const readBytes = async function* (iterable: AsyncIterable<ByteChunk> | unknown, chunkSize?: number): AsyncGenerator<ByteChunk> {
40
+ for await (const chunk of readStream(iterable)) {
41
+ yield* streamChunk(chunk, chunkSize);
42
+ }
43
+ };
44
+
45
+ type ReaderLike = {
46
+ read: () => Promise<{ done: boolean; value: ByteChunk; }>;
47
+ cancel: () => Promise<void>;
48
+ };
49
+
50
+ type StreamLike = {
51
+ [Symbol.asyncIterator]?: () => AsyncIterator<ByteChunk>;
52
+ getReader?: () => ReaderLike;
53
+ };
54
+
55
+ const readStream = async function* (stream: unknown): AsyncGenerator<ByteChunk> {
56
+ const s = stream as StreamLike;
57
+ if (s[Symbol.asyncIterator]) {
58
+ yield* s as AsyncIterable<ByteChunk>;
59
+ return;
60
+ }
61
+
62
+ const reader = s.getReader!();
63
+ try {
64
+ for (;;) {
65
+ // eslint-disable-next-line no-await-in-loop
66
+ const { done, value } = await reader.read();
67
+ if (done) {
68
+ break;
69
+ }
70
+ yield value;
71
+ }
72
+ }
73
+ finally {
74
+ await reader.cancel();
75
+ }
76
+ };
77
+
78
+ export const trackStream = (stream: unknown, chunkSize: number | undefined, onProgress?: ((bytes: number) => void) | null, onFinish?: ((err?: unknown) => void) | null): unknown => {
79
+ const iterator = readBytes(stream, chunkSize);
80
+
81
+ let bytes = 0;
82
+ let done = false;
83
+ const _onFinish = (e?: unknown): void => {
84
+ if (!done) {
85
+ done = true;
86
+ onFinish && onFinish(e);
87
+ }
88
+ };
89
+
90
+ return new ReadableStreamGlobal!(
91
+ {
92
+ async pull(controller: ReadableStreamController) {
93
+ try {
94
+ const { done: iterDone, value } = await iterator.next();
95
+
96
+ if (iterDone) {
97
+ _onFinish();
98
+ controller.close();
99
+ return;
100
+ }
101
+
102
+ const len = value.byteLength;
103
+ if (onProgress) {
104
+ const loadedBytes = (bytes += len);
105
+ onProgress(loadedBytes);
106
+ }
107
+ controller.enqueue(new Uint8Array(value as unknown as ArrayBuffer));
108
+ }
109
+ catch (err) {
110
+ _onFinish(err);
111
+ throw err;
112
+ }
113
+ },
114
+ async cancel(reason?: unknown) {
115
+ _onFinish(reason);
116
+ return iterator.return(undefined);
117
+ },
118
+ },
119
+ {
120
+ highWaterMark: 2,
121
+ }
122
+ );
123
+ };