create-request 0.0.1-beta.7 → 0.0.1-beta.9
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 +215 -128
- package/dist/library/BaseRequest.d.ts +7 -0
- package/dist/library/ResponseWrapper.d.ts +1 -0
- package/dist/library/enums.d.ts +13 -0
- package/dist/library/index.d.ts +1 -1
- package/dist/library/index.esm.js +52 -1
- package/dist/library/index.js +51 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,28 +8,58 @@
|
|
|
8
8
|
|
|
9
9
|
## Core Features
|
|
10
10
|
|
|
11
|
-
- ⛓️ **Chainable API** - Build and execute requests with a fluent interface
|
|
12
11
|
- ⏱️ **Timeout Support** - Set timeouts for any request
|
|
13
|
-
-
|
|
14
|
-
- 🔐 **Auth Helpers** - Simple methods for common authentication patterns
|
|
15
|
-
- 📦 **Typed Responses** - Full TypeScript support for response data
|
|
12
|
+
- 🚀 **Performance** - Tiny bundle size with zero dependencies
|
|
16
13
|
- 🚧 **Error Handling** - Detailed error info with custom error class
|
|
14
|
+
- 🔐 **Auth Helpers** - Simple methods for common authentication patterns
|
|
15
|
+
- ⛓️ **Chainable API** - Build and execute requests with a fluent interface
|
|
16
|
+
- 📉 **Reduced Boilerplate** - Write 60% less code for common API operations
|
|
17
|
+
- 🔁 **Automatic Retries** - Retry failed requests with customizable settings
|
|
18
|
+
- 🛡️ **Type Safety** - Full TypeScript support with intelligent type inference
|
|
17
19
|
- 📝 **Response Caching** - Flexible caching system with multiple storage options
|
|
18
20
|
|
|
19
21
|
## Why create-request?
|
|
20
22
|
|
|
21
|
-
**
|
|
23
|
+
**API interactions often require repetitive code patterns** - handling HTTP status checks, parsing responses, managing errors, and dealing with TypeScript types. `create-request` provides a clean, efficient solution with an elegant API that separates request building from execution:
|
|
22
24
|
|
|
23
25
|
```typescript
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
// Before: Regular fetch
|
|
27
|
+
async function createUser(userData) {
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch('https://api.example.com/users', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
'Authorization': 'Basic ' + btoa('username:password')
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(userData)
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
40
|
+
}
|
|
41
|
+
const data = await response.json();
|
|
42
|
+
return data;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Fetch error:', error);
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// After: With create-request
|
|
50
|
+
import create from 'create-request';
|
|
29
51
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
52
|
+
function createUser(userData) {
|
|
53
|
+
return create.post()
|
|
54
|
+
.withBasicAuth('username', 'password')
|
|
55
|
+
.withBody(userData)
|
|
56
|
+
.sendTo('https://api.example.com/users')
|
|
57
|
+
.getData<User>()
|
|
58
|
+
.catch(error => {
|
|
59
|
+
console.error('Fetch error:', error);
|
|
60
|
+
throw error;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
33
63
|
```
|
|
34
64
|
|
|
35
65
|
## Installation
|
|
@@ -44,67 +74,6 @@ Or with yarn:
|
|
|
44
74
|
yarn add create-request
|
|
45
75
|
```
|
|
46
76
|
|
|
47
|
-
## 🔄 Fetch API Comparison
|
|
48
|
-
|
|
49
|
-
### Fetch API
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
// Basic GET request with fetch
|
|
53
|
-
try {
|
|
54
|
-
const response = await fetch('https://api.example.com/users');
|
|
55
|
-
if (!response.ok) {
|
|
56
|
-
throw new Error(`HTTP error ${response.status}`);
|
|
57
|
-
}
|
|
58
|
-
const users = await response.json();
|
|
59
|
-
console.log(users);
|
|
60
|
-
} catch (error) {
|
|
61
|
-
console.error('Error fetching users:', error);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// POST request with fetch
|
|
65
|
-
try {
|
|
66
|
-
const response = await fetch('https://api.example.com/users', {
|
|
67
|
-
method: 'POST',
|
|
68
|
-
headers: {
|
|
69
|
-
'Content-Type': 'application/json',
|
|
70
|
-
'Authorization': 'Bearer token123'
|
|
71
|
-
},
|
|
72
|
-
body: JSON.stringify({ name: 'John Doe', email: 'john@example.com' })
|
|
73
|
-
});
|
|
74
|
-
if (!response.ok) {
|
|
75
|
-
throw new Error(`HTTP error ${response.status}`);
|
|
76
|
-
}
|
|
77
|
-
const result = await response.json();
|
|
78
|
-
console.log(result);
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error('Error creating user:', error);
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### create-request API
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
// Basic GET request with create-request
|
|
88
|
-
try {
|
|
89
|
-
const users = await create.get().sendTo('https://api.example.com/users').getJson();
|
|
90
|
-
console.log(users);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.error('Error fetching users:', error.message);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// POST request with create-request
|
|
96
|
-
const createUserRequest = create.post()
|
|
97
|
-
.withBody({ name: 'John Doe', email: 'john@example.com' })
|
|
98
|
-
.withBearerToken('token123');
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
const result = await createUserRequest.sendTo('https://api.example.com/users').getJson();
|
|
102
|
-
console.log(result);
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error('Error creating user:', error.message);
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
77
|
## Basic Usage
|
|
109
78
|
|
|
110
79
|
### Creating Requests
|
|
@@ -124,30 +93,75 @@ const optionsRequest = create.options();
|
|
|
124
93
|
|
|
125
94
|
### Request Configuration
|
|
126
95
|
|
|
96
|
+
The library provides a comprehensive set of configuration methods that can be chained together to customize your requests:
|
|
97
|
+
|
|
127
98
|
```typescript
|
|
128
|
-
import { RequestPriority, CredentialsPolicy } from 'create-request';
|
|
99
|
+
import create, { RequestPriority, CredentialsPolicy, RequestMode, CacheMode, RedirectMode, ReferrerPolicy } from 'create-request';
|
|
129
100
|
|
|
130
101
|
// Configure request options
|
|
131
102
|
const request = create.get()
|
|
132
|
-
//
|
|
133
|
-
.withHeaders({ 'X-API-Key': 'abc123' })
|
|
103
|
+
// Basic headers
|
|
104
|
+
.withHeaders({ 'X-API-Key': 'abc123', 'Accept-Language': 'en-US' })
|
|
105
|
+
.withHeader('Custom-Header', 'value') // Add a single header
|
|
134
106
|
|
|
135
|
-
// Timeout
|
|
136
|
-
.withTimeout(5000)
|
|
137
|
-
|
|
107
|
+
// Timeout settings
|
|
108
|
+
.withTimeout(5000) // Request will abort after 5 seconds
|
|
109
|
+
|
|
110
|
+
// Automatic retry configuration
|
|
111
|
+
.withRetries(3) // Retry up to 3 times on failure
|
|
138
112
|
.onRetry(({ attempt, error }) => {
|
|
139
|
-
console.log(`Attempt ${attempt} failed: ${error.message}
|
|
113
|
+
console.log(`Attempt ${attempt} failed: ${error.message}. Retrying...`);
|
|
140
114
|
})
|
|
141
115
|
|
|
142
|
-
// Authentication
|
|
143
|
-
.withBearerToken('your-token')
|
|
116
|
+
// Authentication methods
|
|
117
|
+
.withBearerToken('your-token') // Adds Authorization: Bearer your-token
|
|
118
|
+
.withBasicAuth('username', 'password') // HTTP Basic Authentication
|
|
119
|
+
|
|
120
|
+
// URL parameters
|
|
121
|
+
.withQueryParams({ search: 'term', page: 1, limit: 20 })
|
|
122
|
+
.withQueryParam('filter', 'active') // Add a single query parameter
|
|
144
123
|
|
|
145
|
-
//
|
|
146
|
-
.
|
|
124
|
+
// Request body configuration (for POST/PUT/PATCH)
|
|
125
|
+
.withContentType('application/json') // Set specific content type
|
|
147
126
|
|
|
148
|
-
//
|
|
149
|
-
.withCredentials(CredentialsPolicy.INCLUDE)
|
|
150
|
-
.
|
|
127
|
+
// Fetch API options
|
|
128
|
+
.withCredentials(CredentialsPolicy.INCLUDE) // Includes cookies with cross-origin requests
|
|
129
|
+
.withMode(RequestMode.CORS) // Controls CORS behavior
|
|
130
|
+
.withRedirect(RedirectMode.FOLLOW) // Controls redirect behavior (follow, error, manual)
|
|
131
|
+
.withReferrer('https://example.com') // Sets request referrer
|
|
132
|
+
.withReferrerPolicy(ReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE) // Controls referrer policy
|
|
133
|
+
.withPriority(RequestPriority.HIGH) // Sets request priority
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Each configuration method returns the request object, allowing for a fluent interface where methods can be chained together. You can configure only what you need for a specific request:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Simple example with just what's needed
|
|
140
|
+
const searchUsers = create.get()
|
|
141
|
+
.withBearerToken(userToken)
|
|
142
|
+
.withQueryParams({ q: searchTerm, limit: 20 })
|
|
143
|
+
.withTimeout(3000);
|
|
144
|
+
|
|
145
|
+
// Now execute the request
|
|
146
|
+
const users = await searchUsers.sendTo('https://api.example.com/users').getData();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
You can also create reusable base requests with common settings:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// Create base authenticated request
|
|
153
|
+
const apiBase = create.get()
|
|
154
|
+
.withHeaders({
|
|
155
|
+
'X-API-Version': '1.2',
|
|
156
|
+
'Accept-Language': 'en-US'
|
|
157
|
+
})
|
|
158
|
+
.withBearerToken(authToken)
|
|
159
|
+
.withTimeout(5000)
|
|
160
|
+
.withRetries(2);
|
|
161
|
+
|
|
162
|
+
// Use the base request for different endpoints
|
|
163
|
+
const users = await apiBase.sendTo('https://api.example.com/users').getData();
|
|
164
|
+
const products = await apiBase.sendTo('https://api.example.com/products').getData();
|
|
151
165
|
```
|
|
152
166
|
|
|
153
167
|
### Request Bodies (POST/PUT/PATCH)
|
|
@@ -182,6 +196,56 @@ const textData = await request.sendTo('https://api.example.com/endpoint').getTex
|
|
|
182
196
|
const blobData = await request.sendTo('https://api.example.com/endpoint').getBlob();
|
|
183
197
|
const bodyStream = await request.sendTo('https://api.example.com/endpoint').getBody();
|
|
184
198
|
const arrayBuffer = await request.sendTo('https://api.example.com/endpoint').getArrayBuffer();
|
|
199
|
+
|
|
200
|
+
// Using the data selector API to extract specific data
|
|
201
|
+
const userData = await request.sendTo('https://api.example.com/users')
|
|
202
|
+
.getData(data => data.results.users);
|
|
203
|
+
|
|
204
|
+
// Using the data selector without a selector function just returns the full JSON response
|
|
205
|
+
const fullData = await request.sendTo('https://api.example.com/data').getData();
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Data Selection
|
|
209
|
+
|
|
210
|
+
The `getData` method provides a powerful way to extract and transform specific data from API responses:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Extract specific properties from nested structures
|
|
214
|
+
const posts = await request
|
|
215
|
+
.sendTo('https://api.example.com/feed')
|
|
216
|
+
.getData(data => data.feed.posts);
|
|
217
|
+
|
|
218
|
+
// Transform data in the selector function
|
|
219
|
+
const usernames = await request
|
|
220
|
+
.sendTo('https://api.example.com/users')
|
|
221
|
+
.getData(data => data.users.map(user => user.username));
|
|
222
|
+
|
|
223
|
+
// Apply filtering in the selector
|
|
224
|
+
const activeUsers = await request
|
|
225
|
+
.sendTo('https://api.example.com/users')
|
|
226
|
+
.getData(data => data.users.filter(user => user.isActive));
|
|
227
|
+
|
|
228
|
+
// Combine data from complex nested structures
|
|
229
|
+
const combinedData = await request
|
|
230
|
+
.sendTo('https://api.example.com/dashboard')
|
|
231
|
+
.getData(data => ({
|
|
232
|
+
userCount: data.stats.users.total,
|
|
233
|
+
recentPosts: data.content.recent.slice(0, 5),
|
|
234
|
+
notifications: data.user.notifications.unread
|
|
235
|
+
}));
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
When a selector fails, the error message will contain the original response data to help diagnose the issue:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
try {
|
|
242
|
+
const result = await request
|
|
243
|
+
.sendTo('https://api.example.com/data')
|
|
244
|
+
.getData(data => data.results.items); // Will fail if structure is different
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error(error);
|
|
247
|
+
// Error message includes the original response data
|
|
248
|
+
}
|
|
185
249
|
```
|
|
186
250
|
|
|
187
251
|
### Error Handling
|
|
@@ -285,12 +349,33 @@ interface User {
|
|
|
285
349
|
email: string;
|
|
286
350
|
}
|
|
287
351
|
|
|
352
|
+
interface ApiResponse {
|
|
353
|
+
users: User[];
|
|
354
|
+
pagination: {
|
|
355
|
+
total: number;
|
|
356
|
+
page: number;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
288
360
|
const userRequest = create.get();
|
|
289
|
-
const user = await userRequest.sendTo('https://api.example.com/user/123')
|
|
290
|
-
.getJson<User>();
|
|
291
361
|
|
|
292
|
-
//
|
|
293
|
-
|
|
362
|
+
// Type the full response
|
|
363
|
+
const response = await userRequest
|
|
364
|
+
.sendTo('https://api.example.com/users')
|
|
365
|
+
.getJson<ApiResponse>();
|
|
366
|
+
|
|
367
|
+
// Or use getData with type parameters
|
|
368
|
+
const users = await userRequest
|
|
369
|
+
.sendTo('https://api.example.com/users')
|
|
370
|
+
.getData<ApiResponse, User[]>(data => data.users);
|
|
371
|
+
|
|
372
|
+
// Or just get the full typed response
|
|
373
|
+
const fullData = await userRequest
|
|
374
|
+
.sendTo('https://api.example.com/users')
|
|
375
|
+
.getData<ApiResponse>();
|
|
376
|
+
|
|
377
|
+
// TypeScript knows the types
|
|
378
|
+
console.log(users[0].name);
|
|
294
379
|
```
|
|
295
380
|
|
|
296
381
|
### Promise Chaining
|
|
@@ -323,39 +408,11 @@ const request = create.get()
|
|
|
323
408
|
keyGenerator: (url, method, headers) => {
|
|
324
409
|
// Include user ID from authorization header in the cache key
|
|
325
410
|
const authHeader = headers?.['Authorization'] || '';
|
|
326
|
-
const
|
|
327
|
-
|
|
411
|
+
const userMatch = authHeader.match(/User-(\d+)/);
|
|
412
|
+
const userId = userMatch ? userMatch[1] : 'anonymous';
|
|
413
|
+
return `${method}:${userId}:${url}`;
|
|
328
414
|
}
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
// Simple custom storage provider example
|
|
332
|
-
const customStorage: StorageProvider = {
|
|
333
|
-
get(key: string): string | null {
|
|
334
|
-
// Get from your custom storage
|
|
335
|
-
return localStorage.getItem(`my-app:${key}`);
|
|
336
|
-
},
|
|
337
|
-
set(key: string, value: string): void {
|
|
338
|
-
// Set in your custom storage
|
|
339
|
-
localStorage.setItem(`my-app:${key}`, value);
|
|
340
|
-
},
|
|
341
|
-
has(key: string): boolean {
|
|
342
|
-
// Check if exists in your custom storage
|
|
343
|
-
return localStorage.getItem(`my-app:${key}`) !== null;
|
|
344
|
-
},
|
|
345
|
-
delete(key: string): void {
|
|
346
|
-
// Remove from your custom storage
|
|
347
|
-
localStorage.removeItem(`my-app:${key}`);
|
|
348
|
-
},
|
|
349
|
-
clear(): void {
|
|
350
|
-
// Clear all items from your namespace
|
|
351
|
-
Object.keys(localStorage)
|
|
352
|
-
.filter(key => key.startsWith('my-app:'))
|
|
353
|
-
.forEach(key => localStorage.removeItem(key));
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
const request = create.get()
|
|
358
|
-
.withCache({ storage: customStorage })
|
|
415
|
+
})
|
|
359
416
|
.sendTo('https://api.example.com/data');
|
|
360
417
|
```
|
|
361
418
|
|
|
@@ -424,24 +481,54 @@ With custom storage providers, you can integrate with any storage system, such a
|
|
|
424
481
|
|
|
425
482
|
## CSRF Protection
|
|
426
483
|
|
|
484
|
+
Cross-Site Request Forgery (CSRF) is a type of security vulnerability where unauthorized commands are executed on behalf of an authenticated user. `create-request` provides built-in protection mechanisms to help prevent CSRF attacks.
|
|
485
|
+
|
|
486
|
+
### How CSRF Protection Works
|
|
487
|
+
|
|
488
|
+
The library employs multiple strategies to protect against CSRF attacks:
|
|
489
|
+
|
|
490
|
+
1. **Automatic X-Requested-With Header**: By default, all requests include the `X-Requested-With: XMLHttpRequest` header, which helps servers identify legitimate AJAX requests.
|
|
491
|
+
|
|
492
|
+
2. **CSRF Token Support**: The library can automatically include CSRF tokens in request headers, which servers can validate to ensure the request came from your application.
|
|
493
|
+
|
|
494
|
+
3. **XSRF Cookie Reading**: For frameworks that use the double-submit cookie pattern (like Laravel, Rails, or Django), the library can automatically read XSRF tokens from cookies and include them in request headers.
|
|
495
|
+
|
|
427
496
|
### Global CSRF Configuration
|
|
428
497
|
|
|
498
|
+
You can configure CSRF settings globally for all requests:
|
|
499
|
+
|
|
429
500
|
```typescript
|
|
430
501
|
// Configure CSRF settings for all requests
|
|
431
502
|
create.config.setCsrfToken('your-csrf-token');
|
|
432
|
-
create.config.setCsrfHeaderName('X-CSRF-Token');
|
|
433
|
-
create.config.setXsrfCookieName('XSRF-TOKEN');
|
|
503
|
+
create.config.setCsrfHeaderName('X-CSRF-Token'); // Default header name
|
|
504
|
+
create.config.setXsrfCookieName('XSRF-TOKEN'); // Default cookie name
|
|
505
|
+
create.config.setEnableAntiCsrf(true); // Enable/disable X-Requested-With header
|
|
506
|
+
create.config.setEnableAutoXsrf(true); // Enable/disable automatic cookie-to-header token
|
|
434
507
|
```
|
|
435
508
|
|
|
436
509
|
### Per-Request CSRF Settings
|
|
437
510
|
|
|
511
|
+
You can also configure CSRF protection on individual requests:
|
|
512
|
+
|
|
438
513
|
```typescript
|
|
439
514
|
// Configure CSRF for a specific request
|
|
440
515
|
const request = create.post()
|
|
441
|
-
.withCsrfToken('request-specific-token')
|
|
442
|
-
.
|
|
516
|
+
.withCsrfToken('request-specific-token') // Set a specific token
|
|
517
|
+
.withAntiCsrfHeaders() // Explicitly add X-Requested-With header
|
|
518
|
+
.withoutCsrfProtection(); // Or disable all automatic CSRF protection
|
|
443
519
|
```
|
|
444
520
|
|
|
521
|
+
### Integrating with Backend Frameworks
|
|
522
|
+
|
|
523
|
+
Most modern frameworks support CSRF protection out of the box. The library works seamlessly with:
|
|
524
|
+
|
|
525
|
+
- **Laravel**: Automatically reads XSRF-TOKEN cookie and sends X-XSRF-TOKEN header
|
|
526
|
+
- **Rails**: Works with the Rails CSRF token system
|
|
527
|
+
- **Django**: Compatible with Django's CSRF middleware
|
|
528
|
+
- **Express.js + csurf**: Works with the csurf middleware token pattern
|
|
529
|
+
|
|
530
|
+
When your server sends a CSRF token in a cookie or response header, `create-request` can automatically extract and include it in subsequent requests.
|
|
531
|
+
|
|
445
532
|
## Browser Support
|
|
446
533
|
|
|
447
534
|
This library works with all browsers that support the Fetch API:
|
|
@@ -13,6 +13,7 @@ export declare abstract class BaseRequest {
|
|
|
13
13
|
protected cacheEnabled: boolean;
|
|
14
14
|
constructor();
|
|
15
15
|
withHeaders(headers: Record<string, string>): this;
|
|
16
|
+
withHeader(key: string, value: string): this;
|
|
16
17
|
withTimeout(timeout: number): this;
|
|
17
18
|
withRetries(retries: number): this;
|
|
18
19
|
onRetry(callback: RetryCallback): this;
|
|
@@ -34,6 +35,12 @@ export declare abstract class BaseRequest {
|
|
|
34
35
|
* @returns The instance for chaining
|
|
35
36
|
*/
|
|
36
37
|
withReferrer(referrer: string): this;
|
|
38
|
+
/**
|
|
39
|
+
* Sets the referrer policy for the request
|
|
40
|
+
* @param policy - The referrer policy to use
|
|
41
|
+
* @returns The instance for chaining
|
|
42
|
+
*/
|
|
43
|
+
withReferrerPolicy(policy: ReferrerPolicy): this;
|
|
37
44
|
/**
|
|
38
45
|
* Sets the redirect policy for the request
|
|
39
46
|
* @param redirect - Can be 'follow', 'error', or 'manual'
|
|
@@ -29,4 +29,5 @@ export interface ResponsePromise<T = ResponseWrapper> extends Promise<T> {
|
|
|
29
29
|
getBlob(): Promise<Blob>;
|
|
30
30
|
getArrayBuffer(): Promise<ArrayBuffer>;
|
|
31
31
|
getBody(): Promise<ReadableStream<Uint8Array> | null>;
|
|
32
|
+
getData<T = unknown, R = T>(selector?: (data: T) => R): Promise<T | R>;
|
|
32
33
|
}
|
package/dist/library/enums.d.ts
CHANGED
|
@@ -70,3 +70,16 @@ export declare enum BodyType {
|
|
|
70
70
|
STRING = "string",
|
|
71
71
|
BINARY = "binary"
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Referrer policies for fetch requests
|
|
75
|
+
*/
|
|
76
|
+
export declare enum ReferrerPolicy {
|
|
77
|
+
ORIGIN = "origin",
|
|
78
|
+
UNSAFE_URL = "unsafe-url",
|
|
79
|
+
SAME_ORIGIN = "same-origin",
|
|
80
|
+
NO_REFERRER = "no-referrer",
|
|
81
|
+
STRICT_ORIGIN = "strict-origin",
|
|
82
|
+
ORIGIN_WHEN_CROSS_ORIGIN = "origin-when-cross-origin",
|
|
83
|
+
NO_REFERRER_WHEN_DOWNGRADE = "no-referrer-when-downgrade",
|
|
84
|
+
STRICT_ORIGIN_WHEN_CROSS_ORIGIN = "strict-origin-when-cross-origin"
|
|
85
|
+
}
|
package/dist/library/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { get, put, head, post, patch, del, options } from "./requestFactories";
|
|
2
2
|
import { Config } from "./utils/Config";
|
|
3
|
-
export { HttpMethod, RequestPriority, CredentialsPolicy, RequestMode, RedirectMode, CacheMode, SameSitePolicy } from "./enums";
|
|
3
|
+
export { HttpMethod, RequestPriority, CredentialsPolicy, RequestMode, RedirectMode, CacheMode, SameSitePolicy, ReferrerPolicy } from "./enums";
|
|
4
4
|
export type { RetryCallback, RequestOptions, CookieOptions, CookiesRecord } from "./types";
|
|
5
5
|
export { RequestError } from "./RequestError";
|
|
6
6
|
export { ResponseWrapper } from "./ResponseWrapper";
|
|
@@ -78,6 +78,20 @@ var BodyType;
|
|
|
78
78
|
BodyType["STRING"] = "string";
|
|
79
79
|
BodyType["BINARY"] = "binary";
|
|
80
80
|
})(BodyType || (BodyType = {}));
|
|
81
|
+
/**
|
|
82
|
+
* Referrer policies for fetch requests
|
|
83
|
+
*/
|
|
84
|
+
var ReferrerPolicy;
|
|
85
|
+
(function (ReferrerPolicy) {
|
|
86
|
+
ReferrerPolicy["ORIGIN"] = "origin";
|
|
87
|
+
ReferrerPolicy["UNSAFE_URL"] = "unsafe-url";
|
|
88
|
+
ReferrerPolicy["SAME_ORIGIN"] = "same-origin";
|
|
89
|
+
ReferrerPolicy["NO_REFERRER"] = "no-referrer";
|
|
90
|
+
ReferrerPolicy["STRICT_ORIGIN"] = "strict-origin";
|
|
91
|
+
ReferrerPolicy["ORIGIN_WHEN_CROSS_ORIGIN"] = "origin-when-cross-origin";
|
|
92
|
+
ReferrerPolicy["NO_REFERRER_WHEN_DOWNGRADE"] = "no-referrer-when-downgrade";
|
|
93
|
+
ReferrerPolicy["STRICT_ORIGIN_WHEN_CROSS_ORIGIN"] = "strict-origin-when-cross-origin";
|
|
94
|
+
})(ReferrerPolicy || (ReferrerPolicy = {}));
|
|
81
95
|
|
|
82
96
|
class RequestError extends Error {
|
|
83
97
|
constructor(message, url, method, options = {}) {
|
|
@@ -780,6 +794,9 @@ class BaseRequest {
|
|
|
780
794
|
};
|
|
781
795
|
return this;
|
|
782
796
|
}
|
|
797
|
+
withHeader(key, value) {
|
|
798
|
+
return this.withHeaders({ [key]: value });
|
|
799
|
+
}
|
|
783
800
|
withTimeout(timeout) {
|
|
784
801
|
if (!Number.isFinite(timeout) || timeout <= 0)
|
|
785
802
|
throw new Error("Timeout must be a positive number");
|
|
@@ -823,6 +840,15 @@ class BaseRequest {
|
|
|
823
840
|
this.requestOptions.referrer = referrer;
|
|
824
841
|
return this;
|
|
825
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* Sets the referrer policy for the request
|
|
845
|
+
* @param policy - The referrer policy to use
|
|
846
|
+
* @returns The instance for chaining
|
|
847
|
+
*/
|
|
848
|
+
withReferrerPolicy(policy) {
|
|
849
|
+
this.requestOptions.referrerPolicy = policy;
|
|
850
|
+
return this;
|
|
851
|
+
}
|
|
826
852
|
/**
|
|
827
853
|
* Sets the redirect policy for the request
|
|
828
854
|
* @param redirect - Can be 'follow', 'error', or 'manual'
|
|
@@ -929,6 +955,12 @@ class BaseRequest {
|
|
|
929
955
|
* Works in both browser and Node.js environments
|
|
930
956
|
*/
|
|
931
957
|
encodeBase64(str) {
|
|
958
|
+
// Modern approach using TextEncoder (available in both modern browsers and Node.js)
|
|
959
|
+
if (typeof TextEncoder !== "undefined" && typeof btoa === "function") {
|
|
960
|
+
const encoder = new TextEncoder();
|
|
961
|
+
const bytes = encoder.encode(str);
|
|
962
|
+
return btoa(String.fromCharCode.apply(null, [...new Uint8Array(bytes)]));
|
|
963
|
+
}
|
|
932
964
|
// Browser environment
|
|
933
965
|
if (typeof btoa === "function")
|
|
934
966
|
return btoa(str);
|
|
@@ -1119,6 +1151,25 @@ class BaseRequest {
|
|
|
1119
1151
|
responsePromise.getBody = async () => {
|
|
1120
1152
|
return basePromise.then(response => response.getBody());
|
|
1121
1153
|
};
|
|
1154
|
+
responsePromise.getData = async (selector) => {
|
|
1155
|
+
try {
|
|
1156
|
+
const data = await basePromise.then(response => response.getJson());
|
|
1157
|
+
// If no selector is provided, return the raw JSON data
|
|
1158
|
+
if (!selector)
|
|
1159
|
+
return data;
|
|
1160
|
+
// Apply the selector if provided
|
|
1161
|
+
return selector(data);
|
|
1162
|
+
}
|
|
1163
|
+
catch (error) {
|
|
1164
|
+
if (error instanceof Error) {
|
|
1165
|
+
// If selector fails, enhance the error with the original data
|
|
1166
|
+
const enhancedError = new Error(`Data selector failed: ${error.message}. Original data: ${JSON.stringify(await basePromise.then(response => response.getJson()), null, 2)}`);
|
|
1167
|
+
enhancedError.stack = error.stack;
|
|
1168
|
+
throw enhancedError;
|
|
1169
|
+
}
|
|
1170
|
+
throw error;
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1122
1173
|
return responsePromise;
|
|
1123
1174
|
}
|
|
1124
1175
|
/**
|
|
@@ -1447,4 +1498,4 @@ const create = {
|
|
|
1447
1498
|
config: Config.getInstance(),
|
|
1448
1499
|
};
|
|
1449
1500
|
|
|
1450
|
-
export { CacheManager, CacheMode, CookieUtils, CredentialsPolicy, DeleteRequest, GetRequest, HeadRequest, HttpMethod, OptionsRequest, PatchRequest, PostRequest, PutRequest, RedirectMode, RequestError, RequestMode, RequestPriority, ResponseWrapper, SameSitePolicy, createLocalStorageStorage, createMemoryStorage, createSessionStorageStorage, create as default };
|
|
1501
|
+
export { CacheManager, CacheMode, CookieUtils, CredentialsPolicy, DeleteRequest, GetRequest, HeadRequest, HttpMethod, OptionsRequest, PatchRequest, PostRequest, PutRequest, RedirectMode, ReferrerPolicy, RequestError, RequestMode, RequestPriority, ResponseWrapper, SameSitePolicy, createLocalStorageStorage, createMemoryStorage, createSessionStorageStorage, create as default };
|
package/dist/library/index.js
CHANGED
|
@@ -84,6 +84,20 @@
|
|
|
84
84
|
BodyType["STRING"] = "string";
|
|
85
85
|
BodyType["BINARY"] = "binary";
|
|
86
86
|
})(BodyType || (BodyType = {}));
|
|
87
|
+
/**
|
|
88
|
+
* Referrer policies for fetch requests
|
|
89
|
+
*/
|
|
90
|
+
exports.ReferrerPolicy = void 0;
|
|
91
|
+
(function (ReferrerPolicy) {
|
|
92
|
+
ReferrerPolicy["ORIGIN"] = "origin";
|
|
93
|
+
ReferrerPolicy["UNSAFE_URL"] = "unsafe-url";
|
|
94
|
+
ReferrerPolicy["SAME_ORIGIN"] = "same-origin";
|
|
95
|
+
ReferrerPolicy["NO_REFERRER"] = "no-referrer";
|
|
96
|
+
ReferrerPolicy["STRICT_ORIGIN"] = "strict-origin";
|
|
97
|
+
ReferrerPolicy["ORIGIN_WHEN_CROSS_ORIGIN"] = "origin-when-cross-origin";
|
|
98
|
+
ReferrerPolicy["NO_REFERRER_WHEN_DOWNGRADE"] = "no-referrer-when-downgrade";
|
|
99
|
+
ReferrerPolicy["STRICT_ORIGIN_WHEN_CROSS_ORIGIN"] = "strict-origin-when-cross-origin";
|
|
100
|
+
})(exports.ReferrerPolicy || (exports.ReferrerPolicy = {}));
|
|
87
101
|
|
|
88
102
|
class RequestError extends Error {
|
|
89
103
|
constructor(message, url, method, options = {}) {
|
|
@@ -786,6 +800,9 @@
|
|
|
786
800
|
};
|
|
787
801
|
return this;
|
|
788
802
|
}
|
|
803
|
+
withHeader(key, value) {
|
|
804
|
+
return this.withHeaders({ [key]: value });
|
|
805
|
+
}
|
|
789
806
|
withTimeout(timeout) {
|
|
790
807
|
if (!Number.isFinite(timeout) || timeout <= 0)
|
|
791
808
|
throw new Error("Timeout must be a positive number");
|
|
@@ -829,6 +846,15 @@
|
|
|
829
846
|
this.requestOptions.referrer = referrer;
|
|
830
847
|
return this;
|
|
831
848
|
}
|
|
849
|
+
/**
|
|
850
|
+
* Sets the referrer policy for the request
|
|
851
|
+
* @param policy - The referrer policy to use
|
|
852
|
+
* @returns The instance for chaining
|
|
853
|
+
*/
|
|
854
|
+
withReferrerPolicy(policy) {
|
|
855
|
+
this.requestOptions.referrerPolicy = policy;
|
|
856
|
+
return this;
|
|
857
|
+
}
|
|
832
858
|
/**
|
|
833
859
|
* Sets the redirect policy for the request
|
|
834
860
|
* @param redirect - Can be 'follow', 'error', or 'manual'
|
|
@@ -935,6 +961,12 @@
|
|
|
935
961
|
* Works in both browser and Node.js environments
|
|
936
962
|
*/
|
|
937
963
|
encodeBase64(str) {
|
|
964
|
+
// Modern approach using TextEncoder (available in both modern browsers and Node.js)
|
|
965
|
+
if (typeof TextEncoder !== "undefined" && typeof btoa === "function") {
|
|
966
|
+
const encoder = new TextEncoder();
|
|
967
|
+
const bytes = encoder.encode(str);
|
|
968
|
+
return btoa(String.fromCharCode.apply(null, [...new Uint8Array(bytes)]));
|
|
969
|
+
}
|
|
938
970
|
// Browser environment
|
|
939
971
|
if (typeof btoa === "function")
|
|
940
972
|
return btoa(str);
|
|
@@ -1125,6 +1157,25 @@
|
|
|
1125
1157
|
responsePromise.getBody = async () => {
|
|
1126
1158
|
return basePromise.then(response => response.getBody());
|
|
1127
1159
|
};
|
|
1160
|
+
responsePromise.getData = async (selector) => {
|
|
1161
|
+
try {
|
|
1162
|
+
const data = await basePromise.then(response => response.getJson());
|
|
1163
|
+
// If no selector is provided, return the raw JSON data
|
|
1164
|
+
if (!selector)
|
|
1165
|
+
return data;
|
|
1166
|
+
// Apply the selector if provided
|
|
1167
|
+
return selector(data);
|
|
1168
|
+
}
|
|
1169
|
+
catch (error) {
|
|
1170
|
+
if (error instanceof Error) {
|
|
1171
|
+
// If selector fails, enhance the error with the original data
|
|
1172
|
+
const enhancedError = new Error(`Data selector failed: ${error.message}. Original data: ${JSON.stringify(await basePromise.then(response => response.getJson()), null, 2)}`);
|
|
1173
|
+
enhancedError.stack = error.stack;
|
|
1174
|
+
throw enhancedError;
|
|
1175
|
+
}
|
|
1176
|
+
throw error;
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1128
1179
|
return responsePromise;
|
|
1129
1180
|
}
|
|
1130
1181
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-request",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.9",
|
|
4
4
|
"description": "A modern, chainable wrapper for fetch with automatic retries, timeouts, comprehensive error handling, and first-class TypeScript support",
|
|
5
5
|
"main": "dist/library/index.js",
|
|
6
6
|
"module": "dist/library/index.esm.js",
|