create-request 1.4.3-rc.1 → 1.4.3-rc.3

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.
@@ -95,13 +95,50 @@ exports.CacheMode = void 0;
95
95
  CacheMode["ONLY_IF_CACHED"] = "only-if-cached";
96
96
  })(exports.CacheMode || (exports.CacheMode = {}));
97
97
 
98
+ /**
99
+ * Error class for HTTP request failures.
100
+ * Extends the standard Error class with additional context about the failed request.
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * try {
105
+ * await create.get('/api/users').getJson();
106
+ * } catch (error) {
107
+ * console.log(`Request failed: ${error.message}`);
108
+ * console.log(`URL: ${error.url}`);
109
+ * console.log(`Method: ${error.method}`);
110
+ * console.log(`Status: ${error.status}`);
111
+ * console.log(`Is timeout: ${error.isTimeout}`);
112
+ * console.log(`Is aborted: ${error.isAborted}`);
113
+ * }
114
+ * ```
115
+ */
98
116
  class RequestError extends Error {
117
+ /** HTTP status code if the request received a response (e.g., 404, 500) */
99
118
  status;
119
+ /** The Response object if the request received a response before failing */
100
120
  response;
121
+ /** The URL that was requested */
101
122
  url;
123
+ /** The HTTP method that was used (e.g., 'GET', 'POST') */
102
124
  method;
125
+ /** Whether the request failed due to a timeout */
103
126
  isTimeout;
127
+ /** Whether the request was aborted (cancelled) */
104
128
  isAborted;
129
+ /**
130
+ * Creates a new RequestError instance.
131
+ *
132
+ * @param message - Error message describing what went wrong
133
+ * @param url - The URL that was requested
134
+ * @param method - The HTTP method that was used
135
+ * @param options - Additional error context
136
+ * @param options.status - HTTP status code if available
137
+ * @param options.response - The Response object if available
138
+ * @param options.isTimeout - Whether this was a timeout error
139
+ * @param options.isAborted - Whether the request was aborted
140
+ * @param options.cause - The underlying error that caused this error
141
+ */
105
142
  constructor(message, url, method, options = {}) {
106
143
  super(message, { cause: options.cause });
107
144
  this.name = "RequestError";
@@ -119,19 +156,66 @@ class RequestError extends Error {
119
156
  Object.setPrototypeOf(this, RequestError.prototype);
120
157
  }
121
158
  /**
122
- * Static methods for creating specific types of RequestError
159
+ * Creates a RequestError for a timeout failure.
160
+ *
161
+ * @param url - The URL that timed out
162
+ * @param method - The HTTP method that was used
163
+ * @param timeoutMs - The timeout duration in milliseconds
164
+ * @returns A RequestError with `isTimeout` set to `true`
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * throw RequestError.timeout('/api/data', 'GET', 5000);
169
+ * ```
123
170
  */
124
171
  static timeout(url, method, timeoutMs) {
125
172
  return new RequestError(`Timeout ${timeoutMs}ms`, url, method, {
126
173
  isTimeout: true,
127
174
  });
128
175
  }
176
+ /**
177
+ * Creates a RequestError from an HTTP error response.
178
+ * Used when the server returns a non-2xx status code.
179
+ *
180
+ * @param response - The Response object from the failed request
181
+ * @param url - The URL that was requested
182
+ * @param method - The HTTP method that was used
183
+ * @returns A RequestError with the status code and response object
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * const response = await fetch('/api/users');
188
+ * if (!response.ok) {
189
+ * throw RequestError.fromResponse(response, '/api/users', 'GET');
190
+ * }
191
+ * ```
192
+ */
129
193
  static fromResponse(response, url, method) {
130
194
  return new RequestError(`HTTP ${response.status}`, url, method, {
131
195
  status: response.status,
132
196
  response,
133
197
  });
134
198
  }
199
+ /**
200
+ * Creates a RequestError from a network-level error.
201
+ * Automatically detects and categorizes common network errors (timeouts, DNS errors, connection errors).
202
+ *
203
+ * @param url - The URL that failed
204
+ * @param method - The HTTP method that was used
205
+ * @param originalError - The original error that occurred (e.g., from fetch)
206
+ * @returns A RequestError with enhanced error message and context
207
+ *
208
+ * @example
209
+ * ```typescript
210
+ * try {
211
+ * await fetch('/api/data');
212
+ * } catch (error) {
213
+ * if (error instanceof Error) {
214
+ * throw RequestError.networkError('/api/data', 'GET', error);
215
+ * }
216
+ * }
217
+ * ```
218
+ */
135
219
  static networkError(url, method, originalError) {
136
220
  // Provide more descriptive error messages for common network errors
137
221
  let message = originalError.message;
@@ -189,6 +273,20 @@ class RequestError extends Error {
189
273
  }
190
274
  return error;
191
275
  }
276
+ /**
277
+ * Creates a RequestError for an aborted (cancelled) request.
278
+ *
279
+ * @param url - The URL that was aborted
280
+ * @param method - The HTTP method that was used
281
+ * @returns A RequestError with `isAborted` set to `true`
282
+ *
283
+ * @example
284
+ * ```typescript
285
+ * const controller = new AbortController();
286
+ * controller.abort();
287
+ * throw RequestError.abortError('/api/data', 'GET');
288
+ * ```
289
+ */
192
290
  static abortError(url, method) {
193
291
  return new RequestError("Aborted", url, method, {
194
292
  isAborted: true,
@@ -197,10 +295,23 @@ class RequestError extends Error {
197
295
  }
198
296
 
199
297
  /**
200
- * Wrapper for HTTP responses with methods to transform the response data
298
+ * Wrapper for HTTP responses with methods to transform the response data.
299
+ * Provides convenient methods to parse the response body in different formats.
300
+ * Response bodies are cached after the first read, so you can call multiple methods
301
+ * (e.g., `getJson()` and `getText()`) on the same response.
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * const response = await create.get('/api/users').getResponse();
306
+ * console.log(response.status); // 200
307
+ * console.log(response.ok); // true
308
+ * const data = await response.getJson();
309
+ * ```
201
310
  */
202
311
  class ResponseWrapper {
312
+ /** The URL that was requested (if available) */
203
313
  url;
314
+ /** The HTTP method that was used (if available) */
204
315
  method;
205
316
  response;
206
317
  graphQLOptions;
@@ -219,19 +330,34 @@ class ResponseWrapper {
219
330
  };
220
331
  }
221
332
  }
222
- // Wrapper properties
333
+ /**
334
+ * HTTP status code (e.g., 200, 404, 500)
335
+ */
223
336
  get status() {
224
337
  return this.response.status;
225
338
  }
339
+ /**
340
+ * HTTP status text (e.g., "OK", "Not Found", "Internal Server Error")
341
+ */
226
342
  get statusText() {
227
343
  return this.response.statusText;
228
344
  }
345
+ /**
346
+ * Response headers as a Headers object
347
+ */
229
348
  get headers() {
230
349
  return this.response.headers;
231
350
  }
351
+ /**
352
+ * Whether the response status is in the 200-299 range (successful)
353
+ */
232
354
  get ok() {
233
355
  return this.response.ok;
234
356
  }
357
+ /**
358
+ * The raw Response object from the fetch API.
359
+ * Use this if you need direct access to the underlying Response.
360
+ */
235
361
  get raw() {
236
362
  return this.response;
237
363
  }
@@ -259,7 +385,29 @@ class ResponseWrapper {
259
385
  if (!Array.isArray(responseData.errors) || responseData.errors.length === 0)
260
386
  return;
261
387
  const errors = responseData.errors;
262
- const errorMessages = errors.map(x => typeof x === "string" ? x : x && typeof x === "object" && "message" in x ? String(x.message || "Unknown error") : String(x));
388
+ const errorMessages = errors.map(x => {
389
+ if (typeof x === "string")
390
+ return x;
391
+ if (x && typeof x === "object" && "message" in x) {
392
+ const message = x.message;
393
+ if (message == null)
394
+ return "Unknown error";
395
+ if (typeof message === "string")
396
+ return message;
397
+ if (typeof message === "object") {
398
+ try {
399
+ return JSON.stringify(message);
400
+ }
401
+ catch {
402
+ return "Unknown error";
403
+ }
404
+ }
405
+ // For primitives (number, boolean, etc.), safe to convert
406
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
407
+ return String(message);
408
+ }
409
+ return String(x);
410
+ });
263
411
  const errorMessage = errorMessages.join(", ");
264
412
  throw new RequestError(`GraphQL errors: ${errorMessage}`, this.url || "", this.method || "", {
265
413
  status: this.response.status,
@@ -309,13 +457,17 @@ class ResponseWrapper {
309
457
  }
310
458
  }
311
459
  /**
312
- * Get the response body as text
460
+ * Get the response body as text.
461
+ * The result is cached, so subsequent calls return the same value without re-reading the body.
313
462
  *
314
- * @returns The response text
315
- * @throws {RequestError} When reading fails
463
+ * @returns A promise that resolves to the response body as a string
464
+ * @throws {RequestError} When the body has already been consumed or reading fails
316
465
  *
317
466
  * @example
467
+ * ```typescript
318
468
  * const text = await response.getText();
469
+ * console.log(text); // "Hello, world!"
470
+ * ```
319
471
  */
320
472
  async getText() {
321
473
  if (this.cachedText !== undefined)
@@ -335,14 +487,19 @@ class ResponseWrapper {
335
487
  }
336
488
  }
337
489
  /**
338
- * Get the response body as a Blob
490
+ * Get the response body as a Blob.
491
+ * Useful for downloading files or handling binary data.
492
+ * The result is cached, so subsequent calls return the same value without re-reading the body.
339
493
  *
340
- * @returns The response as a Blob
341
- * @throws {RequestError} When reading fails
494
+ * @returns A promise that resolves to the response body as a Blob
495
+ * @throws {RequestError} When the body has already been consumed or reading fails
342
496
  *
343
497
  * @example
498
+ * ```typescript
344
499
  * const blob = await response.getBlob();
345
500
  * const url = URL.createObjectURL(blob);
501
+ * // Use the blob URL for downloading or displaying
502
+ * ```
346
503
  */
347
504
  async getBlob() {
348
505
  if (this.cachedBlob !== undefined)
@@ -362,14 +519,19 @@ class ResponseWrapper {
362
519
  }
363
520
  }
364
521
  /**
365
- * Get the response body as an ArrayBuffer
522
+ * Get the response body as an ArrayBuffer.
523
+ * Useful for processing binary data at a low level.
524
+ * The result is cached, so subsequent calls return the same value without re-reading the body.
366
525
  *
367
- * @returns The response as an ArrayBuffer
368
- * @throws {RequestError} When reading fails
526
+ * @returns A promise that resolves to the response body as an ArrayBuffer
527
+ * @throws {RequestError} When the body has already been consumed or reading fails
369
528
  *
370
529
  * @example
530
+ * ```typescript
371
531
  * const buffer = await response.getArrayBuffer();
372
532
  * const uint8Array = new Uint8Array(buffer);
533
+ * // Process the binary data
534
+ * ```
373
535
  */
374
536
  async getArrayBuffer() {
375
537
  if (this.cachedArrayBuffer !== undefined) {
@@ -1321,9 +1483,34 @@ class BaseRequest {
1321
1483
  return this.createFluentSetter("cache", cacheOptions);
1322
1484
  }
1323
1485
  /**
1324
- * Adds query parameters to the request URL
1325
- * @param params - An object containing the query parameters
1326
- * @returns The instance for chaining
1486
+ * Adds query parameters to the request URL.
1487
+ * Multiple calls will append parameters. Array values will create multiple query parameters with the same key.
1488
+ * Null and undefined values are ignored.
1489
+ *
1490
+ * @param params - An object containing query parameter key-value pairs.
1491
+ * Values can be strings, numbers, booleans, arrays (for multiple values), or null/undefined (ignored).
1492
+ * @returns The request instance for chaining
1493
+ *
1494
+ * @example
1495
+ * ```typescript
1496
+ * // Simple parameters
1497
+ * request.withQueryParams({ page: 1, limit: 10, active: true });
1498
+ * // Results in: ?page=1&limit=10&active=true
1499
+ * ```
1500
+ *
1501
+ * @example
1502
+ * ```typescript
1503
+ * // Array values create multiple parameters
1504
+ * request.withQueryParams({ tags: ['js', 'ts', 'node'] });
1505
+ * // Results in: ?tags=js&tags=ts&tags=node
1506
+ * ```
1507
+ *
1508
+ * @example
1509
+ * ```typescript
1510
+ * // Null/undefined values are ignored
1511
+ * request.withQueryParams({ page: 1, filter: null, sort: undefined });
1512
+ * // Results in: ?page=1
1513
+ * ```
1327
1514
  */
1328
1515
  withQueryParams(params) {
1329
1516
  Object.entries(params).forEach(([key, value]) => {
@@ -1341,10 +1528,25 @@ class BaseRequest {
1341
1528
  return this;
1342
1529
  }
1343
1530
  /**
1344
- * Adds a single query parameter
1345
- * @param key - The parameter name
1346
- * @param value - The parameter value, can be a single value or array of values
1347
- * @returns The instance for chaining
1531
+ * Adds a single query parameter to the request URL.
1532
+ * Convenience method for adding one parameter at a time.
1533
+ *
1534
+ * @param key - The query parameter name
1535
+ * @param value - The query parameter value. Can be a string, number, boolean, array (for multiple values), or null/undefined (ignored).
1536
+ * @returns The request instance for chaining
1537
+ *
1538
+ * @example
1539
+ * ```typescript
1540
+ * request.withQueryParam('page', 1).withQueryParam('limit', 10);
1541
+ * // Results in: ?page=1&limit=10
1542
+ * ```
1543
+ *
1544
+ * @example
1545
+ * ```typescript
1546
+ * // Array values create multiple parameters
1547
+ * request.withQueryParam('tags', ['js', 'ts']);
1548
+ * // Results in: ?tags=js&tags=ts
1549
+ * ```
1348
1550
  */
1349
1551
  withQueryParam(key, value) {
1350
1552
  return this.withQueryParams({ [key]: value });
@@ -1386,26 +1588,59 @@ class BaseRequest {
1386
1588
  });
1387
1589
  }
1388
1590
  /**
1389
- * Shorthand for setting the Content-Type header
1390
- * @param contentType - The content type
1391
- * @returns The instance for chaining
1591
+ * Sets the Content-Type header for the request.
1592
+ * Shorthand for `withHeader('Content-Type', contentType)`.
1593
+ *
1594
+ * @param contentType - The MIME type (e.g., `'application/json'`, `'text/plain'`, `'multipart/form-data'`)
1595
+ * @returns The request instance for chaining
1596
+ *
1597
+ * @example
1598
+ * ```typescript
1599
+ * request.withContentType('application/json');
1600
+ * ```
1601
+ *
1602
+ * @example
1603
+ * ```typescript
1604
+ * request.withContentType('application/xml');
1605
+ * ```
1392
1606
  */
1393
1607
  withContentType(contentType) {
1394
1608
  return this.withHeader("Content-Type", contentType);
1395
1609
  }
1396
1610
  /**
1397
- * Shorthand for setting the Authorization header
1398
- * @param authValue - The authorization value
1399
- * @returns The instance for chaining
1611
+ * Sets the Authorization header for the request.
1612
+ * Shorthand for `withHeader('Authorization', authValue)`.
1613
+ * For Bearer tokens, use `withBearerToken()` instead. For Basic auth, use `withBasicAuth()`.
1614
+ *
1615
+ * @param authValue - The full authorization header value (e.g., `'Bearer token123'`, `'Basic base64string'`)
1616
+ * @returns The request instance for chaining
1617
+ *
1618
+ * @example
1619
+ * ```typescript
1620
+ * request.withAuthorization('Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
1621
+ * ```
1622
+ *
1623
+ * @example
1624
+ * ```typescript
1625
+ * request.withAuthorization('CustomScheme customToken');
1626
+ * ```
1400
1627
  */
1401
1628
  withAuthorization(authValue) {
1402
1629
  return this.withHeader("Authorization", authValue);
1403
1630
  }
1404
1631
  /**
1405
- * Shorthand for setting up Basic authentication
1406
- * @param username - The username
1407
- * @param password - The password
1408
- * @returns The instance for chaining
1632
+ * Sets up HTTP Basic Authentication.
1633
+ * Encodes the username and password in base64 and sets the Authorization header.
1634
+ *
1635
+ * @param username - The username for Basic authentication
1636
+ * @param password - The password for Basic authentication
1637
+ * @returns The request instance for chaining
1638
+ *
1639
+ * @example
1640
+ * ```typescript
1641
+ * request.withBasicAuth('myuser', 'mypassword');
1642
+ * // Sets: Authorization: Basic bXl1c2VyOm15cGFzc3dvcmQ=
1643
+ * ```
1409
1644
  */
1410
1645
  withBasicAuth(username, password) {
1411
1646
  const credentials = this.encodeBase64(`${username}:${password}`);
@@ -1432,9 +1667,17 @@ class BaseRequest {
1432
1667
  throw new RequestError("Encoding not supported", this.url, this.method);
1433
1668
  }
1434
1669
  /**
1435
- * Sets the bearer token for authentication
1436
- * @param token - The bearer token
1437
- * @returns The instance for chaining
1670
+ * Sets a Bearer token for authentication.
1671
+ * Shorthand for `withAuthorization('Bearer ' + token)`.
1672
+ *
1673
+ * @param token - The Bearer token (JWT, OAuth token, etc.)
1674
+ * @returns The request instance for chaining
1675
+ *
1676
+ * @example
1677
+ * ```typescript
1678
+ * request.withBearerToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
1679
+ * // Sets: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
1680
+ * ```
1438
1681
  */
1439
1682
  withBearerToken(token) {
1440
1683
  return this.withAuthorization(`Bearer ${token}`);
@@ -1459,9 +1702,29 @@ class BaseRequest {
1459
1702
  return Object.keys(headers).some(key => key.toLowerCase() === headerName.toLowerCase());
1460
1703
  }
1461
1704
  /**
1462
- * Sets cookies for the request
1463
- * @param cookies Object containing cookie name-value pairs or cookie options
1464
- * @returns The instance for chaining
1705
+ * Sets cookies for the request.
1706
+ * Cookies are sent in the Cookie header. Multiple calls will merge cookies.
1707
+ * Cookie values can be simple strings or objects with additional cookie options.
1708
+ *
1709
+ * @param cookies - An object where keys are cookie names and values are either:
1710
+ * - A string (the cookie value)
1711
+ * - A CookieOptions object with `value` and optional properties (secure, httpOnly, sameSite, expires, path, domain, maxAge)
1712
+ * @returns The request instance for chaining
1713
+ *
1714
+ * @example
1715
+ * ```typescript
1716
+ * // Simple string cookies
1717
+ * request.withCookies({ sessionId: 'abc123', userId: '456' });
1718
+ * ```
1719
+ *
1720
+ * @example
1721
+ * ```typescript
1722
+ * // Cookies with options (note: options are for documentation only in request cookies)
1723
+ * request.withCookies({
1724
+ * sessionId: 'abc123',
1725
+ * token: { value: 'xyz789', secure: true }
1726
+ * });
1727
+ * ```
1465
1728
  */
1466
1729
  withCookies(cookies) {
1467
1730
  const cookieEntries = Object.entries(cookies || {});
@@ -1499,19 +1762,45 @@ class BaseRequest {
1499
1762
  return this;
1500
1763
  }
1501
1764
  /**
1502
- * Set a single cookie
1503
- * @param name Cookie name
1504
- * @param value Cookie value or options object
1505
- * @returns The instance for chaining
1765
+ * Sets a single cookie for the request.
1766
+ * Convenience method for adding one cookie at a time.
1767
+ *
1768
+ * @param name - The cookie name
1769
+ * @param value - The cookie value as a string, or a CookieOptions object with `value` and optional properties
1770
+ * @returns The request instance for chaining
1771
+ *
1772
+ * @example
1773
+ * ```typescript
1774
+ * request.withCookie('sessionId', 'abc123');
1775
+ * ```
1776
+ *
1777
+ * @example
1778
+ * ```typescript
1779
+ * request.withCookie('token', { value: 'xyz789', secure: true });
1780
+ * ```
1506
1781
  */
1507
1782
  withCookie(name, value) {
1508
1783
  return this.withCookies({ [name]: value });
1509
1784
  }
1510
1785
  /**
1511
- * Sets a CSRF token in the request headers
1512
- * @param token The CSRF token
1513
- * @param headerName The name of the header to use (default: X-CSRF-Token)
1514
- * @returns The instance for chaining
1786
+ * Sets a CSRF (Cross-Site Request Forgery) token in the request headers.
1787
+ * This is commonly used to protect against CSRF attacks in web applications.
1788
+ *
1789
+ * @param token - The CSRF token value
1790
+ * @param headerName - The name of the header to use. Defaults to `'X-CSRF-Token'`.
1791
+ * @returns The request instance for chaining
1792
+ *
1793
+ * @example
1794
+ * ```typescript
1795
+ * request.withCsrfToken('csrf-token-123');
1796
+ * // Sets: X-CSRF-Token: csrf-token-123
1797
+ * ```
1798
+ *
1799
+ * @example
1800
+ * ```typescript
1801
+ * request.withCsrfToken('token', 'X-Custom-CSRF-Header');
1802
+ * // Sets: X-Custom-CSRF-Header: token
1803
+ * ```
1515
1804
  */
1516
1805
  withCsrfToken(token, headerName = "X-CSRF-Token") {
1517
1806
  return this.withHeader(headerName, token);
@@ -1626,36 +1915,54 @@ class BaseRequest {
1626
1915
  return response.getJson();
1627
1916
  }
1628
1917
  /**
1629
- * Execute the request and get the response as text
1918
+ * Execute the request and get the response body as text.
1630
1919
  *
1631
- * @returns A promise that resolves to the response text
1920
+ * @returns A promise that resolves to the response body as a string
1921
+ * @throws {RequestError} When the request fails or reading the response fails
1632
1922
  *
1633
1923
  * @example
1924
+ * ```typescript
1634
1925
  * const text = await request.getText();
1926
+ * console.log(text); // "Hello, world!"
1927
+ * ```
1635
1928
  */
1636
1929
  async getText() {
1637
1930
  const response = await this.getResponse();
1638
1931
  return response.getText();
1639
1932
  }
1640
1933
  /**
1641
- * Execute the request and get the response as a Blob
1934
+ * Execute the request and get the response body as a Blob.
1935
+ * Useful for downloading files or handling binary data.
1642
1936
  *
1643
- * @returns A promise that resolves to the response Blob
1937
+ * @returns A promise that resolves to the response body as a Blob
1938
+ * @throws {RequestError} When the request fails or reading the response fails
1644
1939
  *
1645
1940
  * @example
1941
+ * ```typescript
1646
1942
  * const blob = await request.getBlob();
1943
+ * const url = URL.createObjectURL(blob);
1944
+ * // Use the blob URL (e.g., for downloading or displaying)
1945
+ * ```
1647
1946
  */
1648
1947
  async getBlob() {
1649
1948
  const response = await this.getResponse();
1650
1949
  return response.getBlob();
1651
1950
  }
1652
1951
  /**
1653
- * Execute the request and get the response body as a ReadableStream
1952
+ * Execute the request and get the response body as a ReadableStream.
1953
+ * Note: Unlike other methods, streams cannot be cached. The body can only be consumed once.
1654
1954
  *
1655
- * @returns A promise that resolves to the response body stream
1955
+ * @returns A promise that resolves to the response body as a ReadableStream, or `null` if the body is not available
1956
+ * @throws {RequestError} When the request fails or the body has already been consumed
1656
1957
  *
1657
1958
  * @example
1959
+ * ```typescript
1658
1960
  * const stream = await request.getBody();
1961
+ * if (stream) {
1962
+ * const reader = stream.getReader();
1963
+ * // Process the stream chunk by chunk
1964
+ * }
1965
+ * ```
1659
1966
  */
1660
1967
  async getBody() {
1661
1968
  const response = await this.getResponse();
@@ -1741,7 +2048,7 @@ class BaseRequest {
1741
2048
  });
1742
2049
  return urlObj.toString();
1743
2050
  }
1744
- catch (error) {
2051
+ catch (_error) {
1745
2052
  // Handle relative URLs
1746
2053
  const hasExistingParams = url.includes("?");
1747
2054
  const separator = hasExistingParams ? "&" : "?";
@@ -1871,17 +2178,13 @@ class BaseRequest {
1871
2178
  response: currentError.response,
1872
2179
  });
1873
2180
  }
1874
- else if (currentError instanceof ResponseWrapper && currentError.url && currentError.method) {
1875
- // If it's a ResponseWrapper, we can still create a proper RequestError from its context
1876
- currentError = new RequestError(`Err Interceptor ${i + 1} failed: ${errorMessage}`, currentError.url, currentError.method, {
1877
- status: currentError.status,
1878
- });
1879
- }
1880
2181
  else {
2182
+ /* c8 ignore start */
1881
2183
  // Last resort: if we have no context at all, use the original error's context
1882
2184
  // This shouldn't happen in practice, but handle it gracefully
1883
2185
  const errorObj = interceptorError instanceof Error ? interceptorError : new Error(String(interceptorError));
1884
2186
  currentError = RequestError.networkError(error.url, error.method, errorObj);
2187
+ /* c8 ignore end */
1885
2188
  }
1886
2189
  }
1887
2190
  }
@@ -2089,8 +2392,39 @@ class BodyRequest extends BaseRequest {
2089
2392
  super(url);
2090
2393
  }
2091
2394
  /**
2092
- * Sets the body of the request
2093
- * @param body - The request body
2395
+ * Sets the request body. Automatically detects the body type and sets appropriate Content-Type header.
2396
+ * Supports JSON objects/arrays, strings, FormData, Blob, ArrayBuffer, URLSearchParams, and ReadableStream.
2397
+ *
2398
+ * @param body - The request body. Can be:
2399
+ * - A JSON-serializable object or array (automatically stringified)
2400
+ * - A string (sets Content-Type to `text/plain` if not already set)
2401
+ * - FormData, Blob, File, ArrayBuffer, TypedArray, URLSearchParams, or ReadableStream
2402
+ * @returns The request instance for chaining
2403
+ * @throws {RequestError} If the body is a JSON object that cannot be stringified
2404
+ *
2405
+ * @example
2406
+ * ```typescript
2407
+ * // JSON object (automatically stringified)
2408
+ * request.withBody({ name: 'John', age: 30 });
2409
+ *
2410
+ * @example
2411
+ * // JSON array
2412
+ * request.withBody([1, 2, 3]);
2413
+ *
2414
+ * @example
2415
+ * // String
2416
+ * request.withBody('plain text');
2417
+ *
2418
+ * @example
2419
+ * // FormData
2420
+ * const formData = new FormData();
2421
+ * formData.append('file', fileBlob);
2422
+ * request.withBody(formData);
2423
+ *
2424
+ * @example
2425
+ * // Blob
2426
+ * request.withBody(new Blob(['content'], { type: 'text/plain' }));
2427
+ * ```
2094
2428
  */
2095
2429
  withBody(body) {
2096
2430
  this.body = body;
@@ -2125,26 +2459,41 @@ class BodyRequest extends BaseRequest {
2125
2459
  return this;
2126
2460
  }
2127
2461
  /**
2128
- * Sets a GraphQL query or mutation as the request body
2129
- * Automatically formats the body as JSON and sets Content-Type to application/json
2462
+ * Sets a GraphQL query or mutation as the request body.
2463
+ * Automatically formats the body as JSON and sets Content-Type to `application/json`.
2464
+ * If `throwOnError` is enabled in options, the response will be checked for GraphQL errors
2465
+ * and a RequestError will be thrown if any are found.
2130
2466
  *
2131
- * @param query - The GraphQL query or mutation string
2132
- * @param variables - Optional variables object to pass with the query
2467
+ * @param query - The GraphQL query or mutation string (e.g., `'query { user { id } }'`)
2468
+ * @param variables - Optional variables object to pass with the query. Must be a plain object.
2133
2469
  * @param options - Optional GraphQL-specific options
2470
+ * @param options.throwOnError - If `true`, throws a RequestError when the GraphQL response contains errors
2134
2471
  * @returns The request instance for chaining
2472
+ * @throws {RequestError} If the query is empty, variables is invalid, or JSON stringification fails
2135
2473
  *
2136
2474
  * @example
2137
- * const request = new PostRequest('/graphql')
2475
+ * ```typescript
2476
+ * // Simple query with variables
2477
+ * const request = create.post('/graphql')
2138
2478
  * .withGraphQL('query { user(id: $id) { name email } }', { id: '123' });
2479
+ * const data = await request.getJson();
2480
+ * ```
2139
2481
  *
2140
2482
  * @example
2141
- * const request = new PostRequest('/graphql')
2483
+ * ```typescript
2484
+ * // Mutation with variables
2485
+ * const request = create.post('/graphql')
2142
2486
  * .withGraphQL('mutation { createUser(name: $name) { id } }', { name: 'John' });
2487
+ * ```
2143
2488
  *
2144
2489
  * @example
2145
- * // Throw an error if the GraphQL response contains errors
2146
- * const request = new PostRequest('/graphql')
2490
+ * ```typescript
2491
+ * // Throw error if GraphQL response contains errors
2492
+ * const request = create.post('/graphql')
2147
2493
  * .withGraphQL('query { user { id } }', undefined, { throwOnError: true });
2494
+ * // If the response has errors, this will throw a RequestError
2495
+ * const data = await request.getJson();
2496
+ * ```
2148
2497
  */
2149
2498
  withGraphQL(query, variables, options) {
2150
2499
  if (typeof query !== "string" || query.length === 0) {
@@ -2659,7 +3008,7 @@ class ApiBuilder {
2659
3008
  return propertyValue;
2660
3009
  }
2661
3010
  if (typeof prop === "string" && prop.startsWith("with") && prop !== "withBaseURL") {
2662
- if (prop === "withAbortController" || prop === "withBody" || prop === "withGraphQL")
3011
+ if (prop === "withAbortController" || prop === "withBody" || prop === "withGraphQL" || prop === "withQueryParam" || prop === "withQueryParams")
2663
3012
  return undefined;
2664
3013
  const prototypeMethod = BaseRequest.prototype[prop];
2665
3014
  if (typeof prototypeMethod === "function") {
@@ -2700,8 +3049,28 @@ function api() {
2700
3049
  }
2701
3050
 
2702
3051
  /**
2703
- * Main API object for creating HTTP requests
3052
+ * Main API object for creating HTTP requests.
2704
3053
  * Provides factory methods for all HTTP methods and access to global configuration.
3054
+ *
3055
+ * @example
3056
+ * ```typescript
3057
+ * import create from 'create-request';
3058
+ *
3059
+ * // Simple GET request
3060
+ * const users = await create.get('/api/users').getJson();
3061
+ *
3062
+ * // POST request with body
3063
+ * const newUser = await create.post('/api/users')
3064
+ * .withJson({ name: 'John', email: 'john@example.com' })
3065
+ * .getJson();
3066
+ *
3067
+ * // Configure API instance with defaults
3068
+ * const api = create.api()
3069
+ * .withBaseURL('https://api.example.com')
3070
+ * .withBearerToken('token123');
3071
+ *
3072
+ * const data = await api.get('/users').getJson();
3073
+ * ```
2705
3074
  */
2706
3075
  const create = {
2707
3076
  api,
@@ -2725,5 +3094,13 @@ exports.PostRequest = PostRequest;
2725
3094
  exports.PutRequest = PutRequest;
2726
3095
  exports.RequestError = RequestError;
2727
3096
  exports.ResponseWrapper = ResponseWrapper;
3097
+ exports.api = api;
2728
3098
  exports["default"] = create;
3099
+ exports.del = del;
3100
+ exports.get = get;
3101
+ exports.head = head;
3102
+ exports.options = options;
3103
+ exports.patch = patch;
3104
+ exports.post = post;
3105
+ exports.put = put;
2729
3106
  //# sourceMappingURL=index.cjs.map