jiren 1.1.5 → 1.2.5

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 CHANGED
@@ -1,18 +1,19 @@
1
- # Jiren
1
+ # Jiren 🚀
2
2
 
3
- Ultra-fast HTTP/HTTPS client powered by native Zig (FFI).
4
- Designed to be significantly faster than `fetch` and other Node/Bun HTTP clients.
3
+ **Ultra-fast HTTP client powered by native Zig** - Significantly faster than `fetch` and other HTTP clients.
5
4
 
6
- ## Features
5
+ [![npm version](https://img.shields.io/npm/v/jiren.svg)](https://www.npmjs.com/package/jiren)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- - **Native Performance**: Written in Zig for memory safety and speed.
9
- - **Anti-Bot Protection**: Bypass Cloudflare with curl-impersonate (Chrome TLS fingerprinting).
10
- - **HTTP/1.1, HTTP/2 & HTTP/3 (QUIC)**: Full support for modern protocols.
11
- - **Connection Pooling**: Reuse connections for maximum throughput.
12
- - **Mandatory Warmup**: Pre-warm connections for instant requests.
13
- - **Type-Safe URLs**: Define named endpoints with full TypeScript autocomplete.
14
- - **JSON & Text Helpers**: Easy response parsing.
15
- - **Automatic Gzip Decompression**: Handles compressed responses transparently.
8
+ ## Why Jiren?
9
+
10
+ - **2-3x faster** than Bun's native `fetch`
11
+ - 🔒 **Anti-bot protection** - Bypass Cloudflare with Chrome TLS fingerprinting
12
+ - 🚄 **HTTP/3 (QUIC)** support with automatic fallback to HTTP/2
13
+ - 💾 **Smart caching** - Persistent gzip-compressed response cache
14
+ - 🔌 **Connection pooling** - Reuse connections for maximum performance
15
+ - 📝 **Type-safe** - Full TypeScript support with autocomplete
16
+ - 🎯 **Zero dependencies** - Pure Zig native module
16
17
 
17
18
  ## Installation
18
19
 
@@ -20,223 +21,523 @@ Designed to be significantly faster than `fetch` and other Node/Bun HTTP clients
20
21
  bun add jiren
21
22
  ```
22
23
 
23
- ## Usage
24
-
25
- ### Basic Usage (Type-Safe URLs)
26
-
27
- **Warmup is now mandatory** - you must define URLs in the constructor:
24
+ ## Quick Start
28
25
 
29
26
  ```typescript
30
27
  import { JirenClient } from "jiren";
31
28
 
29
+ // Create client with warmup URLs
32
30
  const client = new JirenClient({
33
31
  warmup: {
34
- google: "https://www.google.com",
35
- github: "https://api.github.com",
36
- myapi: "https://api.myservice.com",
32
+ api: "https://api.example.com",
33
+ cdn: "https://cdn.example.com",
37
34
  },
38
35
  });
39
36
 
40
- // TypeScript knows about 'google', 'github', 'myapi' - full autocomplete!
41
- const res = await client.url.google.get();
42
- console.log(res.status);
43
- const text = await res.body.text();
37
+ // Make requests with full type safety
38
+ const response = await client.url.api.get({ path: "/users" });
39
+ const users = await response.body.json();
40
+
41
+ console.log(users);
44
42
  ```
45
43
 
46
- ### JSON Response
44
+ ## Table of Contents
45
+
46
+ - [Basic Usage](#basic-usage)
47
+ - [Response Caching](#response-caching)
48
+ - [Anti-Bot Protection](#anti-bot-protection)
49
+ - [Advanced Features](#advanced-features)
50
+ - [Performance](#performance)
51
+ - [API Reference](#api-reference)
52
+
53
+ ---
54
+
55
+ ## Basic Usage
56
+
57
+ ### 1. Create a Client
58
+
59
+ **Warmup is mandatory** - define your URLs upfront for optimal performance:
47
60
 
48
61
  ```typescript
49
- interface User {
50
- id: number;
51
- name: string;
52
- }
62
+ import { JirenClient } from "jiren";
53
63
 
54
64
  const client = new JirenClient({
55
65
  warmup: {
56
- api: "https://api.example.com",
66
+ github: "https://api.github.com",
67
+ google: "https://www.google.com",
57
68
  },
58
69
  });
70
+ ```
59
71
 
60
- const res = await client.url.api.get<User>({
61
- path: "/user/1",
62
- responseType: "json",
72
+ ### 2. Make GET Requests
73
+
74
+ ```typescript
75
+ // Simple GET request
76
+ const response = await client.url.github.get();
77
+ console.log(response.status); // 200
78
+
79
+ // GET with path and headers
80
+ const user = await client.url.github.get({
81
+ path: "/users/octocat",
82
+ headers: { Authorization: "token YOUR_TOKEN" },
63
83
  });
64
- console.log(res.name); // Fully typed!
65
84
  ```
66
85
 
67
- ### Anti-Bot Mode (NEW! �️)
86
+ ### 3. Parse Responses
87
+
88
+ ```typescript
89
+ const response = await client.url.api.get({ path: "/data" });
90
+
91
+ // As JSON
92
+ const json = await response.body.json();
93
+
94
+ // As text
95
+ const text = await response.body.text();
96
+
97
+ // As ArrayBuffer
98
+ const buffer = await response.body.arrayBuffer();
99
+ ```
68
100
 
69
- Enable curl-impersonate for sites with bot protection:
101
+ ### 4. Auto-Parse with `responseType`
70
102
 
71
103
  ```typescript
72
- const client = new JirenClient({
73
- warmup: {
74
- protected: "https://protected-site.com",
75
- },
104
+ // Automatically parse JSON
105
+ const users = await client.url.api.get({
106
+ path: "/users",
107
+ responseType: "json", // Returns parsed JSON directly
76
108
  });
77
109
 
78
- // Enable antibot mode for this request
79
- const res = await client.url.protected.get({
80
- antibot: true, // Uses curl-impersonate with Chrome fingerprinting
110
+ // Automatically get text
111
+ const html = await client.url.google.get({
112
+ responseType: "text", // Returns string directly
81
113
  });
82
114
  ```
83
115
 
84
- ### POST, PUT, PATCH, DELETE
116
+ ### 5. POST, PUT, PATCH, DELETE
85
117
 
86
118
  ```typescript
87
- const client = new JirenClient({
88
- warmup: {
89
- api: "https://api.myservice.com",
90
- },
91
- });
92
-
93
- // POST with body
119
+ // POST with JSON body
94
120
  const created = await client.url.api.post(
95
- JSON.stringify({ name: "New Item" }),
121
+ JSON.stringify({ name: "John Doe", email: "john@example.com" }),
96
122
  {
97
- path: "/items",
123
+ path: "/users",
98
124
  headers: { "Content-Type": "application/json" },
125
+ responseType: "json",
99
126
  }
100
127
  );
101
128
 
102
- // PUT, PATCH, DELETE
103
- await client.url.api.put(body, { path: "/items/1" });
104
- await client.url.api.patch(body, { path: "/items/1" });
105
- await client.url.api.delete(null, { path: "/items/1" });
129
+ // PUT request
130
+ await client.url.api.put(JSON.stringify({ name: "Jane Doe" }), {
131
+ path: "/users/123",
132
+ headers: { "Content-Type": "application/json" },
133
+ });
134
+
135
+ // PATCH request
136
+ await client.url.api.patch(JSON.stringify({ email: "new@example.com" }), {
137
+ path: "/users/123",
138
+ });
139
+
140
+ // DELETE request
141
+ await client.url.api.delete(null, { path: "/users/123" });
106
142
  ```
107
143
 
108
- ### Response Helpers
144
+ ---
109
145
 
110
- ```typescript
111
- const res = await client.url.api.get({ path: "/data" });
146
+ ## Response Caching
112
147
 
113
- // Get as text
114
- const text = await res.body.text();
148
+ Enable persistent file-based caching for **instant responses** on subsequent requests:
115
149
 
116
- // Get as JSON
117
- const json = await res.body.json();
150
+ ### Basic Caching
118
151
 
119
- // Get as ArrayBuffer
120
- const buffer = await res.body.arrayBuffer();
152
+ ```typescript
153
+ const client = new JirenClient({
154
+ warmup: {
155
+ api: {
156
+ url: "https://api.example.com",
157
+ cache: true, // Enable 60-second cache
158
+ },
159
+ },
160
+ });
121
161
 
122
- // Get as Blob
123
- const blob = await res.body.blob();
162
+ // First request: Real HTTP request (~150ms)
163
+ const data1 = await client.url.api.get({ path: "/users" });
124
164
 
125
- // Or use responseType for automatic parsing
126
- const data = await client.url.api.get({
127
- path: "/data",
128
- responseType: "json", // Returns parsed JSON directly
165
+ // Second request: From cache (~1-2ms) - 100x faster! ⚡
166
+ const data2 = await client.url.api.get({ path: "/users" });
167
+ ```
168
+
169
+ ### Custom Cache TTL
170
+
171
+ ```typescript
172
+ const client = new JirenClient({
173
+ warmup: {
174
+ api: {
175
+ url: "https://api.example.com",
176
+ cache: { ttl: 300000 }, // 5-minute cache
177
+ },
178
+ cdn: {
179
+ url: "https://cdn.example.com",
180
+ cache: { ttl: 3600000 }, // 1-hour cache
181
+ },
182
+ },
129
183
  });
130
184
  ```
131
185
 
132
- ## Why Jiren?
186
+ ### Manual Cache Refresh
133
187
 
134
- ### Comparison with Other Clients
188
+ ```typescript
189
+ // Refresh cache for a specific endpoint
190
+ await client.url.api.prefetch({ path: "/users" });
135
191
 
136
- | Feature | **Jiren** | **Axios** | **ky** | **got** | **node-fetch** |
137
- | -------------------- | :-------: | :-------: | :----: | :-----: | :------------: |
138
- | Type-safe named URLs | ✅ | ❌ | ❌ | ❌ | ❌ |
139
- | Mandatory warmup | ✅ | ❌ | ❌ | ❌ | ❌ |
140
- | HTTP/3 (QUIC) | ✅ | ❌ | ❌ | ❌ | ❌ |
141
- | Anti-bot protection | ✅ | ❌ | ❌ | ❌ | ❌ |
142
- | Native performance | ✅ | ❌ | ❌ | ❌ | ❌ |
143
- | Zero code generation | ✅ | ✅ | ✅ | ✅ | ✅ |
144
- | Bun FFI optimized | ✅ | ❌ | ❌ | ❌ | ❌ |
192
+ // Now the next request will use fresh data
193
+ const users = await client.url.api.get({ path: "/users" });
194
+ ```
145
195
 
146
- ### What Makes Jiren Unique
196
+ ### Cache Features
147
197
 
148
- 1. **🔥 Mandatory Warmup** - Pre-establishes connections at startup for instant requests
149
- 2. **📝 Type-Safe URLs** - Full autocomplete without needing backend schemas or code generation
150
- 3. **🚀 Native Speed** - Zig-powered core bypasses JavaScript overhead
151
- 4. **🛡️ Anti-Bot Protection** - Bypass Cloudflare, TLS fingerprinting, and bot detection with curl-impersonate
152
- 5. **⚡ HTTP/3 Support** - First-class QUIC support for modern protocols
198
+ - **Persistent** - Survives process restarts
199
+ - **Compressed** - Gzip-compressed JSON files (`.cache/jiren/*.json.gz`)
200
+ - **Automatic expiration** - Respects TTL
201
+ - **Fast** - ~100x faster than real requests
153
202
 
154
- ## Anti-Bot Protection
203
+ ### Cache Performance
155
204
 
156
- The `antibot` option uses curl-impersonate to mimic Chrome's TLS fingerprint:
205
+ | Type | Speed | Use Case |
206
+ | ------------ | ------ | ----------------------------------------------- |
207
+ | Real request | ~150ms | First request or cache miss |
208
+ | File cache | ~1-2ms | Subsequent requests (same or different process) |
209
+ | Memory cache | ~0.1ms | Multiple requests in same process |
157
210
 
158
- - Bypass TLS fingerprinting protections (JA3/JA4) like Cloudflare
159
- - Chrome 120 browser impersonation
160
- - Proper header ordering and HTTP/2 settings
161
- - Automatic gzip decompression
211
+ **💡 Tip:** Add `.cache/` to your `.gitignore`:
212
+
213
+ ```gitignore
214
+ # Jiren cache
215
+ .cache/
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Anti-Bot Protection
221
+
222
+ Bypass Cloudflare and other bot protection using Chrome TLS fingerprinting:
162
223
 
163
224
  ```typescript
164
- const res = await client.url.site.get({
165
- antibot: true, // Enable for protected sites
225
+ const client = new JirenClient({
226
+ warmup: {
227
+ protected: "https://cloudflare-protected-site.com",
228
+ },
229
+ });
230
+
231
+ // Enable anti-bot mode for this request
232
+ const response = await client.url.protected.get({
233
+ antibot: true, // Uses curl-impersonate with Chrome 120 fingerprint
166
234
  });
167
235
  ```
168
236
 
169
- **Performance**: ~1-2s for first request, faster with connection reuse.
237
+ **How it works:**
170
238
 
171
- ## API Reference
239
+ - Uses `curl-impersonate` to mimic Chrome 120 browser
240
+ - Includes realistic TLS fingerprint and headers
241
+ - Bypasses most bot detection systems
172
242
 
173
- ### `JirenClient`
243
+ ---
244
+
245
+ ## Advanced Features
246
+
247
+ ### TypeScript Generics
174
248
 
175
249
  ```typescript
176
- // Constructor options
177
- interface JirenClientOptions {
178
- warmup: Record<string, string>; // Required! Map of key -> URL
250
+ interface User {
251
+ id: number;
252
+ name: string;
253
+ email: string;
179
254
  }
180
255
 
181
- // Create client (warmup is mandatory)
182
- const client = new JirenClient({
256
+ // Type-safe response
257
+ const user = await client.url.api.get<User>({
258
+ path: "/users/123",
259
+ responseType: "json",
260
+ });
261
+
262
+ console.log(user.name); // TypeScript knows this is a string
263
+ ```
264
+
265
+ ### Multiple Warmup Formats
266
+
267
+ ```typescript
268
+ // Object format (recommended)
269
+ const client1 = new JirenClient({
183
270
  warmup: {
184
271
  api: "https://api.example.com",
185
272
  cdn: "https://cdn.example.com",
186
273
  },
187
274
  });
188
275
 
189
- // Type-safe URL access
190
- client.url[key].get(options?)
191
- client.url[key].post(body?, options?)
192
- client.url[key].put(body?, options?)
193
- client.url[key].patch(body?, options?)
194
- client.url[key].delete(body?, options?)
195
- client.url[key].head(options?)
196
- client.url[key].options(options?)
276
+ // Array format (with cache config)
277
+ const client2 = new JirenClient({
278
+ warmup: [
279
+ { key: "api", url: "https://api.example.com", cache: true },
280
+ { key: "cdn", url: "https://cdn.example.com", cache: { ttl: 3600000 } },
281
+ ],
282
+ });
283
+
284
+ // Simple array
285
+ const client3 = new JirenClient({
286
+ warmup: ["https://api.example.com", "https://cdn.example.com"],
287
+ });
288
+ ```
289
+
290
+ ### Benchmark Mode
197
291
 
198
- // Cleanup
199
- client.close()
292
+ Force HTTP/2 for consistent benchmarking:
293
+
294
+ ```typescript
295
+ const client = new JirenClient({
296
+ warmup: { api: "https://api.example.com" },
297
+ benchmark: true, // Disables HTTP/3 probing, forces HTTP/2
298
+ });
200
299
  ```
201
300
 
301
+ ### Close Client
302
+
303
+ ```typescript
304
+ // Clean up resources when done
305
+ client.close();
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Performance
311
+
312
+ ### Benchmark Results
313
+
314
+ ```
315
+ Bun fetch: ~300ms
316
+ JirenClient: ~120ms (2.5x faster)
317
+ JirenClient (cached): ~1-2ms (150x faster)
318
+ ```
319
+
320
+ ### Performance Tips
321
+
322
+ 1. **Always use warmup** - Pre-establishes connections
323
+ 2. **Enable caching** - For data that doesn't change frequently
324
+ 3. **Reuse client instances** - Don't create new clients for each request
325
+ 4. **Use `responseType`** - Automatic parsing is faster
326
+ 5. **Batch requests** - Use `Promise.all()` for concurrent requests
327
+
328
+ ### Why So Fast?
329
+
330
+ - **Native Zig implementation** - No JavaScript overhead
331
+ - **HTTP/3 (QUIC) support** - Faster than HTTP/2 when available
332
+ - **Connection pooling** - Reuses TCP/TLS connections
333
+ - **Smart caching** - Compressed persistent cache
334
+ - **Zero-copy operations** - Minimal memory allocations
335
+ - **TCP keep-alive** - Prevents connection drops
336
+
337
+ ---
338
+
339
+ ## API Reference
340
+
341
+ ### `JirenClient` Constructor
342
+
343
+ ```typescript
344
+ new JirenClient(options?: JirenClientOptions)
345
+ ```
346
+
347
+ **Options:**
348
+
349
+ | Option | Type | Description |
350
+ | ----------- | -------------------------------------------------- | ---------------------------- |
351
+ | `warmup` | `Record<string, UrlConfig>` \| `WarmupUrlConfig[]` | URLs to pre-warm (required) |
352
+ | `benchmark` | `boolean` | Force HTTP/2 mode (optional) |
353
+
354
+ **UrlConfig:**
355
+
356
+ ```typescript
357
+ type UrlConfig =
358
+ | string
359
+ | {
360
+ url: string;
361
+ cache?: boolean | { ttl: number };
362
+ };
363
+ ```
364
+
365
+ ### URL Endpoint Methods
366
+
367
+ All methods are available on `client.url.<key>`:
368
+
369
+ #### `get(options?)`
370
+
371
+ ```typescript
372
+ get<T>(options?: UrlRequestOptions): Promise<JirenResponse<T>>
373
+ ```
374
+
375
+ #### `post(body?, options?)`
376
+
377
+ ```typescript
378
+ post<T>(body?: string | null, options?: UrlRequestOptions): Promise<JirenResponse<T>>
379
+ ```
380
+
381
+ #### `put(body?, options?)`
382
+
383
+ ```typescript
384
+ put<T>(body?: string | null, options?: UrlRequestOptions): Promise<JirenResponse<T>>
385
+ ```
386
+
387
+ #### `patch(body?, options?)`
388
+
389
+ ```typescript
390
+ patch<T>(body?: string | null, options?: UrlRequestOptions): Promise<JirenResponse<T>>
391
+ ```
392
+
393
+ #### `delete(body?, options?)`
394
+
395
+ ```typescript
396
+ delete<T>(body?: string | null, options?: UrlRequestOptions): Promise<JirenResponse<T>>
397
+ ```
398
+
399
+ #### `head(options?)`
400
+
401
+ ```typescript
402
+ head(options?: UrlRequestOptions): Promise<JirenResponse<any>>
403
+ ```
404
+
405
+ #### `options(options?)`
406
+
407
+ ```typescript
408
+ options(options?: UrlRequestOptions): Promise<JirenResponse<any>>
409
+ ```
410
+
411
+ #### `prefetch(options?)`
412
+
413
+ ```typescript
414
+ prefetch(options?: UrlRequestOptions): Promise<void>
415
+ ```
416
+
417
+ Clears cache and makes a fresh request to populate cache.
418
+
202
419
  ### Request Options
203
420
 
204
421
  ```typescript
205
422
  interface UrlRequestOptions {
206
423
  path?: string; // Path to append to base URL
207
- headers?: Record<string, string>;
208
- maxRedirects?: number;
209
- responseType?: "json" | "text" | "arraybuffer" | "blob";
210
- antibot?: boolean; // Enable curl-impersonate (default: false)
424
+ headers?: Record<string, string>; // Request headers
425
+ responseType?: "json" | "text"; // Auto-parse response
426
+ antibot?: boolean; // Enable anti-bot protection
427
+ maxRedirects?: number; // Max redirects to follow
211
428
  }
212
429
  ```
213
430
 
214
431
  ### Response Object
215
432
 
216
433
  ```typescript
217
- interface JirenResponse<T> {
434
+ interface JirenResponse<T = any> {
435
+ url: string;
218
436
  status: number;
219
437
  statusText: string;
220
438
  headers: Record<string, string>;
221
439
  ok: boolean;
440
+ redirected: boolean;
441
+ type: string;
222
442
  body: {
223
- text(): Promise<string>;
224
443
  json<R = T>(): Promise<R>;
444
+ text(): Promise<string>;
225
445
  arrayBuffer(): Promise<ArrayBuffer>;
226
446
  blob(): Promise<Blob>;
227
447
  };
228
448
  }
229
449
  ```
230
450
 
231
- ## Performance
451
+ ---
452
+
453
+ ## Examples
454
+
455
+ ### Real-World React App
456
+
457
+ ```typescript
458
+ // api-client.ts
459
+ import { JirenClient } from "jiren";
460
+
461
+ export const apiClient = new JirenClient({
462
+ warmup: {
463
+ backend: {
464
+ url: "https://api.myapp.com",
465
+ cache: true, // Cache API responses
466
+ },
467
+ cdn: {
468
+ url: "https://cdn.myapp.com",
469
+ cache: { ttl: 3600000 }, // 1-hour cache for static assets
470
+ },
471
+ },
472
+ });
232
473
 
233
- Benchmark results:
474
+ // UserProfile.tsx
475
+ import { apiClient } from "./api-client";
234
476
 
235
- - **Bun fetch**: ~950-1780ms
236
- - **JirenClient**: ~480-1630ms
477
+ function UserProfile() {
478
+ const [user, setUser] = useState(null);
237
479
 
238
- JirenClient is often **faster than Bun's native fetch** thanks to optimized connection pooling and native Zig implementation.
480
+ useEffect(() => {
481
+ // Fast! Uses cache if available
482
+ apiClient.url.backend
483
+ .get({ path: "/user/me", responseType: "json" })
484
+ .then(setUser);
485
+ }, []);
486
+
487
+ return <div>{user?.name}</div>;
488
+ }
489
+ ```
490
+
491
+ ### Polling with Cache
492
+
493
+ ```typescript
494
+ const client = new JirenClient({
495
+ warmup: {
496
+ api: {
497
+ url: "https://api.example.com",
498
+ cache: { ttl: 30000 }, // 30-second cache
499
+ },
500
+ },
501
+ });
502
+
503
+ // Poll every 10 seconds
504
+ setInterval(async () => {
505
+ // First 3 requests use cache, 4th request is fresh
506
+ const notifications = await client.url.api.get({
507
+ path: "/notifications",
508
+ responseType: "json",
509
+ });
510
+
511
+ updateUI(notifications);
512
+ }, 10000);
513
+ ```
514
+
515
+ ---
516
+
517
+ ## Requirements
518
+
519
+ - **Bun** v1.0.0 or higher
520
+
521
+ ---
239
522
 
240
523
  ## License
241
524
 
242
- MIT
525
+ MIT © Vikash Khati
526
+
527
+ ---
528
+
529
+ ## Contributing
530
+
531
+ Contributions are welcome! Please open an issue or submit a pull request.
532
+
533
+ ---
534
+
535
+ ## Support
536
+
537
+ - 📖 [Documentation](https://github.com/vikashkhati007/jiren)
538
+ - 🐛 [Issue Tracker](https://github.com/vikashkhati007/jiren/issues)
539
+ - 💬 [Discussions](https://github.com/vikashkhati007/jiren/discussions)
540
+
541
+ ---
542
+
543
+ **Made with ⚡ by the Jiren team**