@gcmdev/faxios 0.2.1 → 0.2.2

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 (119) 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.map +1 -1
  8. package/dist/lib/adapters/fetch.js +86 -26
  9. package/dist/lib/adapters/fetch.js.map +1 -1
  10. package/dist/lib/cancel/CanceledError.d.ts +1 -1
  11. package/dist/lib/cancel/CanceledError.d.ts.map +1 -1
  12. package/dist/lib/core/Faxios.d.ts +3 -3
  13. package/dist/lib/core/Faxios.d.ts.map +1 -1
  14. package/dist/lib/core/Faxios.js +8 -4
  15. package/dist/lib/core/Faxios.js.map +1 -1
  16. package/dist/lib/core/FaxiosError.d.ts +2 -2
  17. package/dist/lib/core/FaxiosError.d.ts.map +1 -1
  18. package/dist/lib/core/FaxiosHeaders.d.ts +8 -8
  19. package/dist/lib/core/FaxiosHeaders.d.ts.map +1 -1
  20. package/dist/lib/core/define.d.ts +3 -3
  21. package/dist/lib/core/define.d.ts.map +1 -1
  22. package/dist/lib/core/dispatchRequest.d.ts +1 -1
  23. package/dist/lib/core/dispatchRequest.d.ts.map +1 -1
  24. package/dist/lib/core/mergeConfig.d.ts +2 -2
  25. package/dist/lib/core/mergeConfig.d.ts.map +1 -1
  26. package/dist/lib/core/mergeConfig.js +40 -2
  27. package/dist/lib/core/mergeConfig.js.map +1 -1
  28. package/dist/lib/core/route.d.ts +1 -1
  29. package/dist/lib/core/route.d.ts.map +1 -1
  30. package/dist/lib/core/route.js +2 -5
  31. package/dist/lib/core/route.js.map +1 -1
  32. package/dist/lib/core/transformData.d.ts +2 -2
  33. package/dist/lib/core/transformData.d.ts.map +1 -1
  34. package/dist/lib/core/validateSchema.d.ts +2 -2
  35. package/dist/lib/core/validateSchema.d.ts.map +1 -1
  36. package/dist/lib/env/data.d.ts +1 -1
  37. package/dist/lib/env/data.js +1 -1
  38. package/dist/lib/faxios.d.ts +50 -50
  39. package/dist/lib/faxios.d.ts.map +1 -1
  40. package/dist/lib/helpers/cloneConfig.d.ts +0 -1
  41. package/dist/lib/helpers/cloneConfig.d.ts.map +1 -1
  42. package/dist/lib/helpers/cloneConfig.js +2 -2
  43. package/dist/lib/helpers/cloneConfig.js.map +1 -1
  44. package/dist/lib/helpers/cookies.d.ts +1 -1
  45. package/dist/lib/helpers/cookies.d.ts.map +1 -1
  46. package/dist/lib/helpers/formDataToJSON.d.ts +1 -1
  47. package/dist/lib/helpers/formDataToJSON.d.ts.map +1 -1
  48. package/dist/lib/helpers/formDataToJSON.js +1 -1
  49. package/dist/lib/helpers/formDataToJSON.js.map +1 -1
  50. package/dist/lib/helpers/parseHeaders.d.ts +1 -1
  51. package/dist/lib/helpers/parseHeaders.d.ts.map +1 -1
  52. package/dist/lib/helpers/substitutePathParams.d.ts.map +1 -1
  53. package/dist/lib/helpers/substitutePathParams.js +11 -3
  54. package/dist/lib/helpers/substitutePathParams.js.map +1 -1
  55. package/dist/lib/helpers/toFormData.d.ts.map +1 -1
  56. package/dist/lib/helpers/toFormData.js +4 -2
  57. package/dist/lib/helpers/toFormData.js.map +1 -1
  58. package/dist/lib/helpers/validator.d.ts +1 -1
  59. package/dist/lib/helpers/validator.d.ts.map +1 -1
  60. package/dist/lib/platform.d.ts.map +1 -1
  61. package/dist/lib/plugins/authBearer.d.ts +9 -5
  62. package/dist/lib/plugins/authBearer.d.ts.map +1 -1
  63. package/dist/lib/plugins/authBearer.js +6 -0
  64. package/dist/lib/plugins/authBearer.js.map +1 -1
  65. package/dist/lib/plugins/definePlugin.d.ts +3 -3
  66. package/dist/lib/plugins/definePlugin.d.ts.map +1 -1
  67. package/dist/lib/plugins/retry.d.ts +23 -23
  68. package/dist/lib/plugins/retry.d.ts.map +1 -1
  69. package/dist/lib/plugins/timing.d.ts +8 -8
  70. package/dist/lib/plugins/timing.d.ts.map +1 -1
  71. package/dist/lib/types/standard-schema.d.ts +6 -6
  72. package/dist/lib/types/standard-schema.d.ts.map +1 -1
  73. package/dist/lib/types.d.ts +92 -92
  74. package/dist/lib/types.d.ts.map +1 -1
  75. package/dist/lib/utils.d.ts +4 -3
  76. package/dist/lib/utils.d.ts.map +1 -1
  77. package/dist/lib/utils.js +9 -2
  78. package/dist/lib/utils.js.map +1 -1
  79. package/package.json +7 -4
  80. package/skills/configure-requests/SKILL.md +8 -5
  81. package/skills/configure-requests/references/plugins.md +37 -6
  82. package/src/index.ts +15 -15
  83. package/src/lib/adapters/fetch-helpers.ts +3 -3
  84. package/src/lib/adapters/fetch.ts +125 -64
  85. package/src/lib/cancel/CanceledError.ts +1 -1
  86. package/src/lib/core/Faxios.ts +17 -13
  87. package/src/lib/core/FaxiosError.ts +3 -3
  88. package/src/lib/core/FaxiosHeaders.ts +16 -16
  89. package/src/lib/core/define.ts +7 -7
  90. package/src/lib/core/dispatchRequest.ts +2 -2
  91. package/src/lib/core/mergeConfig.ts +42 -4
  92. package/src/lib/core/prepareRequest.ts +1 -1
  93. package/src/lib/core/route.ts +3 -6
  94. package/src/lib/core/transformData.ts +2 -2
  95. package/src/lib/core/validateSchema.ts +4 -4
  96. package/src/lib/defaults/index.ts +1 -1
  97. package/src/lib/env/data.ts +1 -1
  98. package/src/lib/faxios.ts +55 -55
  99. package/src/lib/helpers/HttpStatusCode.ts +1 -1
  100. package/src/lib/helpers/cloneConfig.ts +2 -3
  101. package/src/lib/helpers/composeSignals.ts +4 -4
  102. package/src/lib/helpers/cookies.ts +3 -3
  103. package/src/lib/helpers/formDataToJSON.ts +4 -4
  104. package/src/lib/helpers/parseHeaders.ts +2 -2
  105. package/src/lib/helpers/progressEventReducer.ts +1 -1
  106. package/src/lib/helpers/sanitizeHeaderValue.ts +1 -1
  107. package/src/lib/helpers/substitutePathParams.ts +13 -3
  108. package/src/lib/helpers/throttle.ts +1 -1
  109. package/src/lib/helpers/toFormData.ts +11 -9
  110. package/src/lib/helpers/trackStream.ts +3 -3
  111. package/src/lib/helpers/validator.ts +3 -3
  112. package/src/lib/platform.ts +4 -4
  113. package/src/lib/plugins/authBearer.ts +14 -9
  114. package/src/lib/plugins/definePlugin.ts +3 -3
  115. package/src/lib/plugins/retry.ts +27 -27
  116. package/src/lib/plugins/timing.ts +5 -5
  117. package/src/lib/types/standard-schema.ts +6 -6
  118. package/src/lib/types.ts +125 -125
  119. package/src/lib/utils.ts +21 -12
