create-request 1.6.0 → 1.6.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.
@@ -1,98 +1,99 @@
1
1
  /**
2
2
  * Enum for HTTP methods
3
3
  */
4
- var HttpMethod;
5
- (function (HttpMethod) {
6
- HttpMethod["GET"] = "GET";
7
- HttpMethod["PUT"] = "PUT";
8
- HttpMethod["POST"] = "POST";
9
- HttpMethod["HEAD"] = "HEAD";
10
- HttpMethod["PATCH"] = "PATCH";
11
- HttpMethod["DELETE"] = "DELETE";
12
- HttpMethod["OPTIONS"] = "OPTIONS";
13
- })(HttpMethod || (HttpMethod = {}));
4
+ const HttpMethod = {
5
+ GET: "GET",
6
+ PUT: "PUT",
7
+ POST: "POST",
8
+ HEAD: "HEAD",
9
+ PATCH: "PATCH",
10
+ DELETE: "DELETE",
11
+ OPTIONS: "OPTIONS",
12
+ };
14
13
  /**
15
14
  * Enum for request priorities
16
15
  */
17
- var RequestPriority;
18
- (function (RequestPriority) {
19
- RequestPriority["LOW"] = "low";
20
- RequestPriority["HIGH"] = "high";
21
- RequestPriority["AUTO"] = "auto";
22
- })(RequestPriority || (RequestPriority = {}));
16
+ const RequestPriority = {
17
+ LOW: "low",
18
+ HIGH: "high",
19
+ AUTO: "auto",
20
+ };
23
21
  /**
24
22
  * Enum for credentials policies
25
23
  */
26
- var CredentialsPolicy;
27
- (function (CredentialsPolicy) {
28
- CredentialsPolicy["OMIT"] = "omit";
29
- CredentialsPolicy["INCLUDE"] = "include";
30
- CredentialsPolicy["SAME_ORIGIN"] = "same-origin";
31
- })(CredentialsPolicy || (CredentialsPolicy = {}));
24
+ const CredentialsPolicy = {
25
+ OMIT: "omit",
26
+ INCLUDE: "include",
27
+ SAME_ORIGIN: "same-origin",
28
+ };
32
29
  /**
33
30
  * Enum for request modes
34
31
  */
35
- var RequestMode;
36
- (function (RequestMode) {
37
- RequestMode["CORS"] = "cors";
38
- RequestMode["NO_CORS"] = "no-cors";
39
- RequestMode["SAME_ORIGIN"] = "same-origin";
40
- RequestMode["NAVIGATE"] = "navigate";
41
- })(RequestMode || (RequestMode = {}));
32
+ const RequestMode = {
33
+ CORS: "cors",
34
+ NO_CORS: "no-cors",
35
+ SAME_ORIGIN: "same-origin",
36
+ NAVIGATE: "navigate",
37
+ };
42
38
  /**
43
39
  * Enum for redirect modes
44
40
  */
45
- var RedirectMode;
46
- (function (RedirectMode) {
47
- RedirectMode["ERROR"] = "error";
48
- RedirectMode["FOLLOW"] = "follow";
49
- RedirectMode["MANUAL"] = "manual";
50
- })(RedirectMode || (RedirectMode = {}));
41
+ const RedirectMode = {
42
+ ERROR: "error",
43
+ FOLLOW: "follow",
44
+ MANUAL: "manual",
45
+ };
51
46
  /**
52
47
  * Enum for cookie SameSite policies
53
48
  */
54
- var SameSitePolicy;
55
- (function (SameSitePolicy) {
56
- SameSitePolicy["LAX"] = "Lax";
57
- SameSitePolicy["NONE"] = "None";
58
- SameSitePolicy["STRICT"] = "Strict";
59
- })(SameSitePolicy || (SameSitePolicy = {}));
49
+ const SameSitePolicy = {
50
+ LAX: "Lax",
51
+ NONE: "None",
52
+ STRICT: "Strict",
53
+ };
60
54
  /**
61
55
  * Enum for body types
62
56
  */
63
- var BodyType;
64
- (function (BodyType) {
65
- BodyType["JSON"] = "json";
66
- BodyType["STRING"] = "string";
67
- BodyType["BINARY"] = "binary";
68
- })(BodyType || (BodyType = {}));
57
+ const BodyType = {
58
+ JSON: "json",
59
+ STRING: "string",
60
+ BINARY: "binary",
61
+ };
69
62
  /**
70
63
  * Referrer policies for fetch requests
71
64
  */
72
- var ReferrerPolicy;
73
- (function (ReferrerPolicy) {
74
- ReferrerPolicy["ORIGIN"] = "origin";
75
- ReferrerPolicy["UNSAFE_URL"] = "unsafe-url";
76
- ReferrerPolicy["SAME_ORIGIN"] = "same-origin";
77
- ReferrerPolicy["NO_REFERRER"] = "no-referrer";
78
- ReferrerPolicy["STRICT_ORIGIN"] = "strict-origin";
79
- ReferrerPolicy["ORIGIN_WHEN_CROSS_ORIGIN"] = "origin-when-cross-origin";
80
- ReferrerPolicy["NO_REFERRER_WHEN_DOWNGRADE"] = "no-referrer-when-downgrade";
81
- ReferrerPolicy["STRICT_ORIGIN_WHEN_CROSS_ORIGIN"] = "strict-origin-when-cross-origin";
82
- })(ReferrerPolicy || (ReferrerPolicy = {}));
65
+ const ReferrerPolicy = {
66
+ ORIGIN: "origin",
67
+ UNSAFE_URL: "unsafe-url",
68
+ SAME_ORIGIN: "same-origin",
69
+ NO_REFERRER: "no-referrer",
70
+ STRICT_ORIGIN: "strict-origin",
71
+ ORIGIN_WHEN_CROSS_ORIGIN: "origin-when-cross-origin",
72
+ NO_REFERRER_WHEN_DOWNGRADE: "no-referrer-when-downgrade",
73
+ STRICT_ORIGIN_WHEN_CROSS_ORIGIN: "strict-origin-when-cross-origin",
74
+ };
83
75
  /**
84
76
  * Cache modes for fetch requests
85
77
  */
86
- var CacheMode;
87
- (function (CacheMode) {
88
- CacheMode["RELOAD"] = "reload";
89
- CacheMode["DEFAULT"] = "default";
90
- CacheMode["NO_CACHE"] = "no-cache";
91
- CacheMode["NO_STORE"] = "no-store";
92
- CacheMode["FORCE_CACHE"] = "force-cache";
93
- CacheMode["ONLY_IF_CACHED"] = "only-if-cached";
94
- })(CacheMode || (CacheMode = {}));
78
+ const CacheMode = {
79
+ RELOAD: "reload",
80
+ DEFAULT: "default",
81
+ NO_CACHE: "no-cache",
82
+ NO_STORE: "no-store",
83
+ FORCE_CACHE: "force-cache",
84
+ ONLY_IF_CACHED: "only-if-cached",
85
+ };
95
86
 
87
+ /**
88
+ * Extract a message from an unknown thrown value
89
+ * @internal
90
+ */
91
+ const errorMessage = (e) => (e instanceof Error ? e.message : String(e));
92
+ /**
93
+ * Coerce an unknown thrown value to an Error
94
+ * @internal
95
+ */
96
+ const toError = (e) => (e instanceof Error ? e : new Error(String(e)));
96
97
  /**
97
98
  * Error class for HTTP request failures.
98
99
  * Extends the standard Error class with additional context about the failed request.
@@ -133,7 +134,7 @@ class RequestError extends Error {
133
134
  /** Whether the request was aborted (cancelled) */
134
135
  isAborted;
135
136
  /** Cached result of parsing `body` as JSON (lazily populated by getJson) */
136
- parsedBody;
137
+ _parsed;
137
138
  /**
138
139
  * Creates a new RequestError instance.
139
140
  *
@@ -186,15 +187,15 @@ class RequestError extends Error {
186
187
  * ```
187
188
  */
