@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
@@ -11,7 +11,7 @@ export const progressEventReducer = (listener: (data: FaxiosProgressEvent) => vo
11
11
  if (!e || typeof (e as Record<string, unknown>).loaded !== "number") {
12
12
  return;
13
13
  }
14
- const ev = e as { loaded: number; total?: number; lengthComputable?: boolean; };
14
+ const ev = e as { lengthComputable?: boolean; loaded: number; total?: number; };
15
15
  const rawLoaded = ev.loaded;
16
16
  const total = ev.lengthComputable ? ev.total : undefined;
17
17
  const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
@@ -36,7 +36,7 @@ const INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp("[\\u0000-\\u0008\\u000a-\
36
36
  const INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+", "g");
37
37
 
38
38
  // eslint-disable-next-line sonarjs/function-return-type
39
- function sanitizeValue(value: unknown, invalidChars: RegExp): string | Array<string> {
39
+ function sanitizeValue(value: unknown, invalidChars: RegExp): Array<string> | string {
40
40
  if (utils.isArray(value)) {
41
41
  return (value as Array<unknown>).map(item => sanitizeValue(item, invalidChars) as string);
42
42
  }
@@ -1,13 +1,23 @@
1
+ import FaxiosError from "../core/FaxiosError.js";
2
+
3
+ // `.` and `..` (raw or percent-encoded) would become a dot segment that the URL parser resolves,
4
+ // moving the request to another path.
5
+ const DOT_SEGMENT = /^(?:\.|%2e){1,2}$/i;
6
+
1
7
  /** Expects raw (unencoded) param values — applies encodeURIComponent here. */
2
8
  export function substitutePathParams(url: string, params: Record<string, unknown>): string {
3
9
  return url.replace(/\{([^{}]+)\}/g, (_match, key: string) => {
4
10
  if (!Object.prototype.hasOwnProperty.call(params, key)) {
5
- throw new Error(`Path param "${key}" not found in pathParams`);
11
+ throw new FaxiosError(`Path param "${key}" not found in pathParams`, FaxiosError.ERR_BAD_OPTION_VALUE);
6
12
  }
7
13
  const val = params[key];
8
14
  if (val == null) {
9
- throw new Error(`Path param "${key}" is null or undefined`);
15
+ throw new FaxiosError(`Path param "${key}" is null or undefined`, FaxiosError.ERR_BAD_OPTION_VALUE);
10
16
  }
11
- return encodeURIComponent(String(val));
17
+ const str = String(val);
18
+ if (DOT_SEGMENT.test(str)) {
19
+ throw new FaxiosError(`Path param "${key}" must not be "." or ".." (or a percent-encoded form)`, FaxiosError.ERR_BAD_OPTION_VALUE);
20
+ }
21
+ return encodeURIComponent(str);
12
22
  });
13
23
  }
@@ -8,7 +8,7 @@ function throttle(fn: (...args: Array<unknown>) => void, freq: number): [(...arg
8
8
  let timestamp = 0;
9
9
  const threshold = 1000 / freq;
10
10
  let lastArgs: Array<unknown> | null = null;
11
- let timer: ReturnType<typeof setTimeout> | null = null;
11
+ let timer: null | ReturnType<typeof setTimeout> = null;
12
12
 
13
13
  const invoke = (args: Array<unknown>, now: number = Date.now()) => {
14
14
  timestamp = now;
@@ -2,7 +2,7 @@
2
2
 
3
3
  import FaxiosError from "../core/FaxiosError.js";
4
4
  // temporary hotfix to avoid circular references until FaxiosURLSearchParams is refactored
5
- import type { GenericFormData, SerializerVisitor, FormDataVisitorHelpers } from "../types.js";
5
+ import type { FormDataVisitorHelpers, GenericFormData, SerializerVisitor } from "../types.js";
6
6
  import utils from "../utils.js";
7
7
 
8
8
  // Default nesting limit shared with the inverse transform (formDataToJSON) so
@@ -40,11 +40,11 @@ function removeBrackets(key: string): string {
40
40
  *
41
41
  * @returns {string} The path to the current key.
42
42
  */
43
- function renderKey(path: Array<string | number> | null | undefined, key: string | number, dots: unknown): string {
43
+ function renderKey(path: Array<number | string> | null | undefined, key: number | string, dots: unknown): string {
44
44
  if (!path) return String(key);
45
45
  return path
46
46
  .concat(key)
47
- .map(function each(token: string | number, i: number) {
47
+ .map(function each(token: number | string, i: number) {
48
48
  token = removeBrackets(String(token));
49
49
  return !dots && i ? "[" + token + "]" : token;
50
50
  })
@@ -100,13 +100,15 @@ function toFormData(obj: unknown, formData?: GenericFormData | null, options?: R
100
100
  formData = new FormDataCtor();
101
101
  }
102
102
 
103
+ // Null-prototype destination: `visitor`, `maxDepth` and `Blob` are read below, and a polluted
104
+ // Object.prototype must not supply them.
103
105
  options = utils.toFlatObject(
104
106
  options,
105
- {
107
+ Object.assign(Object.create(null) as Record<string, unknown>, {
106
108
  metaTokens: true,
107
109
  dots: false,
108
110
  indexes: false,
109
- },
111
+ }),
110
112
  false,
111
113
  function defined(option: string, source: unknown) {
112
114
  return !utils.isUndefined((source as Record<string, unknown>)[option]);
@@ -201,7 +203,7 @@ function toFormData(obj: unknown, formData?: GenericFormData | null, options?: R
201
203
  *
202
204
  * @returns {boolean} return true to visit the each prop of the value recursively
203
205
  */
204
- function defaultVisitor(this: GenericFormData, value: unknown, key: string | number, path: null | Array<string | number>, _helpers?: FormDataVisitorHelpers): boolean {
206
+ function defaultVisitor(this: GenericFormData, value: unknown, key: number | string, path: Array<number | string> | null, _helpers?: FormDataVisitorHelpers): boolean {
205
207
  let arr: unknown = value;
206
208
 
207
209
  if (utils.isReactNative(formData) && utils.isReactNativeBlob(value)) {
@@ -254,7 +256,7 @@ function toFormData(obj: unknown, formData?: GenericFormData | null, options?: R
254
256
  isVisitable,
255
257
  });
256
258
 
257
- function build(value: unknown, path?: Array<string | number>, depth = 0): void {
259
+ function build(value: unknown, path?: Array<number | string>, depth = 0): void {
258
260
  if (utils.isUndefined(value)) return;
259
261
 
260
262
  throwIfMaxDepthExceeded(depth);
@@ -271,13 +273,13 @@ function toFormData(obj: unknown, formData?: GenericFormData | null, options?: R
271
273
  visitor.call(
272
274
  formData as GenericFormData,
273
275
  el,
274
- utils.isString(key) ? (key as string).trim() : key as string | number,
276
+ utils.isString(key) ? (key as string).trim() : key as number | string,
275
277
  path ?? null,
276
278
  exposedHelpers
277
279
  );
278
280
 
279
281
  if (result === true) {
280
- build(el, path ? path.concat(key as string | number) : [ key as string | number ], depth + 1);
282
+ build(el, path ? path.concat(key as number | string) : [ key as number | string ], depth + 1);
281
283
  }
282
284
  });
283
285
 
@@ -1,11 +1,11 @@
1
1
  type ReadableStreamController = {
2
- enqueue: (chunk: Uint8Array) => void;
3
2
  close: () => void;
3
+ enqueue: (chunk: Uint8Array) => void;
4
4
  };
5
5
 
6
6
  type ReadableStreamSource = {
7
- pull?: (controller: ReadableStreamController) => Promise<void>;
8
7
  cancel?: (reason?: unknown) => Promise<unknown>;
8
+ pull?: (controller: ReadableStreamController) => Promise<void>;
9
9
  };
10
10
 
11
11
  type ReadableStreamInit = {
@@ -43,8 +43,8 @@ const readBytes = async function* (iterable: AsyncIterable<ByteChunk> | unknown,
43
43
  };
44
44
 
45
45
  type ReaderLike = {
46
- read: () => Promise<{ done: boolean; value: ByteChunk; }>;
47
46
  cancel: () => Promise<void>;
47
+ read: () => Promise<{ done: boolean; value: ByteChunk; }>;
48
48
  };
49
49
 
50
50
  type StreamLike = {
@@ -5,7 +5,7 @@ import { VERSION } from "../env/data.js";
5
5
 
6
6
  export type ValidatorFn = (value: unknown, opt?: string, opts?: unknown) => boolean | string;
7
7
 
8
- const validators: Record<string, ValidatorFn | undefined> = {};
8
+ const validators: Record<string, undefined | ValidatorFn> = {};
9
9
 
10
10
  [ "object", "boolean", "number", "function", "string", "symbol" ].forEach((type, i) => {
11
11
  validators[type] = function validator(thing: unknown): boolean | string {
@@ -24,7 +24,7 @@ const deprecatedWarnings: Record<string, boolean | undefined> = {};
24
24
  *
25
25
  * @returns {function}
26
26
  */
27
- (validators as Record<string, unknown>)["transitional"] = function transitional(validator: ValidatorFn | false | undefined, version?: string, message?: string): ValidatorFn {
27
+ (validators as Record<string, unknown>)["transitional"] = function transitional(validator: false | undefined | ValidatorFn, version?: string, message?: string): ValidatorFn {
28
28
  function formatMessage(opt: string, desc: string): string {
29
29
  return (
30
30
  "[Faxios v" +
@@ -80,7 +80,7 @@ const deprecatedWarnings: Record<string, boolean | undefined> = {};
80
80
  * @returns {object}
81
81
  */
82
82
 
83
- function assertOptions(options: unknown, schema: Record<string, ValidatorFn | undefined>, allowUnknown: boolean): void {
83
+ function assertOptions(options: unknown, schema: Record<string, undefined | ValidatorFn>, allowUnknown: boolean): void {
84
84
  if (typeof options !== "object") {
85
85
  throw new FaxiosError("options must be an object", FaxiosError.ERR_BAD_OPTION_VALUE);
86
86
  }
@@ -3,13 +3,13 @@
3
3
  import FaxiosURLSearchParams from "./helpers/FaxiosURLSearchParams.js";
4
4
 
5
5
  const _globalThis = globalThis as {
6
- window?: { location?: { href?: string; }; };
6
+ Blob?: new (...args: Array<unknown>) => object;
7
7
  document?: unknown;
8
+ FormData?: new () => object;
8
9
  navigator?: { product?: string; userAgent?: string; };
9
- WorkerGlobalScope?: unknown;
10
10
  self?: { importScripts?: unknown; };
11
- FormData?: new () => object;
12
- Blob?: new (...args: Array<unknown>) => object;
11
+ window?: { location?: { href?: string; }; };
12
+ WorkerGlobalScope?: unknown;
13
13
  };
14
14
 
15
15
  const hasBrowserEnv = typeof _globalThis.window !== "undefined" && typeof _globalThis.document !== "undefined";
@@ -13,10 +13,6 @@ import { definePlugin } from "./definePlugin.js";
13
13
  export type AuthBearerCapability = { auth: { getToken: () => Promise<string>; }; };
14
14
 
15
15
  export type AuthBearerOptions = {
16
- /** Replace a header the request already has. Default `false`: an explicit header is kept. */
17
- overwrite?: boolean;
18
- /** Put before the token, separated by a space. Default `"Bearer"`; `""` sends the bare token. */
19
- scheme?: string;
20
16
  /** The header to set. Default `"Authorization"`. */
21
17
  header?: string;
22
18
  /**
@@ -24,6 +20,10 @@ export type AuthBearerOptions = {
24
20
  * with an absolute `baseURL`, only its origin; otherwise only relative request URLs.
25
21
  */
26
22
  origins?: Array<string>;
23
+ /** Replace a header the request already has. Default `false`: an explicit header is kept. */
24
+ overwrite?: boolean;
25
+ /** Put before the token, separated by a space. Default `"Bearer"`; `""` sends the bare token. */
26
+ scheme?: string;
27
27
  };
28
28
 
29
29
  // A header name is a token (RFC 9110 §5.6.2).
@@ -31,7 +31,7 @@ const TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
31
31
 
32
32
  // A bare origin, optionally with a trailing slash. A path would look like a narrower limit than
33
33
  // the origin the token is really sent to.
34
- function originOf(value: unknown): string | null {
34
+ function originOf(value: unknown): null | string {
35
35
  if (typeof value !== "string") return null;
36
36
  try {
37
37
  const { origin } = new URL(value);
@@ -56,7 +56,7 @@ const own = <T extends object, K extends keyof T>(source: T, key: K): T[K] | und
56
56
  // that leaves the page (`//host`, `/\host`) is told apart from one that stays on it.
57
57
  const SAME_ORIGIN = "https://same-origin.invalid";
58
58
 
59
- function resolvedOrigin(url: string, base: string | undefined): string | null {
59
+ function resolvedOrigin(url: string, base: string | undefined): null | string {
60
60
  try {
61
61
  return new URL(url, base).origin;
62
62
  }
@@ -72,7 +72,7 @@ function pageHref(): string | undefined {
72
72
  return undefined;
73
73
  }
74
74
 
75
- function sendsTokenTo(config: InternalFaxiosRequestConfig, origins: ReadonlyArray<string> | null): boolean {
75
+ function sendsTokenTo(config: InternalFaxiosRequestConfig, origins: null | ReadonlyArray<string>): boolean {
76
76
  const baseURL = own(config, "baseURL");
77
77
  const url = buildFullPath(baseURL, own(config, "url"), own(config, "allowAbsoluteUrls"), config);
78
78
  if (origins) {
@@ -91,8 +91,12 @@ function sendsTokenTo(config: InternalFaxiosRequestConfig, origins: ReadonlyArra
91
91
  * can ask for a token too. A header the request already has is kept unless `overwrite` is set.
92
92
  * The token goes only to the `baseURL` origin when `baseURL` is absolute, otherwise only to
93
93
  * relative request URLs; `origins` replaces that rule.
94
+ *
95
+ * When `getToken` gives anything other than a non-empty string (`null`, `undefined`, `""`, a
96
+ * number, an object), the request is sent without the header, so a signed-out state never sends
97
+ * `Bearer null`. The parameter type stays `string`: the guard is for JavaScript callers and casts.
94
98
  */
95
- export function authBearer(getToken: () => string | Promise<string>, options: AuthBearerOptions = {}): FaxiosPlugin<{ provides: AuthBearerCapability; }> {
99
+ export function authBearer(getToken: () => Promise<string> | string, options: AuthBearerOptions = {}): FaxiosPlugin<{ provides: AuthBearerCapability; }> {
96
100
  if (typeof getToken !== "function") {
97
101
  throw new FaxiosError("authBearer: getToken must be a function", FaxiosError.ERR_BAD_OPTION_VALUE);
98
102
  }
@@ -112,7 +116,8 @@ export function authBearer(getToken: () => string | Promise<string>, options: Au
112
116
  provides: { auth },
113
117
  middleware: async (ctx, next) => {
114
118
  if ((!overwrite && ctx.config.headers.has(header)) || !sendsTokenTo(ctx.config, origins)) return next(ctx);
115
- const token = await auth.getToken();
119
+ const token: unknown = await auth.getToken();
120
+ if (typeof token !== "string" || token === "") return next(ctx);
116
121
  // On a copy: middleware that calls next() again (retry installed before this plugin) comes
117
122
  // back through here without the header, so every try asks for a fresh token.
118
123
  const headers = new FaxiosHeaders(ctx.config.headers).set(header, scheme ? `${scheme} ${token}` : token, true);
@@ -19,15 +19,15 @@ type RequiredCapabilities<TCapabilities, TProvides> = [keyof TProvides] extends
19
19
  */
20
20
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- `{}`: no capabilities or options, as in FaxiosContext
21
21
  export function definePlugin<TProvides = {}, TOptions = {}, TCapabilities = TProvides>(plugin: {
22
+ middleware: FaxiosMiddleware<TOptions, TCapabilities>;
22
23
  name: string;
23
24
  // The middleware reads the capabilities it provides from ctx too, so they must have the types
24
25
  // its context declares. NoInfer: TProvides is inferred from the value alone.
25
26
  provides?: TProvides & NoInfer<Pick<TCapabilities, keyof TProvides & keyof TCapabilities>>;
26
- middleware: FaxiosMiddleware<TOptions, TCapabilities>;
27
27
  }): FaxiosPlugin<{
28
- requires: RequiredCapabilities<TCapabilities, TProvides>;
29
- provides: Slot<TProvides>;
30
28
  options: Slot<TOptions>;
29
+ provides: Slot<TProvides>;
30
+ requires: RequiredCapabilities<TCapabilities, TProvides>;
31
31
  }> {
32
32
  // Only the types change: use() reads the fields at install time, as it does for any plugin.
33
33
  return plugin as never;
@@ -55,37 +55,36 @@ function assertRetryOptions(value: unknown, config?: InternalFaxiosRequestConfig
55
55
  export type RetryOptions = {
56
56
  /** Total tries, counting the first request. Default 3. */
57
57
  attempts?: number;
58
- /**
59
- * Whether the try that just failed should be retried. `attempt` counts from 1.
60
- * Default: network errors, timeouts and the `statuses`; never a cancellation. A custom `retryOn`
61
- * replaces that whole predicate, so `statuses` is ignored when both are set. retryOn decides
62
- * only within `methods`; to retry POST, list it in `methods`.
63
- */
64
- retryOn?: (error: unknown, attempt: number) => boolean;
65
- /**
66
- * Response statuses the default predicate retries. Default 408, 429, 500, 502, 503 and 504.
67
- * Ignored when `retryOn` is set.
68
- */
69
- statuses?: ReadonlyArray<number>;
70
58
  /**
71
59
  * Milliseconds to wait before the next try, or a function of the try that failed. Default 100ms,
72
60
  * doubling. Capped at `maxDelay`, then jittered. A 429 or 503 with a `Retry-After` header waits
73
61
  * that long instead, unless `respectRetryAfter` is `false`.
74
62
  */
75
- delay?: number | ((attempt: number, error: unknown) => number);
76
- /** The most the computed backoff waits, in milliseconds. Default 30 000. Doesn't apply to `Retry-After`. */
77
- maxDelay?: number;
63
+ delay?: ((attempt: number, error: unknown) => number) | number;
78
64
  /**
79
65
  * `"full"` (default) waits a random time between 0 and the capped backoff, so clients that failed
80
66
  * together don't retry together; `"none"` waits the capped backoff. Doesn't apply to `Retry-After`.
81
67
  */
82
68
  jitter?: "full" | "none";
69
+ /** The most the computed backoff waits, in milliseconds. Default 30 000. Doesn't apply to `Retry-After`. */
70
+ maxDelay?: number;
83
71
  /**
84
72
  * The longest `Retry-After` (seconds or an HTTP date, on a 429 or 503) to wait, in milliseconds.
85
73
  * Default 300 000 (5 minutes). A longer one rejects with the response's error instead of retrying.
86
74
  * Ignored when `respectRetryAfter` is `false`.
87
75
  */
88
76
  maxRetryAfter?: number;
77
+ /**
78
+ * HTTP methods that may be retried, in any case. Default: GET, HEAD, OPTIONS, PUT, DELETE and
79
+ * QUERY. POST and PATCH aren't idempotent, so add them only if your API dedupes repeats. A request
80
+ * whose method isn't listed is never retried, whatever `retryOn` or `statuses` say.
81
+ */
82
+ methods?: ReadonlyArray<Method>;
83
+ /**
84
+ * Called before each wait with the error, the try that failed and the wait in milliseconds. If it
85
+ * throws, the request rejects with that error and stops retrying.
86
+ */
87
+ onRetry?: (error: unknown, attempt: number, delayMs: number) => void;
89
88
  /**
90
89
  * Whether a 429 or 503's `Retry-After` header sets the wait. Default `true`. With `false`, every
91
90
  * retry waits the computed backoff and `maxRetryAfter` doesn't apply; which requests retry doesn't
@@ -93,20 +92,21 @@ export type RetryOptions = {
93
92
  */
94
93
  respectRetryAfter?: boolean;
95
94
  /**
96
- * Called before each wait with the error, the try that failed and the wait in milliseconds. If it
97
- * throws, the request rejects with that error and stops retrying.
95
+ * Whether the try that just failed should be retried. `attempt` counts from 1.
96
+ * Default: network errors, timeouts and the `statuses`; never a cancellation. A custom `retryOn`
97
+ * replaces that whole predicate, so `statuses` is ignored when both are set. retryOn decides
98
+ * only within `methods`; to retry POST, list it in `methods`.
98
99
  */
99
- onRetry?: (error: unknown, attempt: number, delayMs: number) => void;
100
+ retryOn?: (error: unknown, attempt: number) => boolean;
100
101
  /**
101
- * HTTP methods that may be retried, in any case. Default: GET, HEAD, OPTIONS, PUT, DELETE and
102
- * QUERY. POST and PATCH aren't idempotent, so add them only if your API dedupes repeats. A request
103
- * whose method isn't listed is never retried, whatever `retryOn` or `statuses` say.
102
+ * Response statuses the default predicate retries. Default 408, 429, 500, 502, 503 and 504.
103
+ * Ignored when `retryOn` is set.
104
104
  */
105
- methods?: ReadonlyArray<Method>;
105
+ statuses?: ReadonlyArray<number>;
106
106
  };
107
107
 
108
108
  /** Per-request override: `false` turns retries off, an object overrides the plugin's options. */
109
- export type RetryRequestOptions = { retry?: RetryOptions | false; };
109
+ export type RetryRequestOptions = { retry?: false | RetryOptions; };
110
110
 
111
111
  function retryByDefault(error: unknown, statuses: ReadonlyArray<number>): boolean {
112
112
  if (isCancel(error) || !(error instanceof FaxiosError)) return false;
@@ -164,13 +164,13 @@ function retriesMethod(config: InternalFaxiosRequestConfig, perRequest: RetryOpt
164
164
 
165
165
  type Policy = {
166
166
  attempts: number;
167
- retryOn: (error: unknown, attempt: number) => boolean;
168
- delay: number | ((attempt: number, error: unknown) => number);
169
- maxDelay: number;
167
+ delay: ((attempt: number, error: unknown) => number) | number;
170
168
  jitter: "full" | "none";
169
+ maxDelay: number;
171
170
  maxRetryAfter: number;
172
- respectRetryAfter: boolean;
173
171
  onRetry: ((error: unknown, attempt: number, delayMs: number) => void) | undefined;
172
+ respectRetryAfter: boolean;
173
+ retryOn: (error: unknown, attempt: number) => boolean;
174
174
  };
175
175
 
176
176
  // Per field, request first: no merged object, and only own properties count.
@@ -11,17 +11,17 @@ import { definePlugin } from "./definePlugin.js";
11
11
  * headers or body, so an event is safe to log.
12
12
  */
13
13
  export type TimingEvent = {
14
- /** The request method, upper-cased (`"GET"`). */
15
- method: string;
16
- /** The full request URL without its query string and fragment. */
17
- url: string;
18
14
  /**
19
15
  * The try number from `retry`: each try's when installed after it, the final try's when
20
16
  * installed before it. Absent without `retry`.
21
17
  */
22
18
  attempt?: number;
23
19
  durationMs: number;
24
- } & ({ status: number; error?: undefined; } | { status?: undefined; error: unknown; });
20
+ /** The request method, upper-cased (`"GET"`). */
21
+ method: string;
22
+ /** The full request URL without its query string and fragment. */
23
+ url: string;
24
+ } & ({ error: unknown; status?: undefined; } | { error?: undefined; status: number; });
25
25
 
26
26
  const now = () => (typeof performance === "undefined" ? Date.now() : performance.now());
27
27
 
@@ -13,12 +13,12 @@ export interface StandardSchemaV1<Input = unknown, Output = Input> {
13
13
 
14
14
  export declare namespace StandardSchemaV1 {
15
15
  interface Props<Input = unknown, Output = Input> {
16
- readonly version: 1;
17
- readonly vendor: string;
18
16
  readonly types?: Types<Input, Output>;
19
17
  readonly validate: (
20
18
  value: unknown
21
- ) => Result<Output> | Promise<Result<Output>>;
19
+ ) => Promise<Result<Output>> | Result<Output>;
20
+ readonly vendor: string;
21
+ readonly version: 1;
22
22
  }
23
23
 
24
24
  interface Types<Input = unknown, Output = Input> {
@@ -26,11 +26,11 @@ export declare namespace StandardSchemaV1 {
26
26
  readonly output: Output;
27
27
  }
28
28
 
29
- type Result<Output> = SuccessResult<Output> | FailureResult;
29
+ type Result<Output> = FailureResult | SuccessResult<Output>;
30
30
 
31
31
  interface SuccessResult<Output> {
32
- readonly value: Output;
33
32
  readonly issues?: undefined;
33
+ readonly value: Output;
34
34
  }
35
35
 
36
36
  interface FailureResult {
@@ -40,7 +40,7 @@ export declare namespace StandardSchemaV1 {
40
40
  interface Issue {
41
41
  readonly message: string;
42
42
  readonly path?:
43
- | ReadonlyArray<PropertyKey | PathSegment>
43
+ | ReadonlyArray<PathSegment | PropertyKey>
44
44
  | undefined;
45
45
  }
46
46