@microlink/mql 0.16.1 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +140 -82
  2. package/dist/index.umd.js +140 -82
  3. package/package.json +12 -60
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ function getAugmentedNamespace(n) {
10
10
  var isInstance = false;
11
11
  try {
12
12
  isInstance = this instanceof a;
13
- } catch {}
13
+ } catch (e) {}
14
14
  if (isInstance) {
15
15
  return Reflect.construct(f, arguments, this.constructor);
16
16
  }
@@ -65,6 +65,10 @@ dist.flattie = flattie;
65
65
 
66
66
  /**
67
67
  Base class for all Ky-specific errors. `HTTPError`, `NetworkError`, `TimeoutError`, and `ForceRetryError` extend this class.
68
+
69
+ You can use `instanceof KyError` to check if an error originated from Ky, or use the `isKyError()` type guard for cross-realm compatibility and TypeScript type narrowing.
70
+
71
+ Note: `SchemaValidationError` is intentionally not considered a Ky error. `KyError` covers failures in Ky's HTTP lifecycle (bad status, timeout, retry), while schema validation errors originate from the user-provided schema, not from Ky itself.
68
72
  */
69
73
  class KyError extends Error {
70
74
  name = 'KyError';
@@ -76,7 +80,11 @@ class KyError extends Error {
76
80
  /**
77
81
  Error thrown when the response has a non-2xx status code and `throwHttpErrors` is enabled.
78
82
 
79
- The error has a `response` property with the `Response` object, a `request` property with the `Request` object, an `options` property with the normalized options, and a `data` property with the pre-parsed response body. The response body is automatically consumed when populating `data`, so `response.json()` and other body methods will not work. Use `data` instead.
83
+ The error has a `response` property with the `Response` object, a `request` property with the `Request` object, an `options` property with the normalized options (either passed to `ky` when creating an instance with `ky.create()` or directly when performing the request), and a `data` property with the pre-parsed response body. For JSON responses (based on `Content-Type`), the body is parsed using the `parseJson` option if set, or `JSON.parse` by default. For other content types, it is set as plain text. If the body is empty or parsing fails, `data` will be `undefined`. To avoid hanging or excessive buffering, `error.data` population is bounded by the request timeout and a 10 MiB response body size limit. The `data` property is populated before `beforeError` hooks run, so hooks can access it.
84
+
85
+ The response body is automatically consumed when populating `error.data`, so `error.response.json()` and other body methods will not work. Use `error.data` instead. The `error.response` object is still available for headers, status, etc.
86
+
87
+ Be aware that some types of errors, such as network errors, inherently mean that a response was not received. In that case, the error will be an instance of `NetworkError` instead of `HTTPError` and will not contain a `response` property.
80
88
  */
81
89
  class HTTPError extends KyError {
82
90
  name = 'HTTPError';
@@ -97,9 +105,11 @@ class HTTPError extends KyError {
97
105
  }
98
106
 
99
107
  /**
100
- Error thrown when a network error occurs during the request (e.g., DNS failure, connection refused, offline).
108
+ Error thrown when a network error occurs during the request (e.g., DNS failure, connection refused, offline). It has a `request` property with the `Request` object. The original error is available via the standard `cause` property.
109
+
110
+ Network errors are automatically retried (for retriable methods).
101
111
 
102
- The error has a `request` property with the `Request` object. The original error is available via the standard `cause` property.
112
+ Note: Network errors are detected using runtime-specific heuristics. Unrecognized runtimes may produce errors that are not wrapped in `NetworkError`. Use the `shouldRetry` option to handle such cases.
103
113
  */
104
114
  class NetworkError extends KyError {
105
115
  name = 'NetworkError';
@@ -161,7 +171,7 @@ class ForceRetryError extends KyError {
161
171
  }
162
172
 
163
173
  /**
164
- Thrown when a response body fails validation against a user-provided Standard Schema.
174
+ The error thrown when [Standard Schema](https://github.com/standard-schema/standard-schema) validation fails in `.json(schema)`. It has an `issues` property with the validation issues from the schema.
165
175
 
166
176
  This error intentionally does not extend `KyError` because it does not represent a failure in Ky's HTTP lifecycle. The request succeeded; the user's schema rejected the data. As such, it is not matched by `isKyError()`.
167
177
 
@@ -192,9 +202,7 @@ class SchemaValidationError extends Error {
192
202
  }
193
203
 
194
204
  /**
195
- Error thrown when the request times out.
196
-
197
- The error has a `request` property with the `Request` object.
205
+ Error thrown when the request times out. It has a `request` property with the `Request` object.
198
206
  */
199
207
  class TimeoutError extends KyError {
200
208
  name = 'TimeoutError';
@@ -281,7 +289,7 @@ const api = ky.extend({
281
289
  async ({request, response}) => {
282
290
  // Retry based on response body content
283
291
  if (response.status === 200) {
284
- const data = await response.clone().json();
292
+ const data = await response.json();
285
293
 
286
294
  // Simple retry with default delay
287
295
  if (data.error?.code === 'TEMPORARY_ERROR') {
@@ -365,12 +373,6 @@ const kyOptionKeys = {
365
373
  fetch: true,
366
374
  context: true,
367
375
  };
368
- // Vendor-specific fetch options that should always be passed to fetch()
369
- // even if they appear on the Request object due to vendor patching.
370
- // See: https://github.com/sindresorhus/ky/issues/541
371
- const vendorSpecificOptions = {
372
- next: true, // Next.js cache revalidation (revalidate, tags)
373
- };
374
376
  // Standard RequestInit options that should NOT be passed separately to fetch()
375
377
  // because they're already applied to the Request object.
376
378
  // Note: `dispatcher` and `priority` are NOT included here - they're fetch-only
@@ -495,7 +497,7 @@ const getReplaceState = (value) => isObject(value) && value[replaceSymbol] === t
495
497
  value,
496
498
  };
497
499
  /**
498
- Wraps a value so that `ky.extend()` will replace the parent value instead of merging with it.
500
+ Wraps a value so that `ky.extend()` will replace the parent value instead of merging with it. Works with hooks, headers, search parameters, context, and any other deep-merged option.
499
501
 
500
502
  By default, `.extend()` deep-merges options with the parent instance: hooks get appended, headers get merged, and search parameters get accumulated. Use `replaceOption` when you want to fully replace a merged property instead.
501
503
 
@@ -549,7 +551,13 @@ const isPlainObject = (value) => {
549
551
  };
550
552
  const cloneShallow = (value) => {
551
553
  if (value instanceof URLSearchParams) {
552
- return new URLSearchParams(value);
554
+ const copy = new URLSearchParams(value);
555
+ const deleted = value[deletedParametersSymbol];
556
+ if (deleted) {
557
+ // Preserve internal deletion markers so init-hook cloning does not resurrect params removed during option merging.
558
+ copy[deletedParametersSymbol] = new Set(deleted);
559
+ }
560
+ return copy;
553
561
  }
554
562
  if (value instanceof globalThis.Headers) {
555
563
  return new globalThis.Headers(value);
@@ -760,11 +768,13 @@ const normalizeRetryOptions = (retry = {}) => {
760
768
  if (retry.methods && !Array.isArray(retry.methods)) {
761
769
  throw new Error('retry.methods must be an array');
762
770
  }
763
- retry.methods &&= retry.methods.map(method => method.toLowerCase());
764
771
  if (retry.statusCodes && !Array.isArray(retry.statusCodes)) {
765
772
  throw new Error('retry.statusCodes must be an array');
766
773
  }
767
- const normalizedRetry = Object.fromEntries(Object.entries(retry).filter(([, value]) => value !== undefined));
774
+ const normalizedRetry = Object.fromEntries(Object.entries({
775
+ ...retry,
776
+ methods: retry.methods?.map(method => method.toLowerCase()),
777
+ }).filter(([, value]) => value !== undefined));
768
778
  return {
769
779
  ...defaultRetryOptions,
770
780
  ...normalizedRetry,
@@ -808,20 +818,19 @@ async function delay(ms, { signal }) {
808
818
  });
809
819
  }
810
820
 
811
- const findUnknownOptions = (request, options) => {
821
+ const findUnknownOptions = (options) => {
812
822
  const unknownOptions = {};
813
823
  for (const key in options) {
814
824
  // Skip inherited properties
815
825
  if (!Object.hasOwn(options, key)) {
816
826
  continue;
817
827
  }
818
- // An option is passed to fetch() if:
819
- // 1. It's not a standard RequestInit option (not in requestOptionsRegistry)
820
- // 2. It's not a ky-specific option (not in kyOptionKeys)
821
- // 3. Either:
822
- // a. It's not on the Request object, OR
823
- // b. It's a vendor-specific option that should always be passed (in vendorSpecificOptions)
824
- if (!(key in requestOptionsRegistry) && !(key in kyOptionKeys) && (!(key in request) || key in vendorSpecificOptions)) {
828
+ // Forward every non-standard, non-Ky option to fetch().
829
+ // We intentionally do not check whether the key also exists on `Request`, because some runtimes
830
+ // patch `Request.prototype` with fetch-only extensions. For example, Next.js adds `next`, and the
831
+ // old `key in request` heuristic dropped it unless Ky kept a special-case allowlist.
832
+ // Passing all non-standard keys makes that allowlist unnecessary and preserves future fetch extensions too.
833
+ if (!(key in requestOptionsRegistry) && !(key in kyOptionKeys)) {
825
834
  unknownOptions[key] = options[key];
826
835
  }
827
836
  }
@@ -849,8 +858,8 @@ const hasSearchParameters = (search) => {
849
858
  };
850
859
 
851
860
  // Inlined from https://github.com/sindresorhus/is-network-error v1.3.1
852
- const objectToString = Object.prototype.toString;
853
- const isError = (value) => objectToString.call(value) === '[object Error]';
861
+ const objectToString$1 = Object.prototype.toString;
862
+ const isError = (value) => objectToString$1.call(value) === '[object Error]';
854
863
  const errorMessages = new Set([
855
864
  'network error', // Chrome
856
865
  'NetworkError when attempting to fetch resource.', // Firefox
@@ -1022,16 +1031,43 @@ const createTextDecoder = (contentType) => {
1022
1031
  return new TextDecoder();
1023
1032
  };
1024
1033
  const invalidSchemaMessage = 'The `schema` argument must follow the Standard Schema specification';
1034
+ const cloneRetryOptions = (retry) => {
1035
+ if (typeof retry !== 'object') {
1036
+ return retry;
1037
+ }
1038
+ // Clone nested arrays too so init hooks can mutate retry config without leaking state across requests.
1039
+ return {
1040
+ ...retry,
1041
+ ...(retry.methods && { methods: [...retry.methods] }),
1042
+ ...(retry.statusCodes && { statusCodes: [...retry.statusCodes] }),
1043
+ ...(retry.afterStatusCodes && { afterStatusCodes: [...retry.afterStatusCodes] }),
1044
+ };
1045
+ };
1046
+ const objectToString = Object.prototype.toString;
1047
+ const isRequestInstance = (value) => value instanceof globalThis.Request || objectToString.call(value) === '[object Request]';
1048
+ // Accepted custom responses are treated as full Responses throughout Ky.
1049
+ // If a custom fetch returns one, it must behave like a Response for cloning,
1050
+ // body consumption, `json()` decoration, and any enabled stream features.
1051
+ const isResponseInstance = (value) => value instanceof globalThis.Response || objectToString.call(value) === '[object Response]';
1052
+ const cloneSearchParametersForInitHook = (searchParameters) => {
1053
+ if (Array.isArray(searchParameters)) {
1054
+ return searchParameters.map(parameter => [...parameter]);
1055
+ }
1056
+ return cloneShallow(searchParameters);
1057
+ };
1025
1058
  // Shallow-clone mutable option properties so init hook mutations don't leak across requests.
1026
1059
  function cloneInitHookOptions(options) {
1027
- return {
1060
+ const clonedOptions = {
1028
1061
  ...options,
1029
1062
  json: cloneShallow(options.json),
1030
- retry: cloneShallow(options.retry),
1031
1063
  context: cloneShallow(options.context),
1032
1064
  headers: cloneShallow(options.headers),
1033
- searchParams: cloneShallow(options.searchParams),
1065
+ searchParams: cloneSearchParametersForInitHook(options.searchParams),
1034
1066
  };
1067
+ if (options.retry !== undefined) {
1068
+ clonedOptions.retry = cloneRetryOptions(options.retry);
1069
+ }
1070
+ return clonedOptions;
1035
1071
  }
1036
1072
  const validateJsonWithSchema = async (jsonValue, schema) => {
1037
1073
  if ((typeof schema !== 'object'
@@ -1072,43 +1108,49 @@ class Ky {
1072
1108
  let response = beforeRequestResponse ?? await ky.#retry(async () => ky.#fetch());
1073
1109
  let responseFromHook = beforeRequestResponse !== undefined
1074
1110
  || ky.#consumeReturnedResponseFromBeforeRetryHook();
1075
- if (!(response instanceof globalThis.Response)) {
1076
- return response;
1077
- }
1078
1111
  for (;;) {
1079
- try {
1080
- // eslint-disable-next-line no-await-in-loop
1081
- response = await ky.#runAfterResponseHooks(response);
1112
+ // `undefined` means a hook stopped the flow without providing a response.
1113
+ // Non-native Responses still continue through Ky if they pass `isResponseInstance()`.
1114
+ if (response === undefined) {
1115
+ return response;
1082
1116
  }
1083
- catch (error) {
1084
- if (!(error instanceof ForceRetryError)) {
1085
- throw error;
1117
+ if (isResponseInstance(response)) {
1118
+ try {
1119
+ // eslint-disable-next-line no-await-in-loop
1120
+ response = await ky.#runAfterResponseHooks(response);
1086
1121
  }
1087
- // eslint-disable-next-line no-await-in-loop
1088
- const retriedResponse = await ky.#retryFromError(error, async () => ky.#fetch());
1089
- if (!(retriedResponse instanceof globalThis.Response)) {
1090
- return retriedResponse;
1122
+ catch (error) {
1123
+ if (!(error instanceof ForceRetryError)) {
1124
+ throw error;
1125
+ }
1126
+ // eslint-disable-next-line no-await-in-loop
1127
+ const retriedResponse = await ky.#retryFromError(error, async () => ky.#fetch());
1128
+ if (retriedResponse === undefined) {
1129
+ return retriedResponse;
1130
+ }
1131
+ response = retriedResponse;
1132
+ responseFromHook = ky.#consumeReturnedResponseFromBeforeRetryHook();
1133
+ continue;
1091
1134
  }
1092
- response = retriedResponse;
1093
- responseFromHook = ky.#consumeReturnedResponseFromBeforeRetryHook();
1094
- continue;
1095
1135
  }
1136
+ const currentResponse = response;
1096
1137
  // Opaque responses (`response.type === 'opaque'`) from `no-cors` requests always have `status: 0` and `ok: false`, but this is not a failure - the actual status is hidden by the browser.
1097
- if (!response.ok && response.type !== 'opaque' && (typeof ky.#options.throwHttpErrors === 'function'
1098
- ? ky.#options.throwHttpErrors(response.status)
1138
+ if (!currentResponse.ok && currentResponse.type !== 'opaque' && (typeof ky.#options.throwHttpErrors === 'function'
1139
+ ? ky.#options.throwHttpErrors(currentResponse.status)
1099
1140
  : ky.#options.throwHttpErrors)) {
1100
1141
  // `request` must reflect the request that actually failed, but `options` stays as Ky's
1101
1142
  // normalized options snapshot. Replacement `Request` instances do not preserve the
1102
1143
  // original `BodyInit`, so trying to make `options` mirror arbitrary requests would be lossy.
1103
- const error = new HTTPError(response, ky.#getResponseRequest(response), ky.#getNormalizedOptions());
1144
+ const httpError = new HTTPError(currentResponse, ky.#getResponseRequest(currentResponse), ky.#getNormalizedOptions());
1145
+ const errorToThrow = httpError;
1104
1146
  // eslint-disable-next-line no-await-in-loop
1105
- error.data = await ky.#getResponseData(response);
1147
+ httpError.data = await ky.#getResponseData(currentResponse);
1106
1148
  if (responseFromHook) {
1107
- throw error;
1149
+ throw errorToThrow;
1108
1150
  }
1109
1151
  // eslint-disable-next-line no-await-in-loop
1110
- const retriedResponse = await ky.#retryFromError(error, async () => ky.#fetch());
1111
- if (!(retriedResponse instanceof globalThis.Response)) {
1152
+ const retriedResponse = await ky.#retryFromError(httpError, async () => ky.#fetch());
1153
+ if (retriedResponse === undefined) {
1112
1154
  return retriedResponse;
1113
1155
  }
1114
1156
  response = retriedResponse;
@@ -1117,6 +1159,9 @@ class Ky {
1117
1159
  }
1118
1160
  break;
1119
1161
  }
1162
+ if (!isResponseInstance(response)) {
1163
+ return response;
1164
+ }
1120
1165
  ky.#decorateResponse(response);
1121
1166
  // If `onDownloadProgress` is passed, it uses the stream API internally
1122
1167
  if (ky.#options.onDownloadProgress) {
@@ -1286,6 +1331,13 @@ class Ky {
1286
1331
  this.request = new globalThis.Request(this.#input, this.#options);
1287
1332
  if (hasSearchParameters(this.#options.searchParams)) {
1288
1333
  const url = new URL(this.request.url);
1334
+ const deleted = this.#options.searchParams?.[deletedParametersSymbol];
1335
+ if (deleted) {
1336
+ // Remove keys from the input URL first so later searchParams entries can intentionally re-add them.
1337
+ for (const key of deleted) {
1338
+ url.searchParams.delete(key);
1339
+ }
1340
+ }
1289
1341
  if (typeof this.#options.searchParams === 'string') {
1290
1342
  const stringSearchParameters = this.#options.searchParams.replace(/^\?/, '');
1291
1343
  if (stringSearchParameters !== '') {
@@ -1308,18 +1360,14 @@ class Ky {
1308
1360
  }
1309
1361
  }
1310
1362
  }
1311
- const deleted = this.#options.searchParams?.[deletedParametersSymbol];
1312
- if (deleted) {
1313
- for (const key of deleted) {
1314
- url.searchParams.delete(key);
1315
- }
1316
- }
1317
1363
  // Recreate request with the updated URL. We already have all options in this.#options, including duplex.
1318
1364
  this.request = new globalThis.Request(url, this.#options);
1319
1365
  }
1320
1366
  if (this.#options.onUploadProgress && typeof this.#options.onUploadProgress !== 'function') {
1321
1367
  throw new TypeError('The `onUploadProgress` option must be a function');
1322
1368
  }
1369
+ // `totalTimeout` starts when the request pipeline is created, so it also includes
1370
+ // Ky's internal scheduling and user hook time before the first fetch attempt.
1323
1371
  this.#startTime = typeof this.#options.totalTimeout === 'number' ? this.#getCurrentTime() : undefined;
1324
1372
  }
1325
1373
  #calculateDelay() {
@@ -1564,52 +1612,57 @@ class Ky {
1564
1612
  options: this.#getNormalizedOptions(),
1565
1613
  retryCount: 0,
1566
1614
  });
1567
- if (result instanceof Response) {
1568
- return result;
1569
- }
1570
- if (result instanceof globalThis.Request) {
1615
+ if (isRequestInstance(result)) {
1571
1616
  this.#assignRequest(result);
1572
1617
  }
1618
+ else if (isResponseInstance(result)) {
1619
+ return result;
1620
+ }
1573
1621
  }
1574
1622
  return undefined;
1575
1623
  }
1576
1624
  async #runAfterResponseHooks(response) {
1577
1625
  const responseRequest = this.#getResponseRequest(response);
1578
1626
  for (const hook of this.#options.hooks.afterResponse) {
1579
- // Clone the response before passing to hook so we can cancel it if needed
1580
- const clonedResponse = this.#setResponseRequest(response.clone(), responseRequest);
1581
- this.#decorateResponse(clonedResponse);
1627
+ const hookResponse = this.#setResponseRequest(response.clone(), responseRequest);
1628
+ this.#decorateResponse(hookResponse);
1582
1629
  let modifiedResponse;
1583
1630
  try {
1584
1631
  // eslint-disable-next-line no-await-in-loop
1585
1632
  modifiedResponse = await hook({
1586
1633
  request: this.request,
1587
1634
  options: this.#getNormalizedOptions(),
1588
- response: clonedResponse,
1635
+ response: hookResponse,
1589
1636
  retryCount: this.#retryCount,
1590
1637
  });
1591
1638
  }
1592
1639
  catch (error) {
1593
1640
  // Cancel both responses to prevent memory leaks when hook throws
1594
- this.#cancelResponseBody(clonedResponse);
1641
+ if (hookResponse !== response) {
1642
+ this.#cancelResponseBody(hookResponse);
1643
+ }
1595
1644
  this.#cancelResponseBody(response);
1596
1645
  throw error;
1597
1646
  }
1598
1647
  if (modifiedResponse instanceof RetryMarker) {
1599
1648
  // Cancel both the cloned response passed to the hook and the current response to prevent resource leaks (especially important in Deno/Bun).
1600
1649
  // Do not await cancellation since hooks can clone the response, leaving extra tee branches that keep cancel promises pending per the Streams spec.
1601
- this.#cancelResponseBody(clonedResponse);
1650
+ if (hookResponse !== response) {
1651
+ this.#cancelResponseBody(hookResponse);
1652
+ }
1602
1653
  this.#cancelResponseBody(response);
1603
1654
  throw new ForceRetryError(modifiedResponse.options);
1604
1655
  }
1605
- // Determine which response to use going forward
1606
- const nextResponse = this.#setResponseRequest(modifiedResponse instanceof globalThis.Response ? modifiedResponse : response, responseRequest);
1656
+ const nextResponse = isResponseInstance(modifiedResponse)
1657
+ ? this.#setResponseRequest(modifiedResponse, responseRequest)
1658
+ : response;
1607
1659
  // Cancel any response bodies we won't use to prevent memory leaks.
1608
1660
  // Uses fire-and-forget since hooks may have cloned the response, creating tee branches that block cancellation.
1609
- if (clonedResponse !== nextResponse) {
1610
- this.#cancelResponseBody(clonedResponse);
1661
+ // If the hook wrapped an existing body into a new Response, both Response objects can still point at the same stream.
1662
+ if (hookResponse !== response && hookResponse !== nextResponse && hookResponse.body !== nextResponse.body) {
1663
+ this.#cancelResponseBody(hookResponse);
1611
1664
  }
1612
- if (response !== nextResponse) {
1665
+ if (response !== nextResponse && response.body !== nextResponse.body) {
1613
1666
  this.#cancelResponseBody(response);
1614
1667
  }
1615
1668
  response = nextResponse;
@@ -1645,7 +1698,11 @@ class Ky {
1645
1698
  // Apply custom request from forced retry before beforeRetry hooks
1646
1699
  // Ensure the custom request has the correct managed signal for timeouts and user aborts
1647
1700
  if (error instanceof ForceRetryError && error.customRequest) {
1648
- this.#assignRequest(new globalThis.Request(error.customRequest, this.#options.signal ? { signal: this.#options.signal } : undefined));
1701
+ const customRequest = new globalThis.Request(error.customRequest, this.#options.signal ? { signal: this.#options.signal } : undefined);
1702
+ // Replacement Requests are authoritative by design. Do not rewrite headers here,
1703
+ // even for cross-origin retries. Callers using `ky.retry({request})` explicitly
1704
+ // opted into the exact Request they constructed.
1705
+ this.#assignRequest(customRequest);
1649
1706
  }
1650
1707
  for (const hook of this.#options.hooks.beforeRetry) {
1651
1708
  let hookResult;
@@ -1665,12 +1722,13 @@ class Ky {
1665
1722
  }
1666
1723
  throw hookError;
1667
1724
  }
1668
- if (hookResult instanceof globalThis.Request) {
1725
+ if (isRequestInstance(hookResult)) {
1726
+ // Same contract as `ky.retry({request})`: a Request returned from `beforeRetry`
1727
+ // is used as-is rather than being sanitized or otherwise rewritten by Ky.
1669
1728
  this.#assignRequest(hookResult);
1670
1729
  break;
1671
1730
  }
1672
- // If a Response is returned, use it and skip the retry
1673
- if (hookResult instanceof globalThis.Response) {
1731
+ if (isResponseInstance(hookResult)) {
1674
1732
  this.#returnedResponseFromBeforeRetryHook = true;
1675
1733
  this.#retryCount++;
1676
1734
  return hookResult;
@@ -1697,7 +1755,7 @@ class Ky {
1697
1755
  // Recreate request with new signal
1698
1756
  this.request = new globalThis.Request(this.request, { signal: this.#options.signal });
1699
1757
  }
1700
- const nonRequestOptions = findUnknownOptions(this.request, this.#options);
1758
+ const nonRequestOptions = findUnknownOptions(this.#options);
1701
1759
  const retryRequest = this.#options.retry.limit > 0 ? this.request.clone() : undefined;
1702
1760
  const request = this.#wrapRequestWithUploadProgress(this.request, this.#options.body ?? undefined);
1703
1761
  // Cloning is done here to prepare in advance for retries.
@@ -1811,7 +1869,7 @@ var distribution = /*#__PURE__*/Object.freeze({
1811
1869
 
1812
1870
  var require$$1 = /*@__PURE__*/getAugmentedNamespace(distribution);
1813
1871
 
1814
- const VERSION = '0.16.1';
1872
+ const VERSION = '0.17.1';
1815
1873
 
1816
1874
  var constants = {
1817
1875
  VERSION,
package/dist/index.umd.js CHANGED
@@ -16,7 +16,7 @@
16
16
  var isInstance = false;
17
17
  try {
18
18
  isInstance = this instanceof a;
19
- } catch {}
19
+ } catch (e) {}
20
20
  if (isInstance) {
21
21
  return Reflect.construct(f, arguments, this.constructor);
22
22
  }
@@ -71,6 +71,10 @@
71
71
 
72
72
  /**
73
73
  Base class for all Ky-specific errors. `HTTPError`, `NetworkError`, `TimeoutError`, and `ForceRetryError` extend this class.
74
+
75
+ You can use `instanceof KyError` to check if an error originated from Ky, or use the `isKyError()` type guard for cross-realm compatibility and TypeScript type narrowing.
76
+
77
+ Note: `SchemaValidationError` is intentionally not considered a Ky error. `KyError` covers failures in Ky's HTTP lifecycle (bad status, timeout, retry), while schema validation errors originate from the user-provided schema, not from Ky itself.
74
78
  */
75
79
  class KyError extends Error {
76
80
  name = 'KyError';
@@ -82,7 +86,11 @@
82
86
  /**
83
87
  Error thrown when the response has a non-2xx status code and `throwHttpErrors` is enabled.
84
88
 
85
- The error has a `response` property with the `Response` object, a `request` property with the `Request` object, an `options` property with the normalized options, and a `data` property with the pre-parsed response body. The response body is automatically consumed when populating `data`, so `response.json()` and other body methods will not work. Use `data` instead.
89
+ The error has a `response` property with the `Response` object, a `request` property with the `Request` object, an `options` property with the normalized options (either passed to `ky` when creating an instance with `ky.create()` or directly when performing the request), and a `data` property with the pre-parsed response body. For JSON responses (based on `Content-Type`), the body is parsed using the `parseJson` option if set, or `JSON.parse` by default. For other content types, it is set as plain text. If the body is empty or parsing fails, `data` will be `undefined`. To avoid hanging or excessive buffering, `error.data` population is bounded by the request timeout and a 10 MiB response body size limit. The `data` property is populated before `beforeError` hooks run, so hooks can access it.
90
+
91
+ The response body is automatically consumed when populating `error.data`, so `error.response.json()` and other body methods will not work. Use `error.data` instead. The `error.response` object is still available for headers, status, etc.
92
+
93
+ Be aware that some types of errors, such as network errors, inherently mean that a response was not received. In that case, the error will be an instance of `NetworkError` instead of `HTTPError` and will not contain a `response` property.
86
94
  */
87
95
  class HTTPError extends KyError {
88
96
  name = 'HTTPError';
@@ -103,9 +111,11 @@
103
111
  }
104
112
 
105
113
  /**
106
- Error thrown when a network error occurs during the request (e.g., DNS failure, connection refused, offline).
114
+ Error thrown when a network error occurs during the request (e.g., DNS failure, connection refused, offline). It has a `request` property with the `Request` object. The original error is available via the standard `cause` property.
115
+
116
+ Network errors are automatically retried (for retriable methods).
107
117
 
108
- The error has a `request` property with the `Request` object. The original error is available via the standard `cause` property.
118
+ Note: Network errors are detected using runtime-specific heuristics. Unrecognized runtimes may produce errors that are not wrapped in `NetworkError`. Use the `shouldRetry` option to handle such cases.
109
119
  */
110
120
  class NetworkError extends KyError {
111
121
  name = 'NetworkError';
@@ -167,7 +177,7 @@
167
177
  }
168
178
 
169
179
  /**
170
- Thrown when a response body fails validation against a user-provided Standard Schema.
180
+ The error thrown when [Standard Schema](https://github.com/standard-schema/standard-schema) validation fails in `.json(schema)`. It has an `issues` property with the validation issues from the schema.
171
181
 
172
182
  This error intentionally does not extend `KyError` because it does not represent a failure in Ky's HTTP lifecycle. The request succeeded; the user's schema rejected the data. As such, it is not matched by `isKyError()`.
173
183
 
@@ -198,9 +208,7 @@
198
208
  }
199
209
 
200
210
  /**
201
- Error thrown when the request times out.
202
-
203
- The error has a `request` property with the `Request` object.
211
+ Error thrown when the request times out. It has a `request` property with the `Request` object.
204
212
  */
205
213
  class TimeoutError extends KyError {
206
214
  name = 'TimeoutError';
@@ -287,7 +295,7 @@
287
295
  async ({request, response}) => {
288
296
  // Retry based on response body content
289
297
  if (response.status === 200) {
290
- const data = await response.clone().json();
298
+ const data = await response.json();
291
299
 
292
300
  // Simple retry with default delay
293
301
  if (data.error?.code === 'TEMPORARY_ERROR') {
@@ -371,12 +379,6 @@
371
379
  fetch: true,
372
380
  context: true,
373
381
  };
374
- // Vendor-specific fetch options that should always be passed to fetch()
375
- // even if they appear on the Request object due to vendor patching.
376
- // See: https://github.com/sindresorhus/ky/issues/541
377
- const vendorSpecificOptions = {
378
- next: true, // Next.js cache revalidation (revalidate, tags)
379
- };
380
382
  // Standard RequestInit options that should NOT be passed separately to fetch()
381
383
  // because they're already applied to the Request object.
382
384
  // Note: `dispatcher` and `priority` are NOT included here - they're fetch-only
@@ -501,7 +503,7 @@
501
503
  value,
502
504
  };
503
505
  /**
504
- Wraps a value so that `ky.extend()` will replace the parent value instead of merging with it.
506
+ Wraps a value so that `ky.extend()` will replace the parent value instead of merging with it. Works with hooks, headers, search parameters, context, and any other deep-merged option.
505
507
 
506
508
  By default, `.extend()` deep-merges options with the parent instance: hooks get appended, headers get merged, and search parameters get accumulated. Use `replaceOption` when you want to fully replace a merged property instead.
507
509
 
@@ -555,7 +557,13 @@
555
557
  };
556
558
  const cloneShallow = (value) => {
557
559
  if (value instanceof URLSearchParams) {
558
- return new URLSearchParams(value);
560
+ const copy = new URLSearchParams(value);
561
+ const deleted = value[deletedParametersSymbol];
562
+ if (deleted) {
563
+ // Preserve internal deletion markers so init-hook cloning does not resurrect params removed during option merging.
564
+ copy[deletedParametersSymbol] = new Set(deleted);
565
+ }
566
+ return copy;
559
567
  }
560
568
  if (value instanceof globalThis.Headers) {
561
569
  return new globalThis.Headers(value);
@@ -766,11 +774,13 @@
766
774
  if (retry.methods && !Array.isArray(retry.methods)) {
767
775
  throw new Error('retry.methods must be an array');
768
776
  }
769
- retry.methods &&= retry.methods.map(method => method.toLowerCase());
770
777
  if (retry.statusCodes && !Array.isArray(retry.statusCodes)) {
771
778
  throw new Error('retry.statusCodes must be an array');
772
779
  }
773
- const normalizedRetry = Object.fromEntries(Object.entries(retry).filter(([, value]) => value !== undefined));
780
+ const normalizedRetry = Object.fromEntries(Object.entries({
781
+ ...retry,
782
+ methods: retry.methods?.map(method => method.toLowerCase()),
783
+ }).filter(([, value]) => value !== undefined));
774
784
  return {
775
785
  ...defaultRetryOptions,
776
786
  ...normalizedRetry,
@@ -814,20 +824,19 @@
814
824
  });
815
825
  }
816
826
 
817
- const findUnknownOptions = (request, options) => {
827
+ const findUnknownOptions = (options) => {
818
828
  const unknownOptions = {};
819
829
  for (const key in options) {
820
830
  // Skip inherited properties
821
831
  if (!Object.hasOwn(options, key)) {
822
832
  continue;
823
833
  }
824
- // An option is passed to fetch() if:
825
- // 1. It's not a standard RequestInit option (not in requestOptionsRegistry)
826
- // 2. It's not a ky-specific option (not in kyOptionKeys)
827
- // 3. Either:
828
- // a. It's not on the Request object, OR
829
- // b. It's a vendor-specific option that should always be passed (in vendorSpecificOptions)
830
- if (!(key in requestOptionsRegistry) && !(key in kyOptionKeys) && (!(key in request) || key in vendorSpecificOptions)) {
834
+ // Forward every non-standard, non-Ky option to fetch().
835
+ // We intentionally do not check whether the key also exists on `Request`, because some runtimes
836
+ // patch `Request.prototype` with fetch-only extensions. For example, Next.js adds `next`, and the
837
+ // old `key in request` heuristic dropped it unless Ky kept a special-case allowlist.
838
+ // Passing all non-standard keys makes that allowlist unnecessary and preserves future fetch extensions too.
839
+ if (!(key in requestOptionsRegistry) && !(key in kyOptionKeys)) {
831
840
  unknownOptions[key] = options[key];
832
841
  }
833
842
  }
@@ -855,8 +864,8 @@
855
864
  };
856
865
 
857
866
  // Inlined from https://github.com/sindresorhus/is-network-error v1.3.1
858
- const objectToString = Object.prototype.toString;
859
- const isError = (value) => objectToString.call(value) === '[object Error]';
867
+ const objectToString$1 = Object.prototype.toString;
868
+ const isError = (value) => objectToString$1.call(value) === '[object Error]';
860
869
  const errorMessages = new Set([
861
870
  'network error', // Chrome
862
871
  'NetworkError when attempting to fetch resource.', // Firefox
@@ -1028,16 +1037,43 @@
1028
1037
  return new TextDecoder();
1029
1038
  };
1030
1039
  const invalidSchemaMessage = 'The `schema` argument must follow the Standard Schema specification';
1040
+ const cloneRetryOptions = (retry) => {
1041
+ if (typeof retry !== 'object') {
1042
+ return retry;
1043
+ }
1044
+ // Clone nested arrays too so init hooks can mutate retry config without leaking state across requests.
1045
+ return {
1046
+ ...retry,
1047
+ ...(retry.methods && { methods: [...retry.methods] }),
1048
+ ...(retry.statusCodes && { statusCodes: [...retry.statusCodes] }),
1049
+ ...(retry.afterStatusCodes && { afterStatusCodes: [...retry.afterStatusCodes] }),
1050
+ };
1051
+ };
1052
+ const objectToString = Object.prototype.toString;
1053
+ const isRequestInstance = (value) => value instanceof globalThis.Request || objectToString.call(value) === '[object Request]';
1054
+ // Accepted custom responses are treated as full Responses throughout Ky.
1055
+ // If a custom fetch returns one, it must behave like a Response for cloning,
1056
+ // body consumption, `json()` decoration, and any enabled stream features.
1057
+ const isResponseInstance = (value) => value instanceof globalThis.Response || objectToString.call(value) === '[object Response]';
1058
+ const cloneSearchParametersForInitHook = (searchParameters) => {
1059
+ if (Array.isArray(searchParameters)) {
1060
+ return searchParameters.map(parameter => [...parameter]);
1061
+ }
1062
+ return cloneShallow(searchParameters);
1063
+ };
1031
1064
  // Shallow-clone mutable option properties so init hook mutations don't leak across requests.
1032
1065
  function cloneInitHookOptions(options) {
1033
- return {
1066
+ const clonedOptions = {
1034
1067
  ...options,
1035
1068
  json: cloneShallow(options.json),
1036
- retry: cloneShallow(options.retry),
1037
1069
  context: cloneShallow(options.context),
1038
1070
  headers: cloneShallow(options.headers),
1039
- searchParams: cloneShallow(options.searchParams),
1071
+ searchParams: cloneSearchParametersForInitHook(options.searchParams),
1040
1072
  };
1073
+ if (options.retry !== undefined) {
1074
+ clonedOptions.retry = cloneRetryOptions(options.retry);
1075
+ }
1076
+ return clonedOptions;
1041
1077
  }
1042
1078
  const validateJsonWithSchema = async (jsonValue, schema) => {
1043
1079
  if ((typeof schema !== 'object'
@@ -1078,43 +1114,49 @@
1078
1114
  let response = beforeRequestResponse ?? await ky.#retry(async () => ky.#fetch());
1079
1115
  let responseFromHook = beforeRequestResponse !== undefined
1080
1116
  || ky.#consumeReturnedResponseFromBeforeRetryHook();
1081
- if (!(response instanceof globalThis.Response)) {
1082
- return response;
1083
- }
1084
1117
  for (;;) {
1085
- try {
1086
- // eslint-disable-next-line no-await-in-loop
1087
- response = await ky.#runAfterResponseHooks(response);
1118
+ // `undefined` means a hook stopped the flow without providing a response.
1119
+ // Non-native Responses still continue through Ky if they pass `isResponseInstance()`.
1120
+ if (response === undefined) {
1121
+ return response;
1088
1122
  }
1089
- catch (error) {
1090
- if (!(error instanceof ForceRetryError)) {
1091
- throw error;
1123
+ if (isResponseInstance(response)) {
1124
+ try {
1125
+ // eslint-disable-next-line no-await-in-loop
1126
+ response = await ky.#runAfterResponseHooks(response);
1092
1127
  }
1093
- // eslint-disable-next-line no-await-in-loop
1094
- const retriedResponse = await ky.#retryFromError(error, async () => ky.#fetch());
1095
- if (!(retriedResponse instanceof globalThis.Response)) {
1096
- return retriedResponse;
1128
+ catch (error) {
1129
+ if (!(error instanceof ForceRetryError)) {
1130
+ throw error;
1131
+ }
1132
+ // eslint-disable-next-line no-await-in-loop
1133
+ const retriedResponse = await ky.#retryFromError(error, async () => ky.#fetch());
1134
+ if (retriedResponse === undefined) {
1135
+ return retriedResponse;
1136
+ }
1137
+ response = retriedResponse;
1138
+ responseFromHook = ky.#consumeReturnedResponseFromBeforeRetryHook();
1139
+ continue;
1097
1140
  }
1098
- response = retriedResponse;
1099
- responseFromHook = ky.#consumeReturnedResponseFromBeforeRetryHook();
1100
- continue;
1101
1141
  }
1142
+ const currentResponse = response;
1102
1143
  // Opaque responses (`response.type === 'opaque'`) from `no-cors` requests always have `status: 0` and `ok: false`, but this is not a failure - the actual status is hidden by the browser.
1103
- if (!response.ok && response.type !== 'opaque' && (typeof ky.#options.throwHttpErrors === 'function'
1104
- ? ky.#options.throwHttpErrors(response.status)
1144
+ if (!currentResponse.ok && currentResponse.type !== 'opaque' && (typeof ky.#options.throwHttpErrors === 'function'
1145
+ ? ky.#options.throwHttpErrors(currentResponse.status)
1105
1146
  : ky.#options.throwHttpErrors)) {
1106
1147
  // `request` must reflect the request that actually failed, but `options` stays as Ky's
1107
1148
  // normalized options snapshot. Replacement `Request` instances do not preserve the
1108
1149
  // original `BodyInit`, so trying to make `options` mirror arbitrary requests would be lossy.
1109
- const error = new HTTPError(response, ky.#getResponseRequest(response), ky.#getNormalizedOptions());
1150
+ const httpError = new HTTPError(currentResponse, ky.#getResponseRequest(currentResponse), ky.#getNormalizedOptions());
1151
+ const errorToThrow = httpError;
1110
1152
  // eslint-disable-next-line no-await-in-loop
1111
- error.data = await ky.#getResponseData(response);
1153
+ httpError.data = await ky.#getResponseData(currentResponse);
1112
1154
  if (responseFromHook) {
1113
- throw error;
1155
+ throw errorToThrow;
1114
1156
  }
1115
1157
  // eslint-disable-next-line no-await-in-loop
1116
- const retriedResponse = await ky.#retryFromError(error, async () => ky.#fetch());
1117
- if (!(retriedResponse instanceof globalThis.Response)) {
1158
+ const retriedResponse = await ky.#retryFromError(httpError, async () => ky.#fetch());
1159
+ if (retriedResponse === undefined) {
1118
1160
  return retriedResponse;
1119
1161
  }
1120
1162
  response = retriedResponse;
@@ -1123,6 +1165,9 @@
1123
1165
  }
1124
1166
  break;
1125
1167
  }
1168
+ if (!isResponseInstance(response)) {
1169
+ return response;
1170
+ }
1126
1171
  ky.#decorateResponse(response);
1127
1172
  // If `onDownloadProgress` is passed, it uses the stream API internally
1128
1173
  if (ky.#options.onDownloadProgress) {
@@ -1292,6 +1337,13 @@
1292
1337
  this.request = new globalThis.Request(this.#input, this.#options);
1293
1338
  if (hasSearchParameters(this.#options.searchParams)) {
1294
1339
  const url = new URL(this.request.url);
1340
+ const deleted = this.#options.searchParams?.[deletedParametersSymbol];
1341
+ if (deleted) {
1342
+ // Remove keys from the input URL first so later searchParams entries can intentionally re-add them.
1343
+ for (const key of deleted) {
1344
+ url.searchParams.delete(key);
1345
+ }
1346
+ }
1295
1347
  if (typeof this.#options.searchParams === 'string') {
1296
1348
  const stringSearchParameters = this.#options.searchParams.replace(/^\?/, '');
1297
1349
  if (stringSearchParameters !== '') {
@@ -1314,18 +1366,14 @@
1314
1366
  }
1315
1367
  }
1316
1368
  }
1317
- const deleted = this.#options.searchParams?.[deletedParametersSymbol];
1318
- if (deleted) {
1319
- for (const key of deleted) {
1320
- url.searchParams.delete(key);
1321
- }
1322
- }
1323
1369
  // Recreate request with the updated URL. We already have all options in this.#options, including duplex.
1324
1370
  this.request = new globalThis.Request(url, this.#options);
1325
1371
  }
1326
1372
  if (this.#options.onUploadProgress && typeof this.#options.onUploadProgress !== 'function') {
1327
1373
  throw new TypeError('The `onUploadProgress` option must be a function');
1328
1374
  }
1375
+ // `totalTimeout` starts when the request pipeline is created, so it also includes
1376
+ // Ky's internal scheduling and user hook time before the first fetch attempt.
1329
1377
  this.#startTime = typeof this.#options.totalTimeout === 'number' ? this.#getCurrentTime() : undefined;
1330
1378
  }
1331
1379
  #calculateDelay() {
@@ -1570,52 +1618,57 @@
1570
1618
  options: this.#getNormalizedOptions(),
1571
1619
  retryCount: 0,
1572
1620
  });
1573
- if (result instanceof Response) {
1574
- return result;
1575
- }
1576
- if (result instanceof globalThis.Request) {
1621
+ if (isRequestInstance(result)) {
1577
1622
  this.#assignRequest(result);
1578
1623
  }
1624
+ else if (isResponseInstance(result)) {
1625
+ return result;
1626
+ }
1579
1627
  }
1580
1628
  return undefined;
1581
1629
  }
1582
1630
  async #runAfterResponseHooks(response) {
1583
1631
  const responseRequest = this.#getResponseRequest(response);
1584
1632
  for (const hook of this.#options.hooks.afterResponse) {
1585
- // Clone the response before passing to hook so we can cancel it if needed
1586
- const clonedResponse = this.#setResponseRequest(response.clone(), responseRequest);
1587
- this.#decorateResponse(clonedResponse);
1633
+ const hookResponse = this.#setResponseRequest(response.clone(), responseRequest);
1634
+ this.#decorateResponse(hookResponse);
1588
1635
  let modifiedResponse;
1589
1636
  try {
1590
1637
  // eslint-disable-next-line no-await-in-loop
1591
1638
  modifiedResponse = await hook({
1592
1639
  request: this.request,
1593
1640
  options: this.#getNormalizedOptions(),
1594
- response: clonedResponse,
1641
+ response: hookResponse,
1595
1642
  retryCount: this.#retryCount,
1596
1643
  });
1597
1644
  }
1598
1645
  catch (error) {
1599
1646
  // Cancel both responses to prevent memory leaks when hook throws
1600
- this.#cancelResponseBody(clonedResponse);
1647
+ if (hookResponse !== response) {
1648
+ this.#cancelResponseBody(hookResponse);
1649
+ }
1601
1650
  this.#cancelResponseBody(response);
1602
1651
  throw error;
1603
1652
  }
1604
1653
  if (modifiedResponse instanceof RetryMarker) {
1605
1654
  // Cancel both the cloned response passed to the hook and the current response to prevent resource leaks (especially important in Deno/Bun).
1606
1655
  // Do not await cancellation since hooks can clone the response, leaving extra tee branches that keep cancel promises pending per the Streams spec.
1607
- this.#cancelResponseBody(clonedResponse);
1656
+ if (hookResponse !== response) {
1657
+ this.#cancelResponseBody(hookResponse);
1658
+ }
1608
1659
  this.#cancelResponseBody(response);
1609
1660
  throw new ForceRetryError(modifiedResponse.options);
1610
1661
  }
1611
- // Determine which response to use going forward
1612
- const nextResponse = this.#setResponseRequest(modifiedResponse instanceof globalThis.Response ? modifiedResponse : response, responseRequest);
1662
+ const nextResponse = isResponseInstance(modifiedResponse)
1663
+ ? this.#setResponseRequest(modifiedResponse, responseRequest)
1664
+ : response;
1613
1665
  // Cancel any response bodies we won't use to prevent memory leaks.
1614
1666
  // Uses fire-and-forget since hooks may have cloned the response, creating tee branches that block cancellation.
1615
- if (clonedResponse !== nextResponse) {
1616
- this.#cancelResponseBody(clonedResponse);
1667
+ // If the hook wrapped an existing body into a new Response, both Response objects can still point at the same stream.
1668
+ if (hookResponse !== response && hookResponse !== nextResponse && hookResponse.body !== nextResponse.body) {
1669
+ this.#cancelResponseBody(hookResponse);
1617
1670
  }
1618
- if (response !== nextResponse) {
1671
+ if (response !== nextResponse && response.body !== nextResponse.body) {
1619
1672
  this.#cancelResponseBody(response);
1620
1673
  }
1621
1674
  response = nextResponse;
@@ -1651,7 +1704,11 @@
1651
1704
  // Apply custom request from forced retry before beforeRetry hooks
1652
1705
  // Ensure the custom request has the correct managed signal for timeouts and user aborts
1653
1706
  if (error instanceof ForceRetryError && error.customRequest) {
1654
- this.#assignRequest(new globalThis.Request(error.customRequest, this.#options.signal ? { signal: this.#options.signal } : undefined));
1707
+ const customRequest = new globalThis.Request(error.customRequest, this.#options.signal ? { signal: this.#options.signal } : undefined);
1708
+ // Replacement Requests are authoritative by design. Do not rewrite headers here,
1709
+ // even for cross-origin retries. Callers using `ky.retry({request})` explicitly
1710
+ // opted into the exact Request they constructed.
1711
+ this.#assignRequest(customRequest);
1655
1712
  }
1656
1713
  for (const hook of this.#options.hooks.beforeRetry) {
1657
1714
  let hookResult;
@@ -1671,12 +1728,13 @@
1671
1728
  }
1672
1729
  throw hookError;
1673
1730
  }
1674
- if (hookResult instanceof globalThis.Request) {
1731
+ if (isRequestInstance(hookResult)) {
1732
+ // Same contract as `ky.retry({request})`: a Request returned from `beforeRetry`
1733
+ // is used as-is rather than being sanitized or otherwise rewritten by Ky.
1675
1734
  this.#assignRequest(hookResult);
1676
1735
  break;
1677
1736
  }
1678
- // If a Response is returned, use it and skip the retry
1679
- if (hookResult instanceof globalThis.Response) {
1737
+ if (isResponseInstance(hookResult)) {
1680
1738
  this.#returnedResponseFromBeforeRetryHook = true;
1681
1739
  this.#retryCount++;
1682
1740
  return hookResult;
@@ -1703,7 +1761,7 @@
1703
1761
  // Recreate request with new signal
1704
1762
  this.request = new globalThis.Request(this.request, { signal: this.#options.signal });
1705
1763
  }
1706
- const nonRequestOptions = findUnknownOptions(this.request, this.#options);
1764
+ const nonRequestOptions = findUnknownOptions(this.#options);
1707
1765
  const retryRequest = this.#options.retry.limit > 0 ? this.request.clone() : undefined;
1708
1766
  const request = this.#wrapRequestWithUploadProgress(this.request, this.#options.body ?? undefined);
1709
1767
  // Cloning is done here to prepare in advance for retries.
@@ -1817,7 +1875,7 @@
1817
1875
 
1818
1876
  var require$$1 = /*@__PURE__*/getAugmentedNamespace(distribution);
1819
1877
 
1820
- const VERSION = '0.16.1';
1878
+ const VERSION = '0.17.1';
1821
1879
 
1822
1880
  var constants = {
1823
1881
  VERSION,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@microlink/mql",
3
3
  "description": "Microlink Query Language. The official HTTP client to interact with Microlink API for Node.js, browsers & Deno.",
4
4
  "homepage": "https://microlink.io/mql",
5
- "version": "0.16.1",
5
+ "version": "0.17.1",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
8
8
  "types": "./dist/index.d.ts",
@@ -34,11 +34,12 @@
34
34
  }
35
35
  ],
36
36
  "repository": {
37
+ "directory": "packages/mql",
37
38
  "type": "git",
38
- "url": "git+https://github.com/microlinkhq/mql.git"
39
+ "url": "git+https://github.com/microlinkhq/microlink.git"
39
40
  },
40
41
  "bugs": {
41
- "url": "https://github.com/microlinkhq/mql/issues"
42
+ "url": "https://github.com/microlinkhq/microlink/issues"
42
43
  },
43
44
  "keywords": [
44
45
  "api",
@@ -52,26 +53,15 @@
52
53
  "ky": "~2.0.0"
53
54
  },
54
55
  "devDependencies": {
55
- "@commitlint/cli": "latest",
56
- "@commitlint/config-conventional": "latest",
57
56
  "@rollup/plugin-commonjs": "latest",
58
57
  "@rollup/plugin-node-resolve": "latest",
59
58
  "@rollup/plugin-replace": "latest",
60
59
  "@rollup/plugin-terser": "latest",
61
60
  "async-listen": "latest",
62
61
  "ava": "7",
63
- "c8": "latest",
64
- "ci-publish": "latest",
65
- "git-authors-cli": "latest",
66
- "github-generate-release": "latest",
67
- "nano-staged": "latest",
68
- "prettier-standard": "latest",
69
62
  "rollup": "latest",
70
63
  "rollup-plugin-filesize": "latest",
71
- "simple-git-hooks": "latest",
72
- "standard": "latest",
73
- "standard-markdown": "latest",
74
- "standard-version": "latest",
64
+ "tinyspawn": "latest",
75
65
  "tsd": "latest"
76
66
  },
77
67
  "engines": {
@@ -85,19 +75,12 @@
85
75
  ],
86
76
  "scripts": {
87
77
  "build": "rollup -c rollup.config.js --bundleConfigAsCjs",
88
- "clean": "rm -rf node_modules",
89
78
  "clean:build": "rm -rf dist/index.js",
90
- "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
91
- "dev": "npm run build -- -w",
92
- "lint": "standard && tsd",
93
- "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
94
- "prebuild": "npm run clean:build",
95
- "prepublishOnly": "npm run build",
96
- "pretest": "npm run lint && npm run build",
97
- "release": "standard-version -a",
98
- "release:github": "github-generate-release",
99
- "release:tags": "git push --follow-tags origin HEAD:master",
100
- "test": "c8 ava --verbose"
79
+ "dev": "pnpm run build -- -w",
80
+ "prebuild": "pnpm run clean:build",
81
+ "prepublishOnly": "pnpm run build",
82
+ "pretest": "pnpm run build",
83
+ "test": "ava --verbose && tsd"
101
84
  },
102
85
  "license": "MIT",
103
86
  "ava": {
@@ -107,38 +90,6 @@
107
90
  ],
108
91
  "timeout": "1m"
109
92
  },
110
- "commitlint": {
111
- "extends": [
112
- "@commitlint/config-conventional"
113
- ],
114
- "rules": {
115
- "body-max-line-length": [
116
- 0
117
- ]
118
- }
119
- },
120
- "nano-staged": {
121
- "*.js": [
122
- "npx -y @kikobeats/prettier-standard",
123
- "standard --fix"
124
- ],
125
- "*.md": [
126
- "standard-markdown"
127
- ],
128
- "package.json": [
129
- "finepack"
130
- ]
131
- },
132
- "simple-git-hooks": {
133
- "commit-msg": "npx commitlint --edit",
134
- "pre-commit": "npx nano-staged"
135
- },
136
- "standard": {
137
- "ignore": [
138
- "dist/index.js",
139
- "dist/index.umd.js"
140
- ]
141
- },
142
93
  "tsd": {
143
94
  "compilerOptions": {
144
95
  "baseUrl": ".",
@@ -149,5 +100,6 @@
149
100
  }
150
101
  },
151
102
  "directory": "test"
152
- }
103
+ },
104
+ "gitHead": "28020344ffd40e3253e8cfa345e2a0bfe15deda9"
153
105
  }