@gcmdev/faxios 0.2.1 → 0.2.3

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 (131) hide show
  1. package/dist/index.d.ts +3 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/adapters/fetch-helpers.d.ts +1 -1
  6. package/dist/lib/adapters/fetch-helpers.d.ts.map +1 -1
  7. package/dist/lib/adapters/fetch.d.ts +4 -1
  8. package/dist/lib/adapters/fetch.d.ts.map +1 -1
  9. package/dist/lib/adapters/fetch.js +210 -92
  10. package/dist/lib/adapters/fetch.js.map +1 -1
  11. package/dist/lib/cancel/CanceledError.d.ts +1 -1
  12. package/dist/lib/cancel/CanceledError.d.ts.map +1 -1
  13. package/dist/lib/core/Faxios.d.ts +3 -3
  14. package/dist/lib/core/Faxios.d.ts.map +1 -1
  15. package/dist/lib/core/Faxios.js +8 -4
  16. package/dist/lib/core/Faxios.js.map +1 -1
  17. package/dist/lib/core/FaxiosError.d.ts +2 -2
  18. package/dist/lib/core/FaxiosError.d.ts.map +1 -1
  19. package/dist/lib/core/FaxiosHeaders.d.ts +8 -8
  20. package/dist/lib/core/FaxiosHeaders.d.ts.map +1 -1
  21. package/dist/lib/core/FaxiosHeaders.js +31 -7
  22. package/dist/lib/core/FaxiosHeaders.js.map +1 -1
  23. package/dist/lib/core/define.d.ts +3 -3
  24. package/dist/lib/core/define.d.ts.map +1 -1
  25. package/dist/lib/core/dispatchRequest.d.ts +1 -1
  26. package/dist/lib/core/dispatchRequest.d.ts.map +1 -1
  27. package/dist/lib/core/dispatchRequest.js +6 -1
  28. package/dist/lib/core/dispatchRequest.js.map +1 -1
  29. package/dist/lib/core/mergeConfig.d.ts +2 -2
  30. package/dist/lib/core/mergeConfig.d.ts.map +1 -1
  31. package/dist/lib/core/mergeConfig.js +40 -2
  32. package/dist/lib/core/mergeConfig.js.map +1 -1
  33. package/dist/lib/core/route.d.ts +1 -1
  34. package/dist/lib/core/route.d.ts.map +1 -1
  35. package/dist/lib/core/route.js +2 -5
  36. package/dist/lib/core/route.js.map +1 -1
  37. package/dist/lib/core/transformData.d.ts +2 -2
  38. package/dist/lib/core/transformData.d.ts.map +1 -1
  39. package/dist/lib/core/validateSchema.d.ts +2 -2
  40. package/dist/lib/core/validateSchema.d.ts.map +1 -1
  41. package/dist/lib/env/data.d.ts +1 -1
  42. package/dist/lib/env/data.js +1 -1
  43. package/dist/lib/faxios.d.ts +50 -50
  44. package/dist/lib/faxios.d.ts.map +1 -1
  45. package/dist/lib/helpers/cloneConfig.d.ts +0 -1
  46. package/dist/lib/helpers/cloneConfig.d.ts.map +1 -1
  47. package/dist/lib/helpers/cloneConfig.js +2 -2
  48. package/dist/lib/helpers/cloneConfig.js.map +1 -1
  49. package/dist/lib/helpers/cookies.d.ts +1 -1
  50. package/dist/lib/helpers/cookies.d.ts.map +1 -1
  51. package/dist/lib/helpers/formDataToJSON.d.ts +1 -1
  52. package/dist/lib/helpers/formDataToJSON.d.ts.map +1 -1
  53. package/dist/lib/helpers/formDataToJSON.js +1 -1
  54. package/dist/lib/helpers/formDataToJSON.js.map +1 -1
  55. package/dist/lib/helpers/parseHeaders.d.ts +1 -1
  56. package/dist/lib/helpers/parseHeaders.d.ts.map +1 -1
  57. package/dist/lib/helpers/progressEventReducer.d.ts.map +1 -1
  58. package/dist/lib/helpers/progressEventReducer.js +14 -1
  59. package/dist/lib/helpers/progressEventReducer.js.map +1 -1
  60. package/dist/lib/helpers/substitutePathParams.d.ts.map +1 -1
  61. package/dist/lib/helpers/substitutePathParams.js +11 -3
  62. package/dist/lib/helpers/substitutePathParams.js.map +1 -1
  63. package/dist/lib/helpers/toFormData.d.ts.map +1 -1
  64. package/dist/lib/helpers/toFormData.js +16 -20
  65. package/dist/lib/helpers/toFormData.js.map +1 -1
  66. package/dist/lib/helpers/trackStream.d.ts.map +1 -1
  67. package/dist/lib/helpers/trackStream.js +27 -3
  68. package/dist/lib/helpers/trackStream.js.map +1 -1
  69. package/dist/lib/helpers/validator.d.ts +1 -1
  70. package/dist/lib/helpers/validator.d.ts.map +1 -1
  71. package/dist/lib/platform.d.ts.map +1 -1
  72. package/dist/lib/plugins/authBearer.d.ts +9 -5
  73. package/dist/lib/plugins/authBearer.d.ts.map +1 -1
  74. package/dist/lib/plugins/authBearer.js +6 -0
  75. package/dist/lib/plugins/authBearer.js.map +1 -1
  76. package/dist/lib/plugins/definePlugin.d.ts +3 -3
  77. package/dist/lib/plugins/definePlugin.d.ts.map +1 -1
  78. package/dist/lib/plugins/retry.d.ts +23 -23
  79. package/dist/lib/plugins/retry.d.ts.map +1 -1
  80. package/dist/lib/plugins/timing.d.ts +8 -8
  81. package/dist/lib/plugins/timing.d.ts.map +1 -1
  82. package/dist/lib/types/standard-schema.d.ts +6 -6
  83. package/dist/lib/types/standard-schema.d.ts.map +1 -1
  84. package/dist/lib/types.d.ts +106 -92
  85. package/dist/lib/types.d.ts.map +1 -1
  86. package/dist/lib/utils.d.ts +4 -3
  87. package/dist/lib/utils.d.ts.map +1 -1
  88. package/dist/lib/utils.js +18 -5
  89. package/dist/lib/utils.js.map +1 -1
  90. package/package.json +7 -4
  91. package/skills/configure-requests/SKILL.md +14 -8
  92. package/skills/configure-requests/references/axios-differences.md +1 -1
  93. package/skills/configure-requests/references/plugins.md +37 -6
  94. package/src/index.ts +15 -15
  95. package/src/lib/adapters/fetch-helpers.ts +3 -3
  96. package/src/lib/adapters/fetch.ts +263 -144
  97. package/src/lib/cancel/CanceledError.ts +1 -1
  98. package/src/lib/core/Faxios.ts +17 -13
  99. package/src/lib/core/FaxiosError.ts +3 -3
  100. package/src/lib/core/FaxiosHeaders.ts +50 -23
  101. package/src/lib/core/define.ts +7 -7
  102. package/src/lib/core/dispatchRequest.ts +8 -3
  103. package/src/lib/core/mergeConfig.ts +42 -4
  104. package/src/lib/core/prepareRequest.ts +1 -1
  105. package/src/lib/core/route.ts +3 -6
  106. package/src/lib/core/transformData.ts +2 -2
  107. package/src/lib/core/validateSchema.ts +4 -4
  108. package/src/lib/defaults/index.ts +1 -1
  109. package/src/lib/env/data.ts +1 -1
  110. package/src/lib/faxios.ts +55 -55
  111. package/src/lib/helpers/HttpStatusCode.ts +1 -1
  112. package/src/lib/helpers/cloneConfig.ts +2 -3
  113. package/src/lib/helpers/composeSignals.ts +4 -4
  114. package/src/lib/helpers/cookies.ts +3 -3
  115. package/src/lib/helpers/formDataToJSON.ts +4 -4
  116. package/src/lib/helpers/parseHeaders.ts +2 -2
  117. package/src/lib/helpers/progressEventReducer.ts +15 -2
  118. package/src/lib/helpers/sanitizeHeaderValue.ts +1 -1
  119. package/src/lib/helpers/substitutePathParams.ts +13 -3
  120. package/src/lib/helpers/throttle.ts +1 -1
  121. package/src/lib/helpers/toFormData.ts +26 -28
  122. package/src/lib/helpers/trackStream.ts +40 -12
  123. package/src/lib/helpers/validator.ts +3 -3
  124. package/src/lib/platform.ts +4 -4
  125. package/src/lib/plugins/authBearer.ts +14 -9
  126. package/src/lib/plugins/definePlugin.ts +3 -3
  127. package/src/lib/plugins/retry.ts +27 -27
  128. package/src/lib/plugins/timing.ts +5 -5
  129. package/src/lib/types/standard-schema.ts +6 -6
  130. package/src/lib/types.ts +139 -125
  131. package/src/lib/utils.ts +30 -15