@@ -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>;
@@ -31,7 +31,7 @@ function normalizeHeader(header: string): string {
31
31
  // eslint-disable-next-line sonarjs/function-return-type
32
32
  function normalizeValue(
33
33
  value: FaxiosHeaderValue | undefined
34
- ): string | Array<string> | false | null | undefined {
34
+ ): Array<string> | false | null | string | undefined {
35
35
  if (value == null) {
36
36
  return value;
37
37
  }
@@ -64,9 +64,9 @@ function matchHeaderValue(
64
64
  value: unknown,
65
65
  header: string,
66
66
  filter:
67
- | string
68
- | RegExp
69
67
  | ((this: FaxiosHeaders, value: string, name: string) => boolean)
68
+ | RegExp
69
+ | string
70
70
  | undefined,
71
71
  isHeaderNameFilter?: boolean
72
72
  ): boolean | undefined {
@@ -176,7 +176,7 @@ class FaxiosHeaders {
176
176
  declare hasAuthorization: (matcher?: HeaderMatcher) => boolean;
177
177
 
178
178
  constructor(
179
- headers?: Record<string, unknown> | FaxiosHeaders | string | null
179
+ headers?: FaxiosHeaders | null | Record<string, unknown> | string
180
180
  ) {
181
181
  headers && this.set(headers);
182
182
  }
@@ -244,17 +244,17 @@ class FaxiosHeaders {
244
244
 
245
245
  get(header: string): FaxiosHeaderValue | undefined;
246
246
  get(header: string, parser: true): Record<string, string> | undefined;
247
- get(header: string, parser: RegExp): RegExpExecArray | null | undefined;
247
+ get(header: string, parser: RegExp): null | RegExpExecArray | undefined;
248
248
  get<R>(header: string, parser: (this: FaxiosHeaders, value: FaxiosHeaderValue, header: string) => R): R | undefined;
249
249
  get(
250
250
  header: string,
251
251
  parser?:
252
- | RegExp
253
252
  | ((
254
253
  this: FaxiosHeaders,
255
254
  value: FaxiosHeaderValue,
256
255
  header: string
257
256
  ) => unknown)
257
+ | RegExp
258
258
  | true
259
259
  ): unknown {
260
260
  header = normalizeHeader(header);
@@ -317,7 +317,7 @@ class FaxiosHeaders {
317
317
  return false;
318
318
  }
319
319
 
320
- delete(header: string | Array<string>, matcher?: HeaderMatcher): boolean {
320
+ delete(header: Array<string> | string, matcher?: HeaderMatcher): boolean {
321
321
  const self = this;
322
322
  let deleted = false;
323
323
 
@@ -450,15 +450,15 @@ class FaxiosHeaders {
450
450
  }
451
451
 
452
452
  static from(
453
- thing?: Record<string, unknown> | FaxiosHeaders | string | null
453
+ thing?: FaxiosHeaders | null | Record<string, unknown> | string
454
454
  ): FaxiosHeaders {
455
455
  return thing instanceof this ? thing : new this(thing);
456
456
  }
457
457
 
458
458
  static concat(
459
- first: Record<string, unknown> | FaxiosHeaders | string | undefined | null,
459
+ first: FaxiosHeaders | null | Record<string, unknown> | string | undefined,
460
460
  ...targets: Array<
461
- Record<string, unknown> | FaxiosHeaders | string | undefined | null
461
+ FaxiosHeaders | null | Record<string, unknown> | string | undefined
462
462
  >
463
463
  ): FaxiosHeaders {
464
464
  const computed = new this(first);
@@ -468,7 +468,7 @@ class FaxiosHeaders {
468
468
  return computed;
469
469
  }
470
470
 
471
- static accessor(header: string | Array<string>): typeof FaxiosHeaders {
471
+ static accessor(header: Array<string> | string): typeof FaxiosHeaders {
472
472
  const self = this as unknown as Record<
473
473
  symbol,
474
474
  { 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
 
@@ -151,7 +151,7 @@ export default async function dispatchRequest(this: unknown, config: InternalFax
151
151
  if (!isCancel(reason)) {
152
152
  throwIfCancellationRequested(config);
153
153
 
154
- const r = reason as { response?: { data?: unknown; headers?: unknown; status?: number; [k: string]: unknown; }; } | null;
154
+ const r = reason as null | { response?: { [k: string]: unknown; data?: unknown; headers?: unknown; status?: number; }; };
155
155
  if (r?.response) {
156
156
  (config as unknown as Record<string, unknown>)["response"] = r.response;
157
157
  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.2";
package/src/lib/faxios.ts CHANGED
@@ -15,8 +15,8 @@ import formDataToJSON from "./helpers/formDataToJSON.js";
15
15
  import HttpStatusCode from "./helpers/HttpStatusCode.js";
16
16
  import isFaxiosError from "./helpers/isFaxiosError.js";
17
17
  import toFormData from "./helpers/toFormData.js";
18
+ import type { CreateFaxiosDefaults, FaxiosDefaults, FaxiosHeaderValue, FaxiosMiddleware, FaxiosPluginArgument, FaxiosRequestConfig, FaxiosResponse, HeadersDefaults, Method, SchemaConfig, StringLiteralsOrString } from "./types.js";
18
19
  import type { StandardSchemaV1 } from "./types/standard-schema.js";
19
- import type { Method, StringLiteralsOrString, CreateFaxiosDefaults, FaxiosDefaults, FaxiosHeaderValue, FaxiosMiddleware, FaxiosPluginArgument, FaxiosRequestConfig, HeadersDefaults, FaxiosResponse, SchemaConfig } from "./types.js";
20
20
  import utils from "./utils.js";
21
21
 
22
22
  /**
@@ -91,11 +91,11 @@ type ProvidedCapabilities<TProv> = [TProv] extends [null | undefined] ? {} : TPr
91
91
  // use() reads capability names with Object.keys() and skips the keys that could pollute a prototype,
92
92
  // so the registry only holds string names. A symbol, number or dangerous key would be typed on
93
93
  // ctx.capabilities without matching a registered name, and nothing could satisfy a requirement for one.
94
- type UnsupportedCapabilityKeys<TCaps> = Extract<keyof TCaps, symbol | number | "__proto__" | "constructor" | "prototype">;
94
+ type UnsupportedCapabilityKeys<TCaps> = Extract<keyof TCaps, "__proto__" | "constructor" | "prototype" | number | symbol>;
95
95
 
96
- type RejectUnsupportedCapabilityKeys<TReq, TProv> = [UnsupportedCapabilityKeys<TReq> | UnsupportedCapabilityKeys<TProv>] extends [never]
96
+ type RejectUnsupportedCapabilityKeys<TReq, TProv> = [UnsupportedCapabilityKeys<TProv> | UnsupportedCapabilityKeys<TReq>] extends [never]
97
97
  ? unknown
98
- : { "faxios: capability names must be strings other than __proto__, constructor and prototype": UnsupportedCapabilityKeys<TReq> | UnsupportedCapabilityKeys<TProv>; };
98
+ : { "faxios: capability names must be strings other than __proto__, constructor and prototype": UnsupportedCapabilityKeys<TProv> | UnsupportedCapabilityKeys<TReq>; };
99
99
 
100
100
  // Nothing sets a plugin option for the caller, so a required one would be typed as present in the
101
101
  // plugin's middleware while every request that omits it leaves it undefined.
@@ -130,23 +130,6 @@ type CheckPlugin<THave, TReq, TProv, TOpt> = RequireCapabilities<THave, TReq>
130
130
  // without narrowing first.
131
131
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- see above
132
132
  export type FaxiosInstance<TOpts = {}, TCaps = {}> = {
133
- /**
134
- * Register middleware or a plugin and return this instance, typed with the plugin's request
135
- * options and capabilities added. A plugin whose required capabilities aren't installed yet, or
136
- * that provides a capability another installed plugin already provides, is a type error.
137
- */
138
- use: <TReq = unknown, TProv = unknown, TOpt = unknown>(
139
- middleware: FaxiosMiddleware<TOpts, TCaps> | (FaxiosPluginArgument<TReq, TProv, TOpt> & CheckPlugin<TCaps, TReq, TProv, TOpt>)
140
- ) => FaxiosInstance<TOpts & TOpt, TCaps & ProvidedCapabilities<TProv>>;
141
- /**
142
- * Remove middleware or a plugin registered with use(), by reference. In-flight requests are
143
- * unaffected. The instance type is not narrowed: request options and capabilities the ejected
144
- * plugin added stay in its type.
145
- */
146
- // A method, so its parameter is checked bivariantly: middleware typed for this instance's
147
- // options and capabilities is accepted.
148
- // eslint-disable-next-line @typescript-eslint/method-signature-style -- see above
149
- eject<TReq = unknown, TProv = unknown, TOpt = unknown>(middleware: FaxiosMiddleware<TOpt> | FaxiosPluginArgument<TReq, TProv, TOpt>): void;
150
133
  /**
151
134
  * Define a typed endpoint for `method` and `url` (with optional `{key}` placeholders). `config`
152
135
  * holds request defaults and the `pathParamsSchema`, `paramsSchema`, `requestSchema` and
@@ -165,6 +148,15 @@ export type FaxiosInstance<TOpts = {}, TCaps = {}> = {
165
148
  url: string,
166
149
  config?: DefineConfig<PP, P, D, R> & TOpts
167
150
  ) => DefinedEndpoint<PP, P, D, R, TOpts>;
151
+ /**
152
+ * Remove middleware or a plugin registered with use(), by reference. In-flight requests are
153
+ * unaffected. The instance type is not narrowed: request options and capabilities the ejected
154
+ * plugin added stay in its type.
155
+ */
156
+ // A method, so its parameter is checked bivariantly: middleware typed for this instance's
157
+ // options and capabilities is accepted.
158
+ // eslint-disable-next-line @typescript-eslint/method-signature-style -- see above
159
+ eject<TReq = unknown, TProv = unknown, TOpt = unknown>(middleware: FaxiosMiddleware<TOpt> | FaxiosPluginArgument<TReq, TProv, TOpt>): void;
168
160
  /**
169
161
  * Group endpoints that share `url` and `config`. Returns one endpoint factory per method (`get`,
170
162
  * `post`, `put`, `patch`, `delete`, `head`, `options`; no `query`), each taking `paramsSchema`,
@@ -176,22 +168,38 @@ export type FaxiosInstance<TOpts = {}, TCaps = {}> = {
176
168
  url: string,
177
169
  config?: RouteConfig<PP> & TOpts
178
170
  ) => RouteBuilder<PP, TOpts>;
171
+ /**
172
+ * Register middleware or a plugin and return this instance, typed with the plugin's request
173
+ * options and capabilities added. A plugin whose required capabilities aren't installed yet, or
174
+ * that provides a capability another installed plugin already provides, is a type error.
175
+ */
176
+ use: <TReq = unknown, TProv = unknown, TOpt = unknown>(
177
+ middleware: FaxiosMiddleware<TOpts, TCaps> | (FaxiosPluginArgument<TReq, TProv, TOpt> & CheckPlugin<TCaps, TReq, TProv, TOpt>)
178
+ ) => FaxiosInstance<TOpts & TOpt, TCaps & ProvidedCapabilities<TProv>>;
179
179
  <O, D = unknown>(config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
180
180
  <O, D = unknown>(url: string, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
181
181
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(config: FaxiosRequestConfig<D> & TOpts): Promise<R>;
182
182
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
183
- request: {
184
- <O, D = unknown>(config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
185
- <T = unknown, R = FaxiosResponse<T>, D = unknown>(config: FaxiosRequestConfig<D> & TOpts): Promise<R>;
186
- };
187
- get: {
183
+ create: (instanceConfig?: CreateFaxiosDefaults) => FaxiosInstance;
184
+ // `common` plus one header group per method; a key set directly on
185
+ // `headers` applies to every method.
186
+ defaults: Omit<FaxiosDefaults, "headers"> & {
187
+ headers: HeadersDefaults & { [key: string]: FaxiosHeaderValue | undefined; };
188
+ } & Partial<TOpts>;
189
+ delete: {
188
190
  <O, D = unknown>(url: string, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
189
191
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
190
192
  };
191
- delete: {
193
+ get: {
192
194
  <O, D = unknown>(url: string, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
193
195
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
194
196
  };
197
+ /**
198
+ * Build the URL for `config` without sending a request. Applies `baseURL`, `params` and
199
+ * `paramsSerializer`, but does not substitute `pathParams` or run schemas, so `{key}`
200
+ * placeholders come back as written.
201
+ */
202
+ getUri: (config?: FaxiosRequestConfig & TOpts) => string;
195
203
  head: {
196
204
  <O, D = unknown>(url: string, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
197
205
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
@@ -200,23 +208,23 @@ export type FaxiosInstance<TOpts = {}, TCaps = {}> = {
200
208
  <O, D = unknown>(url: string, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
201
209
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
202
210
  };
203
- post: {
211
+ patch: {
204
212
  <O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
205
213
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
206
214
  };
207
- put: {
215
+ patchForm: {
208
216
  <O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
209
217
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
210
218
  };
211
- patch: {
219
+ post: {
212
220
  <O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
213
221
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
214
222
  };
215
- query: {
223
+ postForm: {
216
224
  <O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
217
225
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
218
226
  };
219
- postForm: {
227
+ put: {
220
228
  <O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
221
229
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
222
230
  };
@@ -224,41 +232,33 @@ export type FaxiosInstance<TOpts = {}, TCaps = {}> = {
224
232
  <O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
225
233
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
226
234
  };
227
- patchForm: {
235
+ query: {
228
236
  <O, D = unknown>(url: string, data: D | undefined, config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
229
237
  <T = unknown, R = FaxiosResponse<T>, D = unknown>(url: string, data?: D, config?: FaxiosRequestConfig<D> & TOpts): Promise<R>;
230
238
  };
231
- // `common` plus one header group per method; a key set directly on
232
- // `headers` applies to every method.
233
- defaults: Omit<FaxiosDefaults, "headers"> & {
234
- headers: HeadersDefaults & { [key: string]: FaxiosHeaderValue | undefined; };
235
- } & Partial<TOpts>;
236
- /**
237
- * Build the URL for `config` without sending a request. Applies `baseURL`, `params` and
238
- * `paramsSerializer`, but does not substitute `pathParams` or run schemas, so `{key}`
239
- * placeholders come back as written.
240
- */
241
- getUri: (config?: FaxiosRequestConfig & TOpts) => string;
242
- create: (instanceConfig?: CreateFaxiosDefaults) => FaxiosInstance;
239
+ request: {
240
+ <O, D = unknown>(config: SchemaConfig<O, D> & TOpts): Promise<FaxiosResponse<O, D>>;
241
+ <T = unknown, R = FaxiosResponse<T>, D = unknown>(config: FaxiosRequestConfig<D> & TOpts): Promise<R>;
242
+ };
243
243
  };
244
244
 
245
245
  /** The default export: an instance plus the static helpers only it carries. */
246
246
  export type FaxiosStatic = FaxiosInstance & {
247
- Faxios: typeof Faxios;
247
+ all: (promises: Array<Promise<unknown>>) => Promise<Array<unknown>>;
248
+ Cancel: typeof CanceledError;
248
249
  CanceledError: typeof CanceledError;
249
- isCancel: typeof isCancel;
250
- VERSION: typeof VERSION;
251
- toFormData: typeof toFormData;
250
+ default: FaxiosStatic;
251
+ Faxios: typeof Faxios;
252
252
  FaxiosError: typeof FaxiosError;
253
- Cancel: typeof CanceledError;
254
- all: (promises: Array<Promise<unknown>>) => Promise<Array<unknown>>;
255
- spread: (fn: (...args: Array<unknown>) => unknown) => (arr: Array<unknown>) => unknown;
256
- isFaxiosError: typeof isFaxiosError;
257
- mergeConfig: typeof mergeConfig;
258
253
  FaxiosHeaders: typeof FaxiosHeaders;
259
254
  formToJSON: (thing: unknown) => unknown;
260
255
  HttpStatusCode: typeof HttpStatusCode;
261
- default: FaxiosStatic;
256
+ isCancel: typeof isCancel;
257
+ isFaxiosError: typeof isFaxiosError;
258
+ mergeConfig: typeof mergeConfig;
259
+ spread: (fn: (...args: Array<unknown>) => unknown) => (arr: Array<unknown>) => unknown;
260
+ toFormData: typeof toFormData;
261
+ VERSION: typeof VERSION;
262
262
  };
263
263
 
264
264
  // Create the default instance to be exported; the statics are attached below.
@@ -71,7 +71,7 @@ const HttpStatusCode = {
71
71
  };
72
72
 
73
73
  Object.entries(HttpStatusCode).forEach(([ key, value ]) => {
74
- (HttpStatusCode as Record<string | number, string | number>)[value] = key;
74
+ (HttpStatusCode as Record<number | string, number | string>)[value] = key;
75
75
  });
76
76
 
77
77
  export default HttpStatusCode;
@@ -1,6 +1,5 @@
1
1
  import type { FaxiosRequestConfig } from "../types.js";
2
-
3
- export const DANGEROUS_KEYS = new Set([ "__proto__", "constructor", "prototype" ]);
2
+ import utils from "../utils.js";
4
3
 
5
4
  // ponytail: null-proto shallow clone; replaces mergeConfig({}, config) which ran the full
6
5
  // two-config merge machinery just to get a defensive copy. Security invariants preserved:
@@ -15,7 +14,7 @@ export default function cloneConfig<T extends FaxiosRequestConfig>(src: T): T &
15
14
  enumerable: false,
16
15
  }));
17
16
  for (const key of Object.keys(src)) {
18
- if (!DANGEROUS_KEYS.has(key)) {
17
+ if (!utils.isDangerousKey(key)) {
19
18
  (dst as Record<string, unknown>)[key] = (src as Record<string, unknown>)[key];
20
19
  }
21
20
  }
@@ -5,11 +5,11 @@ import utils from "../utils.js";
5
5
  type AbortHandler = (this: AbortSignal & { reason?: unknown; }, reason: unknown) => void;
6
6
  type EventListenerFn = (event: unknown) => void;
7
7
  type SignalLike = {
8
- unsubscribe?: (() => void) | ((handler: AbortHandler) => void);
9
- addEventListener: (type: string, listener: EventListenerFn) => void;
10
- removeEventListener: (type: string, listener: EventListenerFn) => void;
11
8
  aborted: boolean;
9
+ addEventListener: (type: string, listener: EventListenerFn) => void;
12
10
  reason?: unknown;
11
+ removeEventListener: (type: string, listener: EventListenerFn) => void;
12
+ unsubscribe?: (() => void) | ((handler: AbortHandler) => void);
13
13
  };
14
14
  export type ExtendedAbortSignal = AbortSignal & { unsubscribe?: (() => void) | ((handler: AbortHandler) => void); };
15
15
 
@@ -35,7 +35,7 @@ const composeSignals = (signals: Array<unknown> | null | undefined, timeout?: nu
35
35
  }
36
36
  };
37
37
 
38
- let timer: ReturnType<typeof setTimeout> | null =
38
+ let timer: null | ReturnType<typeof setTimeout> =
39
39
  timeout
40
40
  ? setTimeout(() => {
41
41
  timer = null;
@@ -2,9 +2,9 @@ import platform from "../platform.js";
2
2
  import utils from "../utils.js";
3
3
 
4
4
  type CookieManager = {
5
- write: (name: string, value: string, expires?: number, path?: string, domain?: string, secure?: boolean, sameSite?: string) => void;
6
- read: (name: string) => string | null;
5
+ read: (name: string) => null | string;
7
6
  remove: (name: string) => void;
7
+ write: (name: string, value: string, expires?: number, path?: string, domain?: string, secure?: boolean, sameSite?: string) => void;
8
8
  };
9
9
 
10
10
  const _globalThis = globalThis as { document?: { cookie?: string; }; };
@@ -36,7 +36,7 @@ export default platform.hasStandardBrowserEnv
36
36
  _globalThis.document.cookie = cookie.join("; ");
37
37
  },
38
38
 
39
- read(name: string): string | null {
39
+ read(name: string): null | string {
40
40
  if (!_globalThis.document) return null;
41
41
  // Match name=value by splitting on the semicolon separator instead of building a
42
42
  // RegExp from `name` — interpolating an unescaped string into a RegExp would let
@@ -29,7 +29,7 @@ function parsePropPath(name: string): Array<string> {
29
29
  // foo x y z
30
30
  const path: Array<string> = [];
31
31
  const pattern = /\w+|\[(\w*)]/g;
32
- let match: RegExpExecArray | null;
32
+ let match: null | RegExpExecArray;
33
33
 
34
34
  while ((match = pattern.exec(name)) !== null) {
35
35
  throwIfDepthExceeded(path.length);
@@ -66,13 +66,13 @@ function arrayToObject(arr: Array<unknown>): Record<string, unknown> {
66
66
  *
67
67
  * @returns {Object<string, any> | null} The converted object.
68
68
  */
69
- function formDataToJSON(formData: unknown): Record<string, unknown> | null {
69
+ function formDataToJSON(formData: unknown): null | Record<string, unknown> {
70
70
  function buildPath(path: Array<string>, value: unknown, target: Record<string, unknown>, index: number): boolean {
71
71
  throwIfDepthExceeded(index);
72
72
 
73
- let name: string | number = path[index++]!;
73
+ let name: number | string = path[index++]!;
74
74
 
75
- if (name === "__proto__") return true;
75
+ if (utils.isDangerousKey(name)) return true;
76
76
 
77
77
  const isNumericKey = Number.isFinite(+name);
78
78
  const isLast = index >= path.length;
@@ -38,8 +38,8 @@ const ignoreDuplicateOf = utils.toObjectSet([
38
38
  *
39
39
  * @returns {Object} Headers parsed into an object
40
40
  */
41
- export default (rawHeaders: string): Record<string, string | Array<string>> => {
42
- const parsed: Record<string, string | Array<string>> = {};
41
+ export default (rawHeaders: string): Record<string, Array<string> | string> => {
42
+ const parsed: Record<string, Array<string> | string> = {};
43
43
  let key: string;
44
44
  let val: string;
45
45
  let i: number;