create-request 1.3.0 → 1.4.0

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.
@@ -94,6 +94,12 @@ var CacheMode;
94
94
  })(CacheMode || (CacheMode = {}));
95
95
 
96
96
  class RequestError extends Error {
97
+ status;
98
+ response;
99
+ url;
100
+ method;
101
+ isTimeout;
102
+ isAborted;
97
103
  constructor(message, url, method, options = {}) {
98
104
  super(message);
99
105
  this.name = "RequestError";
@@ -192,6 +198,11 @@ class RequestError extends Error {
192
198
  * Wrapper for HTTP responses with methods to transform the response data
193
199
  */
194
200
  class ResponseWrapper {
201
+ response;
202
+ url;
203
+ method;
204
+ // GraphQL-specific options
205
+ graphQLOptions;
195
206
  constructor(response, url, method, graphQLOptions) {
196
207
  this.response = response;
197
208
  this.url = url;
@@ -224,8 +235,7 @@ class ResponseWrapper {
224
235
  * @throws RequestError if GraphQL response contains errors and throwOnError is enabled
225
236
  */
226
237
  checkGraphQLErrors(data) {
227
- var _a;
228
- if (!((_a = this.graphQLOptions) === null || _a === void 0 ? void 0 : _a.throwOnError) || typeof data !== "object" || data === null)
238
+ if (!this.graphQLOptions?.throwOnError || typeof data !== "object" || data === null)
229
239
  return;
230
240
  const responseData = data;
231
241
  if (!Array.isArray(responseData.errors) || responseData.errors.length === 0)
@@ -486,7 +496,7 @@ class CsrfUtils {
486
496
  return null;
487
497
  }
488
498
  const meta = document.querySelector(`meta[name="${metaName}"]`);
489
- return (meta === null || meta === void 0 ? void 0 : meta.getAttribute("content")) || null;
499
+ return meta?.getAttribute("content") || null;
490
500
  }
491
501
  /**
492
502
  * Extracts CSRF token from a cookie
@@ -543,20 +553,20 @@ class CsrfUtils {
543
553
  * Global configuration for create-request
544
554
  */
545
555
  class Config {
546
- constructor() {
547
- // CSRF configuration
548
- this.csrfHeaderName = "X-CSRF-Token";
549
- this.xsrfCookieName = "XSRF-TOKEN";
550
- this.xsrfHeaderName = "X-XSRF-TOKEN";
551
- this.csrfToken = null;
552
- this.enableAutoXsrf = true;
553
- this.enableAntiCsrf = true; // X-Requested-With header
554
- // Interceptor configuration
555
- this.requestInterceptors = [];
556
- this.responseInterceptors = [];
557
- this.errorInterceptors = [];
558
- this.nextInterceptorId = 1;
559
- }
556
+ static instance;
557
+ // CSRF configuration
558
+ csrfHeaderName = "X-CSRF-Token";
559
+ xsrfCookieName = "XSRF-TOKEN";
560
+ xsrfHeaderName = "X-XSRF-TOKEN";
561
+ csrfToken = null;
562
+ enableAutoXsrf = true;
563
+ enableAntiCsrf = true; // X-Requested-With header
564
+ // Interceptor configuration
565
+ requestInterceptors = [];
566
+ responseInterceptors = [];
567
+ errorInterceptors = [];
568
+ nextInterceptorId = 1;
569
+ constructor() { }
560
570
  /**
561
571
  * Get the singleton instance of the Config class
562
572
  *
@@ -839,16 +849,18 @@ class Config {
839
849
  * Provides the core request building and execution capabilities.
840
850
  */
841
851
  class BaseRequest {
852
+ url;
853
+ requestOptions = {
854
+ headers: {},
855
+ };
856
+ abortController;
857
+ queryParams = new URLSearchParams();
858
+ autoApplyCsrfProtection = true;
859
+ // Per-request interceptors
860
+ requestInterceptors = [];
861
+ responseInterceptors = [];
862
+ errorInterceptors = [];
842
863
  constructor(url) {
843
- this.requestOptions = {
844
- headers: {},
845
- };
846
- this.queryParams = new URLSearchParams();
847
- this.autoApplyCsrfProtection = true;
848
- // Per-request interceptors
849
- this.requestInterceptors = [];
850
- this.responseInterceptors = [];
851
- this.errorInterceptors = [];
852
864
  this.url = url;
853
865
  }
854
866
  /**
@@ -879,7 +891,7 @@ class BaseRequest {
879
891
  return Object.assign(callable, fluent);
880
892
  }
881
893
  validateUrl(url) {
882
- if (!(url === null || url === void 0 ? void 0 : url.trim()))
894
+ if (!url?.trim())
883
895
  throw new RequestError("URL cannot be empty", url, this.method);
884
896
  if (url.includes("\0") || url.includes("\r") || url.includes("\n")) {
885
897
  throw new RequestError("Invalid URL (control chars)", url, this.method);
@@ -889,7 +901,7 @@ class BaseRequest {
889
901
  try {
890
902
  new URL(trimmed);
891
903
  }
892
- catch (_a) {
904
+ catch {
893
905
  throw new RequestError(`Invalid URL: ${trimmed}`, trimmed, this.method);
894
906
  }
895
907
  }
@@ -957,17 +969,60 @@ class BaseRequest {
957
969
  /**
958
970
  * Configure automatic retry behavior for failed requests
959
971
  *
960
- * @param retries - Number of retry attempts before failing
972
+ * @param retries - Number of retry attempts before failing, or a configuration object
961
973
  * @returns The request instance for chaining
962
- * @throws RequestError if retries is not a non-negative integer
974
+ * @throws RequestError if retries is not a non-negative integer or invalid config
963
975
  *
964
976
  * @example
977
+ * // Simple number (backward compatible)
965
978
  * request.withRetries(3); // Retry up to 3 times
979
+ *
980
+ * @example
981
+ * // With fixed delay
982
+ * request.withRetries({ attempts: 3, delay: 1000 }); // Retry 3 times with 1 second delay
983
+ *
984
+ * @example
985
+ * // With exponential backoff function
986
+ * request.withRetries({
987
+ * attempts: 3,
988
+ * delay: ({ attempt }) => Math.min(1000 * Math.pow(2, attempt - 1), 10000)
989
+ * });
990
+ *
991
+ * @example
992
+ * // With delay function based on error
993
+ * request.withRetries({
994
+ * attempts: 3,
995
+ * delay: ({ attempt, error }) => {
996
+ * if (error.status === 429) return 5000; // Rate limited, wait longer
997
+ * return attempt * 1000; // Exponential backoff
998
+ * }
999
+ * });
966
1000
  */
967
1001
  withRetries(retries) {
968
- if (!Number.isInteger(retries) || retries < 0)
969
- throw new RequestError("Retry count must be a non-negative integer", this.url, this.method);
970
- this.requestOptions.retries = retries;
1002
+ if (typeof retries === "number") {
1003
+ if (!Number.isInteger(retries) || retries < 0) {
1004
+ throw new RequestError(`Invalid retries: ${retries}`, this.url, this.method);
1005
+ }
1006
+ this.requestOptions.retries = retries;
1007
+ }
1008
+ else {
1009
+ // Validate RetryConfig
1010
+ if (!Number.isInteger(retries.attempts) || retries.attempts < 0) {
1011
+ throw new RequestError(`Invalid attempts: ${retries.attempts}`, this.url, this.method);
1012
+ }
1013
+ // Validate delay if provided
1014
+ if (retries.delay !== undefined) {
1015
+ if (typeof retries.delay === "number") {
1016
+ if (!Number.isFinite(retries.delay) || retries.delay < 0) {
1017
+ throw new RequestError(`Invalid delay: ${retries.delay}`, this.url, this.method);
1018
+ }
1019
+ }
1020
+ else if (typeof retries.delay !== "function") {
1021
+ throw new RequestError(`Invalid delay: ${typeof retries.delay}`, this.url, this.method);
1022
+ }
1023
+ }
1024
+ this.requestOptions.retries = retries;
1025
+ }
971
1026
  return this;
972
1027
  }
973
1028
  /**
@@ -988,10 +1043,26 @@ class BaseRequest {
988
1043
  return this;
989
1044
  }
990
1045
  /**
991
- * Sets credentials policy - supports both direct call and fluent API
1046
+ * Sets the credentials policy for the request, controlling whether cookies and authentication
1047
+ * headers are sent with cross-origin requests.
1048
+ *
1049
+ * @param credentialsPolicy - The credentials policy to use:
1050
+ * - `"include"` or `CredentialsPolicy.INCLUDE`: Always send credentials (cookies, authorization headers) with the request, even for cross-origin requests.
1051
+ * - `"omit"` or `CredentialsPolicy.OMIT`: Never send credentials, even for same-origin requests.
1052
+ * - `"same-origin"` or `CredentialsPolicy.SAME_ORIGIN`: Only send credentials for same-origin requests (default behavior in most browsers).
1053
+ *
1054
+ * @returns The request instance for chaining
1055
+ *
992
1056
  * @example
1057
+ * // Using string values
993
1058
  * request.withCredentials("include")
1059
+ *
1060
+ * @example
1061
+ * // Using enum values
994
1062
  * request.withCredentials(CredentialsPolicy.INCLUDE)
1063
+ *
1064
+ * @example
1065
+ * // Using fluent API
995
1066
  * request.withCredentials.INCLUDE()
996
1067
  */
997
1068
  get withCredentials() {
@@ -1002,28 +1073,83 @@ class BaseRequest {
1002
1073
  });
1003
1074
  }
1004
1075
  /**
1005
- * Allows providing an external AbortController to cancel the request
1006
- * @param controller - The AbortController to use for this request
1007
- * @returns The instance for chaining
1076
+ * Allows providing an external AbortController to cancel the request.
1077
+ * This is useful when you need to cancel a request from outside the request chain,
1078
+ *
1079
+ * @param controller - The AbortController to use for this request. When `controller.abort()` is called,
1080
+ * the request will be cancelled and throw an abort error.
1081
+ *
1082
+ * @returns The request instance for chaining
1083
+ *
1084
+ * @example
1085
+ * const controller = new AbortController();
1086
+ * const request = createRequest('/api/data')
1087
+ * .withAbortController(controller)
1088
+ * .getJson();
1089
+ *
1090
+ * // Later, cancel the request
1091
+ * controller.abort();
1092
+ *
1093
+ * @example
1094
+ * // Share abort controller across multiple requests
1095
+ * const controller = new AbortController();
1096
+ * request1.withAbortController(controller).getJson();
1097
+ * request2.withAbortController(controller).getJson();
1098
+ * // Aborting will cancel both requests
1099
+ * controller.abort();
1008
1100
  */
1009
1101
  withAbortController(controller) {
1010
1102
  this.abortController = controller;
1011
1103
  return this;
1012
1104
  }
1013
1105
  /**
1014
- * Sets the referrer for the request
1015
- * @param referrer - The referrer URL or policy
1016
- * @returns The instance for chaining
1106
+ * Sets the referrer URL for the request. The referrer is the URL of the page that initiated the request.
1107
+ * This can be used to override the default referrer that the browser would normally send.
1108
+ *
1109
+ * @param referrer - The referrer URL to send with the request. Can be:
1110
+ * - A full URL (e.g., "https://example.com/page")
1111
+ * - An empty string to omit the referrer
1112
+ * - A relative URL (will be resolved relative to the current page)
1113
+ *
1114
+ * @returns The request instance for chaining
1115
+ *
1116
+ * @example
1117
+ * request.withReferrer("https://example.com/previous-page")
1118
+ *
1119
+ * @example
1120
+ * // Omit referrer
1121
+ * request.withReferrer("")
1017
1122
  */
1018
1123
  withReferrer(referrer) {
1019
1124
  this.requestOptions.referrer = referrer;
1020
1125
  return this;
1021
1126
  }
1022
1127
  /**
1023
- * Sets referrer policy - supports both direct call and fluent API
1128
+ * Sets the referrer policy for the request, controlling how much referrer information
1129
+ * is sent with the request. This helps balance privacy and functionality.
1130
+ *
1131
+ * @param policy - The referrer policy to use:
1132
+ * - `"no-referrer"` or `ReferrerPolicy.NO_REFERRER`: Never send the referrer header.
1133
+ * - `"no-referrer-when-downgrade"` or `ReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE`: Send full referrer for same-origin or HTTPS→HTTPS, omit for HTTPS→HTTP (default in most browsers).
1134
+ * - `"origin"` or `ReferrerPolicy.ORIGIN`: Only send the origin (scheme, host, port), not the full URL.
1135
+ * - `"origin-when-cross-origin"` or `ReferrerPolicy.ORIGIN_WHEN_CROSS_ORIGIN`: Send full referrer for same-origin, only origin for cross-origin.
1136
+ * - `"same-origin"` or `ReferrerPolicy.SAME_ORIGIN`: Send full referrer for same-origin requests only, omit for cross-origin.
1137
+ * - `"strict-origin"` or `ReferrerPolicy.STRICT_ORIGIN`: Send origin for HTTPS→HTTPS or HTTP→HTTP, omit for HTTPS→HTTP.
1138
+ * - `"strict-origin-when-cross-origin"` or `ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN`: Send full referrer for same-origin, origin for cross-origin HTTPS→HTTPS, omit for HTTPS→HTTP.
1139
+ * - `"unsafe-url"` or `ReferrerPolicy.UNSAFE_URL`: Always send the full referrer URL (may leak sensitive information).
1140
+ *
1141
+ * @returns The request instance for chaining
1142
+ *
1024
1143
  * @example
1144
+ * // Using string values
1025
1145
  * request.withReferrerPolicy("no-referrer")
1146
+ *
1147
+ * @example
1148
+ * // Using enum values
1026
1149
  * request.withReferrerPolicy(ReferrerPolicy.NO_REFERRER)
1150
+ *
1151
+ * @example
1152
+ * // Using fluent API
1027
1153
  * request.withReferrerPolicy.NO_REFERRER()
1028
1154
  */
1029
1155
  get withReferrerPolicy() {
@@ -1039,11 +1165,30 @@ class BaseRequest {
1039
1165
  });
1040
1166
  }
1041
1167
  /**
1042
- * Sets redirect mode - supports both direct call and fluent API
1168
+ * Sets how the request handles HTTP redirects (3xx status codes).
1169
+ *
1170
+ * @param redirect - The redirect handling mode:
1171
+ * - `"follow"` or `RedirectMode.FOLLOW`: Automatically follow redirects. The fetch will transparently follow redirects and return the final response (default behavior).
1172
+ * - `"error"` or `RedirectMode.ERROR`: Treat redirects as errors. If a redirect occurs, the request will fail with an error.
1173
+ * - `"manual"` or `RedirectMode.MANUAL`: Return the redirect response without following it. The response will have a `type` of "opaqueredirect" and you can manually handle the redirect.
1174
+ *
1175
+ * @returns The request instance for chaining
1176
+ *
1043
1177
  * @example
1178
+ * // Using string values
1044
1179
  * request.withRedirect("follow")
1180
+ *
1181
+ * @example
1182
+ * // Using enum values
1045
1183
  * request.withRedirect(RedirectMode.FOLLOW)
1184
+ *
1185
+ * @example
1186
+ * // Using fluent API
1046
1187
  * request.withRedirect.FOLLOW()
1188
+ *
1189
+ * @example
1190
+ * // Fail on redirects
1191
+ * request.withRedirect.ERROR()
1047
1192
  */
1048
1193
  get withRedirect() {
1049
1194
  return this.createFluentSetter("redirect", {
@@ -1053,20 +1198,50 @@ class BaseRequest {
1053
1198
  });
1054
1199
  }
1055
1200
  /**
1056
- * Sets the keepalive flag for the request
1057
- * @param keepalive - Whether to allow the request to outlive the page
1058
- * @returns The instance for chaining
1201
+ * Sets the keepalive flag for the request. When enabled, the request can continue
1202
+ * even after the page that initiated it is closed. This is useful for analytics,
1203
+ * logging, or other background requests that should complete even if the user navigates away.
1204
+ *
1205
+ * @param keepalive - Whether to allow the request to outlive the page:
1206
+ * - `true`: The request will continue even if the page is closed or navigated away.
1207
+ * - `false`: The request will be cancelled if the page is closed (default).
1208
+ *
1209
+ * @returns The request instance for chaining
1210
+ *
1211
+ * @example
1212
+ * // Send analytics event that should complete even if user navigates away
1213
+ * request.withKeepAlive(true)
1059
1214
  */
1060
1215
  withKeepAlive(keepalive) {
1061
1216
  this.requestOptions.keepalive = keepalive;
1062
1217
  return this;
1063
1218
  }
1064
1219
  /**
1065
- * Sets request priority - supports both direct call and fluent API
1220
+ * Sets the priority hint for the request, indicating to the browser how important
1221
+ * this request is relative to other requests. This helps the browser optimize resource loading.
1222
+ *
1223
+ * @param priority - The request priority:
1224
+ * - `"high"` or `RequestPriority.HIGH`: High priority - the browser should prioritize this request.
1225
+ * - `"low"` or `RequestPriority.LOW`: Low priority - the browser can defer this request if needed.
1226
+ * - `"auto"` or `RequestPriority.AUTO`: Automatic priority based on the request type (default).
1227
+ *
1228
+ * @returns The request instance for chaining
1229
+ *
1066
1230
  * @example
1231
+ * // Using string values
1067
1232
  * request.withPriority("high")
1233
+ *
1234
+ * @example
1235
+ * // Using enum values
1068
1236
  * request.withPriority(RequestPriority.HIGH)
1237
+ *
1238
+ * @example
1239
+ * // Using fluent API
1069
1240
  * request.withPriority.HIGH()
1241
+ *
1242
+ * @example
1243
+ * // Low priority for non-critical requests
1244
+ * request.withPriority.LOW()
1070
1245
  */
1071
1246
  get withPriority() {
1072
1247
  return this.createFluentSetter("priority", {
@@ -1076,22 +1251,62 @@ class BaseRequest {
1076
1251
  });
1077
1252
  }
1078
1253
  /**
1079
- * Sets the integrity hash for subresource integrity verification
1080
- * @param integrity - The integrity hash string (e.g., "sha256-...")
1081
- * @returns The instance for chaining
1254
+ * Sets the integrity hash for Subresource Integrity (SRI) verification.
1255
+ * This allows the browser to verify that the fetched resource hasn't been tampered with
1256
+ * by comparing its hash against the provided value. If the hashes don't match, the request fails.
1257
+ *
1258
+ * @param integrity - The integrity hash string in the format `"algorithm-hash"`:
1259
+ * - Example: `"sha256-abcdef1234567890..."` (SHA-256 hash)
1260
+ * - Example: `"sha384-abcdef1234567890..."` (SHA-384 hash)
1261
+ * - Example: `"sha512-abcdef1234567890..."` (SHA-512 hash)
1262
+ * - Multiple hashes can be separated by spaces: `"sha256-... sha384-..."`
1263
+ *
1264
+ * @returns The request instance for chaining
1265
+ *
1082
1266
  * @example
1083
1267
  * request.withIntegrity("sha256-abcdef1234567890...")
1268
+ *
1269
+ * @example
1270
+ * // Multiple algorithms for better compatibility
1271
+ * request.withIntegrity("sha256-... sha384-...")
1084
1272
  */
1085
1273
  withIntegrity(integrity) {
1086
1274
  this.requestOptions.integrity = integrity;
1087
1275
  return this;
1088
1276
  }
1089
1277
  /**
1090
- * Sets cache mode - supports both direct call and fluent API
1278
+ * Sets the cache mode for the request, controlling how the browser's HTTP cache
1279
+ * is used for this request.
1280
+ *
1281
+ * @param cache - The cache mode:
1282
+ * - `"default"` or `CacheMode.DEFAULT`: Use the browser's default cache behavior. The browser will check the cache and use it if valid, otherwise fetch from network.
1283
+ * - `"no-store"` or `CacheMode.NO_STORE`: Never use the cache and don't store the response in cache. Always fetch from network.
1284
+ * - `"reload"` or `CacheMode.RELOAD`: Bypass the cache but store the response. Always fetch from network, ignoring cached responses.
1285
+ * - `"no-cache"` or `CacheMode.NO_CACHE`: Check the cache but revalidate with the server. Use cached response only if server confirms it's still valid.
1286
+ * - `"force-cache"` or `CacheMode.FORCE_CACHE`: Use the cache if available, even if stale. Only fetch from network if not in cache.
1287
+ * - `"only-if-cached"` or `CacheMode.ONLY_IF_CACHED`: Only use the cache. If not in cache, return an error. Never fetch from network.
1288
+ *
1289
+ * @returns The request instance for chaining
1290
+ *
1091
1291
  * @example
1292
+ * // Using string values
1092
1293
  * request.withCache("no-cache")
1294
+ *
1295
+ * @example
1296
+ * // Using enum values
1093
1297
  * request.withCache(CacheMode.NO_CACHE)
1298
+ *
1299
+ * @example
1300
+ * // Using fluent API
1094
1301
  * request.withCache.NO_CACHE()
1302
+ *
1303
+ * @example
1304
+ * // Always fetch fresh data
1305
+ * request.withCache.RELOAD()
1306
+ *
1307
+ * @example
1308
+ * // Use cache only, fail if not cached
1309
+ * request.withCache.ONLY_IF_CACHED()
1095
1310
  */
1096
1311
  get withCache() {
1097
1312
  const cacheOptions = {
@@ -1140,11 +1355,32 @@ class BaseRequest {
1140
1355
  return this;
1141
1356
  }
1142
1357
  /**
1143
- * Sets request mode - supports both direct call and fluent API
1358
+ * Sets the request mode, which determines the CORS (Cross-Origin Resource Sharing) behavior
1359
+ * for the request. This controls how the browser handles cross-origin requests.
1360
+ *
1361
+ * @param mode - The request mode:
1362
+ * - `"cors"` or `RequestMode.CORS`: Enable CORS. The browser will send CORS headers and enforce CORS rules. This is the default for most cross-origin requests.
1363
+ * - `"no-cors"` or `RequestMode.NO_CORS`: Disable CORS. The request is sent as a "simple" request without CORS headers. The response will be opaque (you can't read it).
1364
+ * - `"same-origin"` or `RequestMode.SAME_ORIGIN`: Only allow same-origin requests. Cross-origin requests will fail.
1365
+ * - `"navigate"` or `RequestMode.NAVIGATE`: Used for navigation requests (typically only used by the browser itself).
1366
+ *
1367
+ * @returns The request instance for chaining
1368
+ *
1144
1369
  * @example
1370
+ * // Using string values
1145
1371
  * request.withMode("cors")
1372
+ *
1373
+ * @example
1374
+ * // Using enum values
1146
1375
  * request.withMode(RequestMode.CORS)
1376
+ *
1377
+ * @example
1378
+ * // Using fluent API
1147
1379
  * request.withMode.CORS()
1380
+ *
1381
+ * @example
1382
+ * // Restrict to same-origin only
1383
+ * request.withMode.SAME_ORIGIN()
1148
1384
  */
1149
1385
  get withMode() {
1150
1386
  return this.createFluentSetter("mode", {
@@ -1539,7 +1775,8 @@ class BaseRequest {
1539
1775
  * @throws RequestError if the request fails after all retries
1540
1776
  */
1541
1777
  async executeWithRetries(url, fetchOptions) {
1542
- const maxRetries = this.requestOptions.retries || 0;
1778
+ const retriesConfig = this.requestOptions.retries;
1779
+ const maxRetries = typeof retriesConfig === "number" ? retriesConfig : retriesConfig?.attempts || 0;
1543
1780
  const method = typeof fetchOptions.method === "string" ? fetchOptions.method : "GET";
1544
1781
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
1545
1782
  try {
@@ -1549,9 +1786,22 @@ class BaseRequest {
1549
1786
  const requestError = error instanceof RequestError ? error : RequestError.networkError(url, method, error instanceof Error ? error : new Error(String(error)));
1550
1787
  if (attempt >= maxRetries)
1551
1788
  throw requestError;
1789
+ // Call onRetry callback if provided
1552
1790
  if (this.requestOptions.onRetry) {
1553
1791
  await this.requestOptions.onRetry({ attempt: attempt + 1, error: requestError });
1554
1792
  }
1793
+ // Apply delay if configured
1794
+ if (typeof retriesConfig === "object" && retriesConfig.delay !== undefined) {
1795
+ const delay = typeof retriesConfig.delay === "function" ? retriesConfig.delay({ attempt: attempt + 1, error: requestError }) : retriesConfig.delay;
1796
+ // Validate delay result
1797
+ if (typeof delay !== "number" || !Number.isFinite(delay) || delay < 0) {
1798
+ throw new RequestError(`Invalid retry delay: ${delay}`, url, method);
1799
+ }
1800
+ // Wait for the delay
1801
+ if (delay > 0) {
1802
+ await new Promise(resolve => setTimeout(resolve, delay));
1803
+ }
1804
+ }
1555
1805
  }
1556
1806
  }
1557
1807
  // This should never happen but is needed for type safety
@@ -1668,7 +1918,7 @@ class BaseRequest {
1668
1918
  // No timeout - just use external controller
1669
1919
  if (!timeoutMs) {
1670
1920
  return {
1671
- signal: externalController === null || externalController === void 0 ? void 0 : externalController.signal,
1921
+ signal: externalController?.signal,
1672
1922
  cleanup: () => { },
1673
1923
  wasTimeout: () => false,
1674
1924
  };
@@ -1851,9 +2101,11 @@ class BaseRequest {
1851
2101
  * Base class for requests that can have a body (POST, PUT, PATCH)
1852
2102
  */
1853
2103
  class BodyRequest extends BaseRequest {
2104
+ body;
2105
+ bodyType;
2106
+ graphQLOptions = undefined;
1854
2107
  constructor(url) {
1855
2108
  super(url);
1856
- this.graphQLOptions = undefined;
1857
2109
  }
1858
2110
  /**
1859
2111
  * Sets the body of the request
@@ -1868,7 +2120,13 @@ class BodyRequest extends BaseRequest {
1868
2120
  }
1869
2121
  else if (body !== null &&
1870
2122
  typeof body === "object" &&
1871
- !(body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer || body instanceof URLSearchParams || body instanceof ReadableStream)) {
2123
+ !(body instanceof FormData ||
2124
+ body instanceof Blob ||
2125
+ body instanceof File ||
2126
+ body instanceof ArrayBuffer ||
2127
+ ArrayBuffer.isView(body) || // Handles TypedArray and DataView
2128
+ body instanceof URLSearchParams ||
2129
+ body instanceof ReadableStream)) {
1872
2130
  this.bodyType = BodyType.JSON;
1873
2131
  this.setContentTypeIfNeeded("application/json");
1874
2132
  // Validate JSON is stringifiable early
@@ -1998,9 +2256,9 @@ class BodyRequest extends BaseRequest {
1998
2256
  * const data = await request.getData();
1999
2257
  */
2000
2258
  class GetRequest extends BaseRequest {
2259
+ method = HttpMethod.GET;
2001
2260
  constructor(url) {
2002
2261
  super(url);
2003
- this.method = HttpMethod.GET;
2004
2262
  }
2005
2263
  }
2006
2264
  /**
@@ -2012,9 +2270,9 @@ class GetRequest extends BaseRequest {
2012
2270
  * const response = await request.getResponse();
2013
2271
  */
2014
2272
  class HeadRequest extends BaseRequest {
2273
+ method = HttpMethod.HEAD;
2015
2274
  constructor(url) {
2016
2275
  super(url);
2017
- this.method = HttpMethod.HEAD;
2018
2276
  }
2019
2277
  }
2020
2278
  /**
@@ -2026,9 +2284,9 @@ class HeadRequest extends BaseRequest {
2026
2284
  * const response = await request.getResponse();
2027
2285
  */
2028
2286
  class OptionsRequest extends BaseRequest {
2287
+ method = HttpMethod.OPTIONS;
2029
2288
  constructor(url) {
2030
2289
  super(url);
2031
- this.method = HttpMethod.OPTIONS;
2032
2290
  }
2033
2291
  }
2034
2292
  /**
@@ -2040,9 +2298,9 @@ class OptionsRequest extends BaseRequest {
2040
2298
  * await request.getData();
2041
2299
  */
2042
2300
  class DeleteRequest extends BaseRequest {
2301
+ method = HttpMethod.DELETE;
2043
2302
  constructor(url) {
2044
2303
  super(url);
2045
- this.method = HttpMethod.DELETE;
2046
2304
  }
2047
2305
  }
2048
2306
  /**
@@ -2055,9 +2313,9 @@ class DeleteRequest extends BaseRequest {
2055
2313
  * const data = await request.getData();
2056
2314
  */
2057
2315
  class PostRequest extends BodyRequest {
2316
+ method = HttpMethod.POST;
2058
2317
  constructor(url) {
2059
2318
  super(url);
2060
- this.method = HttpMethod.POST;
2061
2319
  }
2062
2320
  }
2063
2321
  /**
@@ -2070,9 +2328,9 @@ class PostRequest extends BodyRequest {
2070
2328
  * const data = await request.getData();
2071
2329
  */
2072
2330
  class PutRequest extends BodyRequest {
2331
+ method = HttpMethod.PUT;
2073
2332
  constructor(url) {
2074
2333
  super(url);
2075
- this.method = HttpMethod.PUT;
2076
2334
  }
2077
2335
  }
2078
2336
  /**
@@ -2085,9 +2343,9 @@ class PutRequest extends BodyRequest {
2085
2343
  * const data = await request.getData();
2086
2344
  */
2087
2345
  class PatchRequest extends BodyRequest {
2346
+ method = HttpMethod.PATCH;
2088
2347
  constructor(url) {
2089
2348
  super(url);
2090
- this.method = HttpMethod.PATCH;
2091
2349
  }
2092
2350
  }
2093
2351