188
189
  getJson() {
189
- if (this.parsedBody === undefined && this.body) {
190
+ if (this._parsed === undefined && this.body) {
190
191
  try {
191
- this.parsedBody = JSON.parse(this.body);
192
+ this._parsed = JSON.parse(this.body);
192
193
  }
193
194
  catch {
194
195
  // Body is not valid JSON - leave parsedBody undefined
195
196
  }
196
197
  }
197
- return this.parsedBody;
198
+ return this._parsed;
198
199
  }
199
200
  /**
200
201
  * Safely reads the body of a Response as text without consuming it.
@@ -290,55 +291,29 @@ class RequestError extends Error {
290
291
  let message = originalError.message;
291
292
  // Check for Node.js error codes (e.g., from undici/dns errors)
292
293
  const errorCode = originalError.code;
293
- const errorName = originalError.name;
294
294
  const stack = originalError.stack || "";
295
- const errorMessageLower = message.toLowerCase();
296
295
  // Check for timeout errors (Node.js/undici TimeoutError)
297
296
  // Note: While explicit timeouts set via withTimeout() are handled in BaseRequest,
298
- // this detection serves as a safety net for:
299
- // 1. Timeout errors from external AbortControllers (e.g., AbortSignal.timeout())
300
- // 2. Different runtime implementations that may throw timeout errors differently
301
- // 3. Network-level timeouts (ETIMEDOUT)
302
- const isTimeoutError = errorName === "TimeoutError" ||
303
- errorMessageLower.includes("timeout") ||
304
- errorMessageLower.includes("aborted due to timeout") ||
297
+ // this detection serves as a safety net for timeout errors from external
298
+ // AbortControllers, other runtimes, and network-level timeouts (ETIMEDOUT).
299
+ const isTimeoutError = originalError.name === "TimeoutError" ||
300
+ message.toLowerCase().includes("timeout") ||
305
301
  errorCode === "ETIMEDOUT" ||
306
302
  stack.includes("TimeoutError") ||
307
303
  stack.includes("timeout");
308
304
  // If the error message is generic "fetch failed", provide more context
309
305
  if (message === "fetch failed" || message === "Failed to fetch") {
310
306
  // Check for DNS resolution errors
311
- const isDnsError = errorCode === "ENOTFOUND" ||
312
- errorCode === "EAI_AGAIN" ||
313
- errorCode === "EAI_NODATA" ||
314
- stack.includes("getaddrinfo") ||
315
- stack.includes("ENOTFOUND") ||
316
- stack.includes("EAI_AGAIN");
307
+ const isDnsError = errorCode === "ENOTFOUND" || errorCode === "EAI_AGAIN" || errorCode === "EAI_NODATA" || /getaddrinfo|ENOTFOUND|EAI_AGAIN/.test(stack);
317
308
  // Check for connection errors (but not timeout errors)
318
309
  const isConnectionError = !isTimeoutError && (errorCode === "ECONNREFUSED" || errorCode === "ECONNRESET" || stack.includes("ECONNREFUSED") || stack.includes("connect"));
319
- if (isTimeoutError) {
320
- message = `Timeout:${url}`;
321
- }
322
- else if (isDnsError) {
323
- message = `DNS:${url}`;
324
- }
325
- else if (isConnectionError) {
326
- message = `Conn:${url}`;
327
- }
328
- else {
329
- message = `Net:${url}`;
330
- }
310
+ message = (isTimeoutError ? "Timeout:" : isDnsError ? "DNS:" : isConnectionError ? "Conn:" : "Net:") + url;
331
311
  }
332
- const error = new RequestError(message, url, method, {
333
- ...(isTimeoutError ? { isTimeout: true } : {}),
334
- });
335
- // Create a proper RequestError stack trace, but append the original stack for debugging
336
- // This way Node.js will show "RequestError: ..." instead of "TypeError: ..."
312
+ const error = new RequestError(message, url, method, isTimeoutError ? { isTimeout: true } : {});
313
+ // Create a proper RequestError stack trace, but append the original stack for
314
+ // debugging context, so Node.js shows "RequestError: ..." instead of "TypeError: ..."
337
315
  if (originalError.stack) {
338
- // Get the current stack (which will start with RequestError)
339
- const currentStack = error.stack || "";
340
- // Append the original error's stack as "Caused by:" for debugging context
341
- error.stack = `${currentStack}\n\nCaused by: ${originalError.stack}`;
316
+ error.stack = `${error.stack || ""}\n\nCaused by: ${originalError.stack}`;
342
317
  }
343
318
  return error;
344
319
  }
@@ -382,19 +357,19 @@ class ResponseWrapper {
382
357
  url;
383
358
  /** The HTTP method that was used (if available) */
384
359
  method;
385
- response;
386
- graphQLOptions;
360
+ _res;
361
+ _gqlOpts;
387
362
  // Cache the body as the last used method
388
- cachedBlob;
389
- cachedText;
390
- cachedJson;
391
- cachedArrayBuffer;
363
+ _blob;
364
+ _text;
365
+ _json;
366
+ _buf;
392
367
  constructor(response, url, method, graphQLOptions) {
393
- this.response = response;
368
+ this._res = response;
394
369
  this.url = url;
395
370
  this.method = method;
396
371
  if (graphQLOptions) {
397
- this.graphQLOptions = {
372
+ this._gqlOpts = {
398
373
  throwOnError: graphQLOptions.throwOnError,
399
374
  };
400
375
  }
@@ -403,43 +378,65 @@ class ResponseWrapper {
403
378
  * HTTP status code (e.g., 200, 404, 500)
404
379
  */
405
380
  get status() {
406
- return this.response.status;
381
+ return this._res.status;
407
382
  }
408
383
  /**
409
384
  * HTTP status text (e.g., "OK", "Not Found", "Internal Server Error")
410
385
  */
411
386
  get statusText() {
412
- return this.response.statusText;
387
+ return this._res.statusText;
413
388
  }
414
389
  /**
415
390
  * Response headers as a Headers object
416
391
  */
417
392
  get headers() {
418
- return this.response.headers;
393
+ return this._res.headers;
419
394
  }
420
395
  /**
421
396
  * Whether the response status is in the 200-299 range (successful)
422
397
  */
423
398
  get ok() {
424
- return this.response.ok;
399
+ return this._res.ok;
425
400
  }
426
401
  /**
427
402
  * The raw Response object from the fetch API.
428
403
  * Use this if you need direct access to the underlying Response.
429
404
  */
430
405
  get raw() {
431
- return this.response;
406
+ return this._res;
407
+ }
408
+ /**
409
+ * Create a RequestError carrying this response's context
410
+ * @param message - The error message
411
+ * @param withBody - Whether to attach the cached body text to the error
412
+ */
413
+ _err(message, withBody) {
414
+ return new RequestError(message, this.url || "", this.method || "", {
415
+ status: this._res.status,
416
+ response: this._res,
417
+ body: withBody ? this._text : undefined,
418
+ });
419
+ }
420
+ /**
421
+ * Read the response body via the given reader, wrapping failures in a RequestError
422
+ * @throws RequestError if the body has already been consumed or reading fails
423
+ */
424
+ async _read(reader) {
425
+ this._checkUsed();
426
+ try {
427
+ return await reader();
428
+ }
429
+ catch (e) {
430
+ throw this._err(`Read: ${errorMessage(e)}`);
431
+ }
432
432
  }
433
433
  /**
434
434
  * Check if the response body has already been consumed and throw an error if so
435
435
  * @throws RequestError if the body has already been consumed
436
436
  */
437
- checkBodyNotConsumed() {
438
- if (this.response.bodyUsed) {
439
- throw new RequestError("Body used", this.url || "", this.method || "", {
440
- status: this.response.status,
441
- response: this.response,
442
- });
437
+ _checkUsed() {
438
+ if (this._res.bodyUsed) {
439
+ throw this._err("Body used");
443
440
  }
444
441
  }
445
442
  /**
@@ -447,8 +444,8 @@ class ResponseWrapper {
447
444
  * @param data - The parsed JSON data
448
445
  * @throws RequestError if GraphQL response contains errors and throwOnError is enabled
449
446
  */
450
- checkGraphQLErrors(data) {
451
- if (!this.graphQLOptions?.throwOnError || typeof data !== "object" || data === null)
447
+ _checkGql(data) {
448
+ if (!this._gqlOpts?.throwOnError || typeof data !== "object" || data === null)
452
449
  return;
453
450
  const responseData = data;
454
451
  if (!Array.isArray(responseData.errors) || responseData.errors.length === 0)
@@ -477,12 +474,7 @@ class ResponseWrapper {
477
474
  }
478
475
  return String(x);
479
476
  });
480
- const errorMessage = errorMessages.join(", ");
481
- throw new RequestError(`GQL: ${errorMessage}`, this.url || "", this.method || "", {
482
- status: this.response.status,
483
- response: this.response,
484
- body: this.cachedText,
485
- });
477
+ throw this._err(`GQL: ${errorMessages.join(", ")}`, true);
486
478
  }
487
479
  /**
488
480
  * Parse the response body as JSON
@@ -511,39 +503,35 @@ class ResponseWrapper {
511
503
  * }
512
504
  */
513
505
  async getJson() {
514
- if (this.cachedJson !== undefined)
515
- return this.cachedJson;
506
+ if (this._json !== undefined)
507
+ return this._json;
516
508
  // Handle empty responses: 204 No Content or content-length: 0
517
- const contentLength = this.response.headers.get("content-length");
518
- if (this.response.status === 204 || contentLength === "0") {
519
- this.cachedJson = null;
509
+ const contentLength = this._res.headers.get("content-length");
510
+ if (this._res.status === 204 || contentLength === "0") {
511
+ this._json = null;
520
512
  return null;
521
513
  }
522
- this.checkBodyNotConsumed();
514
+ this._checkUsed();
523
515
  try {
524
516
  // Read as text first to handle empty bodies and cache for getText()
525
- const text = await this.response.text();
526
- this.cachedText = text;
517
+ const text = await this._res.text();
518
+ this._text = text;
527
519
  // Handle empty or whitespace-only responses
528
520
  if (!text || text.trim() === "") {
529
- this.cachedJson = null;
521
+ this._json = null;
530
522
  return null;
531
523
  }
532
524
  // Parse the text as JSON
533
525
  const parsed = JSON.parse(text);
534
- this.cachedJson = parsed;
535
- this.checkGraphQLErrors(parsed);
526
+ this._json = parsed;
527
+ this._checkGql(parsed);
536
528
  return parsed;
537
529
  }
538
530
  catch (error) {
539
531
  if (error instanceof RequestError) {
540
532
  throw error;
541
533
  }
542
- throw new RequestError(`Bad JSON: ${error instanceof Error ? error.message : String(error)}`, this.url || "", this.method || "", {
543
- status: this.response.status,
544
- response: this.response,
545
- body: this.cachedText,
546
- });
534
+ throw this._err(`Bad JSON: ${errorMessage(error)}`, true);
547
535
  }
548
536
  }
549
537
  /**
@@ -560,20 +548,9 @@ class ResponseWrapper {
560
548
  * ```
561
549
  */
562
550
  async getText() {
563
- if (this.cachedText !== undefined)
564
- return this.cachedText;
565
- this.checkBodyNotConsumed();
566
- try {
567
- const text = await this.response.text();
568
- this.cachedText = text;
569
- return text;
570
- }
571
- catch (e) {
572
- throw new RequestError(`Read: ${e instanceof Error ? e.message : String(e)}`, this.url || "", this.method || "", {
573
- status: this.response.status,
574
- response: this.response,
575
- });
576
- }
551
+ if (this._text !== undefined)
552
+ return this._text;
553
+ return (this._text = await this._read(() => this._res.text()));
577
554
  }
578
555
  /**
579
556
  * Get the response body as a Blob.
@@ -591,20 +568,9 @@ class ResponseWrapper {
591
568
  * ```
592
569
  */
593
570
  async getBlob() {
594
- if (this.cachedBlob !== undefined)
595
- return this.cachedBlob;
596
- this.checkBodyNotConsumed();
597
- try {
598
- const blob = await this.response.blob();
599
- this.cachedBlob = blob;
600
- return blob;
601
- }
602
- catch (e) {
603
- throw new RequestError(`Read: ${e instanceof Error ? e.message : String(e)}`, this.url || "", this.method || "", {
604
- status: this.response.status,
605
- response: this.response,
606
- });
607
- }
571
+ if (this._blob !== undefined)
572
+ return this._blob;
573
+ return (this._blob = await this._read(() => this._res.blob()));
608
574
  }
609
575
  /**
610
576
  * Get the response body as an ArrayBuffer.
@@ -622,21 +588,10 @@ class ResponseWrapper {
622
588
  * ```
623
589
  */
624
590
  async getArrayBuffer() {
625
- if (this.cachedArrayBuffer !== undefined) {
626
- return this.cachedArrayBuffer;
627
- }
628
- this.checkBodyNotConsumed();
629
- try {
630
- const arrayBuffer = await this.response.arrayBuffer();
631
- this.cachedArrayBuffer = arrayBuffer;
632
- return arrayBuffer;
633
- }
634
- catch (e) {
635
- throw new RequestError(`Read: ${e instanceof Error ? e.message : String(e)}`, this.url || "", this.method || "", {
636
- status: this.response.status,
637
- response: this.response,
638
- });
591
+ if (this._buf !== undefined) {
592
+ return this._buf;
639
593
  }
594
+ return (this._buf = await this._read(() => this._res.arrayBuffer()));
640
595
  }
641
596
  /**
642
597
  * Get the raw response body as a ReadableStream
@@ -654,8 +609,8 @@ class ResponseWrapper {
654
609
  * }
655
610
  */
656
611
  getBody() {
657
- this.checkBodyNotConsumed();
658
- return this.response.body;
612
+ this._checkUsed();
613
+ return this._res.body;
659
614
  }
660
615
  /**
661
616
  * Extract specific data using a selector function
@@ -705,16 +660,11 @@ class ResponseWrapper {
705
660
  }
706
661
  // Enhance selector errors with context
707
662
  if (selector) {
708
- throw new RequestError(`Selector: ${error instanceof Error ? error.message : String(error)}`, this.url || "", this.method || "", {
709
- status: this.response.status,
710
- response: this.response,
711
- body: this.cachedText,
712
- });
663
+ throw this._err(`Selector: ${errorMessage(error)}`, true);
713
664
  }
714
665
  // If we get here and it's not a RequestError, wrap it
715
666
  // This should rarely happen as getJson() should throw RequestError
716
- const errorObj = error instanceof Error ? error : new Error(String(error));
717
- throw RequestError.networkError(this.url || "", this.method || "", errorObj);
667
+ throw RequestError.networkError(this.url || "", this.method || "", toError(error));
718
668
  }
719
669
  }
720
670
  }
@@ -726,20 +676,9 @@ class CookieUtils {
726
676
  * @returns Formatted cookie string for the Cookie header
727
677
  */
728
678
  static formatRequestCookies(cookies) {
729
- const cookiePairs = [];
730
- Object.entries(cookies).forEach(([name, valueOrOptions]) => {
731
- let value;
732
- if (typeof valueOrOptions === "string") {
733
- value = valueOrOptions;
734
- }
735
- else {
736
- // Extract value from options object without validation
737
- value = valueOrOptions.value;
738
- }
739
- // Add the cookie to the request
740
- cookiePairs.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);
741
- });
742
- return cookiePairs.join("; ");
679
+ return Object.entries(cookies)
680
+ .map(([name, valueOrOptions]) => `${encodeURIComponent(name)}=${encodeURIComponent(typeof valueOrOptions === "string" ? valueOrOptions : valueOrOptions.value)}`)
681
+ .join("; ");
743
682
  }
744
683
  }
745
684
 
@@ -793,17 +732,11 @@ class CsrfUtils {
793
732
  // If token is longer than 10 chars, perform additional security checks
794
733
  if (token.length > 10) {
795
734
  // Check for valid character set (alphanumeric & common token symbols)
796
- const validTokenRegex = /^[A-Za-z0-9\-_=+/.]+$/;
797
- if (!validTokenRegex.test(token)) {
735
+ if (!/^[A-Za-z0-9\-_=+/.]+$/.test(token)) {
798
736
  return false;
799
737
  }
800
738
  // For longer tokens, check for sufficient entropy (at least 2 character types)
801
- const hasUpperCase = /[A-Z]/.test(token);
802
- const hasLowerCase = /[a-z]/.test(token);
803
- const hasNumbers = /[0-9]/.test(token);
804
- const hasSpecials = /[-_=+/.]/.test(token);
805
- const characterTypesCount = [hasUpperCase, hasLowerCase, hasNumbers, hasSpecials].filter(Boolean).length;
806
- return characterTypesCount >= 2;
739
+ return [/[A-Z]/, /[a-z]/, /[0-9]/, /[-_=+/.]/].filter(re => re.test(token)).length >= 2;
807
740
  }
808
741
  // For shorter tokens (8-10 chars), just return true if we reached here
809
742
  return true;
@@ -814,19 +747,19 @@ class CsrfUtils {
814
747
  * Global configuration for create-request
815
748
  */
816
749
  class Config {
817
- static instance;
750
+ static _instance;
818
751
  // CSRF configuration
819
- csrfHeaderName = "X-CSRF-Token";
820
- xsrfCookieName = "XSRF-TOKEN";
821
- xsrfHeaderName = "X-XSRF-TOKEN";
822
- csrfToken = null;
823
- enableAutoXsrf = true;
824
- enableAntiCsrf = true; // X-Requested-With header
752
+ _csrfHeader = "X-CSRF-Token";
753
+ _xsrfCookie = "XSRF-TOKEN";
754
+ _xsrfHeader = "X-XSRF-TOKEN";
755
+ _csrfToken = null;
756
+ _autoXsrf = true;
757
+ _antiCsrf = true; // X-Requested-With header
825
758
  // Interceptor configuration
826
- requestInterceptors = [];
827
- responseInterceptors = [];
828
- errorInterceptors = [];
829
- nextInterceptorId = 1;
759
+ _reqI = [];
760
+ _resI = [];
761
+ _errI = [];
762
+ _nextId = 1;
830
763
  constructor() { }
831
764
  /**
832
765
  * Get the singleton instance of the Config class
@@ -838,10 +771,10 @@ class Config {
838
771
  * config.setCsrfToken('token123');
839
772
  */
840
773
  static getInstance() {
841
- if (!Config.instance) {
842
- Config.instance = new Config();
774
+ if (!Config._instance) {
775
+ Config._instance = new Config();
843
776
  }
844
- return Config.instance;
777
+ return Config._instance;
845
778
  }
846
779
  /**
847
780
  * Set a global CSRF token to be used for all requests
@@ -853,7 +786,7 @@ class Config {
853
786
  * Config.getInstance().setCsrfToken('myToken123');
854
787
  */
855
788
  setCsrfToken(token) {
856
- this.csrfToken = token;
789
+ this._csrfToken = token;
857
790
  return this;
858
791
  }
859
792
  /**
@@ -862,7 +795,7 @@ class Config {
862
795
  * @returns The current CSRF token or null if not set
863
796
  */
864
797
  getCsrfToken() {
865
- return this.csrfToken;
798
+ return this._csrfToken;
866
799
  }
867
800
  /**
868
801
  * Set the CSRF header name used when sending the token
@@ -874,7 +807,7 @@ class Config {
874
807
  * Config.getInstance().setCsrfHeaderName('X-My-CSRF-Token');
875
808
  */
876
809
  setCsrfHeaderName(name) {
877
- this.csrfHeaderName = name;
810
+ this._csrfHeader = name;
878
811
  return this;
879
812
  }
880
813
  /**
@@ -883,7 +816,7 @@ class Config {
883
816
  * @returns The current CSRF header name
884
817
  */
885
818
  getCsrfHeaderName() {
886
- return this.csrfHeaderName;
819
+ return this._csrfHeader;
887
820
  }
888
821
  /**
889
822
  * Set the XSRF cookie name to look for when extracting tokens from cookies
@@ -895,7 +828,7 @@ class Config {
895
828
  * Config.getInstance().setXsrfCookieName('MY-XSRF-COOKIE');
896
829
  */
897
830
  setXsrfCookieName(name) {
898
- this.xsrfCookieName = name;
831
+ this._xsrfCookie = name;
899
832
  return this;
900
833
  }
901
834
  /**
@@ -904,7 +837,7 @@ class Config {
904
837
  * @returns The current XSRF cookie name
905
838
  */
906
839
  getXsrfCookieName() {
907
- return this.xsrfCookieName;
840
+ return this._xsrfCookie;
908
841
  }
909
842
  /**
910
843
  * Set the XSRF header name for sending tokens extracted from cookies
@@ -913,7 +846,7 @@ class Config {
913
846
  * @returns The config instance for chaining
914
847
  */
915
848
  setXsrfHeaderName(name) {
916
- this.xsrfHeaderName = name;
849
+ this._xsrfHeader = name;
917
850
  return this;
918
851
  }
919
852
  /**
@@ -922,7 +855,7 @@ class Config {
922
855
  * @returns The current XSRF header name
923
856
  */
924
857
  getXsrfHeaderName() {
925
- return this.xsrfHeaderName;
858
+ return this._xsrfHeader;
926
859
  }
927
860
  /**
928
861
  * Enable or disable automatic extraction of XSRF tokens from cookies
@@ -936,7 +869,7 @@ class Config {
936
869
  * Config.getInstance().setEnableAutoXsrf(false); // Disable XSRF extraction
937
870
  */
938
871
  setEnableAutoXsrf(enable) {
939
- this.enableAutoXsrf = enable;
872
+ this._autoXsrf = enable;
940
873
  return this;
941
874
  }
942
875
  /**
@@ -945,7 +878,7 @@ class Config {
945
878
  * @returns True if automatic XSRF is enabled
946
879
  */
947
880
  isAutoXsrfEnabled() {
948
- return this.enableAutoXsrf;
881
+ return this._autoXsrf;
949
882
  }
950
883
  /**
951
884
  * Enable or disable automatic addition of anti-CSRF headers
@@ -955,7 +888,7 @@ class Config {
955
888
  * @returns The config instance for chaining
956
889
  */
957
890
  setEnableAntiCsrf(enable) {
958
- this.enableAntiCsrf = enable;
891
+ this._antiCsrf = enable;
959
892
  return this;
960
893
  }
961
894
  /**
@@ -964,7 +897,7 @@ class Config {
964
897
  * @returns True if anti-CSRF protection is enabled
965
898
  */
966
899
  isAntiCsrfEnabled() {
967
- return this.enableAntiCsrf;
900
+ return this._antiCsrf;
968
901
  }
969
902
  /**
970
903
  * Add a global request interceptor
@@ -980,8 +913,8 @@ class Config {
980
913
  * });
981
914
  */
982
915
  addRequestInterceptor(interceptor) {
983
- const id = this.nextInterceptorId++;
984
- this.requestInterceptors.push({ id, interceptor });
916
+ const id = this._nextId++;
917
+ this._reqI.push([id, interceptor]);
985
918
  return id;
986
919
  }
987
920
  /**
@@ -998,8 +931,8 @@ class Config {
998
931
  * });
999
932
  */
1000
933
  addResponseInterceptor(interceptor) {
1001
- const id = this.nextInterceptorId++;
1002
- this.responseInterceptors.push({ id, interceptor });
934
+ const id = this._nextId++;
935
+ this._resI.push([id, interceptor]);
1003
936
  return id;
1004
937
  }
1005
938
  /**
@@ -1016,8 +949,8 @@ class Config {
1016
949
  * });
1017
950
  */
1018
951
  addErrorInterceptor(interceptor) {
1019
- const id = this.nextInterceptorId++;
1020
- this.errorInterceptors.push({ id, interceptor });
952
+ const id = this._nextId++;
953
+ this._errI.push([id, interceptor]);
1021
954
  return id;
1022
955
  }
1023
956
  /**
@@ -1029,7 +962,7 @@ class Config {
1029
962
  * Config.getInstance().removeRequestInterceptor(id);
1030
963
  */
1031
964
  removeRequestInterceptor(id) {
1032
- this.requestInterceptors = this.requestInterceptors.filter(item => item.id !== id);
965
+ this._reqI = this._reqI.filter(item => item[0] !== id);
1033
966
  }
1034
967
  /**
1035
968
  * Remove a response interceptor by its ID
@@ -1040,7 +973,7 @@ class Config {
1040
973
  * Config.getInstance().removeResponseInterceptor(id);
1041
974
  */
1042
975
  removeResponseInterceptor(id) {
1043
- this.responseInterceptors = this.responseInterceptors.filter(item => item.id !== id);
976
+ this._resI = this._resI.filter(item => item[0] !== id);
1044
977
  }
1045
978
  /**
1046
979
  * Remove an error interceptor by its ID
@@ -1051,7 +984,7 @@ class Config {
1051
984
  * Config.getInstance().removeErrorInterceptor(id);
1052
985
  */
1053
986
  removeErrorInterceptor(id) {
1054
- this.errorInterceptors = this.errorInterceptors.filter(item => item.id !== id);
987
+ this._errI = this._errI.filter(item => item[0] !== id);
1055
988
  }
1056
989
  /**
1057
990
  * Clear all interceptors (request, response, and error)
@@ -1060,30 +993,30 @@ class Config {
1060
993
  * Config.getInstance().clearInterceptors();
1061
994
  */
1062
995
  clearInterceptors() {
1063
- this.requestInterceptors = [];
1064
- this.responseInterceptors = [];
1065
- this.errorInterceptors = [];
996
+ this._reqI = [];
997
+ this._resI = [];
998
+ this._errI = [];
1066
999
  }
1067
1000
  /**
1068
1001
  * Get all global request interceptors (in registration order)
1069
1002
  * @internal
1070
1003
  */
1071
1004
  getRequestInterceptors() {
1072
- return this.requestInterceptors.map(item => item.interceptor);
1005
+ return this._reqI.map(item => item[1]);
1073
1006
  }
1074
1007
  /**
1075
1008
  * Get all global response interceptors (in registration order)
1076
1009
  * @internal
1077
1010
  */
1078
1011
  getResponseInterceptors() {
1079
- return this.responseInterceptors.map(item => item.interceptor);
1012
+ return this._resI.map(item => item[1]);
1080
1013
  }
1081
1014
  /**
1082
1015
  * Get all global error interceptors (in registration order)
1083
1016
  * @internal
1084
1017
  */
1085
1018
  getErrorInterceptors() {
1086
- return this.errorInterceptors.map(item => item.interceptor);
1019
+ return this._errI.map(item => item[1]);
1087
1020
  }
1088
1021
  /**
1089
1022
  * Reset all configuration options to their default values
@@ -1094,12 +1027,12 @@ class Config {
1094
1027
  * Config.getInstance().reset();
1095
1028
  */
1096
1029
  reset() {
1097
- this.csrfToken = null;
1098
- this.csrfHeaderName = "X-CSRF-Token";
1099
- this.enableAntiCsrf = true;
1100
- this.xsrfCookieName = "XSRF-TOKEN";
1101
- this.xsrfHeaderName = "X-XSRF-TOKEN";
1102
- this.enableAutoXsrf = true;
1030
+ this._csrfToken = null;
1031
+ this._csrfHeader = "X-CSRF-Token";
1032
+ this._antiCsrf = true;
1033
+ this._xsrfCookie = "XSRF-TOKEN";
1034
+ this._xsrfHeader = "X-XSRF-TOKEN";
1035
+ this._autoXsrf = true;
1103
1036
  this.clearInterceptors();
1104
1037
  return this;
1105
1038
  }
@@ -1110,54 +1043,54 @@ class Config {
1110
1043
  * Provides the core request building and execution capabilities.
1111
1044
  */
1112
1045
  class BaseRequest {
1113
- url;
1114
- requestOptions = {
1046
+ _url;
1047
+ _opts = {
1115
1048
  headers: {},
1116
1049
  };
1117
- abortController;
1118
- customFetch;
1119
- queryParams = new URLSearchParams();
1120
- autoApplyCsrfProtection = true;
1050
+ _ctrl;
1051
+ _fetch;
1052
+ _query = new URLSearchParams();
1053
+ _autoCsrf = true;
1121
1054
  // Per-request interceptors
1122
- requestInterceptors = [];
1123
- responseInterceptors = [];
1124
- errorInterceptors = [];
1055
+ _reqI = [];
1056
+ _resI = [];
1057
+ _errI = [];
1125
1058
  constructor(url) {
1126
- this.url = url;
1059
+ this._url = url;
1127
1060
  }
1128
1061
  /**
1129
1062
  * Get GraphQL options if set (only for BodyRequest subclasses)
1130
1063
  * @returns GraphQL options or undefined
1131
1064
  */
1132
- getGraphQLOptions() {
1065
+ _gql() {
1133
1066
  return undefined;
1134
1067
  }
1135
1068
  /**
1136
1069
  * Creates a fluent API for setting enum-based options
1137
1070
  * Combines direct setter with convenience methods
1138
1071
  */
1139
- createFluentSetter(optionName, options) {
1072
+ _fluent(optionName, options) {
1140
1073
  const fluent = {};
1141
1074
  // Create convenience methods for each enum value
1142
1075
  Object.entries(options).forEach(([key, value]) => {
1143
1076
  fluent[key] = () => {
1144
- this.requestOptions[optionName] = value;
1077
+ this._opts[optionName] = value;
1145
1078
  return this;
1146
1079
  };
1147
1080
  });
1148
1081
  // Create the callable setter
1149
1082
  const callable = (value) => {
1150
- this.requestOptions[optionName] = value;
1083
+ this._opts[optionName] = value;
1151
1084
  return this;
1152
1085
  };
1153
1086
  return Object.assign(callable, fluent);
1154
1087
  }
1155
- validateUrl(url) {
1088
+ _validateUrl(url) {
1156
1089
  const errorMessage = "Bad URL";
1157
1090
  if (!url?.trim())
1158
- throw new RequestError(errorMessage, url, this.method);
1091
+ throw new RequestError(errorMessage, url, this._method);
1159
1092
  if (url.includes("\0") || url.includes("\r") || url.includes("\n")) {
1160
- throw new RequestError(errorMessage, url, this.method);
1093
+ throw new RequestError(errorMessage, url, this._method);
1161
1094
  }
1162
1095
  const trimmed = url.trim();
1163
1096
  if (/^https?:\/\//.test(trimmed)) {
@@ -1165,7 +1098,7 @@ class BaseRequest {
1165
1098
  new URL(trimmed);
1166
1099
  }
1167
1100
  catch {
1168
- throw new RequestError(errorMessage, trimmed, this.method);
1101
+ throw new RequestError(errorMessage, trimmed, this._method);
1169
1102
  }
1170
1103
  }
1171
1104
  }
@@ -1183,16 +1116,12 @@ class BaseRequest {
1183
1116
  */
1184
1117
  withHeaders(headers) {
1185
1118
  // Filter out null and undefined values
1186
- const filteredHeaders = {};
1187
- Object.entries(headers).forEach(([key, value]) => {
1188
- if (value !== null && value !== undefined) {
1189
- filteredHeaders[key] = value;
1190
- }
1191
- });
1192
- this.requestOptions.headers = {
1193
- ...this.getHeadersRecord(),
1194
- ...filteredHeaders,
1195
- };
1119
+ const merged = { ...this._headers() };
1120
+ for (const [key, value] of Object.entries(headers)) {
1121
+ if (value != null)
1122
+ merged[key] = value;
1123
+ }
1124
+ this._opts.headers = merged;
1196
1125
  return this;
1197
1126
  }
1198
1127
  /**
@@ -1221,8 +1150,8 @@ class BaseRequest {
1221
1150
  */
1222
1151
  withTimeout(timeout) {
1223
1152
  if (!Number.isFinite(timeout) || timeout <= 0)
1224
- throw new RequestError("Bad timeout", this.url, this.method);
1225
- this.requestOptions.timeout = timeout;
1153
+ throw new RequestError("Bad timeout", this._url, this._method);
1154
+ this._opts.timeout = timeout;
1226
1155
  return this;
1227
1156
  }
1228
1157
  /**
@@ -1258,30 +1187,22 @@ class BaseRequest {
1258
1187
  * });
1259
1188
  */
1260
1189
  withRetries(retries) {
1261
- if (typeof retries === "number") {
1262
- if (!Number.isInteger(retries) || retries < 0) {
1263
- throw new RequestError(`Bad retries: ${retries}`, this.url, this.method);
1264
- }
1265
- this.requestOptions.retries = retries;
1190
+ const isNumber = typeof retries === "number";
1191
+ const attempts = isNumber ? retries : retries.attempts;
1192
+ if (!Number.isInteger(attempts) || attempts < 0) {
1193
+ throw new RequestError(`Bad ${isNumber ? "retries" : "attempts"}: ${attempts}`, this._url, this._method);
1266
1194
  }
1267
- else {
1268
- // Validate RetryConfig
1269
- if (!Number.isInteger(retries.attempts) || retries.attempts < 0) {
1270
- throw new RequestError(`Bad attempts: ${retries.attempts}`, this.url, this.method);
1195
+ if (!isNumber && retries.delay !== undefined) {
1196
+ const delay = retries.delay;
1197
+ if (typeof delay === "number") {
1198
+ if (!Number.isFinite(delay) || delay < 0)
1199
+ throw new RequestError(`Bad delay: ${delay}`, this._url, this._method);
1271
1200
  }
1272
- // Validate delay if provided
1273
- if (retries.delay !== undefined) {
1274
- if (typeof retries.delay === "number") {
1275
- if (!Number.isFinite(retries.delay) || retries.delay < 0) {
1276
- throw new RequestError(`Bad delay: ${retries.delay}`, this.url, this.method);
1277
- }
1278
- }
1279
- else if (typeof retries.delay !== "function") {
1280
- throw new RequestError(`Bad delay: ${typeof retries.delay}`, this.url, this.method);
1281
- }
1201
+ else if (typeof delay !== "function") {
1202
+ throw new RequestError(`Bad delay: ${typeof delay}`, this._url, this._method);
1282
1203
  }
1283
- this.requestOptions.retries = retries;
1284
1204
  }
1205
+ this._opts.retries = retries;
1285
1206
  return this;
1286
1207
  }
1287
1208
  /**
@@ -1298,7 +1219,7 @@ class BaseRequest {
1298
1219
  * });
1299
1220
  */
1300
1221
  onRetry(callback) {
1301
- this.requestOptions.onRetry = callback;
1222
+ this._opts.onRetry = callback;
1302
1223
  return this;
1303
1224
  }
1304
1225
  /**
@@ -1325,11 +1246,7 @@ class BaseRequest {
1325
1246
  * request.withCredentials.INCLUDE()
1326
1247
  */
1327
1248
  get withCredentials() {
1328
- return this.createFluentSetter("credentials", {
1329
- INCLUDE: CredentialsPolicy.INCLUDE,
1330
- OMIT: CredentialsPolicy.OMIT,
1331
- SAME_ORIGIN: CredentialsPolicy.SAME_ORIGIN,
1332
- });
1249
+ return this._fluent("credentials", CredentialsPolicy);
1333
1250
  }
1334
1251
  /**
1335
1252
  * Allows providing an external AbortController to cancel the request.
@@ -1358,7 +1275,7 @@ class BaseRequest {
1358
1275
  * controller.abort();
1359
1276
  */
1360
1277
  withAbortController(controller) {
1361
- this.abortController = controller;
1278
+ this._ctrl = controller;
1362
1279
  return this;
1363
1280
  }
1364
1281
  /**
@@ -1392,8 +1309,8 @@ class BaseRequest {
1392
1309
  */
1393
1310
  withFetch(fetchFn) {
1394
1311
  if (typeof fetchFn !== "function")
1395
- throw new RequestError("Bad fetch", this.url, this.method);
1396
- this.customFetch = fetchFn;
1312
+ throw new RequestError("Bad fetch", this._url, this._method);
1313
+ this._fetch = fetchFn;
1397
1314
  return this;
1398
1315
  }
1399
1316
  /**
@@ -1415,7 +1332,7 @@ class BaseRequest {
1415
1332
  * request.withReferrer("")
1416
1333
  */
1417
1334
  withReferrer(referrer) {
1418
- this.requestOptions.referrer = referrer;
1335
+ this._opts.referrer = referrer;
1419
1336
  return this;
1420
1337
  }
1421
1338
  /**
@@ -1447,16 +1364,7 @@ class BaseRequest {
1447
1364
  * request.withReferrerPolicy.NO_REFERRER()
1448
1365
  */
1449
1366
  get withReferrerPolicy() {
1450
- return this.createFluentSetter("referrerPolicy", {
1451
- ORIGIN: ReferrerPolicy.ORIGIN,
1452
- UNSAFE_URL: ReferrerPolicy.UNSAFE_URL,
1453
- SAME_ORIGIN: ReferrerPolicy.SAME_ORIGIN,
1454
- NO_REFERRER: ReferrerPolicy.NO_REFERRER,
1455
- STRICT_ORIGIN: ReferrerPolicy.STRICT_ORIGIN,
1456
- ORIGIN_WHEN_CROSS_ORIGIN: ReferrerPolicy.ORIGIN_WHEN_CROSS_ORIGIN,
1457
- NO_REFERRER_WHEN_DOWNGRADE: ReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE,
1458
- STRICT_ORIGIN_WHEN_CROSS_ORIGIN: ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN,
1459
- });
1367
+ return this._fluent("referrerPolicy", ReferrerPolicy);
1460
1368
  }
1461
1369
  /**
1462
1370
  * Sets how the request handles HTTP redirects (3xx status codes).
@@ -1485,11 +1393,7 @@ class BaseRequest {
1485
1393
  * request.withRedirect.ERROR()
1486
1394
  */
1487
1395
  get withRedirect() {
1488
- return this.createFluentSetter("redirect", {
1489
- FOLLOW: RedirectMode.FOLLOW,
1490
- ERROR: RedirectMode.ERROR,
1491
- MANUAL: RedirectMode.MANUAL,
1492
- });
1396
+ return this._fluent("redirect", RedirectMode);
1493
1397
  }
1494
1398
  /**
1495
1399
  * Sets the keepalive flag for the request. When enabled, the request can continue
@@ -1507,7 +1411,7 @@ class BaseRequest {
1507
1411
  * request.withKeepAlive(true)
1508
1412
  */
1509
1413
  withKeepAlive(keepalive) {
1510
- this.requestOptions.keepalive = keepalive;
1414
+ this._opts.keepalive = keepalive;
1511
1415
  return this;
1512
1416
  }
1513
1417
  /**
@@ -1538,11 +1442,7 @@ class BaseRequest {
1538
1442
  * request.withPriority.LOW()
1539
1443
  */
1540
1444
  get withPriority() {
1541
- return this.createFluentSetter("priority", {
1542
- HIGH: RequestPriority.HIGH,
1543
- LOW: RequestPriority.LOW,
1544
- AUTO: RequestPriority.AUTO,
1545
- });
1445
+ return this._fluent("priority", RequestPriority);
1546
1446
  }
1547
1447
  /**
1548
1448
  * Sets the integrity hash for Subresource Integrity (SRI) verification.
@@ -1565,7 +1465,7 @@ class BaseRequest {
1565
1465
  * request.withIntegrity("sha256-... sha384-...")
1566
1466
  */
1567
1467
  withIntegrity(integrity) {
1568
- this.requestOptions.integrity = integrity;
1468
+ this._opts.integrity = integrity;
1569
1469
  return this;
1570
1470
  }
1571
1471
  /**
@@ -1603,15 +1503,7 @@ class BaseRequest {
1603
1503
  * request.withCache.ONLY_IF_CACHED()
1604
1504
  */
1605
1505
  get withCache() {
1606
- const cacheOptions = {
1607
- DEFAULT: "default",
1608
- NO_STORE: "no-store",
1609
- RELOAD: "reload",
1610
- NO_CACHE: "no-cache",
1611
- FORCE_CACHE: "force-cache",
1612
- ONLY_IF_CACHED: "only-if-cached",
1613
- };
1614
- return this.createFluentSetter("cache", cacheOptions);
1506
+ return this._fluent("cache", CacheMode);
1615
1507
  }
1616
1508
  /**
1617
1509
  * Adds query parameters to the request URL.
@@ -1650,10 +1542,10 @@ class BaseRequest {
1650
1542
  }
1651
1543
  if (Array.isArray(value)) {
1652
1544
  // Handle array values - add multiple entries with the same key
1653
- value.forEach(v => this.queryParams.append(key, String(v)));
1545
+ value.forEach(v => this._query.append(key, String(v)));
1654
1546
  }
1655
1547
  else {
1656
- this.queryParams.append(key, String(value));
1548
+ this._query.append(key, String(value));
1657
1549
  }
1658
1550
  });
1659
1551
  return this;
@@ -1711,12 +1603,7 @@ class BaseRequest {
1711
1603
  * request.withMode.SAME_ORIGIN()
1712
1604
  */
1713
1605
  get withMode() {
1714
- return this.createFluentSetter("mode", {
1715
- CORS: RequestMode.CORS,
1716
- NO_CORS: RequestMode.NO_CORS,
1717
- SAME_ORIGIN: RequestMode.SAME_ORIGIN,
1718
- NAVIGATE: RequestMode.NAVIGATE,
1719
- });
1606
+ return this._fluent("mode", RequestMode);
1720
1607
  }
1721
1608
  /**
1722
1609
  * Sets the Content-Type header for the request.
@@ -1774,28 +1661,26 @@ class BaseRequest {
1774
1661
  * ```
1775
1662
  */
1776
1663
  withBasicAuth(username, password) {
1777
- const credentials = this.encodeBase64(`${username}:${password}`);
1664
+ const credentials = this._b64(`${username}:${password}`);
1778
1665
  return this.withAuthorization(`Basic ${credentials}`);
1779
1666
  }
1780
1667
  /**
1781
1668
  * Cross-environment base64 encoding
1782
1669
  * Works in both browser and Node.js environments
1783
1670
  */
1784
- encodeBase64(str) {
1671
+ _b64(str) {
1785
1672
  // Modern approach using TextEncoder (available in both modern browsers and Node.js)
1786
- if (typeof TextEncoder !== "undefined" && typeof btoa === "function") {
1787
- const encoder = new TextEncoder();
1788
- const bytes = encoder.encode(str);
1789
- return btoa(String.fromCharCode.apply(null, [...new Uint8Array(bytes)]));
1790
- }
1791
- // Browser environment
1792
- if (typeof btoa === "function")
1673
+ if (typeof btoa === "function") {
1674
+ if (typeof TextEncoder !== "undefined")
1675
+ return btoa(String.fromCharCode(...new TextEncoder().encode(str)));
1676
+ // Browser environment without TextEncoder
1793
1677
  return btoa(str);
1678
+ }
1794
1679
  // Node.js environment
1795
1680
  if (typeof Buffer !== "undefined")
1796
1681
  return Buffer.from(str).toString("base64");
1797
1682
  // Fallback (should never happen in modern environments)
1798
- throw new RequestError("No encoder", this.url, this.method);
1683
+ throw new RequestError("No encoder", this._url, this._method);
1799
1684
  }
1800
1685
  /**
1801
1686
  * Sets a Bearer token for authentication.
@@ -1817,9 +1702,9 @@ class BaseRequest {
1817
1702
  * Safely get headers as a Record<string, string>
1818
1703
  * @returns The headers object
1819
1704
  */
1820
- getHeadersRecord() {
1821
- if (typeof this.requestOptions.headers === "object" && this.requestOptions.headers !== null) {
1822
- return this.requestOptions.headers;
1705
+ _headers() {
1706
+ if (typeof this._opts.headers === "object" && this._opts.headers !== null) {
1707
+ return this._opts.headers;
1823
1708
  }
1824
1709
  return {};
1825
1710
  }
@@ -1828,8 +1713,8 @@ class BaseRequest {
1828
1713
  * @param headerName Header name to check
1829
1714
  * @returns Boolean indicating if the header exists (case-insensitive)
1830
1715
  */
1831
- hasHeader(headerName) {
1832
- const headers = this.getHeadersRecord();
1716
+ _hasHeader(headerName) {
1717
+ const headers = this._headers();
1833
1718
  return Object.keys(headers).some(key => key.toLowerCase() === headerName.toLowerCase());
1834
1719
  }
1835
1720
  /**
@@ -1858,37 +1743,26 @@ class BaseRequest {
1858
1743
  * ```
1859
1744
  */
1860
1745
  withCookies(cookies) {
1861
- const cookieEntries = Object.entries(cookies || {});
1862
- if (cookieEntries.length === 0) {
1746
+ if (Object.keys(cookies || {}).length === 0)
1863
1747
  return this;
1864
- }
1865
- const currentHeaders = this.getHeadersRecord();
1866
- // Get all existing cookie headers with different cases
1748
+ // Collect existing cookie header values (any casing), preserving the first header's case
1749
+ const newHeaders = { ...this._headers() };
1867
1750
  const cookieValues = [];
1868
- const cookieHeaderKeys = [];
1869
- Object.keys(currentHeaders).forEach(key => {
1751
+ let headerName = "";
1752
+ for (const key of Object.keys(newHeaders)) {
1870
1753
  if (key.toLowerCase() === "cookie") {
1871
1754
  // Don't add empty cookie values
1872
- if (currentHeaders[key])
1873
- cookieValues.push(currentHeaders[key]);
1874
- cookieHeaderKeys.push(key);
1755
+ if (newHeaders[key])
1756
+ cookieValues.push(newHeaders[key]);
1757
+ headerName ||= key;
1758
+ delete newHeaders[key];
1875
1759
  }
1876
- });
1877
- // Format the new cookies
1878
- const cookieString = CookieUtils.formatRequestCookies(cookies);
1879
- // Choose which header name to use - preserve existing case if possible
1880
- const headerName = cookieHeaderKeys.length > 0 ? cookieHeaderKeys[0] : "Cookie";
1881
- // Combine all existing cookie values with the new ones
1882
- const combinedCookieValue = [...cookieValues, cookieString].filter(Boolean).join("; ");
1883
- // Create a new headers object without any cookie headers
1884
- const newHeaders = { ...currentHeaders };
1885
- cookieHeaderKeys.forEach(key => {
1886
- delete newHeaders[key];
1887
- });
1888
- // Set the new combined cookie header
1889
- this.requestOptions.headers = {
1760
+ }
1761
+ // Combine all existing cookie values with the newly formatted ones
1762
+ cookieValues.push(CookieUtils.formatRequestCookies(cookies));
1763
+ this._opts.headers = {
1890
1764
  ...newHeaders,
1891
- [headerName]: combinedCookieValue,
1765
+ [headerName || "Cookie"]: cookieValues.filter(Boolean).join("; "),
1892
1766
  };
1893
1767
  return this;
1894
1768
  }
@@ -1942,7 +1816,7 @@ class BaseRequest {
1942
1816
  * @returns The instance for chaining
1943
1817
  */
1944
1818
  withoutCsrfProtection() {
1945
- this.autoApplyCsrfProtection = false;
1819
+ this._autoCsrf = false;
1946
1820
  return this;
1947
1821
  }
1948
1822
  /**
@@ -1966,7 +1840,7 @@ class BaseRequest {
1966
1840
  * });
1967
1841
  */
1968
1842
  withRequestInterceptor(interceptor) {
1969
- this.requestInterceptors.push(interceptor);
1843
+ this._reqI.push(interceptor);
1970
1844
  return this;
1971
1845
  }
1972
1846
  /**
@@ -1983,7 +1857,7 @@ class BaseRequest {
1983
1857
  * });
1984
1858
  */
1985
1859
  withResponseInterceptor(interceptor) {
1986
- this.responseInterceptors.push(interceptor);
1860
+ this._resI.push(interceptor);
1987
1861
  return this;
1988
1862
  }
1989
1863
  /**
@@ -2000,7 +1874,7 @@ class BaseRequest {
2000
1874
  * });
2001
1875
  */
2002
1876
  withErrorInterceptor(interceptor) {
2003
- this.errorInterceptors.push(interceptor);
1877
+ this._errI.push(interceptor);
2004
1878
  return this;
2005
1879
  }
2006
1880
  /**
@@ -2014,13 +1888,13 @@ class BaseRequest {
2014
1888
  * console.log(response.status);
2015
1889
  */
2016
1890
  async getResponse() {
2017
- const url = this.formatUrlWithQueryParams(this.url);
2018
- this.applyCsrfProtection();
1891
+ const url = this._fullUrl(this._url);
1892
+ this._applyCsrf();
2019
1893
  const fetchOptions = {
2020
- ...this.requestOptions,
2021
- method: this.method,
1894
+ ...this._opts,
1895
+ method: this._method,
2022
1896
  };
2023
- return !this.requestOptions.retries ? this.executeRequest(url, fetchOptions) : this.executeWithRetries(url, fetchOptions);
1897
+ return !this._opts.retries ? this._run(url, fetchOptions) : this._retry(url, fetchOptions);
2024
1898
  }
2025
1899
  /**
2026
1900
  * Execute the request and parse the response as JSON
@@ -2161,8 +2035,8 @@ class BaseRequest {
2161
2035
  /**
2162
2036
  * Apply CSRF protection headers based on configuration
2163
2037
  */
2164
- applyCsrfProtection() {
2165
- if (!this.autoApplyCsrfProtection)
2038
+ _applyCsrf() {
2039
+ if (!this._autoCsrf)
2166
2040
  return;
2167
2041
  const config = Config.getInstance();
2168
2042
  // Apply anti-CSRF headers if enabled
@@ -2173,7 +2047,7 @@ class BaseRequest {
2173
2047
  const globalToken = config.getCsrfToken();
2174
2048
  if (globalToken) {
2175
2049
  const csrfHeaderName = config.getCsrfHeaderName();
2176
- const hasLocalToken = this.hasHeader("X-CSRF-Token") || this.hasHeader(csrfHeaderName);
2050
+ const hasLocalToken = this._hasHeader("X-CSRF-Token") || this._hasHeader(csrfHeaderName);
2177
2051
  if (!hasLocalToken) {
2178
2052
  this.withHeader(csrfHeaderName, globalToken);
2179
2053
  }
@@ -2183,7 +2057,7 @@ class BaseRequest {
2183
2057
  const xsrfToken = CsrfUtils.getTokenFromCookie(config.getXsrfCookieName());
2184
2058
  if (xsrfToken && CsrfUtils.isValidToken(xsrfToken)) {
2185
2059
  const xsrfHeaderName = config.getXsrfHeaderName();
2186
- const hasLocalToken = this.hasHeader("X-XSRF-TOKEN") || this.hasHeader(xsrfHeaderName);
2060
+ const hasLocalToken = this._hasHeader("X-XSRF-TOKEN") || this._hasHeader(xsrfHeaderName);
2187
2061
  if (!hasLocalToken) {
2188
2062
  this.withHeader(xsrfHeaderName, xsrfToken);
2189
2063
  }
@@ -2195,8 +2069,8 @@ class BaseRequest {
2195
2069
  * @param url The base URL
2196
2070
  * @returns The URL with query parameters appended
2197
2071
  */
2198
- formatUrlWithQueryParams(url) {
2199
- const queryString = this.queryParams.toString();
2072
+ _fullUrl(url) {
2073
+ const queryString = this._query.toString();
2200
2074
  if (!queryString) {
2201
2075
  return url;
2202
2076
  }
@@ -2204,7 +2078,7 @@ class BaseRequest {
2204
2078
  // Try to use the URL constructor (works for absolute URLs)
2205
2079
  const urlObj = new URL(url);
2206
2080
  // Merge our query params with any that might be in the URL already
2207
- this.queryParams.forEach((value, key) => {
2081
+ this._query.forEach((value, key) => {
2208
2082
  urlObj.searchParams.append(key, value);
2209
2083
  });
2210
2084
  return urlObj.toString();
@@ -2223,21 +2097,21 @@ class BaseRequest {
2223
2097
  * @returns A wrapped response object
2224
2098
  * @throws RequestError if the request fails after all retries
2225
2099
  */
2226
- async executeWithRetries(url, fetchOptions) {
2227
- const retriesConfig = this.requestOptions.retries;
2100
+ async _retry(url, fetchOptions) {
2101
+ const retriesConfig = this._opts.retries;
2228
2102
  const maxRetries = typeof retriesConfig === "number" ? retriesConfig : retriesConfig?.attempts || 0;
2229
2103
  const method = typeof fetchOptions.method === "string" ? fetchOptions.method : "GET";
2230
2104
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
2231
2105
  try {
2232
- return await this.executeRequest(url, fetchOptions);
2106
+ return await this._run(url, fetchOptions);
2233
2107
  }
2234
2108
  catch (error) {
2235
- const requestError = error instanceof RequestError ? error : RequestError.networkError(url, method, error instanceof Error ? error : new Error(String(error)));
2109
+ const requestError = error instanceof RequestError ? error : RequestError.networkError(url, method, toError(error));
2236
2110
  if (attempt >= maxRetries)
2237
2111
  throw requestError;
2238
2112
  // Call onRetry callback if provided
2239
- if (this.requestOptions.onRetry) {
2240
- await this.requestOptions.onRetry({ attempt: attempt + 1, error: requestError });
2113
+ if (this._opts.onRetry) {
2114
+ await this._opts.onRetry({ attempt: attempt + 1, error: requestError });
2241
2115
  }
2242
2116
  // Apply delay if configured
2243
2117
  if (typeof retriesConfig === "object" && retriesConfig.delay !== undefined) {
@@ -2261,9 +2135,9 @@ class BaseRequest {
2261
2135
  * @param configParam - The request configuration
2262
2136
  * @returns Modified config or a Response to short-circuit
2263
2137
  */
2264
- async runRequestInterceptors(configParam) {
2138
+ async _runReqI(configParam) {
2265
2139
  const globalConfig = Config.getInstance();
2266
- const allInterceptors = [...globalConfig.getRequestInterceptors(), ...this.requestInterceptors];
2140
+ const allInterceptors = [...globalConfig.getRequestInterceptors(), ...this._reqI];
2267
2141
  let currentConfig = configParam;
2268
2142
  for (let i = 0; i < allInterceptors.length; i++) {
2269
2143
  try {
@@ -2275,7 +2149,7 @@ class BaseRequest {
2275
2149
  currentConfig = result;
2276
2150
  }
2277
2151
  catch (error) {
2278
- throw new RequestError(`ReqI: ${error instanceof Error ? error.message : String(error)}`, currentConfig.url, currentConfig.method);
2152
+ throw new RequestError(`ReqI: ${errorMessage(error)}`, currentConfig.url, currentConfig.method);
2279
2153
  }
2280
2154
  }
2281
2155
  return currentConfig;
@@ -2285,18 +2159,18 @@ class BaseRequest {
2285
2159
  * @param response - The response wrapper
2286
2160
  * @returns Modified response wrapper
2287
2161
  */
2288
- async runResponseInterceptors(response) {
2162
+ async _runResI(response) {
2289
2163
  const globalConfig = Config.getInstance();
2290
2164
  const globalInterceptors = globalConfig.getResponseInterceptors();
2291
2165
  // Per-request in order, then global in reverse
2292
- const allInterceptors = [...this.responseInterceptors, ...[...globalInterceptors].reverse()];
2166
+ const allInterceptors = [...this._resI, ...[...globalInterceptors].reverse()];
2293
2167
  let currentResponse = response;
2294
2168
  for (let i = 0; i < allInterceptors.length; i++) {
2295
2169
  try {
2296
2170
  currentResponse = await allInterceptors[i](currentResponse);
2297
2171
  }
2298
2172
  catch (error) {
2299
- throw new RequestError(`ResI: ${error instanceof Error ? error.message : String(error)}`, currentResponse.url || "", currentResponse.method || "");
2173
+ throw new RequestError(`ResI: ${errorMessage(error)}`, currentResponse.url || "", currentResponse.method || "");
2300
2174
  }
2301
2175
  }
2302
2176
  return currentResponse;
@@ -2306,11 +2180,11 @@ class BaseRequest {
2306
2180
  * @param error - The error that occurred
2307
2181
  * @returns Modified error or a ResponseWrapper to recover
2308
2182
  */
2309
- async runErrorInterceptors(error) {
2183
+ async _runErrI(error) {
2310
2184
  const globalConfig = Config.getInstance();
2311
2185
  const globalInterceptors = globalConfig.getErrorInterceptors();
2312
2186
  // Per-request in order, then global in reverse
2313
- const allInterceptors = [...this.errorInterceptors, ...[...globalInterceptors].reverse()];
2187
+ const allInterceptors = [...this._errI, ...[...globalInterceptors].reverse()];
2314
2188
  let currentError = error;
2315
2189
  for (let i = 0; i < allInterceptors.length; i++) {
2316
2190
  try {
@@ -2326,24 +2200,20 @@ class BaseRequest {
2326
2200
  if (interceptorError instanceof RequestError) {
2327
2201
  currentError = interceptorError;
2328
2202
  }
2329
- else {
2330
- const em = interceptorError instanceof Error ? interceptorError.message : String(interceptorError);
2203
+ else if (currentError instanceof RequestError) {
2331
2204
  // Always wrap in RequestError when we have context
2332
- if (currentError instanceof RequestError) {
2333
- currentError = new RequestError(`ErrI${i + 1}: ${em}`, currentError.url, currentError.method, {
2334
- status: currentError.status,
2335
- response: currentError.response,
2336
- body: currentError.body,
2337
- });
2338
- }
2339
- else {
2340
- /* c8 ignore start */
2341
- // Last resort: if we have no context at all, use the original error's context
2342
- // This shouldn't happen in practice, but handle it gracefully
2343
- const errorObj = interceptorError instanceof Error ? interceptorError : new Error(String(interceptorError));
2344
- currentError = RequestError.networkError(error.url, error.method, errorObj);
2345
- /* c8 ignore end */
2346
- }
2205
+ currentError = new RequestError(`ErrI${i + 1}: ${errorMessage(interceptorError)}`, currentError.url, currentError.method, {
2206
+ status: currentError.status,
2207
+ response: currentError.response,
2208
+ body: currentError.body,
2209
+ });
2210
+ }
2211
+ else {
2212
+ /* c8 ignore start */
2213
+ // Last resort: if we have no context at all, use the original error's context
2214
+ // This shouldn't happen in practice, but handle it gracefully
2215
+ currentError = RequestError.networkError(error.url, error.method, toError(interceptorError));
2216
+ /* c8 ignore end */
2347
2217
  }
2348
2218
  }
2349
2219
  }
@@ -2353,7 +2223,7 @@ class BaseRequest {
2353
2223
  * Helper to create an abort signal with timeout support
2354
2224
  * Handles various AbortSignal API levels gracefully
2355
2225
  */
2356
- createAbortSignal(timeoutMs, externalController) {
2226
+ _signal(timeoutMs, externalController) {
2357
2227
  let timeoutId;
2358
2228
  let timeoutController;
2359
2229
  let isTimeout = false;
@@ -2389,7 +2259,7 @@ class BaseRequest {
2389
2259
  const finalSignal = externalController && hasAbortSignalAny
2390
2260
  ? AbortSignal.any([externalController.signal, timeoutSignal])
2391
2261
  : externalController
2392
- ? this.combineSignalsManually(externalController.signal, timeoutSignal)
2262
+ ? this._combine(externalController.signal, timeoutSignal)
2393
2263
  : timeoutSignal;
2394
2264
  return {
2395
2265
  signal: finalSignal,
@@ -2404,7 +2274,7 @@ class BaseRequest {
2404
2274
  * Manually combine two abort signals for older environments
2405
2275
  * Returns the first signal and listens to the second
2406
2276
  */
2407
- combineSignalsManually(signal1, signal2) {
2277
+ _combine(signal1, signal2) {
2408
2278
  // If either is already aborted, use that one
2409
2279
  if (signal1.aborted)
2410
2280
  return signal1;
@@ -2420,9 +2290,9 @@ class BaseRequest {
2420
2290
  /**
2421
2291
  * Convert fetchOptions to RequestConfig with proper typing
2422
2292
  */
2423
- createRequestConfig(url, fetchOptions) {
2293
+ _config(url, fetchOptions) {
2424
2294
  const method = typeof fetchOptions.method === "string" ? fetchOptions.method : "GET";
2425
- const headers = this.getHeadersRecord();
2295
+ const headers = this._headers();
2426
2296
  const extendedOptions = fetchOptions;
2427
2297
  return {
2428
2298
  url,
@@ -2444,7 +2314,7 @@ class BaseRequest {
2444
2314
  /**
2445
2315
  * Apply interceptor results back to fetchOptions
2446
2316
  */
2447
- applyRequestConfig(config, fetchOptions) {
2317
+ _applyConfig(config, fetchOptions) {
2448
2318
  fetchOptions.headers = config.headers;
2449
2319
  if (config.body !== undefined) {
2450
2320
  fetchOptions.body = config.body;
@@ -2456,54 +2326,54 @@ class BaseRequest {
2456
2326
  fetchOptions.cache = config.cache;
2457
2327
  }
2458
2328
  }
2459
- async executeRequest(url, fetchOptions) {
2329
+ async _run(url, fetchOptions) {
2460
2330
  const method = typeof fetchOptions.method === "string" ? fetchOptions.method : "GET";
2461
2331
  // Setup abort signal with timeout
2462
- const abortSignal = this.createAbortSignal(this.requestOptions.timeout, this.abortController);
2332
+ const abortSignal = this._signal(this._opts.timeout, this._ctrl);
2463
2333
  try {
2464
2334
  // Run request interceptors before making the request
2465
- const requestConfig = this.createRequestConfig(url, fetchOptions);
2466
- const interceptorResult = await this.runRequestInterceptors(requestConfig);
2335
+ const requestConfig = this._config(url, fetchOptions);
2336
+ const interceptorResult = await this._runReqI(requestConfig);
2467
2337
  // If interceptor returned a Response, short-circuit and wrap it
2468
2338
  if (interceptorResult instanceof Response) {
2469
- const graphQLOptions = this.getGraphQLOptions();
2470
- const wrappedResponse = new ResponseWrapper(interceptorResult, this.url, this.method, graphQLOptions);
2471
- return await this.runResponseInterceptors(wrappedResponse);
2339
+ const graphQLOptions = this._gql();
2340
+ const wrappedResponse = new ResponseWrapper(interceptorResult, this._url, this._method, graphQLOptions);
2341
+ return await this._runResI(wrappedResponse);
2472
2342
  }
2473
2343
  // Update fetchOptions with interceptor modifications
2474
2344
  url = interceptorResult.url;
2475
- this.validateUrl(url);
2476
- this.applyRequestConfig(interceptorResult, fetchOptions);
2345
+ this._validateUrl(url);
2346
+ this._applyConfig(interceptorResult, fetchOptions);
2477
2347
  // Set the combined abort signal
2478
2348
  if (abortSignal.signal) {
2479
2349
  fetchOptions.signal = abortSignal.signal;
2480
2350
  }
2481
2351
  // Execute fetch (custom implementation if provided, global fetch otherwise)
2482
- const fetchFn = this.customFetch ?? globalThis.fetch;
2352
+ const fetchFn = this._fetch ?? globalThis.fetch;
2483
2353
  let response;
2484
2354
  try {
2485
2355
  response = await fetchFn(url, fetchOptions);
2486
2356
  }
2487
2357
  catch (error) {
2488
- const errorObj = error instanceof Error ? error : new Error(String(error));
2358
+ const errorObj = toError(error);
2489
2359
  const errorName = errorObj.name;
2490
- const errorMessage = errorObj.message.toLowerCase();
2360
+ const lowerMessage = errorObj.message.toLowerCase();
2491
2361
  // Check if this is a timeout error from our internal timeout
2492
2362
  const isOurTimeout = abortSignal.wasTimeout();
2493
2363
  // Check if it's an abort error (DOMException in browsers, or AbortSignal abort)
2494
2364
  if (error instanceof DOMException && error.name === "AbortError") {
2495
2365
  // If it was our timeout that caused the abort, throw timeout error
2496
- if (isOurTimeout && this.requestOptions.timeout) {
2497
- throw RequestError.timeout(url, method, this.requestOptions.timeout);
2366
+ if (isOurTimeout && this._opts.timeout) {
2367
+ throw RequestError.timeout(url, method, this._opts.timeout);
2498
2368
  }
2499
2369
  // Otherwise it's a manual abort
2500
2370
  throw RequestError.abortError(url, method);
2501
2371
  }
2502
2372
  // Check for Node.js/undici TimeoutError or other timeout indicators
2503
2373
  // This catches timeout errors that aren't thrown as AbortError
2504
- const isTimeoutError = isOurTimeout || errorName === "TimeoutError" || errorMessage.includes("timeout") || errorMessage.includes("aborted due to timeout");
2505
- if (isTimeoutError && this.requestOptions.timeout) {
2506
- throw RequestError.timeout(url, method, this.requestOptions.timeout);
2374
+ const isTimeoutError = isOurTimeout || errorName === "TimeoutError" || lowerMessage.includes("timeout");
2375
+ if (isTimeoutError && this._opts.timeout) {
2376
+ throw RequestError.timeout(url, method, this._opts.timeout);
2507
2377
  }
2508
2378
  // For other network errors, let RequestError.networkError handle them
2509
2379
  // It will check for timeout patterns as a safety net (useful for external AbortControllers)
@@ -2519,22 +2389,15 @@ class BaseRequest {
2519
2389
  // (reads from a clone, so error.response remains readable)
2520
2390
  throw RequestError.fromResponse(response, url, method, await RequestError.captureBody(response));
2521
2391
  }
2522
- const graphQLOptions = this.getGraphQLOptions();
2392
+ const graphQLOptions = this._gql();
2523
2393
  const wrappedResponse = new ResponseWrapper(response, url, method, graphQLOptions);
2524
- return await this.runResponseInterceptors(wrappedResponse);
2394
+ return await this._runResI(wrappedResponse);
2525
2395
  }
2526
2396
  catch (error) {
2527
2397
  // Convert to RequestError if needed
2528
- let requestError;
2529
- if (error instanceof RequestError) {
2530
- requestError = error;
2531
- }
2532
- else {
2533
- const errorObj = error instanceof Error ? error : new Error(String(error));
2534
- requestError = RequestError.networkError(url, method, errorObj);
2535
- }
2398
+ const requestError = error instanceof RequestError ? error : RequestError.networkError(url, method, toError(error));
2536
2399
  // Run error interceptors
2537
- const interceptorResult = await this.runErrorInterceptors(requestError);
2400
+ const interceptorResult = await this._runErrI(requestError);
2538
2401
  // If error interceptor returned a ResponseWrapper, recover from error
2539
2402
  if (interceptorResult instanceof ResponseWrapper) {
2540
2403
  return interceptorResult;
@@ -2551,12 +2414,9 @@ class BaseRequest {
2551
2414
  * Base class for requests that can have a body (POST, PUT, PATCH)
2552
2415
  */
2553
2416
  class BodyRequest extends BaseRequest {
2554
- body;
2555
- bodyType;
2556
- graphQLOptions = undefined;
2557
- constructor(url) {
2558
- super(url);
2559
- }
2417
+ _body;
2418
+ _bodyType;
2419
+ _gqlOpts = undefined;
2560
2420
  /**
2561
2421
  * Sets the request body. Automatically detects the body type and sets appropriate Content-Type header.
2562
2422
  * Supports JSON objects/arrays, strings, FormData, Blob, ArrayBuffer, URLSearchParams, and ReadableStream.
@@ -2593,11 +2453,11 @@ class BodyRequest extends BaseRequest {
2593
2453
  * ```
2594
2454
  */
2595
2455
  withBody(body) {
2596
- this.body = body;
2456
+ this._body = body;
2597
2457
  // Set body type and validate
2598
2458
  if (typeof body === "string") {
2599
- this.bodyType = BodyType.STRING;
2600
- this.setContentTypeIfNeeded("text/plain");
2459
+ this._bodyType = BodyType.STRING;
2460
+ this._setCT("text/plain");
2601
2461
  }
2602
2462
  else if (body !== null &&
2603
2463
  typeof body === "object" &&
@@ -2608,18 +2468,18 @@ class BodyRequest extends BaseRequest {
2608
2468
  ArrayBuffer.isView(body) || // Handles TypedArray and DataView
2609
2469
  body instanceof URLSearchParams ||
2610
2470
  body instanceof ReadableStream)) {
2611
- this.bodyType = BodyType.JSON;
2612
- this.setContentTypeIfNeeded("application/json");
2471
+ this._bodyType = BodyType.JSON;
2472
+ this._setCT("application/json");
2613
2473
  // Validate JSON is stringifiable early
2614
2474
  try {
2615
2475
  JSON.stringify(body);
2616
2476
  }
2617
2477
  catch (error) {
2618
- throw new RequestError(`Bad JSON: ${error instanceof Error ? error.message : String(error)}`, this.url, this.method);
2478
+ throw new RequestError(`Bad JSON: ${errorMessage(error)}`, this._url, this._method);
2619
2479
  }
2620
2480
  }
2621
2481
  else {
2622
- this.bodyType = BodyType.BINARY;
2482
+ this._bodyType = BodyType.BINARY;
2623
2483
  }
2624
2484
  return this;
2625
2485
  }
@@ -2662,25 +2522,25 @@ class BodyRequest extends BaseRequest {
2662
2522
  */
2663
2523
  withGraphQL(query, variables, options) {
2664
2524
  if (typeof query !== "string" || query.length === 0) {
2665
- throw new RequestError("Bad query", this.url, this.method);
2525
+ throw new RequestError("Bad query", this._url, this._method);
2666
2526
  }
2667
2527
  const graphQLBody = {
2668
2528
  query: query,
2669
2529
  };
2670
2530
  if (variables !== undefined) {
2671
2531
  if (typeof variables !== "object" || variables === null || Array.isArray(variables)) {
2672
- throw new RequestError("Bad vars", this.url, this.method);
2532
+ throw new RequestError("Bad vars", this._url, this._method);
2673
2533
  }
2674
2534
  graphQLBody.variables = variables;
2675
2535
  }
2676
2536
  // Store GraphQL options if provided
2677
2537
  if (options !== undefined) {
2678
2538
  if (typeof options !== "object" || options === null || Array.isArray(options)) {
2679
- throw new RequestError("Bad opts", this.url, this.method);
2539
+ throw new RequestError("Bad opts", this._url, this._method);
2680
2540
  }
2681
2541
  // Store only the known GraphQL options properties
2682
2542
  const opts = options;
2683
- this.graphQLOptions = {
2543
+ this._gqlOpts = {
2684
2544
  throwOnError: typeof opts.throwOnError === "boolean" ? opts.throwOnError : undefined,
2685
2545
  };
2686
2546
  }
@@ -2689,26 +2549,26 @@ class BodyRequest extends BaseRequest {
2689
2549
  JSON.stringify(graphQLBody);
2690
2550
  }
2691
2551
  catch (error) {
2692
- throw new RequestError(`Bad JSON: ${error instanceof Error ? error.message : String(error)}`, this.url, this.method);
2552
+ throw new RequestError(`Bad JSON: ${errorMessage(error)}`, this._url, this._method);
2693
2553
  }
2694
- this.body = graphQLBody;
2695
- this.bodyType = BodyType.JSON;
2696
- this.setContentTypeIfNeeded("application/json");
2554
+ this._body = graphQLBody;
2555
+ this._bodyType = BodyType.JSON;
2556
+ this._setCT("application/json");
2697
2557
  return this;
2698
2558
  }
2699
2559
  /**
2700
2560
  * Check if Content-Type header is already set (case-insensitive)
2701
2561
  */
2702
- hasContentType() {
2703
- const headers = this.requestOptions.headers;
2562
+ _hasCT() {
2563
+ const headers = this._opts.headers;
2704
2564
  if (typeof headers === "object" && headers !== null) {
2705
2565
  const headersObj = headers;
2706
2566
  return Object.keys(headersObj).some(header => header.toLowerCase() === "content-type");
2707
2567
  }
2708
2568
  return false;
2709
2569
  }
2710
- setContentTypeIfNeeded(contentType) {
2711
- if (!this.hasContentType()) {
2570
+ _setCT(contentType) {
2571
+ if (!this._hasCT()) {
2712
2572
  this.withContentType(contentType);
2713
2573
  }
2714
2574
  }
@@ -2716,24 +2576,24 @@ class BodyRequest extends BaseRequest {
2716
2576
  * Get the GraphQL options if set
2717
2577
  * @returns The GraphQL options or undefined
2718
2578
  */
2719
- getGraphQLOptions() {
2720
- return this.graphQLOptions;
2579
+ _gql() {
2580
+ return this._gqlOpts;
2721
2581
  }
2722
2582
  /**
2723
2583
  * Execute the request and return the ResponseWrapper
2724
2584
  * Overrides the base implementation to add body handling
2725
2585
  */
2726
2586
  async getResponse() {
2727
- if (this.body !== undefined) {
2587
+ if (this._body !== undefined) {
2728
2588
  // Remove previous body if it exists
2729
- if (this.requestOptions.body)
2730
- delete this.requestOptions.body;
2589
+ if (this._opts.body)
2590
+ delete this._opts.body;
2731
2591
  // Process the body based on its type
2732
- if (this.bodyType === BodyType.JSON) {
2733
- this.requestOptions.body = JSON.stringify(this.body);
2592
+ if (this._bodyType === BodyType.JSON) {
2593
+ this._opts.body = JSON.stringify(this._body);
2734
2594
  }
2735
2595
  else {
2736
- this.requestOptions.body = this.body;
2596
+ this._opts.body = this._body;
2737
2597
  }
2738
2598
  }
2739
2599
  return super.getResponse();
@@ -2750,10 +2610,7 @@ class BodyRequest extends BaseRequest {
2750
2610
  * const data = await request.getData();
2751
2611
  */
2752
2612
  class GetRequest extends BaseRequest {
2753
- method = HttpMethod.GET;
2754
- constructor(url) {
2755
- super(url);
2756
- }
2613
+ _method = HttpMethod.GET;
2757
2614
  }
2758
2615
  /**
2759
2616
  * HTTP HEAD request implementation
@@ -2764,10 +2621,7 @@ class GetRequest extends BaseRequest {
2764
2621
  * const response = await request.getResponse();
2765
2622
  */
2766
2623
  class HeadRequest extends BaseRequest {
2767
- method = HttpMethod.HEAD;
2768
- constructor(url) {
2769
- super(url);
2770
- }
2624
+ _method = HttpMethod.HEAD;
2771
2625
  }
2772
2626
  /**
2773
2627
  * HTTP OPTIONS request implementation
@@ -2778,10 +2632,7 @@ class HeadRequest extends BaseRequest {
2778
2632
  * const response = await request.getResponse();
2779
2633
  */
2780
2634
  class OptionsRequest extends BaseRequest {
2781
- method = HttpMethod.OPTIONS;
2782
- constructor(url) {
2783
- super(url);
2784
- }
2635
+ _method = HttpMethod.OPTIONS;
2785
2636
  }
2786
2637
  /**
2787
2638
  * HTTP DELETE request implementation
@@ -2792,10 +2643,7 @@ class OptionsRequest extends BaseRequest {
2792
2643
  * await request.getData();
2793
2644
  */
2794
2645
  class DeleteRequest extends BaseRequest {
2795
- method = HttpMethod.DELETE;
2796
- constructor(url) {
2797
- super(url);
2798
- }
2646
+ _method = HttpMethod.DELETE;
2799
2647
  }
2800
2648
  /**
2801
2649
  * HTTP POST request implementation
@@ -2807,10 +2655,7 @@ class DeleteRequest extends BaseRequest {
2807
2655
  * const data = await request.getData();
2808
2656
  */
2809
2657
  class PostRequest extends BodyRequest {
2810
- method = HttpMethod.POST;
2811
- constructor(url) {
2812
- super(url);
2813
- }
2658
+ _method = HttpMethod.POST;
2814
2659
  }
2815
2660
  /**
2816
2661
  * HTTP PUT request implementation
@@ -2822,10 +2667,7 @@ class PostRequest extends BodyRequest {
2822
2667
  * const data = await request.getData();
2823
2668
  */
2824
2669
  class PutRequest extends BodyRequest {
2825
- method = HttpMethod.PUT;
2826
- constructor(url) {
2827
- super(url);
2828
- }
2670
+ _method = HttpMethod.PUT;
2829
2671
  }
2830
2672
  /**
2831
2673
  * HTTP PATCH request implementation
@@ -2837,10 +2679,7 @@ class PutRequest extends BodyRequest {
2837
2679
  * const data = await request.getData();
2838
2680
  */
2839
2681
  class PatchRequest extends BodyRequest {
2840
- method = HttpMethod.PATCH;
2841
- constructor(url) {
2842
- super(url);
2843
- }
2682
+ _method = HttpMethod.PATCH;
2844
2683
  }
2845
2684
 
2846
2685
  /**
@@ -2952,73 +2791,60 @@ function options(url) {
2952
2791
  * Internal API builder implementation.
2953
2792
  */
2954
2793
  class ApiBuilderImpl {
2955
- baseURL;
2956
- modifiers = [];
2957
- proxy;
2794
+ _baseURL;
2795
+ _mods = [];
2796
+ _proxy;
2958
2797
  withBaseURL(baseURL) {
2959
- this.baseURL = baseURL;
2960
- return this.getProxy();
2798
+ this._baseURL = baseURL;
2799
+ return this._getProxy();
2961
2800
  }
2962
- resolveURL(url) {
2801
+ _resolve(url) {
2963
2802
  if (!url)
2964
- return this.baseURL || "";
2803
+ return this._baseURL || "";
2965
2804
  if (/^https?:\/\//.test(url))
2966
2805
  return url;
2967
- if (!this.baseURL)
2806
+ if (!this._baseURL)
2968
2807
  return url;
2969
- return this.baseURL.replace(/\/$/, "") + (url[0] === "/" ? url : "/" + url);
2808
+ return this._baseURL.replace(/\/$/, "") + (url[0] === "/" ? url : "/" + url);
2970
2809
  }
2971
- applyModifiers(request) {
2972
- if (this.modifiers)
2973
- for (const modifier of this.modifiers)
2974
- modifier(request);
2810
+ _new(Ctor, url) {
2811
+ const request = new Ctor(this._resolve(url));
2812
+ for (const modifier of this._mods)
2813
+ modifier(request);
2814
+ return request;
2975
2815
  }
2976
2816
  get(url) {
2977
- const request = new GetRequest(this.resolveURL(url));
2978
- this.applyModifiers(request);
2979
- return request;
2817
+ return this._new(GetRequest, url);
2980
2818
  }
2981
2819
  post(url) {
2982
- const request = new PostRequest(this.resolveURL(url));
2983
- this.applyModifiers(request);
2984
- return request;
2820
+ return this._new(PostRequest, url);
2985
2821
  }
2986
2822
  put(url) {
2987
- const request = new PutRequest(this.resolveURL(url));
2988
- this.applyModifiers(request);
2989
- return request;
2823
+ return this._new(PutRequest, url);
2990
2824
  }
2991
2825
  del(url) {
2992
- const request = new DeleteRequest(this.resolveURL(url));
2993
- this.applyModifiers(request);
2994
- return request;
2826
+ return this._new(DeleteRequest, url);
2995
2827
  }
2996
2828
  patch(url) {
2997
- const request = new PatchRequest(this.resolveURL(url));
2998
- this.applyModifiers(request);
2999
- return request;
2829
+ return this._new(PatchRequest, url);
3000
2830
  }
3001
2831
  head(url) {
3002
- const request = new HeadRequest(this.resolveURL(url));
3003
- this.applyModifiers(request);
3004
- return request;
2832
+ return this._new(HeadRequest, url);
3005
2833
  }
3006
2834
  options(url) {
3007
- const request = new OptionsRequest(this.resolveURL(url));
3008
- this.applyModifiers(request);
3009
- return request;
2835
+ return this._new(OptionsRequest, url);
3010
2836
  }
3011
- addModifier(modifier) {
3012
- this.modifiers.push(modifier);
3013
- return this.getProxy();
2837
+ _add(modifier) {
2838
+ this._mods.push(modifier);
2839
+ return this._getProxy();
3014
2840
  }
3015
- getProxy() {
3016
- if (!this.proxy) {
3017
- this.proxy = this.createProxy();
2841
+ _getProxy() {
2842
+ if (!this._proxy) {
2843
+ this._proxy = this._mkProxy();
3018
2844
  }
3019
- return this.proxy;
2845
+ return this._proxy;
3020
2846
  }
3021
- createProxy() {
2847
+ _mkProxy() {
3022
2848
  const disallowedMethods = new Set(["withBody", "withGraphQL", "withAbortController"]);
3023
2849
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
3024
2850
  return new Proxy(this, {
@@ -3040,7 +2866,7 @@ class ApiBuilderImpl {
3040
2866
  // If it's a 'with...' method or other chainable method, create a modifier for it
3041
2867
  if (typeof prop === "string" && (prop.startsWith("with") || prop === "onRetry")) {
3042
2868
  return (...args) => {
3043
- return implTarget.addModifier((request) => {
2869
+ return implTarget._add((request) => {
3044
2870
  const method = request[prop];
3045
2871
  if (typeof method === "function") {
3046
2872
  method.apply(request, args);
@@ -3055,7 +2881,7 @@ class ApiBuilderImpl {
3055
2881
  });
3056
2882
  }
3057
2883
  static create() {
3058
- return new ApiBuilderImpl().getProxy();
2884
+ return new ApiBuilderImpl()._getProxy();
3059
2885
  }
3060
2886
  }
3061
2887
  /**