create-request 1.2.3 → 1.3.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.
@@ -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";
@@ -190,11 +196,14 @@ class RequestError extends Error {
190
196
 
191
197
  /**
192
198
  * Wrapper for HTTP responses with methods to transform the response data
193
- * Provides caching and conversion between different response formats.
194
199
  */
195
200
  class ResponseWrapper {
201
+ response;
202
+ url;
203
+ method;
204
+ // GraphQL-specific options
205
+ graphQLOptions;
196
206
  constructor(response, url, method, graphQLOptions) {
197
- this.bodyUsed = false;
198
207
  this.response = response;
199
208
  this.url = url;
200
209
  this.method = method;
@@ -226,8 +235,7 @@ class ResponseWrapper {
226
235
  * @throws RequestError if GraphQL response contains errors and throwOnError is enabled
227
236
  */
228
237
  checkGraphQLErrors(data) {
229
- var _a;
230
- 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)
231
239
  return;
232
240
  const responseData = data;
233
241
  if (!Array.isArray(responseData.errors) || responseData.errors.length === 0)
@@ -242,7 +250,7 @@ class ResponseWrapper {
242
250
  }
243
251
  /**
244
252
  * Parse the response body as JSON
245
- * Caches the result for subsequent calls.
253
+ * Note: This consumes the response body and can only be called once.
246
254
  * If GraphQL options are set with throwOnError=true, will check for GraphQL errors and throw.
247
255
  *
248
256
  * @returns The parsed JSON data
@@ -263,40 +271,14 @@ class ResponseWrapper {
263
271
  * }
264
272
  */
265
273
  async getJson() {
266
- if (this.jsonCache !== undefined) {
267
- this.checkGraphQLErrors(this.jsonCache);
268
- return this.jsonCache;
269
- }
270
- if (this.bodyUsed) {
271
- // If we already have text, try to parse it as JSON
272
- if (this.textCache !== undefined) {
273
- try {
274
- const parsed = JSON.parse(this.textCache);
275
- this.jsonCache = parsed;
276
- this.checkGraphQLErrors(parsed);
277
- return parsed;
278
- }
279
- catch (error) {
280
- // Re-throw RequestErrors from checkGraphQLErrors without wrapping
281
- if (error instanceof RequestError) {
282
- throw error;
283
- }
284
- const errorMessage = error instanceof Error ? error.message : String(error);
285
- throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url || "", this.method || "", {
286
- status: this.response.status,
287
- response: this.response,
288
- });
289
- }
290
- }
274
+ if (this.response.bodyUsed) {
291
275
  throw new RequestError("Body already consumed", this.url || "", this.method || "", {
292
276
  status: this.response.status,
293
277
  response: this.response,
294
278
  });
295
279
  }
296
- this.bodyUsed = true;
297
280
  try {
298
281
  const parsed = await this.response.json();
299
- this.jsonCache = parsed;
300
282
  this.checkGraphQLErrors(parsed);
301
283
  return parsed;
302
284
  }
@@ -314,48 +296,23 @@ class ResponseWrapper {
314
296
  }
315
297
  /**
316
298
  * Get the response body as text
317
- * Caches the result for subsequent calls. Attempts to convert from JSON or Blob
318
- * if the body has already been consumed in those formats.
299
+ * Note: This consumes the response body and can only be called once.
319
300
  *
320
301
  * @returns The response text
321
- * @throws {RequestError} When reading fails or the response has already been consumed in an incompatible format
302
+ * @throws {RequestError} When reading fails or the response has already been consumed
322
303
  *
323
304
  * @example
324
305
  * const text = await response.getText();
325
306
  */
326
307
  async getText() {
327
- if (this.textCache !== undefined) {
328
- return this.textCache;
329
- }
330
- if (this.bodyUsed) {
331
- // If we already have JSON, convert it to text
332
- if (this.jsonCache !== undefined) {
333
- this.textCache = JSON.stringify(this.jsonCache);
334
- return this.textCache;
335
- }
336
- // If we have blob, convert to text
337
- if (this.blobCache !== undefined) {
338
- try {
339
- this.textCache = await this.blobCache.text();
340
- return this.textCache;
341
- }
342
- catch (e) {
343
- const errorMessage = e instanceof Error ? e.message : String(e);
344
- throw new RequestError(`Cannot convert to text: ${errorMessage}`, this.url || "", this.method || "", {
345
- status: this.response.status,
346
- response: this.response,
347
- });
348
- }
349
- }
350
- throw new RequestError("Cannot convert to text", this.url || "", this.method || "", {
308
+ if (this.response.bodyUsed) {
309
+ throw new RequestError("Body already consumed", this.url || "", this.method || "", {
351
310
  status: this.response.status,
352
311
  response: this.response,
353
312
  });
354
313
  }
355
- this.bodyUsed = true;
356
314
  try {
357
- this.textCache = await this.response.text();
358
- return this.textCache;
315
+ return await this.response.text();
359
316
  }
360
317
  catch (e) {
361
318
  const errorMessage = e instanceof Error ? e.message : String(e);
@@ -367,35 +324,53 @@ class ResponseWrapper {
367
324
  }
368
325
  /**
369
326
  * Get the response body as a Blob
370
- * Caches the result for subsequent calls. Attempts to convert from text
371
- * if the body has already been consumed as text.
327
+ * Note: This consumes the response body and can only be called once.
372
328
  *
373
329
  * @returns The response as a Blob
374
- * @throws {RequestError} When reading fails or the response has already been consumed in an incompatible format
330
+ * @throws {RequestError} When reading fails or the response has already been consumed
375
331
  *
376
332
  * @example
377
333
  * const blob = await response.getBlob();
378
334
  * const url = URL.createObjectURL(blob);
379
335
  */
380
336
  async getBlob() {
381
- if (this.blobCache !== undefined) {
382
- return this.blobCache;
337
+ if (this.response.bodyUsed) {
338
+ throw new RequestError("Body already consumed", this.url || "", this.method || "", {
339
+ status: this.response.status,
340
+ response: this.response,
341
+ });
383
342
  }
384
- if (this.bodyUsed) {
385
- // If we have text, convert to Blob
386
- if (this.textCache !== undefined) {
387
- this.blobCache = new Blob([this.textCache], { type: "text/plain" });
388
- return this.blobCache;
389
- }
390
- throw new RequestError("Cannot convert to Blob", this.url || "", this.method || "", {
343
+ try {
344
+ return await this.response.blob();
345
+ }
346
+ catch (e) {
347
+ const errorMessage = e instanceof Error ? e.message : String(e);
348
+ throw new RequestError(`Read failed: ${errorMessage}`, this.url || "", this.method || "", {
349
+ status: this.response.status,
350
+ response: this.response,
351
+ });
352
+ }
353
+ }
354
+ /**
355
+ * Get the response body as an ArrayBuffer
356
+ * Note: This consumes the response body and can only be called once.
357
+ *
358
+ * @returns The response as an ArrayBuffer
359
+ * @throws {RequestError} When reading fails or the response has already been consumed
360
+ *
361
+ * @example
362
+ * const buffer = await response.getArrayBuffer();
363
+ * const uint8Array = new Uint8Array(buffer);
364
+ */
365
+ async getArrayBuffer() {
366
+ if (this.response.bodyUsed) {
367
+ throw new RequestError("Body already consumed", this.url || "", this.method || "", {
391
368
  status: this.response.status,
392
369
  response: this.response,
393
370
  });
394
371
  }
395
- this.bodyUsed = true;
396
372
  try {
397
- this.blobCache = await this.response.blob();
398
- return this.blobCache;
373
+ return await this.response.arrayBuffer();
399
374
  }
400
375
  catch (e) {
401
376
  const errorMessage = e instanceof Error ? e.message : String(e);
@@ -407,7 +382,7 @@ class ResponseWrapper {
407
382
  }
408
383
  /**
409
384
  * Get the raw response body as a ReadableStream
410
- * This method consumes the body and should only be called once.
385
+ * Note: This consumes the response body and should only be called once.
411
386
  *
412
387
  * @returns The response body as a ReadableStream or null
413
388
  * @throws {RequestError} When the response body has already been consumed
@@ -420,13 +395,12 @@ class ResponseWrapper {
420
395
  * }
421
396
  */
422
397
  getBody() {
423
- if (this.bodyUsed) {
398
+ if (this.response.bodyUsed) {
424
399
  throw new RequestError("Body already consumed", this.url || "", this.method || "", {
425
400
  status: this.response.status,
426
401
  response: this.response,
427
402
  });
428
403
  }
429
- this.bodyUsed = true;
430
404
  return this.response.body;
431
405
  }
432
406
  /**
@@ -522,7 +496,7 @@ class CsrfUtils {
522
496
  return null;
523
497
  }
524
498
  const meta = document.querySelector(`meta[name="${metaName}"]`);
525
- return (meta === null || meta === void 0 ? void 0 : meta.getAttribute("content")) || null;
499
+ return meta?.getAttribute("content") || null;
526
500
  }
527
501
  /**
528
502
  * Extracts CSRF token from a cookie
@@ -579,20 +553,20 @@ class CsrfUtils {
579
553
  * Global configuration for create-request
580
554
  */
581
555
  class Config {
582
- constructor() {
583
- // CSRF configuration
584
- this.csrfHeaderName = "X-CSRF-Token";
585
- this.xsrfCookieName = "XSRF-TOKEN";
586
- this.xsrfHeaderName = "X-XSRF-TOKEN";
587
- this.csrfToken = null;
588
- this.enableAutoXsrf = true;
589
- this.enableAntiCsrf = true; // X-Requested-With header
590
- // Interceptor configuration
591
- this.requestInterceptors = [];
592
- this.responseInterceptors = [];
593
- this.errorInterceptors = [];
594
- this.nextInterceptorId = 1;
595
- }
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() { }
596
570
  /**
597
571
  * Get the singleton instance of the Config class
598
572
  *
@@ -875,16 +849,18 @@ class Config {
875
849
  * Provides the core request building and execution capabilities.
876
850
  */
877
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 = [];
878
863
  constructor(url) {
879
- this.requestOptions = {
880
- headers: {},
881
- };
882
- this.queryParams = new URLSearchParams();
883
- this.autoApplyCsrfProtection = true;
884
- // Per-request interceptors
885
- this.requestInterceptors = [];
886
- this.responseInterceptors = [];
887
- this.errorInterceptors = [];
888
864
  this.url = url;
889
865
  }
890
866
  /**
@@ -915,7 +891,7 @@ class BaseRequest {
915
891
  return Object.assign(callable, fluent);
916
892
  }
917
893
  validateUrl(url) {
918
- if (!(url === null || url === void 0 ? void 0 : url.trim()))
894
+ if (!url?.trim())
919
895
  throw new RequestError("URL cannot be empty", url, this.method);
920
896
  if (url.includes("\0") || url.includes("\r") || url.includes("\n")) {
921
897
  throw new RequestError("Invalid URL (control chars)", url, this.method);
@@ -925,7 +901,7 @@ class BaseRequest {
925
901
  try {
926
902
  new URL(trimmed);
927
903
  }
928
- catch (_a) {
904
+ catch {
929
905
  throw new RequestError(`Invalid URL: ${trimmed}`, trimmed, this.method);
930
906
  }
931
907
  }
@@ -1024,10 +1000,26 @@ class BaseRequest {
1024
1000
  return this;
1025
1001
  }
1026
1002
  /**
1027
- * Sets credentials policy - supports both direct call and fluent API
1003
+ * Sets the credentials policy for the request, controlling whether cookies and authentication
1004
+ * headers are sent with cross-origin requests.
1005
+ *
1006
+ * @param credentialsPolicy - The credentials policy to use:
1007
+ * - `"include"` or `CredentialsPolicy.INCLUDE`: Always send credentials (cookies, authorization headers) with the request, even for cross-origin requests.
1008
+ * - `"omit"` or `CredentialsPolicy.OMIT`: Never send credentials, even for same-origin requests.
1009
+ * - `"same-origin"` or `CredentialsPolicy.SAME_ORIGIN`: Only send credentials for same-origin requests (default behavior in most browsers).
1010
+ *
1011
+ * @returns The request instance for chaining
1012
+ *
1028
1013
  * @example
1014
+ * // Using string values
1029
1015
  * request.withCredentials("include")
1016
+ *
1017
+ * @example
1018
+ * // Using enum values
1030
1019
  * request.withCredentials(CredentialsPolicy.INCLUDE)
1020
+ *
1021
+ * @example
1022
+ * // Using fluent API
1031
1023
  * request.withCredentials.INCLUDE()
1032
1024
  */
1033
1025
  get withCredentials() {
@@ -1038,28 +1030,83 @@ class BaseRequest {
1038
1030
  });
1039
1031
  }
1040
1032
  /**
1041
- * Allows providing an external AbortController to cancel the request
1042
- * @param controller - The AbortController to use for this request
1043
- * @returns The instance for chaining
1033
+ * Allows providing an external AbortController to cancel the request.
1034
+ * This is useful when you need to cancel a request from outside the request chain,
1035
+ *
1036
+ * @param controller - The AbortController to use for this request. When `controller.abort()` is called,
1037
+ * the request will be cancelled and throw an abort error.
1038
+ *
1039
+ * @returns The request instance for chaining
1040
+ *
1041
+ * @example
1042
+ * const controller = new AbortController();
1043
+ * const request = createRequest('/api/data')
1044
+ * .withAbortController(controller)
1045
+ * .getJson();
1046
+ *
1047
+ * // Later, cancel the request
1048
+ * controller.abort();
1049
+ *
1050
+ * @example
1051
+ * // Share abort controller across multiple requests
1052
+ * const controller = new AbortController();
1053
+ * request1.withAbortController(controller).getJson();
1054
+ * request2.withAbortController(controller).getJson();
1055
+ * // Aborting will cancel both requests
1056
+ * controller.abort();
1044
1057
  */
1045
1058
  withAbortController(controller) {
1046
1059
  this.abortController = controller;
1047
1060
  return this;
1048
1061
  }
1049
1062
  /**
1050
- * Sets the referrer for the request
1051
- * @param referrer - The referrer URL or policy
1052
- * @returns The instance for chaining
1063
+ * Sets the referrer URL for the request. The referrer is the URL of the page that initiated the request.
1064
+ * This can be used to override the default referrer that the browser would normally send.
1065
+ *
1066
+ * @param referrer - The referrer URL to send with the request. Can be:
1067
+ * - A full URL (e.g., "https://example.com/page")
1068
+ * - An empty string to omit the referrer
1069
+ * - A relative URL (will be resolved relative to the current page)
1070
+ *
1071
+ * @returns The request instance for chaining
1072
+ *
1073
+ * @example
1074
+ * request.withReferrer("https://example.com/previous-page")
1075
+ *
1076
+ * @example
1077
+ * // Omit referrer
1078
+ * request.withReferrer("")
1053
1079
  */
1054
1080
  withReferrer(referrer) {
1055
1081
  this.requestOptions.referrer = referrer;
1056
1082
  return this;
1057
1083
  }
1058
1084
  /**
1059
- * Sets referrer policy - supports both direct call and fluent API
1085
+ * Sets the referrer policy for the request, controlling how much referrer information
1086
+ * is sent with the request. This helps balance privacy and functionality.
1087
+ *
1088
+ * @param policy - The referrer policy to use:
1089
+ * - `"no-referrer"` or `ReferrerPolicy.NO_REFERRER`: Never send the referrer header.
1090
+ * - `"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).
1091
+ * - `"origin"` or `ReferrerPolicy.ORIGIN`: Only send the origin (scheme, host, port), not the full URL.
1092
+ * - `"origin-when-cross-origin"` or `ReferrerPolicy.ORIGIN_WHEN_CROSS_ORIGIN`: Send full referrer for same-origin, only origin for cross-origin.
1093
+ * - `"same-origin"` or `ReferrerPolicy.SAME_ORIGIN`: Send full referrer for same-origin requests only, omit for cross-origin.
1094
+ * - `"strict-origin"` or `ReferrerPolicy.STRICT_ORIGIN`: Send origin for HTTPS→HTTPS or HTTP→HTTP, omit for HTTPS→HTTP.
1095
+ * - `"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.
1096
+ * - `"unsafe-url"` or `ReferrerPolicy.UNSAFE_URL`: Always send the full referrer URL (may leak sensitive information).
1097
+ *
1098
+ * @returns The request instance for chaining
1099
+ *
1060
1100
  * @example
1101
+ * // Using string values
1061
1102
  * request.withReferrerPolicy("no-referrer")
1103
+ *
1104
+ * @example
1105
+ * // Using enum values
1062
1106
  * request.withReferrerPolicy(ReferrerPolicy.NO_REFERRER)
1107
+ *
1108
+ * @example
1109
+ * // Using fluent API
1063
1110
  * request.withReferrerPolicy.NO_REFERRER()
1064
1111
  */
1065
1112
  get withReferrerPolicy() {
@@ -1075,11 +1122,30 @@ class BaseRequest {
1075
1122
  });
1076
1123
  }
1077
1124
  /**
1078
- * Sets redirect mode - supports both direct call and fluent API
1125
+ * Sets how the request handles HTTP redirects (3xx status codes).
1126
+ *
1127
+ * @param redirect - The redirect handling mode:
1128
+ * - `"follow"` or `RedirectMode.FOLLOW`: Automatically follow redirects. The fetch will transparently follow redirects and return the final response (default behavior).
1129
+ * - `"error"` or `RedirectMode.ERROR`: Treat redirects as errors. If a redirect occurs, the request will fail with an error.
1130
+ * - `"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.
1131
+ *
1132
+ * @returns The request instance for chaining
1133
+ *
1079
1134
  * @example
1135
+ * // Using string values
1080
1136
  * request.withRedirect("follow")
1137
+ *
1138
+ * @example
1139
+ * // Using enum values
1081
1140
  * request.withRedirect(RedirectMode.FOLLOW)
1141
+ *
1142
+ * @example
1143
+ * // Using fluent API
1082
1144
  * request.withRedirect.FOLLOW()
1145
+ *
1146
+ * @example
1147
+ * // Fail on redirects
1148
+ * request.withRedirect.ERROR()
1083
1149
  */
1084
1150
  get withRedirect() {
1085
1151
  return this.createFluentSetter("redirect", {
@@ -1089,20 +1155,50 @@ class BaseRequest {
1089
1155
  });
1090
1156
  }
1091
1157
  /**
1092
- * Sets the keepalive flag for the request
1093
- * @param keepalive - Whether to allow the request to outlive the page
1094
- * @returns The instance for chaining
1158
+ * Sets the keepalive flag for the request. When enabled, the request can continue
1159
+ * even after the page that initiated it is closed. This is useful for analytics,
1160
+ * logging, or other background requests that should complete even if the user navigates away.
1161
+ *
1162
+ * @param keepalive - Whether to allow the request to outlive the page:
1163
+ * - `true`: The request will continue even if the page is closed or navigated away.
1164
+ * - `false`: The request will be cancelled if the page is closed (default).
1165
+ *
1166
+ * @returns The request instance for chaining
1167
+ *
1168
+ * @example
1169
+ * // Send analytics event that should complete even if user navigates away
1170
+ * request.withKeepAlive(true)
1095
1171
  */
1096
1172
  withKeepAlive(keepalive) {
1097
1173
  this.requestOptions.keepalive = keepalive;
1098
1174
  return this;
1099
1175
  }
1100
1176
  /**
1101
- * Sets request priority - supports both direct call and fluent API
1177
+ * Sets the priority hint for the request, indicating to the browser how important
1178
+ * this request is relative to other requests. This helps the browser optimize resource loading.
1179
+ *
1180
+ * @param priority - The request priority:
1181
+ * - `"high"` or `RequestPriority.HIGH`: High priority - the browser should prioritize this request.
1182
+ * - `"low"` or `RequestPriority.LOW`: Low priority - the browser can defer this request if needed.
1183
+ * - `"auto"` or `RequestPriority.AUTO`: Automatic priority based on the request type (default).
1184
+ *
1185
+ * @returns The request instance for chaining
1186
+ *
1102
1187
  * @example
1188
+ * // Using string values
1103
1189
  * request.withPriority("high")
1190
+ *
1191
+ * @example
1192
+ * // Using enum values
1104
1193
  * request.withPriority(RequestPriority.HIGH)
1194
+ *
1195
+ * @example
1196
+ * // Using fluent API
1105
1197
  * request.withPriority.HIGH()
1198
+ *
1199
+ * @example
1200
+ * // Low priority for non-critical requests
1201
+ * request.withPriority.LOW()
1106
1202
  */
1107
1203
  get withPriority() {
1108
1204
  return this.createFluentSetter("priority", {
@@ -1112,22 +1208,62 @@ class BaseRequest {
1112
1208
  });
1113
1209
  }
1114
1210
  /**
1115
- * Sets the integrity hash for subresource integrity verification
1116
- * @param integrity - The integrity hash string (e.g., "sha256-...")
1117
- * @returns The instance for chaining
1211
+ * Sets the integrity hash for Subresource Integrity (SRI) verification.
1212
+ * This allows the browser to verify that the fetched resource hasn't been tampered with
1213
+ * by comparing its hash against the provided value. If the hashes don't match, the request fails.
1214
+ *
1215
+ * @param integrity - The integrity hash string in the format `"algorithm-hash"`:
1216
+ * - Example: `"sha256-abcdef1234567890..."` (SHA-256 hash)
1217
+ * - Example: `"sha384-abcdef1234567890..."` (SHA-384 hash)
1218
+ * - Example: `"sha512-abcdef1234567890..."` (SHA-512 hash)
1219
+ * - Multiple hashes can be separated by spaces: `"sha256-... sha384-..."`
1220
+ *
1221
+ * @returns The request instance for chaining
1222
+ *
1118
1223
  * @example
1119
1224
  * request.withIntegrity("sha256-abcdef1234567890...")
1225
+ *
1226
+ * @example
1227
+ * // Multiple algorithms for better compatibility
1228
+ * request.withIntegrity("sha256-... sha384-...")
1120
1229
  */
1121
1230
  withIntegrity(integrity) {
1122
1231
  this.requestOptions.integrity = integrity;
1123
1232
  return this;
1124
1233
  }
1125
1234
  /**
1126
- * Sets cache mode - supports both direct call and fluent API
1235
+ * Sets the cache mode for the request, controlling how the browser's HTTP cache
1236
+ * is used for this request.
1237
+ *
1238
+ * @param cache - The cache mode:
1239
+ * - `"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.
1240
+ * - `"no-store"` or `CacheMode.NO_STORE`: Never use the cache and don't store the response in cache. Always fetch from network.
1241
+ * - `"reload"` or `CacheMode.RELOAD`: Bypass the cache but store the response. Always fetch from network, ignoring cached responses.
1242
+ * - `"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.
1243
+ * - `"force-cache"` or `CacheMode.FORCE_CACHE`: Use the cache if available, even if stale. Only fetch from network if not in cache.
1244
+ * - `"only-if-cached"` or `CacheMode.ONLY_IF_CACHED`: Only use the cache. If not in cache, return an error. Never fetch from network.
1245
+ *
1246
+ * @returns The request instance for chaining
1247
+ *
1127
1248
  * @example
1249
+ * // Using string values
1128
1250
  * request.withCache("no-cache")
1251
+ *
1252
+ * @example
1253
+ * // Using enum values
1129
1254
  * request.withCache(CacheMode.NO_CACHE)
1255
+ *
1256
+ * @example
1257
+ * // Using fluent API
1130
1258
  * request.withCache.NO_CACHE()
1259
+ *
1260
+ * @example
1261
+ * // Always fetch fresh data
1262
+ * request.withCache.RELOAD()
1263
+ *
1264
+ * @example
1265
+ * // Use cache only, fail if not cached
1266
+ * request.withCache.ONLY_IF_CACHED()
1131
1267
  */
1132
1268
  get withCache() {
1133
1269
  const cacheOptions = {
@@ -1176,11 +1312,32 @@ class BaseRequest {
1176
1312
  return this;
1177
1313
  }
1178
1314
  /**
1179
- * Sets request mode - supports both direct call and fluent API
1315
+ * Sets the request mode, which determines the CORS (Cross-Origin Resource Sharing) behavior
1316
+ * for the request. This controls how the browser handles cross-origin requests.
1317
+ *
1318
+ * @param mode - The request mode:
1319
+ * - `"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.
1320
+ * - `"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).
1321
+ * - `"same-origin"` or `RequestMode.SAME_ORIGIN`: Only allow same-origin requests. Cross-origin requests will fail.
1322
+ * - `"navigate"` or `RequestMode.NAVIGATE`: Used for navigation requests (typically only used by the browser itself).
1323
+ *
1324
+ * @returns The request instance for chaining
1325
+ *
1180
1326
  * @example
1327
+ * // Using string values
1181
1328
  * request.withMode("cors")
1329
+ *
1330
+ * @example
1331
+ * // Using enum values
1182
1332
  * request.withMode(RequestMode.CORS)
1333
+ *
1334
+ * @example
1335
+ * // Using fluent API
1183
1336
  * request.withMode.CORS()
1337
+ *
1338
+ * @example
1339
+ * // Restrict to same-origin only
1340
+ * request.withMode.SAME_ORIGIN()
1184
1341
  */
1185
1342
  get withMode() {
1186
1343
  return this.createFluentSetter("mode", {
@@ -1704,7 +1861,7 @@ class BaseRequest {
1704
1861
  // No timeout - just use external controller
1705
1862
  if (!timeoutMs) {
1706
1863
  return {
1707
- signal: externalController === null || externalController === void 0 ? void 0 : externalController.signal,
1864
+ signal: externalController?.signal,
1708
1865
  cleanup: () => { },
1709
1866
  wasTimeout: () => false,
1710
1867
  };
@@ -1887,9 +2044,11 @@ class BaseRequest {
1887
2044
  * Base class for requests that can have a body (POST, PUT, PATCH)
1888
2045
  */
1889
2046
  class BodyRequest extends BaseRequest {
2047
+ body;
2048
+ bodyType;
2049
+ graphQLOptions = undefined;
1890
2050
  constructor(url) {
1891
2051
  super(url);
1892
- this.graphQLOptions = undefined;
1893
2052
  }
1894
2053
  /**
1895
2054
  * Sets the body of the request
@@ -1904,7 +2063,13 @@ class BodyRequest extends BaseRequest {
1904
2063
  }
1905
2064
  else if (body !== null &&
1906
2065
  typeof body === "object" &&
1907
- !(body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer || body instanceof URLSearchParams || body instanceof ReadableStream)) {
2066
+ !(body instanceof FormData ||
2067
+ body instanceof Blob ||
2068
+ body instanceof File ||
2069
+ body instanceof ArrayBuffer ||
2070
+ ArrayBuffer.isView(body) || // Handles TypedArray and DataView
2071
+ body instanceof URLSearchParams ||
2072
+ body instanceof ReadableStream)) {
1908
2073
  this.bodyType = BodyType.JSON;
1909
2074
  this.setContentTypeIfNeeded("application/json");
1910
2075
  // Validate JSON is stringifiable early
@@ -2034,9 +2199,9 @@ class BodyRequest extends BaseRequest {
2034
2199
  * const data = await request.getData();
2035
2200
  */
2036
2201
  class GetRequest extends BaseRequest {
2202
+ method = HttpMethod.GET;
2037
2203
  constructor(url) {
2038
2204
  super(url);
2039
- this.method = HttpMethod.GET;
2040
2205
  }
2041
2206
  }
2042
2207
  /**
@@ -2048,9 +2213,9 @@ class GetRequest extends BaseRequest {
2048
2213
  * const response = await request.getResponse();
2049
2214
  */
2050
2215
  class HeadRequest extends BaseRequest {
2216
+ method = HttpMethod.HEAD;
2051
2217
  constructor(url) {
2052
2218
  super(url);
2053
- this.method = HttpMethod.HEAD;
2054
2219
  }
2055
2220
  }
2056
2221
  /**
@@ -2062,9 +2227,9 @@ class HeadRequest extends BaseRequest {
2062
2227
  * const response = await request.getResponse();
2063
2228
  */
2064
2229
  class OptionsRequest extends BaseRequest {
2230
+ method = HttpMethod.OPTIONS;
2065
2231
  constructor(url) {
2066
2232
  super(url);
2067
- this.method = HttpMethod.OPTIONS;
2068
2233
  }
2069
2234
  }
2070
2235
  /**
@@ -2076,9 +2241,9 @@ class OptionsRequest extends BaseRequest {
2076
2241
  * await request.getData();
2077
2242
  */
2078
2243
  class DeleteRequest extends BaseRequest {
2244
+ method = HttpMethod.DELETE;
2079
2245
  constructor(url) {
2080
2246
  super(url);
2081
- this.method = HttpMethod.DELETE;
2082
2247
  }
2083
2248
  }
2084
2249
  /**
@@ -2091,9 +2256,9 @@ class DeleteRequest extends BaseRequest {
2091
2256
  * const data = await request.getData();
2092
2257
  */
2093
2258
  class PostRequest extends BodyRequest {
2259
+ method = HttpMethod.POST;
2094
2260
  constructor(url) {
2095
2261
  super(url);
2096
- this.method = HttpMethod.POST;
2097
2262
  }
2098
2263
  }
2099
2264
  /**
@@ -2106,9 +2271,9 @@ class PostRequest extends BodyRequest {
2106
2271
  * const data = await request.getData();
2107
2272
  */
2108
2273
  class PutRequest extends BodyRequest {
2274
+ method = HttpMethod.PUT;
2109
2275
  constructor(url) {
2110
2276
  super(url);
2111
- this.method = HttpMethod.PUT;
2112
2277
  }
2113
2278
  }
2114
2279
  /**
@@ -2121,9 +2286,9 @@ class PutRequest extends BodyRequest {
2121
2286
  * const data = await request.getData();
2122
2287
  */
2123
2288
  class PatchRequest extends BodyRequest {
2289
+ method = HttpMethod.PATCH;
2124
2290
  constructor(url) {
2125
2291
  super(url);
2126
- this.method = HttpMethod.PATCH;
2127
2292
  }
2128
2293
  }
2129
2294