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.
- package/README.md +150 -20
- package/dist/library/BaseRequest.d.ts +182 -37
- package/dist/library/BodyRequest.d.ts +56 -10
- package/dist/library/RequestError.d.ts +99 -1
- package/dist/library/ResponseWrapper.d.ts +53 -10
- package/dist/library/apiBuilder.d.ts +20 -20
- package/dist/library/index.cjs +435 -62
- package/dist/library/index.cjs.map +1 -1
- package/dist/library/index.d.ts +21 -1
- package/dist/library/index.esm.js +435 -62
- package/dist/library/index.esm.js.map +1 -1
- package/dist/library/index.esm.min.js +1 -1
- package/dist/library/index.esm.min.js.map +1 -1
- package/dist/library/index.min.cjs +1 -1
- package/dist/library/index.min.cjs.map +1 -1
- package/dist/library/types.d.ts +233 -19
- package/package.json +15 -8
|
@@ -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
|
-
*
|
|
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
|
-
|
|
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 =>
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
1324
|
-
*
|
|
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
|
-
*
|
|
1344
|
-
*
|
|
1345
|
-
* @
|
|
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
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
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
|
-
*
|
|
1396
|
-
*
|
|
1397
|
-
*
|
|
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
|
-
*
|
|
1404
|
-
*
|
|
1405
|
-
*
|
|
1406
|
-
* @
|
|
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
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
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
|
-
*
|
|
1462
|
-
*
|
|
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
|
-
*
|
|
1501
|
-
*
|
|
1502
|
-
*
|
|
1503
|
-
* @
|
|
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
|
-
*
|
|
1511
|
-
*
|
|
1512
|
-
* @
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
2087
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
2140
|
-
*
|
|
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,
|