jiren 1.1.1 → 1.2.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 CHANGED
@@ -1,17 +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
- - **Zero-Copy (Planned)**: Minimal overhead FFI.
10
- - **HTTP/1.1 & HTTP/3 (QUIC)**: Support for modern protocols.
11
- - **Connection Pooling**: Reuse connections for maximum throughput.
12
- - **0-RTT Session Resumption**: Extremely fast subsequent requests.
13
- - **Smart Warmup**: Pre-warm connections to reduce latency.
14
- - **JSON & Text Helpers**: Easy response parsing.
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
15
17
 
16
18
  ## Installation
17
19
 
@@ -19,61 +21,523 @@ Designed to be significantly faster than `fetch` and other Node/Bun HTTP clients
19
21
  bun add jiren
20
22
  ```
21
23
 
22
- ## Usage
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { JirenClient } from "jiren";
28
+
29
+ // Create client with warmup URLs
30
+ const client = new JirenClient({
31
+ warmup: {
32
+ api: "https://api.example.com",
33
+ cdn: "https://cdn.example.com",
34
+ },
35
+ });
36
+
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);
42
+ ```
43
+
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
+ ---
23
54
 
24
- ### Basic GET
55
+ ## Basic Usage
56
+
57
+ ### 1. Create a Client
58
+
59
+ **Warmup is mandatory** - define your URLs upfront for optimal performance:
25
60
 
26
61
  ```typescript
27
62
  import { JirenClient } from "jiren";
28
63
 
29
- const client = new JirenClient();
30
- const res = await client.get("https://example.com");
64
+ const client = new JirenClient({
65
+ warmup: {
66
+ github: "https://api.github.com",
67
+ google: "https://www.google.com",
68
+ },
69
+ });
70
+ ```
71
+
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" },
83
+ });
84
+ ```
85
+
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
+ ```
100
+
101
+ ### 4. Auto-Parse with `responseType`
102
+
103
+ ```typescript
104
+ // Automatically parse JSON
105
+ const users = await client.url.api.get({
106
+ path: "/users",
107
+ responseType: "json", // Returns parsed JSON directly
108
+ });
109
+
110
+ // Automatically get text
111
+ const html = await client.url.google.get({
112
+ responseType: "text", // Returns string directly
113
+ });
114
+ ```
115
+
116
+ ### 5. POST, PUT, PATCH, DELETE
117
+
118
+ ```typescript
119
+ // POST with JSON body
120
+ const created = await client.url.api.post(
121
+ JSON.stringify({ name: "John Doe", email: "john@example.com" }),
122
+ {
123
+ path: "/users",
124
+ headers: { "Content-Type": "application/json" },
125
+ responseType: "json",
126
+ }
127
+ );
128
+
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" });
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Response Caching
147
+
148
+ Enable persistent file-based caching for **instant responses** on subsequent requests:
31
149
 
32
- console.log(res.status);
33
- const text = await res.text();
34
- console.log(text);
150
+ ### Basic Caching
151
+
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
+ });
161
+
162
+ // First request: Real HTTP request (~150ms)
163
+ const data1 = await client.url.api.get({ path: "/users" });
164
+
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
+ },
183
+ });
184
+ ```
185
+
186
+ ### Manual Cache Refresh
187
+
188
+ ```typescript
189
+ // Refresh cache for a specific endpoint
190
+ await client.url.api.prefetch({ path: "/users" });
191
+
192
+ // Now the next request will use fresh data
193
+ const users = await client.url.api.get({ path: "/users" });
194
+ ```
195
+
196
+ ### Cache Features
197
+
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
202
+
203
+ ### Cache Performance
204
+
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 |
210
+
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:
223
+
224
+ ```typescript
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
234
+ });
35
235
  ```
36
236
 
37
- ### JSON Response
237
+ **How it works:**
238
+
239
+ - Uses `curl-impersonate` to mimic Chrome 120 browser
240
+ - Includes realistic TLS fingerprint and headers
241
+ - Bypasses most bot detection systems
242
+
243
+ ---
244
+
245
+ ## Advanced Features
246
+
247
+ ### TypeScript Generics
38
248
 
39
249
  ```typescript
40
250
  interface User {
41
251
  id: number;
42
252
  name: string;
253
+ email: string;
254
+ }
255
+
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({
270
+ warmup: {
271
+ api: "https://api.example.com",
272
+ cdn: "https://cdn.example.com",
273
+ },
274
+ });
275
+
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
291
+
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
+ });
299
+ ```
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
+
419
+ ### Request Options
420
+
421
+ ```typescript
422
+ interface UrlRequestOptions {
423
+ path?: string; // Path to append to base URL
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
43
428
  }
429
+ ```
430
+
431
+ ### Response Object
44
432
 
45
- const res = await client.get<User>("https://api.example.com/user/1");
46
- const user = await res.json();
47
- console.log(user.name);
433
+ ```typescript
434
+ interface JirenResponse<T = any> {
435
+ url: string;
436
+ status: number;
437
+ statusText: string;
438
+ headers: Record<string, string>;
439
+ ok: boolean;
440
+ redirected: boolean;
441
+ type: string;
442
+ body: {
443
+ json<R = T>(): Promise<R>;
444
+ text(): Promise<string>;
445
+ arrayBuffer(): Promise<ArrayBuffer>;
446
+ blob(): Promise<Blob>;
447
+ };
448
+ }
48
449
  ```
49
450
 
50
- ### Warmup / Prefetching
451
+ ---
51
452
 
52
- Warm up DNS and TLS handshakes to ensure subsequent requests are instant.
53
- You can do this in the constructor or via the `warmup` method.
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
+ });
473
+
474
+ // UserProfile.tsx
475
+ import { apiClient } from "./api-client";
476
+
477
+ function UserProfile() {
478
+ const [user, setUser] = useState(null);
479
+
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
54
492
 
55
493
  ```typescript
56
- // Option 1: In constructor
57
494
  const client = new JirenClient({
58
- warmup: ["https://google.com", "https://cloudflare.com"],
495
+ warmup: {
496
+ api: {
497
+ url: "https://api.example.com",
498
+ cache: { ttl: 30000 }, // 30-second cache
499
+ },
500
+ },
59
501
  });
60
502
 
61
- // Option 2: Explicit method call
62
- client.warmup(["https://example.org"]);
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
+ });
63
510
 
64
- // ... later, requests are instant
65
- const res = await client.get("https://google.com");
511
+ updateUI(notifications);
512
+ }, 10000);
66
513
  ```
67
514
 
68
- ## Benchmarks
515
+ ---
516
+
517
+ ## Requirements
518
+
519
+ - **Bun** v1.0.0 or higher
520
+
521
+ ---
522
+
523
+ ## License
524
+
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
69
536
 
70
- **Jiren** delivers native performance by bypassing the JavaScript engine overhead for network I/O.
537
+ - 📖 [Documentation](https://github.com/vikashkhati007/jiren)
538
+ - 🐛 [Issue Tracker](https://github.com/vikashkhati007/jiren/issues)
539
+ - 💬 [Discussions](https://github.com/vikashkhati007/jiren/discussions)
71
540
 
72
- | Client | Requests/sec | Relative Speed |
73
- | ----------------- | ------------- | -------------- |
74
- | **Jiren** | **1,550,000** | **1.0x** |
75
- | Bun `fetch` | 45,000 | 34x Slower |
76
- | Node `http` | 32,000 | 48x Slower |
77
- | Python `requests` | 6,500 | 238x Slower |
541
+ ---
78
542
 
79
- > Benchmarks run on MacBook Pro M3 Max, localhost loopback.
543
+ **Made with by the Jiren team**