create-request 1.4.3-rc.2 → 1.4.3-rc.4

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