@indra211/httpease 1.0.0
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/LICENSE +40 -0
- package/README.md +425 -0
- package/package.json +35 -0
- package/src/HttpEase.js +372 -0
- package/src/errors/HttpError.js +27 -0
- package/src/index.js +19 -0
- package/src/interceptors/InterceptorManager.js +67 -0
- package/src/types/index.d.ts +221 -0
- package/src/utils/helpers.js +86 -0
- package/src/utils/progress.js +166 -0
- package/src/utils/transformers.js +45 -0
- package/src/utils/validators.js +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Copyright (c) 2026 INDRA211. All rights reserved.
|
|
2
|
+
|
|
3
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
exclusive intellectual property of INDRA211 ("the Author").
|
|
7
|
+
|
|
8
|
+
PERMITTED USES
|
|
9
|
+
--------------
|
|
10
|
+
You are permitted to:
|
|
11
|
+
- Install and use the Software in your own projects (personal or commercial).
|
|
12
|
+
- Import or require the Software as a dependency in your applications.
|
|
13
|
+
|
|
14
|
+
RESTRICTIONS
|
|
15
|
+
------------
|
|
16
|
+
You are NOT permitted to:
|
|
17
|
+
- Copy, modify, merge, adapt, or create derivative works of the Software.
|
|
18
|
+
- Redistribute, sublicense, sell, or transfer the Software or any portion
|
|
19
|
+
of it to any third party.
|
|
20
|
+
- Submit pull requests, patches, or any form of contribution to this project.
|
|
21
|
+
All updates, improvements, and maintenance are exclusively reserved for
|
|
22
|
+
the Author.
|
|
23
|
+
- Remove or alter this license notice from any copy of the Software.
|
|
24
|
+
|
|
25
|
+
NO CONTRIBUTIONS
|
|
26
|
+
----------------
|
|
27
|
+
This project does not accept external contributions of any kind. The Author
|
|
28
|
+
is the sole maintainer and retains full control over all changes and releases.
|
|
29
|
+
If you discover a bug or have a feature request, you may open an issue for
|
|
30
|
+
the Author's consideration, but no code contributions will be accepted or
|
|
31
|
+
merged.
|
|
32
|
+
|
|
33
|
+
DISCLAIMER
|
|
34
|
+
----------
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
37
|
+
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
38
|
+
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN
|
|
39
|
+
ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN
|
|
40
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# ð HTTP Ease
|
|
2
|
+
|
|
3
|
+
A lightweight, powerful HTTP client for JavaScript & TypeScript â Built on native fetch with automatic retry, interceptors, progress tracking, and more.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/http-ease)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## âĻ Why HTTP Ease?
|
|
9
|
+
|
|
10
|
+
HTTP Ease is a modern HTTP client that combines the simplicity of native `fetch` with the power of Axios, **without any dependencies**.
|
|
11
|
+
|
|
12
|
+
### Key Features
|
|
13
|
+
|
|
14
|
+
- ðŠķ **Lightweight** - Zero dependencies, ~5KB gzipped
|
|
15
|
+
- ð **Built-in Retry** - Automatic retry with exponential backoff (unlike Axios!)
|
|
16
|
+
- ðŊ **Interceptors** - Request and response interceptors like Axios
|
|
17
|
+
- ⥠**Modern** - Built on native Fetch API
|
|
18
|
+
- âąïļ **Timeout Support** - Automatic request cancellation
|
|
19
|
+
- ðĶ **Universal** - Works in Node.js 18+ and all modern browsers
|
|
20
|
+
- ðĻ **TypeScript Ready** - Full type definitions included, zero extra setup
|
|
21
|
+
- ð **Progress Tracking** - Upload & download progress via native streams
|
|
22
|
+
- ð§ **Customizable** - Transform requests/responses, custom validators
|
|
23
|
+
|
|
24
|
+
## ðĶ Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install httpease
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## ðŊ Quick Start
|
|
31
|
+
|
|
32
|
+
### JavaScript
|
|
33
|
+
```javascript
|
|
34
|
+
const httpEase = require('httpease');
|
|
35
|
+
|
|
36
|
+
// Simple GET request
|
|
37
|
+
const response = await httpEase.get('https://api.example.com/users');
|
|
38
|
+
console.log(response.data);
|
|
39
|
+
|
|
40
|
+
// POST request
|
|
41
|
+
const newUser = await httpEase.post('https://api.example.com/users', {
|
|
42
|
+
name: 'John Doe',
|
|
43
|
+
email: 'john@example.com'
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### TypeScript
|
|
48
|
+
```typescript
|
|
49
|
+
import httpEase, { create, HttpEaseResponse } from 'httpease';
|
|
50
|
+
|
|
51
|
+
interface User {
|
|
52
|
+
id: number;
|
|
53
|
+
name: string;
|
|
54
|
+
email: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Fully typed response
|
|
58
|
+
const response = await httpEase.get<User[]>('https://api.example.com/users');
|
|
59
|
+
const users: User[] = response.data; // â
type-safe
|
|
60
|
+
|
|
61
|
+
// Create a typed instance
|
|
62
|
+
const api = create({ baseURL: 'https://api.example.com' });
|
|
63
|
+
|
|
64
|
+
const user = await api.get<User>('/users/1');
|
|
65
|
+
console.log(user.data.name); // â
IntelliSense works
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## ð Documentation
|
|
69
|
+
|
|
70
|
+
### Creating an Instance
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { create } from 'httpease';
|
|
74
|
+
|
|
75
|
+
const api = create({
|
|
76
|
+
baseURL: 'https://api.example.com',
|
|
77
|
+
timeout: 10000,
|
|
78
|
+
headers: {
|
|
79
|
+
'Authorization': 'Bearer YOUR_TOKEN',
|
|
80
|
+
'Content-Type': 'application/json'
|
|
81
|
+
},
|
|
82
|
+
retries: 3,
|
|
83
|
+
retryDelay: 1000
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Making Requests
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// GET
|
|
91
|
+
const users = await api.get('/users');
|
|
92
|
+
const user = await api.get('/users/123');
|
|
93
|
+
|
|
94
|
+
// GET with query parameters
|
|
95
|
+
const filtered = await api.get('/users', {
|
|
96
|
+
params: {
|
|
97
|
+
role: 'admin',
|
|
98
|
+
active: true
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// POST
|
|
103
|
+
const created = await api.post('/users', {
|
|
104
|
+
name: 'Jane Doe',
|
|
105
|
+
email: 'jane@example.com'
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// PUT
|
|
109
|
+
const updated = await api.put('/users/123', { name: 'Jane Smith' });
|
|
110
|
+
|
|
111
|
+
// PATCH
|
|
112
|
+
const patched = await api.patch('/users/123', { email: 'jane.smith@example.com' });
|
|
113
|
+
|
|
114
|
+
// DELETE
|
|
115
|
+
await api.delete('/users/123');
|
|
116
|
+
|
|
117
|
+
// HEAD
|
|
118
|
+
const headers = await api.head('/users/123');
|
|
119
|
+
|
|
120
|
+
// OPTIONS
|
|
121
|
+
const options = await api.options('/users');
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Response Object
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
{
|
|
128
|
+
data: {}, // Parsed response data (auto-JSON)
|
|
129
|
+
status: 200, // HTTP status code
|
|
130
|
+
statusText: 'OK', // HTTP status text
|
|
131
|
+
headers: {}, // Response headers (plain object)
|
|
132
|
+
config: {}, // Request configuration used
|
|
133
|
+
request: {}, // { url, method }
|
|
134
|
+
duration: 234 // Round-trip time in ms
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### TypeScript â Generic Responses
|
|
139
|
+
|
|
140
|
+
No type assertions needed. Pass the expected type as a generic:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
interface Product {
|
|
144
|
+
id: number;
|
|
145
|
+
name: string;
|
|
146
|
+
price: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// api.get<T> â Promise<HttpEaseResponse<T>>
|
|
150
|
+
const { data } = await api.get<Product[]>('/products');
|
|
151
|
+
// ^ Product[] â fully typed, no casting
|
|
152
|
+
|
|
153
|
+
const { data: product } = await api.post<Product>('/products', {
|
|
154
|
+
name: 'Widget',
|
|
155
|
+
price: 9.99
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### ð Progress Tracking
|
|
160
|
+
|
|
161
|
+
Progress tracking works with **zero dependencies** using native `ReadableStream` / `TransformStream` (Node.js 18+, all modern browsers).
|
|
162
|
+
|
|
163
|
+
**Download Progress:**
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const response = await api.get('/files/large-dataset.json', {
|
|
167
|
+
onDownloadProgress: ({ loaded, total, percentage }) => {
|
|
168
|
+
if (total > 0) {
|
|
169
|
+
process.stdout.write(`\rDownloading... ${percentage.toFixed(1)}%`);
|
|
170
|
+
} else {
|
|
171
|
+
console.log(`Downloaded ${loaded} bytes`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
console.log('\nDone!', response.data);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Upload Progress:**
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const payload = JSON.stringify({ items: largeArray });
|
|
182
|
+
|
|
183
|
+
const response = await api.post('/data/import', payload, {
|
|
184
|
+
onUploadProgress: ({ loaded, total, percentage }) => {
|
|
185
|
+
console.log(`Uploading: ${percentage.toFixed(1)}% (${loaded}/${total} bytes)`);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**With FormData (browser):**
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const form = new FormData();
|
|
194
|
+
form.append('file', fileInput.files[0]);
|
|
195
|
+
|
|
196
|
+
await api.post('/upload', form, {
|
|
197
|
+
onUploadProgress: ({ loaded, total, percentage }) => {
|
|
198
|
+
progressBar.style.width = `${percentage}%`;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Progress Event Object:**
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
interface ProgressEvent {
|
|
207
|
+
loaded: number; // bytes transferred so far
|
|
208
|
+
total: number; // total bytes (0 if unknown â no Content-Length)
|
|
209
|
+
percentage: number; // 0â100, or 0 when total is unknown
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
> **Note:** Upload progress requires `TransformStream` (Node.js 18+, Chrome 67+, Firefox 102+, Safari 14.1+). The library falls back silently to a non-streaming body in older environments.
|
|
214
|
+
|
|
215
|
+
### Interceptors
|
|
216
|
+
|
|
217
|
+
**Request Interceptor:**
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
api.interceptors.request.use(
|
|
221
|
+
(config) => {
|
|
222
|
+
// Modify request before sending
|
|
223
|
+
config.headers['X-Custom-Header'] = 'value';
|
|
224
|
+
console.log('Sending request to:', config.url);
|
|
225
|
+
return config;
|
|
226
|
+
},
|
|
227
|
+
(error) => {
|
|
228
|
+
return Promise.reject(error);
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Response Interceptor:**
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
api.interceptors.response.use(
|
|
237
|
+
(response) => {
|
|
238
|
+
console.log('Received:', response.status);
|
|
239
|
+
return response;
|
|
240
|
+
},
|
|
241
|
+
(error) => {
|
|
242
|
+
if (error.response?.status === 401) {
|
|
243
|
+
// Redirect to login
|
|
244
|
+
}
|
|
245
|
+
return Promise.reject(error);
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Remove an interceptor:**
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const id = api.interceptors.request.use(myHandler);
|
|
254
|
+
api.interceptors.request.eject(id); // remove one
|
|
255
|
+
api.interceptors.request.clear(); // remove all
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Automatic Retry
|
|
259
|
+
|
|
260
|
+
**Basic Retry:**
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
const api = create({
|
|
264
|
+
baseURL: 'https://api.example.com',
|
|
265
|
+
retries: 3, // Retry up to 3 times
|
|
266
|
+
retryDelay: 1000, // Start with 1 second delay
|
|
267
|
+
onRetry: (attempt, delay, error) => {
|
|
268
|
+
console.log(`Retry ${attempt} after ${delay}ms`);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Custom Retry Logic:**
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
const api = create({
|
|
277
|
+
retries: 5,
|
|
278
|
+
retryDelay: (attempt) => {
|
|
279
|
+
// Custom backoff: 1s, 2s, 4s, 8s, 16s
|
|
280
|
+
return Math.pow(2, attempt - 1) * 1000;
|
|
281
|
+
},
|
|
282
|
+
retryCondition: (error, attempt) => {
|
|
283
|
+
// Only retry on network errors and 503
|
|
284
|
+
if (!error.response) return true;
|
|
285
|
+
return error.response.status === 503;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Per-Request Retry:**
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// Override retry config for a specific request
|
|
294
|
+
await api.get('/critical-endpoint', {
|
|
295
|
+
retries: 5,
|
|
296
|
+
retryDelay: 2000
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Error Handling
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { HttpEaseError } from 'httpease';
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const response = await api.get('/users/999');
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (error.isHttpError) {
|
|
309
|
+
if (error.response) {
|
|
310
|
+
// Server responded with error status
|
|
311
|
+
console.error('Status:', error.response.status);
|
|
312
|
+
console.error('Data:', error.response.data);
|
|
313
|
+
} else if (error.code === 'ETIMEDOUT') {
|
|
314
|
+
console.error('Request timed out');
|
|
315
|
+
} else {
|
|
316
|
+
console.error('Network error:', error.message);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Configuration Options
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
{
|
|
326
|
+
// Base URL for all requests
|
|
327
|
+
baseURL: 'https://api.example.com',
|
|
328
|
+
|
|
329
|
+
// Request timeout in milliseconds (default: 30000)
|
|
330
|
+
timeout: 30000,
|
|
331
|
+
|
|
332
|
+
// Custom headers
|
|
333
|
+
headers: { 'Content-Type': 'application/json' },
|
|
334
|
+
|
|
335
|
+
// Number of retry attempts (default: 0)
|
|
336
|
+
retries: 0,
|
|
337
|
+
|
|
338
|
+
// Retry delay â ms number or function
|
|
339
|
+
retryDelay: 1000,
|
|
340
|
+
// retryDelay: (attempt) => Math.pow(2, attempt - 1) * 1000,
|
|
341
|
+
|
|
342
|
+
// Custom retry condition
|
|
343
|
+
retryCondition: (error, attempt) => boolean,
|
|
344
|
+
|
|
345
|
+
// Callback on retry
|
|
346
|
+
onRetry: (attempt, delay, error) => void,
|
|
347
|
+
|
|
348
|
+
// Query parameters
|
|
349
|
+
params: {},
|
|
350
|
+
|
|
351
|
+
// Request data
|
|
352
|
+
data: {},
|
|
353
|
+
|
|
354
|
+
// Validate status code
|
|
355
|
+
validateStatus: (status) => status >= 200 && status < 300,
|
|
356
|
+
|
|
357
|
+
// Include credentials (CORS)
|
|
358
|
+
withCredentials: false,
|
|
359
|
+
|
|
360
|
+
// Transform request data before sending
|
|
361
|
+
transformRequest: [(data, headers) => data],
|
|
362
|
+
|
|
363
|
+
// Transform response data after receiving
|
|
364
|
+
transformResponse: [(data) => data],
|
|
365
|
+
|
|
366
|
+
// Upload progress callback
|
|
367
|
+
onUploadProgress: ({ loaded, total, percentage }) => void,
|
|
368
|
+
|
|
369
|
+
// Download progress callback
|
|
370
|
+
onDownloadProgress: ({ loaded, total, percentage }) => void,
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## ð Comparison with Axios
|
|
375
|
+
|
|
376
|
+
| Feature | HTTP Ease | Axios |
|
|
377
|
+
| ----------------------------| --------- | -------------------- |
|
|
378
|
+
| **Size** | ~5KB | ~13KB |
|
|
379
|
+
| **Dependencies** | 0 | Many |
|
|
380
|
+
| **Built-in Retry** | â
Yes | â No (needs plugin) |
|
|
381
|
+
| **Interceptors** | â
Yes | â
Yes |
|
|
382
|
+
| **Timeout** | â
Yes | â
Yes |
|
|
383
|
+
| **Auto JSON** | â
Yes | â
Yes |
|
|
384
|
+
| **Query Params** | â
Yes | â
Yes |
|
|
385
|
+
| **Progress Tracking** | â
Yes | â
Yes |
|
|
386
|
+
| **Cancel Requests** | â
Yes | â
Yes |
|
|
387
|
+
| **TypeScript** | â
Yes | â
Yes |
|
|
388
|
+
|
|
389
|
+
## ðŊ Use Cases
|
|
390
|
+
|
|
391
|
+
Perfect for:
|
|
392
|
+
|
|
393
|
+
- â
Building typed API clients in TypeScript
|
|
394
|
+
- â
Making HTTP requests in React/Vue/Angular apps
|
|
395
|
+
- â
Node.js backend services
|
|
396
|
+
- â
File upload/download with progress UI
|
|
397
|
+
- â
Projects where bundle size matters
|
|
398
|
+
- â
Apps needing automatic retry logic
|
|
399
|
+
|
|
400
|
+
## ð Examples
|
|
401
|
+
|
|
402
|
+
Check out the `/examples` directory for:
|
|
403
|
+
|
|
404
|
+
- `basic.js` - Basic usage examples
|
|
405
|
+
- `interceptors.js` - Request/response interceptors
|
|
406
|
+
- `retry.js` - Retry configuration examples
|
|
407
|
+
- `progress.js` - Upload & download progress examples
|
|
408
|
+
|
|
409
|
+
## ðŦ Contributing
|
|
410
|
+
|
|
411
|
+
This project does **not** accept external contributions. Only the author pushes updates and new releases. If you encounter a bug or have a feature idea, you are welcome to open an issue â but pull requests and code patches will not be reviewed or merged.
|
|
412
|
+
|
|
413
|
+
## ð License
|
|
414
|
+
|
|
415
|
+
Proprietary ÂĐ 2026 **INDRA211**. All rights reserved.
|
|
416
|
+
|
|
417
|
+
This software is **not open source**. You may install and use it in your projects, but you may not copy, modify, redistribute, or contribute to it. See the [LICENSE](./LICENSE) file for full terms.
|
|
418
|
+
|
|
419
|
+
## ð Acknowledgments
|
|
420
|
+
|
|
421
|
+
Inspired by [Axios](https://github.com/axios/axios) but built for the modern web with native fetch and zero dependencies.
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
**Made with âĪïļ by INDRA211**
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@indra211/httpease",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Lightweight HTTP client built on native fetch â zero dependencies, TypeScript support, retry, interceptors & progress tracking.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/types/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"LICENSE",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18.0.0"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "node test/test.js"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"http",
|
|
20
|
+
"fetch",
|
|
21
|
+
"client",
|
|
22
|
+
"typescript",
|
|
23
|
+
"retry",
|
|
24
|
+
"interceptors",
|
|
25
|
+
"progress",
|
|
26
|
+
"http-client",
|
|
27
|
+
"zero-dependency",
|
|
28
|
+
"upload-progress",
|
|
29
|
+
"download-progress"
|
|
30
|
+
],
|
|
31
|
+
"author": "INDRA211",
|
|
32
|
+
"license": "UNLICENSED",
|
|
33
|
+
"private": false,
|
|
34
|
+
"type": "commonjs"
|
|
35
|
+
}
|