zipfetch 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/README.md ADDED
@@ -0,0 +1,328 @@
1
+ # zipfetch
2
+
3
+ > Ultra-fast, lightweight HTTP client built on native fetch - retries, interceptors, caching, rate limiting
4
+
5
+ [![npm version](https://img.shields.io/npm/v/zipfetch.svg)](https://www.npmjs.com/package/zipfetch)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Why zipfetch?
9
+
10
+ - **Tiny**: ~5KB minified (vs Axios 29KB, Got 48KB)
11
+ - **Zero dependencies**: Built on native `fetch` (Node 18+)
12
+ - **Modern**: ESM, TypeScript, async/await
13
+ - **Powerful**: Retries, interceptors, caching, rate limiting
14
+ - **Familiar API**: Similar to Axios, easy to migrate
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install zipfetch
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import zipfetch from 'zipfetch';
26
+
27
+ // Simple GET request
28
+ const { data } = await zipfetch.get('https://api.example.com/users');
29
+
30
+ // POST with data
31
+ const { data: user } = await zipfetch.post('https://api.example.com/users', {
32
+ name: 'John',
33
+ email: 'john@example.com'
34
+ });
35
+
36
+ // With query params
37
+ const { data: results } = await zipfetch.get('https://api.example.com/search', {
38
+ params: { q: 'typescript', page: 1 }
39
+ });
40
+ ```
41
+
42
+ ## Comparison with Alternatives
43
+
44
+ | Feature | zipfetch | Axios | Got | node-fetch |
45
+ |---------|----------|-------|-----|------------|
46
+ | Size (gzip) | **~5KB** | 29KB | 48KB | 8KB |
47
+ | Dependencies | **0** | 8 | 11 | 0 |
48
+ | Native fetch | **Yes** | No | No | Polyfill |
49
+ | Retries | **Built-in** | No | Yes | No |
50
+ | Interceptors | **Yes** | Yes | Hooks | No |
51
+ | Caching | **Built-in** | No | Plugin | No |
52
+ | Rate Limiting | **Built-in** | No | Plugin | No |
53
+ | TypeScript | **Yes** | Yes | Yes | @types |
54
+ | Node 18+ | **Yes** | Yes | Yes | Yes |
55
+ | Browser | **Yes** | Yes | No | No |
56
+
57
+ ## API Reference
58
+
59
+ ### Creating an Instance
60
+
61
+ ```typescript
62
+ import { create } from 'zipfetch';
63
+
64
+ const api = create({
65
+ baseURL: 'https://api.example.com',
66
+ timeout: 10000,
67
+ headers: {
68
+ 'Authorization': 'Bearer token'
69
+ }
70
+ });
71
+
72
+ const { data } = await api.get('/users');
73
+ ```
74
+
75
+ ### Request Methods
76
+
77
+ ```typescript
78
+ zipfetch.get(url, config?)
79
+ zipfetch.post(url, data?, config?)
80
+ zipfetch.put(url, data?, config?)
81
+ zipfetch.patch(url, data?, config?)
82
+ zipfetch.delete(url, config?)
83
+ zipfetch.head(url, config?)
84
+ zipfetch.options(url, config?)
85
+ ```
86
+
87
+ ### Request Config
88
+
89
+ ```typescript
90
+ interface RequestConfig {
91
+ url?: string;
92
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
93
+ baseURL?: string;
94
+ headers?: Record<string, string>;
95
+ params?: Record<string, string | number | boolean>;
96
+ data?: unknown;
97
+ timeout?: number;
98
+ retry?: {
99
+ attempts?: number;
100
+ delay?: number;
101
+ backoff?: 'linear' | 'exponential';
102
+ retryOn?: number[];
103
+ };
104
+ cache?: boolean;
105
+ }
106
+ ```
107
+
108
+ ### Response Object
109
+
110
+ ```typescript
111
+ interface ZipResponse<T> {
112
+ data: T;
113
+ status: number;
114
+ statusText: string;
115
+ headers: Headers;
116
+ config: RequestConfig;
117
+ }
118
+ ```
119
+
120
+ ## Features
121
+
122
+ ### Automatic Retries
123
+
124
+ ```typescript
125
+ import { create } from 'zipfetch';
126
+
127
+ const api = create({
128
+ retry: {
129
+ attempts: 3, // Retry up to 3 times
130
+ delay: 1000, // Start with 1 second delay
131
+ backoff: 'exponential', // 1s, 2s, 4s
132
+ retryOn: [500, 502, 503] // Retry on these status codes
133
+ }
134
+ });
135
+
136
+ // Will automatically retry on failure
137
+ const { data } = await api.get('/flaky-endpoint');
138
+ ```
139
+
140
+ ### Interceptors
141
+
142
+ ```typescript
143
+ import zipfetch from 'zipfetch';
144
+
145
+ // Request interceptor
146
+ zipfetch.interceptors.request.use((config) => {
147
+ config.headers = {
148
+ ...config.headers,
149
+ 'X-Request-ID': crypto.randomUUID()
150
+ };
151
+ return config;
152
+ });
153
+
154
+ // Response interceptor
155
+ zipfetch.interceptors.response.use((response) => {
156
+ console.log(`Response: ${response.status}`);
157
+ return response;
158
+ });
159
+
160
+ // Error interceptor
161
+ zipfetch.interceptors.error.use((error) => {
162
+ if (error.status === 401) {
163
+ // Handle unauthorized
164
+ window.location.href = '/login';
165
+ }
166
+ return error;
167
+ });
168
+ ```
169
+
170
+ ### Response Caching
171
+
172
+ ```typescript
173
+ import { create } from 'zipfetch';
174
+
175
+ const api = create({
176
+ cache: {
177
+ enabled: true,
178
+ ttl: 60000, // Cache for 60 seconds
179
+ methods: ['GET'] // Only cache GET requests
180
+ }
181
+ });
182
+
183
+ // First request hits the network
184
+ await api.get('/users');
185
+
186
+ // Second request returns cached response
187
+ await api.get('/users');
188
+
189
+ // Clear cache manually
190
+ api.clearCache();
191
+ ```
192
+
193
+ ### Rate Limiting
194
+
195
+ ```typescript
196
+ import { create } from 'zipfetch';
197
+
198
+ const api = create({
199
+ rateLimit: {
200
+ requests: 10, // Max 10 requests
201
+ interval: 1000 // Per second
202
+ }
203
+ });
204
+
205
+ // Requests will automatically queue if rate limit is exceeded
206
+ for (let i = 0; i < 20; i++) {
207
+ api.get('/endpoint'); // Will spread across 2 seconds
208
+ }
209
+ ```
210
+
211
+ ### Timeout
212
+
213
+ ```typescript
214
+ import zipfetch from 'zipfetch';
215
+
216
+ try {
217
+ await zipfetch.get('/slow-endpoint', {
218
+ timeout: 5000 // 5 second timeout
219
+ });
220
+ } catch (error) {
221
+ if (error.code === 'TIMEOUT') {
222
+ console.log('Request timed out');
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### Error Handling
228
+
229
+ ```typescript
230
+ import zipfetch, { ZipError } from 'zipfetch';
231
+
232
+ try {
233
+ await zipfetch.get('/not-found');
234
+ } catch (error) {
235
+ if (error instanceof ZipError) {
236
+ console.log(error.status); // 404
237
+ console.log(error.response); // Full response object
238
+ console.log(error.config); // Request config
239
+ console.log(error.code); // 'TIMEOUT' | 'NETWORK' | 'ABORT' | undefined
240
+ }
241
+ }
242
+ ```
243
+
244
+ ### FormData & File Uploads
245
+
246
+ ```typescript
247
+ import zipfetch from 'zipfetch';
248
+
249
+ const formData = new FormData();
250
+ formData.append('file', fileInput.files[0]);
251
+ formData.append('name', 'My File');
252
+
253
+ const { data } = await zipfetch.post('/upload', formData);
254
+ // Content-Type is automatically set to multipart/form-data
255
+ ```
256
+
257
+ ## Migration from Axios
258
+
259
+ ```typescript
260
+ // Axios
261
+ import axios from 'axios';
262
+ const api = axios.create({ baseURL: 'https://api.example.com' });
263
+ const { data } = await api.get('/users');
264
+
265
+ // zipfetch
266
+ import { create } from 'zipfetch';
267
+ const api = create({ baseURL: 'https://api.example.com' });
268
+ const { data } = await api.get('/users');
269
+ ```
270
+
271
+ ## Migration from node-fetch
272
+
273
+ ```typescript
274
+ // node-fetch
275
+ import fetch from 'node-fetch';
276
+ const response = await fetch('https://api.example.com/users');
277
+ const data = await response.json();
278
+
279
+ // zipfetch
280
+ import zipfetch from 'zipfetch';
281
+ const { data } = await zipfetch.get('https://api.example.com/users');
282
+ ```
283
+
284
+ ## TypeScript
285
+
286
+ Full TypeScript support with generics:
287
+
288
+ ```typescript
289
+ import zipfetch from 'zipfetch';
290
+
291
+ interface User {
292
+ id: number;
293
+ name: string;
294
+ email: string;
295
+ }
296
+
297
+ // Type-safe response
298
+ const { data } = await zipfetch.get<User[]>('/users');
299
+ data.forEach(user => console.log(user.name));
300
+
301
+ // Type-safe post
302
+ const { data: newUser } = await zipfetch.post<User>('/users', {
303
+ name: 'John',
304
+ email: 'john@example.com'
305
+ });
306
+ ```
307
+
308
+ ## Browser Support
309
+
310
+ Works in all modern browsers that support native `fetch`:
311
+ - Chrome 42+
312
+ - Firefox 39+
313
+ - Safari 10.1+
314
+ - Edge 14+
315
+
316
+ For older browsers, use a fetch polyfill.
317
+
318
+ ## Node.js Support
319
+
320
+ Requires Node.js 18+ (native fetch support).
321
+
322
+ ## License
323
+
324
+ MIT
325
+
326
+ ---
327
+
328
+ **Made for speed and simplicity**
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Response caching implementation
3
+ */
4
+ import type { RequestConfig, ZipResponse } from './types.js';
5
+ export declare class ResponseCache {
6
+ private cache;
7
+ private generateKey;
8
+ get<T>(url: string, config: RequestConfig): ZipResponse<T> | null;
9
+ set<T>(url: string, config: RequestConfig, response: ZipResponse<T>, ttl: number): void;
10
+ clear(): void;
11
+ delete(url: string, config: RequestConfig): boolean;
12
+ size(): number;
13
+ }
14
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAQ7D,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAA0C;IAEvD,OAAO,CAAC,WAAW;IAMnB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAcjE,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IASvF,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO;IAKnD,IAAI,IAAI,MAAM;CAGf"}
package/dist/cache.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Response caching implementation
3
+ */
4
+ export class ResponseCache {
5
+ cache = new Map();
6
+ generateKey(url, config) {
7
+ const params = config.params ? JSON.stringify(config.params) : '';
8
+ const headers = config.headers ? JSON.stringify(config.headers) : '';
9
+ return `${config.method || 'GET'}:${url}:${params}:${headers}`;
10
+ }
11
+ get(url, config) {
12
+ const key = this.generateKey(url, config);
13
+ const entry = this.cache.get(key);
14
+ if (!entry)
15
+ return null;
16
+ if (Date.now() - entry.timestamp > entry.ttl) {
17
+ this.cache.delete(key);
18
+ return null;
19
+ }
20
+ return entry.data;
21
+ }
22
+ set(url, config, response, ttl) {
23
+ const key = this.generateKey(url, config);
24
+ this.cache.set(key, {
25
+ data: response,
26
+ timestamp: Date.now(),
27
+ ttl,
28
+ });
29
+ }
30
+ clear() {
31
+ this.cache.clear();
32
+ }
33
+ delete(url, config) {
34
+ const key = this.generateKey(url, config);
35
+ return this.cache.delete(key);
36
+ }
37
+ size() {
38
+ return this.cache.size;
39
+ }
40
+ }
41
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,MAAM,OAAO,aAAa;IAChB,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IAE/C,WAAW,CAAC,GAAW,EAAE,MAAqB;QACpD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,KAAK,IAAI,GAAG,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;IACjE,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,MAAqB;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAA8B,CAAC;QAE/D,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YAC7C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,IAAsB,CAAC;IACtC,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,MAAqB,EAAE,QAAwB,EAAE,GAAW;QAC9E,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,GAAG;SACJ,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,GAAW,EAAE,MAAqB;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Main ZipFetch client class
3
+ */
4
+ import type { ZipFetchConfig, RequestConfig, ZipResponse, RequestInterceptor, ResponseInterceptor, ErrorInterceptor } from './types.js';
5
+ export declare class ZipFetch {
6
+ private config;
7
+ private cache;
8
+ private rateLimiter?;
9
+ private requestInterceptors;
10
+ private responseInterceptors;
11
+ private errorInterceptors;
12
+ constructor(config?: ZipFetchConfig);
13
+ interceptors: {
14
+ request: {
15
+ use: (interceptor: RequestInterceptor) => number;
16
+ eject: (index: number) => void;
17
+ clear: () => void;
18
+ };
19
+ response: {
20
+ use: (interceptor: ResponseInterceptor) => number;
21
+ eject: (index: number) => void;
22
+ clear: () => void;
23
+ };
24
+ error: {
25
+ use: (interceptor: ErrorInterceptor) => number;
26
+ eject: (index: number) => void;
27
+ clear: () => void;
28
+ };
29
+ };
30
+ request<T = unknown>(config: RequestConfig): Promise<ZipResponse<T>>;
31
+ private buildUrl;
32
+ private isCacheEnabled;
33
+ private executeWithRetry;
34
+ private executeRequest;
35
+ private prepareBody;
36
+ private parseResponse;
37
+ private shouldRetry;
38
+ private delay;
39
+ get<T = unknown>(url: string, config?: Omit<RequestConfig, 'url' | 'method'>): Promise<ZipResponse<T>>;
40
+ post<T = unknown>(url: string, data?: unknown, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ZipResponse<T>>;
41
+ put<T = unknown>(url: string, data?: unknown, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ZipResponse<T>>;
42
+ patch<T = unknown>(url: string, data?: unknown, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ZipResponse<T>>;
43
+ delete<T = unknown>(url: string, config?: Omit<RequestConfig, 'url' | 'method'>): Promise<ZipResponse<T>>;
44
+ head<T = unknown>(url: string, config?: Omit<RequestConfig, 'url' | 'method'>): Promise<ZipResponse<T>>;
45
+ options<T = unknown>(url: string, config?: Omit<RequestConfig, 'url' | 'method'>): Promise<ZipResponse<T>>;
46
+ clearCache(): void;
47
+ create(config: ZipFetchConfig): ZipFetch;
48
+ getConfig(): ZipFetchConfig;
49
+ }
50
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,WAAW,EAGX,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAKpB,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAc;IAElC,OAAO,CAAC,mBAAmB,CAA4B;IACvD,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,iBAAiB,CAA0B;gBAEvC,MAAM,GAAE,cAAmB;IAkBvC,YAAY;;+BAEW,kBAAkB;2BAItB,MAAM;;;;+BAQF,mBAAmB;2BAIvB,MAAM;;;;+BAQF,gBAAgB;2BAIpB,MAAM;;;MAOvB;IAMI,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAyC1E,OAAO,CAAC,QAAQ;IAyBhB,OAAO,CAAC,cAAc;YAQR,gBAAgB;YAoChB,cAAc;IAqE5B,OAAO,CAAC,WAAW;YAsBL,aAAa;IAc3B,OAAO,CAAC,WAAW;YAYL,KAAK;IAqBnB,GAAG,CAAC,CAAC,GAAG,OAAO,EACb,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,CAAC,GAC7C,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAI1B,IAAI,CAAC,CAAC,GAAG,OAAO,EACd,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAI1B,GAAG,CAAC,CAAC,GAAG,OAAO,EACb,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAI1B,KAAK,CAAC,CAAC,GAAG,OAAO,EACf,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAI1B,MAAM,CAAC,CAAC,GAAG,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,CAAC,GAC7C,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAI1B,IAAI,CAAC,CAAC,GAAG,OAAO,EACd,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,CAAC,GAC7C,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAI1B,OAAO,CAAC,CAAC,GAAG,OAAO,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,QAAQ,CAAC,GAC7C,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAQ1B,UAAU,IAAI,IAAI;IAIlB,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ;IAIxC,SAAS,IAAI,cAAc;CAG5B"}