@@ -13,7 +13,7 @@ class CanceledError extends FaxiosError {
13
13
  *
14
14
  * @returns {CanceledError} The created error.
15
15
  */
16
- constructor(message?: string | null, config?: FaxiosRequestConfig, request?: unknown) {
16
+ constructor(message?: null | string, config?: FaxiosRequestConfig, request?: unknown) {
17
17
  super(message == null ? "canceled" : message, FaxiosError.ERR_CANCELED, config as InternalFaxiosRequestConfig, request);
18
18
  this.name = "CanceledError";
19
19
  (this as unknown as Record<string, unknown>)["__CANCEL__"] = true;
@@ -2,10 +2,9 @@
2
2
 
3
3
  import CanceledError from "../cancel/CanceledError.js";
4
4
  import buildURL from "../helpers/buildURL.js";
5
- import cloneConfig, { DANGEROUS_KEYS } from "../helpers/cloneConfig.js";
5
+ import cloneConfig from "../helpers/cloneConfig.js";
6
6
  import validator from "../helpers/validator.js";
7
7
  import type { ValidatorFn } from "../helpers/validator.js";
8
- import type { StandardSchemaV1 } from "../types/standard-schema.js";
9
8
  import type {
10
9
  FaxiosContext,
11
10
  FaxiosMiddleware,
@@ -21,6 +20,7 @@ import type {
21
20
  SchemaConfig,
22
21
  StringLiteralsOrString
23
22
  } from "../types.js";
23
+ import type { StandardSchemaV1 } from "../types/standard-schema.js";
24
24
  import utils from "../utils.js";
25
25
  import buildFullPath from "./buildFullPath.js";
26
26
  import { createDefinedEndpoint } from "./define.js";
@@ -29,21 +29,21 @@ import dispatchRequest from "./dispatchRequest.js";
29
29
  import FaxiosError from "./FaxiosError.js";
30
30
  import FaxiosHeaders from "./FaxiosHeaders.js";
31
31
  import mergeConfig from "./mergeConfig.js";
32
- import type { RouteConfig, RouteBuilder } from "./route.js";
32
+ import type { RouteBuilder, RouteConfig } from "./route.js";
33
33
  import { createRouteBuilder } from "./route.js";
34
34
 
35
35
  type TransitionalFn = (
36
- validator: ValidatorFn | false | undefined,
36
+ validator: false | undefined | ValidatorFn,
37
37
  version?: string,
38
38
  message?: string
39
39
  ) => ValidatorFn;
40
40
  type SpellingFn = (correctSpelling: string) => ValidatorFn;
41
41
  const validators = validator.validators as Record<
42
42
  string,
43
- ValidatorFn | undefined
43
+ undefined | ValidatorFn
44
44
  > & {
45
- transitional?: TransitionalFn;
46
45
  spelling?: SpellingFn;
46
+ transitional?: TransitionalFn;
47
47
  };
48
48
 
49
49
  // Every method header group declared on HeadersDefaults. `satisfies` keeps this
@@ -133,7 +133,10 @@ function resolveAllowAbsoluteUrls(
133
133
  defaults: FaxiosRequestConfig
134
134
  ): void {
135
135
  if (config.allowAbsoluteUrls === undefined) {
136
- config.allowAbsoluteUrls = defaults.allowAbsoluteUrls ?? !defaults.baseURL;
136
+ // Own reads only: instance defaults may be a plain object (the default instance's are).
137
+ const allowAbsoluteUrls = utils.hasOwnProp(defaults, "allowAbsoluteUrls") ? defaults.allowAbsoluteUrls : undefined;
138
+ const baseURL = utils.hasOwnProp(defaults, "baseURL") ? defaults.baseURL : undefined;
139
+ config.allowAbsoluteUrls = allowAbsoluteUrls ?? !baseURL;
137
140
  }
138
141
  }
139
142
 
@@ -143,10 +146,10 @@ type AnyContextMiddleware = FaxiosMiddleware<unknown, unknown>;
143
146
  type AnyContextNext = FaxiosNext<unknown, unknown>;
144
147
 
145
148
  type MiddlewareEntry = {
149
+ provided: Array<string>;
146
150
  // The value passed to use(), kept only for eject()'s identity check.
147
151
  ref: unknown;
148
152
  run: AnyContextMiddleware;
149
- provided: Array<string>;
150
153
  };
151
154
 
152
155
  function composeMiddleware(entries: ReadonlyArray<MiddlewareEntry>, dispatch: AnyContextNext): AnyContextNext {
@@ -272,7 +275,7 @@ class Faxios {
272
275
 
273
276
  #addCapabilities(pluginName: string, provides: unknown): Array<string> {
274
277
  const source = provides as Record<string, unknown>;
275
- const keys = Object.keys(source).filter(key => !DANGEROUS_KEYS.has(key));
278
+ const keys = Object.keys(source).filter(key => !utils.isDangerousKey(key));
276
279
  for (const key of keys) {
277
280
  if (utils.hasOwnProp(this.#capabilities, key)) {
278
281
  throw new FaxiosError(`Plugin "${pluginName}" provides capability "${key}", which another plugin already provides`, FaxiosError.ERR_BAD_OPTION);
@@ -295,9 +298,9 @@ class Faxios {
295
298
  */
296
299
 
297
300
  async request<O, D = unknown>(config: SchemaConfig<O, D>): Promise<FaxiosResponse<O, D>>;
298
- async request<T = unknown, R = FaxiosResponse<T>, D = unknown>(configOrUrl: string | FaxiosRequestConfig<D>, config?: FaxiosRequestConfig<D>): Promise<R>;
301
+ async request<T = unknown, R = FaxiosResponse<T>, D = unknown>(configOrUrl: FaxiosRequestConfig<D> | string, config?: FaxiosRequestConfig<D>): Promise<R>;
299
302
  async request(
300
- configOrUrl: string | FaxiosRequestConfig,
303
+ configOrUrl: FaxiosRequestConfig | string,
301
304
  config?: FaxiosRequestConfig
302
305
  ) {
303
306
  try {
@@ -313,7 +316,7 @@ class Faxios {
313
316
  }
314
317
 
315
318
  async #request(
316
- configOrUrl: string | FaxiosRequestConfig,
319
+ configOrUrl: FaxiosRequestConfig | string,
317
320
  config?: FaxiosRequestConfig
318
321
  ): Promise<unknown> {
319
322
  /*eslint no-param-reassign:0*/
@@ -361,8 +364,9 @@ class Faxios {
361
364
  );
362
365
 
363
366
  // Set config.method
367
+ const defaultMethod = utils.hasOwnProp(this.defaults, "method") ? this.defaults.method : undefined;
364
368
  config.method = (
365
- (config.method || this.defaults.method || "get") as string
369
+ (config.method || defaultMethod || "get") as string
366
370
  ).toLowerCase();
367
371
 
368
372
  // Flatten headers
@@ -1,8 +1,8 @@
1
1
  // @ts-self-types="./FaxiosError.d.ts" — required for Deno: index.d.ts re-exports SchemaValidationError from here
2
2
  "use strict";
3
3
 
4
+ import type { FaxiosResponse, InternalFaxiosRequestConfig } from "../types.js";
4
5
  import type { StandardSchemaV1 } from "../types/standard-schema.js";
5
- import type { InternalFaxiosRequestConfig, FaxiosResponse } from "../types.js";
6
6
  import utils from "../utils.js";
7
7
  import FaxiosHeaders from "./FaxiosHeaders.js";
8
8
 
@@ -247,9 +247,9 @@ export type SchemaValidationError =
247
247
  }
248
248
  | FaxiosError & {
249
249
  code:
250
- | typeof FaxiosError.ERR_BAD_REQUEST_SCHEMA
251
250
  | typeof FaxiosError.ERR_BAD_PARAMS_SCHEMA
252
- | typeof FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA;
251
+ | typeof FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA
252
+ | typeof FaxiosError.ERR_BAD_REQUEST_SCHEMA;
253
253
  issues: SchemaIssues;
254
254
  };
255
255
 
@@ -9,16 +9,16 @@ import utils from "../utils.js";
9
9
  const $internals = Symbol("internals");
10
10
 
11
11
  type HeaderMatcher =
12
- | string
12
+ | ((this: FaxiosHeaders, value: string, name: string) => boolean)
13
13
  | RegExp
14
- | ((this: FaxiosHeaders, value: string, name: string) => boolean);
14
+ | string;
15
15
 
16
16
  type HeaderInput =
17
- | Record<string, unknown>
18
17
  | FaxiosHeaders
18
+ | null
19
+ | Record<string, unknown>
19
20
  | string
20
- | undefined
21
- | null;
21
+ | undefined;
22
22
 
23
23
  /** Matches a `FaxiosHeaders` instance by its type-only brand. */
24
24
  export type FaxiosHeadersInstance = Pick<FaxiosHeaders, typeof faxiosHeadersBrand>;
@@ -28,10 +28,29 @@ function normalizeHeader(header: string): string {
28
28
  .toLowerCase();
29
29
  }
30
30
 
31
+ // Per instance: lowercased own key -> own key. Callers may also write and delete headers as plain
32
+ // properties, so an entry is only trusted while its key is still own, and a miss rebuilds the index.
33
+ const keyIndexes = new WeakMap<object, Map<string, string>>();
34
+
35
+ function indexKeys(headers: object): Map<string, string> {
36
+ const index = new Map<string, string>();
37
+ // Later keys overwrite earlier ones, matching utils.findKey, which scans from the end.
38
+ for (const key of Object.keys(headers)) {
39
+ index.set(key.toLowerCase(), key);
40
+ }
41
+ keyIndexes.set(headers, index);
42
+ return index;
43
+ }
44
+
45
+ function findHeaderKey(headers: object, lHeader: string): string | undefined {
46
+ const key = keyIndexes.get(headers)?.get(lHeader);
47
+ return key !== undefined && utils.hasOwnProp(headers, key) ? key : indexKeys(headers).get(lHeader);
48
+ }
49
+
31
50
  // eslint-disable-next-line sonarjs/function-return-type
32
51
  function normalizeValue(
33
52
  value: FaxiosHeaderValue | undefined
34
- ): string | Array<string> | false | null | undefined {
53
+ ): Array<string> | false | null | string | undefined {
35
54
  if (value == null) {
36
55
  return value;
37
56
  }
@@ -64,9 +83,9 @@ function matchHeaderValue(
64
83
  value: unknown,
65
84
  header: string,
66
85
  filter:
67
- | string
68
- | RegExp
69
86
  | ((this: FaxiosHeaders, value: string, name: string) => boolean)
87
+ | RegExp
88
+ | string
70
89
  | undefined,
71
90
  isHeaderNameFilter?: boolean
72
91
  ): boolean | undefined {
@@ -176,7 +195,7 @@ class FaxiosHeaders {
176
195
  declare hasAuthorization: (matcher?: HeaderMatcher) => boolean;
177
196
 
178
197
  constructor(
179
- headers?: Record<string, unknown> | FaxiosHeaders | string | null
198
+ headers?: FaxiosHeaders | null | Record<string, unknown> | string
180
199
  ) {
181
200
  headers && this.set(headers);
182
201
  }
@@ -187,6 +206,9 @@ class FaxiosHeaders {
187
206
  rewrite?: boolean
188
207
  ): this {
189
208
  const self = this;
209
+ // Set once a lookup misses, which rebuilds the index from the own keys. Only setHeader writes
210
+ // to self until this call returns, so from then on the index is complete and a miss is final.
211
+ let index: Map<string, string> | undefined;
190
212
 
191
213
  function setHeader(
192
214
  _value: unknown,
@@ -199,7 +221,11 @@ class FaxiosHeaders {
199
221
  return;
200
222
  }
201
223
 
202
- const key = utils.findKey(self, lHeader) as string | undefined;
224
+ const key = index ? index.get(lHeader) : findHeaderKey(self, lHeader);
225
+ if (key === undefined) {
226
+ index ??= keyIndexes.get(self)!;
227
+ index.set(String(_header).toLowerCase(), _header);
228
+ }
203
229
 
204
230
  if (
205
231
  !key ||
@@ -244,23 +270,23 @@ class FaxiosHeaders {
244
270
 
245
271
  get(header: string): FaxiosHeaderValue | undefined;
246
272
  get(header: string, parser: true): Record<string, string> | undefined;
247
- get(header: string, parser: RegExp): RegExpExecArray | null | undefined;
273
+ get(header: string, parser: RegExp): null | RegExpExecArray | undefined;
248
274
  get<R>(header: string, parser: (this: FaxiosHeaders, value: FaxiosHeaderValue, header: string) => R): R | undefined;
249
275
  get(
250
276
  header: string,
251
277
  parser?:
252
- | RegExp
253
278
  | ((
254
279
  this: FaxiosHeaders,
255
280
  value: FaxiosHeaderValue,
256
281
  header: string
257
282
  ) => unknown)
283
+ | RegExp
258
284
  | true
259
285
  ): unknown {
260
286
  header = normalizeHeader(header);
261
287
 
262
288
  if (header) {
263
- const key = utils.findKey(this, header) as string | undefined;
289
+ const key = findHeaderKey(this, header);
264
290
 
265
291
  if (key) {
266
292
  const value = (this as Record<string, unknown>)[
@@ -299,7 +325,7 @@ class FaxiosHeaders {
299
325
  header = normalizeHeader(header);
300
326
 
301
327
  if (header) {
302
- const key = utils.findKey(this, header) as string | undefined;
328
+ const key = findHeaderKey(this, header);
303
329
 
304
330
  return !!(
305
331
  key &&
@@ -317,7 +343,7 @@ class FaxiosHeaders {
317
343
  return false;
318
344
  }
319
345
 
320
- delete(header: string | Array<string>, matcher?: HeaderMatcher): boolean {
346
+ delete(header: Array<string> | string, matcher?: HeaderMatcher): boolean {
321
347
  const self = this;
322
348
  let deleted = false;
323
349
 
@@ -325,7 +351,7 @@ class FaxiosHeaders {
325
351
  _header = normalizeHeader(_header);
326
352
 
327
353
  if (_header) {
328
- const key = utils.findKey(self, _header) as string | undefined;
354
+ const key = findHeaderKey(self, _header);
329
355
 
330
356
  if (
331
357
  key &&
@@ -381,11 +407,12 @@ class FaxiosHeaders {
381
407
 
382
408
  normalize(format: boolean = false): this {
383
409
  const self = this;
384
- const headers: Record<string, unknown> = {};
410
+ // Lowercased normalized name -> normalized name, for names already kept.
411
+ const kept = new Map<string, string>();
385
412
 
386
413
  utils.forEach(this, (value: unknown, _header: unknown) => {
387
414
  const header = _header as string;
388
- const key = utils.findKey(headers, header) as string | undefined;
415
+ const key = kept.get(header.toLowerCase());
389
416
 
390
417
  if (key) {
391
418
  (self as Record<string, unknown>)[key] = normalizeValue(
@@ -405,7 +432,7 @@ class FaxiosHeaders {
405
432
  value as FaxiosHeaderValue
406
433
  );
407
434
 
408
- headers[normalized] = true;
435
+ kept.set(normalized.toLowerCase(), normalized);
409
436
  });
410
437
 
411
438
  return this;
@@ -450,15 +477,15 @@ class FaxiosHeaders {
450
477
  }
451
478
 
452
479
  static from(
453
- thing?: Record<string, unknown> | FaxiosHeaders | string | null
480
+ thing?: FaxiosHeaders | null | Record<string, unknown> | string
454
481
  ): FaxiosHeaders {
455
482
  return thing instanceof this ? thing : new this(thing);
456
483
  }
457
484
 
458
485
  static concat(
459
- first: Record<string, unknown> | FaxiosHeaders | string | undefined | null,
486
+ first: FaxiosHeaders | null | Record<string, unknown> | string | undefined,
460
487
  ...targets: Array<
461
- Record<string, unknown> | FaxiosHeaders | string | undefined | null
488
+ FaxiosHeaders | null | Record<string, unknown> | string | undefined
462
489
  >
463
490
  ): FaxiosHeaders {
464
491
  const computed = new this(first);
@@ -468,7 +495,7 @@ class FaxiosHeaders {
468
495
  return computed;
469
496
  }
470
497
 
471
- static accessor(header: string | Array<string>): typeof FaxiosHeaders {
498
+ static accessor(header: Array<string> | string): typeof FaxiosHeaders {
472
499
  const self = this as unknown as Record<
473
500
  symbol,
474
501
  { accessors: Record<string, boolean>; }
@@ -1,19 +1,19 @@
1
1
  // @ts-self-types="./define.d.ts" — required for Deno: maps built .js to adjacent .d.ts in dist/
2
2
 
3
+ import type { FaxiosRequestConfig, FaxiosResponse, Method, StringLiteralsOrString } from "../types.js";
3
4
  import type { StandardSchemaV1 } from "../types/standard-schema.js";
4
- import type { FaxiosRequestConfig, FaxiosResponse, StringLiteralsOrString, Method } from "../types.js";
5
5
  import mergeConfig from "./mergeConfig.js";
6
6
 
7
7
  type StrippedFields =
8
- | "url"
8
+ | "data"
9
9
  | "method"
10
- | "pathParams"
11
10
  | "params"
12
- | "data"
13
- | "pathParamsSchema"
14
11
  | "paramsSchema"
12
+ | "pathParams"
13
+ | "pathParamsSchema"
15
14
  | "requestSchema"
16
- | "responseSchema";
15
+ | "responseSchema"
16
+ | "url";
17
17
 
18
18
  /** Request config accepted by a defined endpoint call: everything except `url`, `method`, `pathParams`, `params`, `data` and the schemas. */
19
19
  export type BasePerCallConfig = Omit<FaxiosRequestConfig, StrippedFields>;
@@ -47,12 +47,12 @@ export type DefineConfig<
47
47
  D extends StandardSchemaV1 | undefined = undefined,
48
48
  R extends StandardSchemaV1 | undefined = undefined
49
49
  > = BasePerCallConfig & {
50
+ paramsSchema?: P;
50
51
  /**
51
52
  * Standard Schema that validates `pathParams` on every call; its output fills the `{key}`
52
53
  * placeholders. Makes `pathParams` required per call. A failure rejects with `ERR_BAD_PATH_PARAMS_SCHEMA`.
53
54
  */
54
55
  pathParamsSchema?: PP;
55
- paramsSchema?: P;
56
56
  requestSchema?: D;
57
57
  responseSchema?: R;
58
58
  };
@@ -7,7 +7,7 @@ import FaxiosError from "../core/FaxiosError.js";
7
7
  import FaxiosHeaders from "../core/FaxiosHeaders.js";
8
8
  import { validateSchema } from "../core/validateSchema.js";
9
9
  import { substitutePathParams } from "../helpers/substitutePathParams.js";
10
- import type { InternalFaxiosRequestConfig, FaxiosResponse } from "../types.js";
10
+ import type { FaxiosResponse, InternalFaxiosRequestConfig } from "../types.js";
11
11
  import utils from "../utils.js";
12
12
  import transformData from "./transformData.js";
13
13
 
@@ -104,7 +104,12 @@ export default async function dispatchRequest(this: unknown, config: InternalFax
104
104
 
105
105
  config.data = transformData.call(config, config.transformRequest);
106
106
 
107
- if (config.data != null && !utils.isFormData(config.data) && [ "post", "put", "patch" ].indexOf(config.method as string) !== -1) {
107
+ const data: unknown = config.data;
108
+ // Binary and stream bodies keep their own type: fetch uses `Blob.type` or sends none.
109
+ const isBinaryOrStream = utils.isBlob(data) || utils.isFile(data) || utils.isArrayBuffer(data) || utils.isArrayBufferView(data) ||
110
+ utils.isReadableStream?.(data) || utils.isStream(data) ||
111
+ (typeof data === "object" && data !== null && Symbol.asyncIterator in data);
112
+ if (data != null && !utils.isFormData(data) && !isBinaryOrStream && [ "post", "put", "patch" ].indexOf(config.method as string) !== -1) {
108
113
  (config.headers as unknown as { setContentType: (v: string, r: boolean) => void; }).setContentType("application/x-www-form-urlencoded", false);
109
114
  }
110
115
 
@@ -151,7 +156,7 @@ export default async function dispatchRequest(this: unknown, config: InternalFax
151
156
  if (!isCancel(reason)) {
152
157
  throwIfCancellationRequested(config);
153
158
 
154
- const r = reason as { response?: { data?: unknown; headers?: unknown; status?: number; [k: string]: unknown; }; } | null;
159
+ const r = reason as null | { response?: { [k: string]: unknown; data?: unknown; headers?: unknown; status?: number; }; };
155
160
  if (r?.response) {
156
161
  (config as unknown as Record<string, unknown>)["response"] = r.response;
157
162
  try {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- import type { FaxiosRequestConfig, FaxiosDefaults } from "../types.js";
3
+ import type { FaxiosDefaults, FaxiosRequestConfig } from "../types.js";
4
4
  import utils from "../utils.js";
5
5
  import FaxiosHeaders from "./FaxiosHeaders.js";
6
6
 
@@ -15,7 +15,7 @@ const headersToObject = (thing: unknown) => (thing instanceof FaxiosHeaders ? {
15
15
  *
16
16
  * @returns {Object} New object resulting from merging config2 to config1
17
17
  */
18
- export default function mergeConfig(config1: FaxiosRequestConfig | FaxiosDefaults | Record<string, unknown>, config2?: FaxiosRequestConfig | FaxiosDefaults | Record<string, unknown>): FaxiosRequestConfig & Record<string, unknown> {
18
+ export default function mergeConfig(config1: FaxiosDefaults | FaxiosRequestConfig | Record<string, unknown>, config2?: FaxiosDefaults | FaxiosRequestConfig | Record<string, unknown>): FaxiosRequestConfig & Record<string, unknown> {
19
19
 
20
20
  config2 = config2 || {};
21
21
 
@@ -79,6 +79,40 @@ export default function mergeConfig(config1: FaxiosRequestConfig | FaxiosDefault
79
79
  return undefined;
80
80
  }
81
81
 
82
+ // Shallow own-key copy into a null-prototype object, later sources winning. Every own key is
83
+ // kept, including `constructor`, `prototype` and `__proto__`: `params` are caller data that
84
+ // reach the query string, and defineProperty stores them as plain data slots.
85
+ function ownCopy(...sources: Array<unknown>): Record<string, unknown> {
86
+ const out: Record<string, unknown> = Object.create(null);
87
+ for (const source of sources) {
88
+ if (!utils.isPlainObject(source)) continue;
89
+ const record = source as Record<string, unknown>;
90
+ for (const key of Object.keys(record)) {
91
+ Object.defineProperty(out, key, Object.assign(Object.create(null) as PropertyDescriptor, {
92
+ value: record[key],
93
+ enumerable: true,
94
+ writable: true,
95
+ configurable: true,
96
+ }));
97
+ }
98
+ }
99
+ return out;
100
+ }
101
+
102
+ // `params`: a plain object is copied with every own key; anything else (URLSearchParams,
103
+ // a custom serializer's input) passes through as given.
104
+ function mergeParams(a: unknown, b: unknown): unknown {
105
+ const source = utils.isUndefined(b) ? a : b;
106
+ if (!utils.isPlainObject(source)) return source;
107
+ return utils.isUndefined(b) ? ownCopy(a) : ownCopy(a, b);
108
+ }
109
+
110
+ // `env`: shallow, null-prototype, so `fetch`, `Request` and `Response` can only be own values.
111
+ function mergeEnv(a: unknown, b: unknown): unknown {
112
+ if (utils.isUndefined(a) && utils.isUndefined(b)) return undefined;
113
+ return ownCopy(a, b);
114
+ }
115
+
82
116
  function getMergedTransitionalOption(prop: string): unknown {
83
117
  const c2 = config2 as Record<string, unknown>;
84
118
  const c1 = config1 as Record<string, unknown>;
@@ -117,7 +151,11 @@ export default function mergeConfig(config1: FaxiosRequestConfig | FaxiosDefault
117
151
  const mergeMap = {
118
152
  url: valueFromConfig2,
119
153
  method: valueFromConfig2,
120
- data: valueFromConfig2,
154
+ // The body is passed by reference: faxios never mutates it, and copying would drop keys such
155
+ // as `constructor` and cost a deep clone per request.
156
+ data: (_a: unknown, b: unknown) => b,
157
+ params: mergeParams,
158
+ env: mergeEnv,
121
159
  baseURL: defaultToConfig2,
122
160
  transformRequest: defaultToConfig2,
123
161
  transformResponse: defaultToConfig2,
@@ -150,7 +188,7 @@ export default function mergeConfig(config1: FaxiosRequestConfig | FaxiosDefault
150
188
 
151
189
  utils.forEach(Object.keys({ ...config1, ...config2 }), function computeConfigValue(_value: unknown, _prop: unknown) {
152
190
  const key = _value as string;
153
- if (key === "__proto__" || key === "constructor" || key === "prototype") return;
191
+ if (utils.isDangerousKey(key)) return;
154
192
  const mergeFn = (utils.hasOwnProp(mergeMap, key) ? (mergeMap as Record<string, typeof mergeDeepProperties>)[key] : mergeDeepProperties)!;
155
193
  const a = utils.hasOwnProp(config1, key) ? c1[key] : undefined;
156
194
  const b = utils.hasOwnProp(config2, key) ? c2[key] : undefined;
@@ -96,7 +96,7 @@ function prepareRequest(config: FaxiosRequestConfig): FaxiosRequestConfig {
96
96
  const url = own("url");
97
97
 
98
98
  const headers: FaxiosHeaders = FaxiosHeaders.from(
99
- own("headers") as Record<string, unknown> | null | undefined
99
+ own("headers") as null | Record<string, unknown> | undefined
100
100
  );
101
101
  newConfig.headers = headers;
102
102
 
@@ -1,5 +1,6 @@
1
1
  // @ts-self-types="./route.d.ts" — required for Deno: maps built .js to adjacent .d.ts in dist/
2
2
 
3
+ import cloneConfig from "../helpers/cloneConfig.js";
3
4
  import type { StandardSchemaV1 } from "../types/standard-schema.js";
4
5
  import type { BasePerCallConfig, DefineConfig, DefinedEndpoint, FaxiosLike } from "./define.js";
5
6
  import { createDefinedEndpoint } from "./define.js";
@@ -28,7 +29,7 @@ export type RouteMethodConfig<
28
29
 
29
30
  /** The object `route()` returns: one endpoint factory per HTTP method (no `query`). */
30
31
  export type RouteBuilder<PP extends StandardSchemaV1<unknown, Record<string, unknown>> | undefined, TOpts = unknown> = {
31
- [M in "get" | "post" | "put" | "patch" | "delete" | "head" | "options"]: <
32
+ [M in "delete" | "get" | "head" | "options" | "patch" | "post" | "put"]: <
32
33
  P extends StandardSchemaV1 | undefined = undefined,
33
34
  D extends StandardSchemaV1 | undefined = undefined,
34
35
  R extends StandardSchemaV1 | undefined = undefined
@@ -43,11 +44,7 @@ export function createRouteBuilder<PP extends StandardSchemaV1<unknown, Record<s
43
44
  url: string,
44
45
  routeConfig?: RouteConfig<PP>
45
46
  ): 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;
47
+ const { pathParamsSchema, ...routeDefaults } = cloneConfig(routeConfig ?? {});
51
48
 
52
49
  const builder = {} as RouteBuilder<PP>;
53
50
  for (const method of methods) {
@@ -2,12 +2,12 @@
2
2
 
3
3
  import FaxiosHeaders from "../core/FaxiosHeaders.js";
4
4
  import defaults from "../defaults/index.js";
5
- import type { InternalFaxiosRequestConfig, FaxiosRequestHeaders, FaxiosRequestTransformer, FaxiosResponseTransformer } from "../types.js";
5
+ import type { FaxiosRequestHeaders, FaxiosRequestTransformer, FaxiosResponseTransformer, InternalFaxiosRequestConfig } from "../types.js";
6
6
  import utils from "../utils.js";
7
7
 
8
8
  type TransformFn = FaxiosRequestTransformer | FaxiosResponseTransformer;
9
9
 
10
- export default function transformData(this: unknown, fns: TransformFn | Array<TransformFn> | undefined, response?: { data?: unknown; headers?: unknown; status?: number; } | null): unknown {
10
+ export default function transformData(this: unknown, fns: Array<TransformFn> | TransformFn | undefined, response?: null | { data?: unknown; headers?: unknown; status?: number; }): unknown {
11
11
  const config = (this || defaults) as InternalFaxiosRequestConfig;
12
12
  const context = response || config;
13
13
  const headers = FaxiosHeaders.from(context.headers as Record<string, unknown> | undefined);
@@ -1,13 +1,13 @@
1
1
  import isCancel from "../cancel/isCancel.js";
2
+ import type { FaxiosResponse, InternalFaxiosRequestConfig } from "../types.js";
2
3
  import type { StandardSchemaV1 } from "../types/standard-schema.js";
3
- import type { InternalFaxiosRequestConfig, FaxiosResponse } from "../types.js";
4
4
  import FaxiosError from "./FaxiosError.js";
5
5
 
6
6
  type SchemaErrorCode =
7
- | typeof FaxiosError.ERR_BAD_RESPONSE_SCHEMA
8
- | typeof FaxiosError.ERR_BAD_REQUEST_SCHEMA
9
7
  | typeof FaxiosError.ERR_BAD_PARAMS_SCHEMA
10
- | typeof FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA;
8
+ | typeof FaxiosError.ERR_BAD_PATH_PARAMS_SCHEMA
9
+ | typeof FaxiosError.ERR_BAD_REQUEST_SCHEMA
10
+ | typeof FaxiosError.ERR_BAD_RESPONSE_SCHEMA;
11
11
 
12
12
  export async function validateSchema<S extends StandardSchemaV1>(
13
13
  schema: S,
@@ -96,7 +96,7 @@ const defaults: FaxiosDefaults = {
96
96
  headers: FaxiosRequestHeaders
97
97
  ) {
98
98
  const contentType =
99
- (headers.getContentType() as string | null | undefined) || "";
99
+ (headers.getContentType() as null | string | undefined) || "";
100
100
  const hasJSONContentType = contentType.indexOf("application/json") > -1;
101
101
  const isObjectPayload = utils.isObject(data);
102
102
 
@@ -1 +1 @@
1
- export const VERSION = "0.2.1";
1
+ export const VERSION = "0.2.3";