jiren 3.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.
Files changed (53) hide show
  1. package/README.md +768 -0
  2. package/components/cache.ts +451 -0
  3. package/components/client-node-native.ts +1410 -0
  4. package/components/client.ts +1852 -0
  5. package/components/index.ts +37 -0
  6. package/components/metrics.ts +314 -0
  7. package/components/native-cache-node.ts +170 -0
  8. package/components/native-cache.ts +222 -0
  9. package/components/native-json.ts +195 -0
  10. package/components/native-node.ts +138 -0
  11. package/components/native.ts +418 -0
  12. package/components/persistent-worker.ts +67 -0
  13. package/components/subprocess-worker.ts +60 -0
  14. package/components/types.ts +317 -0
  15. package/components/worker-pool.ts +153 -0
  16. package/components/worker.ts +154 -0
  17. package/dist/components/cache.d.ts +32 -0
  18. package/dist/components/cache.d.ts.map +1 -0
  19. package/dist/components/cache.js +374 -0
  20. package/dist/components/cache.js.map +1 -0
  21. package/dist/components/client-node-native.d.ts +71 -0
  22. package/dist/components/client-node-native.d.ts.map +1 -0
  23. package/dist/components/client-node-native.js +1055 -0
  24. package/dist/components/client-node-native.js.map +1 -0
  25. package/dist/components/metrics.d.ts +14 -0
  26. package/dist/components/metrics.d.ts.map +1 -0
  27. package/dist/components/metrics.js +260 -0
  28. package/dist/components/metrics.js.map +1 -0
  29. package/dist/components/native-cache-node.d.ts +41 -0
  30. package/dist/components/native-cache-node.d.ts.map +1 -0
  31. package/dist/components/native-cache-node.js +133 -0
  32. package/dist/components/native-cache-node.js.map +1 -0
  33. package/dist/components/native-node.d.ts +82 -0
  34. package/dist/components/native-node.d.ts.map +1 -0
  35. package/dist/components/native-node.js +124 -0
  36. package/dist/components/native-node.js.map +1 -0
  37. package/dist/components/types.d.ts +248 -0
  38. package/dist/components/types.d.ts.map +1 -0
  39. package/dist/components/types.js +2 -0
  40. package/dist/components/types.js.map +1 -0
  41. package/dist/index-node.d.ts +3 -0
  42. package/dist/index-node.d.ts.map +1 -0
  43. package/dist/index-node.js +5 -0
  44. package/dist/index-node.js.map +1 -0
  45. package/index-node.ts +10 -0
  46. package/index.ts +9 -0
  47. package/lib/libcurl-impersonate.dylib +0 -0
  48. package/lib/libhttpclient.dylib +0 -0
  49. package/lib/libidn2.0.dylib +0 -0
  50. package/lib/libintl.8.dylib +0 -0
  51. package/lib/libunistring.5.dylib +0 -0
  52. package/lib/libzstd.1.5.7.dylib +0 -0
  53. package/package.json +62 -0
package/README.md ADDED
@@ -0,0 +1,768 @@
1
+ # Jiren 🚀
2
+
3
+ **The fastest HTTP client for JavaScript** - Simple, type-safe, and blazingly fast.
4
+
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
+
8
+ ---
9
+
10
+ ## ⚡ Performance: Fastest in the World
11
+
12
+ Jiren outperforms top clients in every metric—throughput, latency, and stability.
13
+
14
+ ### Concurrent Benchmark (mitata)
15
+
16
+ | Client | Avg Latency | Req/sec | vs Jiren |
17
+ | ---------- | ----------- | ------------ | -------------- |
18
+ | **Jiren** | **20.9 µs** | **47,800/s** | 🏆 **Fastest** |
19
+ | Bun Fetch | 31.7 µs | 31,500/s | 52% slower |
20
+ | Node-Fetch | 29.4 µs | 34,000/s | 41% slower |
21
+ | Undici | 37.1 µs | 27,000/s | 77% slower |
22
+ | Ky | 36.5 µs | 27,400/s | 75% slower |
23
+ | Axios | 59.5 µs | 16,800/s | 185% slower |
24
+ | Got | 61.3 µs | 16,300/s | 193% slower |
25
+
26
+ ### Sequential Benchmark
27
+
28
+ | Client | Avg Latency | Req/sec | vs Jiren |
29
+ | ---------- | ----------- | ------------ | -------------- |
30
+ | **Jiren** | **20.7 µs** | **48,300/s** | 🏆 **Fastest** |
31
+ | Bun Fetch | 27.9 µs | 35,800/s | 35% slower |
32
+ | Node-Fetch | 29.8 µs | 33,600/s | 44% slower |
33
+ | Undici | 30.6 µs | 32,700/s | 48% slower |
34
+ | Ky | 35.6 µs | 28,100/s | 72% slower |
35
+ | Axios | 56.6 µs | 17,700/s | 173% slower |
36
+ | Got | 59.9 µs | 16,700/s | 189% slower |
37
+
38
+ ---
39
+
40
+ ## ✨ Why Jiren?
41
+
42
+ | Feature | Benefit |
43
+ | ----------------------- | ------------------------------------------------- |
44
+ | ⚡ **Blazing Fast** | Proven to be the fastest JS HTTP client |
45
+ | **HTTP/3 Support** | Automatic protocol upgrade for faster connections |
46
+ | 💾 **Built-in Caching** | Automatic response caching with zero config |
47
+ | � **Progress Tracking** | Real-time download progress with speed & ETA |
48
+ | �📝 **Type-Safe** | Full TypeScript support with autocomplete |
49
+ | 🔒 **Anti-Bot Ready** | Bypass common bot protections easily |
50
+ | � **Built-in Metrics** | Track performance out of the box |
51
+
52
+ ---
53
+
54
+ ## 📦 Installation
55
+
56
+ ```bash
57
+ bun add jiren
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 🚀 Quick Start
63
+
64
+ ### Step 1: Create Your Client
65
+
66
+ ```typescript
67
+ import { JirenClient } from "jiren";
68
+
69
+ const client = new JirenClient({
70
+ targets: {
71
+ api: "https://api.example.com",
72
+ github: "https://api.github.com",
73
+ },
74
+ });
75
+ ```
76
+
77
+ ### Step 2: Make Requests
78
+
79
+ ```typescript
80
+ // GET request
81
+ const response = await client.url.api.get({ path: "/users" });
82
+ const users = await response.body.json();
83
+
84
+ // POST request
85
+ await client.url.api.post(JSON.stringify({ name: "John" }), {
86
+ path: "/users",
87
+ headers: { "Content-Type": "application/json" },
88
+ });
89
+ ```
90
+
91
+ That's it! 🎉
92
+
93
+ ---
94
+
95
+ ## 📖 Table of Contents
96
+
97
+ 1. [Making Requests](#-making-requests)
98
+ 2. [Response Handling](#-response-handling)
99
+ 3. [Caching](#-caching)
100
+ 4. [Progress Tracking](#-progress-tracking)
101
+ 5. [Timeout Configuration](#%EF%B8%8F-timeout-configuration)
102
+ 6. [Anti-Bot Protection](#-anti-bot-protection)
103
+ 7. [Interceptors](#-interceptors)
104
+ 8. [Metrics](#-metrics)
105
+ 9. [TypeScript Support](#-typescript-support)
106
+ 10. [API Reference](#-api-reference)
107
+
108
+ ---
109
+
110
+ ## 🌐 Making Requests
111
+
112
+ ### GET Requests
113
+
114
+ ```typescript
115
+ // Simple GET
116
+ const response = await client.url.api.get();
117
+
118
+ // GET with path
119
+ const user = await client.url.github.get({ path: "/users/octocat" });
120
+
121
+ // GET with headers
122
+ const data = await client.url.api.get({
123
+ path: "/protected",
124
+ headers: { Authorization: "Bearer token123" },
125
+ });
126
+ ```
127
+
128
+ ### POST, PUT, PATCH, DELETE
129
+
130
+ ```typescript
131
+ // POST
132
+ await client.url.api.post(JSON.stringify({ name: "Jane" }), {
133
+ path: "/users",
134
+ headers: { "Content-Type": "application/json" },
135
+ });
136
+
137
+ // PUT
138
+ await client.url.api.put(JSON.stringify({ name: "Updated" }), {
139
+ path: "/users/123",
140
+ });
141
+
142
+ // PATCH
143
+ await client.url.api.patch(JSON.stringify({ email: "new@email.com" }), {
144
+ path: "/users/123",
145
+ });
146
+
147
+ // DELETE
148
+ await client.url.api.delete(null, { path: "/users/123" });
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 📤 Response Handling
154
+
155
+ ### Manual Parsing
156
+
157
+ ```typescript
158
+ const response = await client.url.api.get({ path: "/data" });
159
+
160
+ // Parse as JSON
161
+ const json = await response.body.json();
162
+
163
+ // Parse as text
164
+ const text = await response.body.text();
165
+
166
+ // Get as buffer
167
+ const buffer = await response.body.arrayBuffer();
168
+ ```
169
+
170
+ ### Auto-Parse (Recommended)
171
+
172
+ Let Jiren parse the response automatically:
173
+
174
+ ```typescript
175
+ // Auto-parse JSON
176
+ const users = await client.url.api.get({
177
+ path: "/users",
178
+ responseType: "json", // ← Returns parsed data directly!
179
+ });
180
+
181
+ // Auto-parse text
182
+ const html = await client.url.api.get({
183
+ path: "/page",
184
+ responseType: "text",
185
+ });
186
+ ```
187
+
188
+ ### 🚀 Specific JSON Field Extraction
189
+
190
+ Extract specific fields from JSON responses with optimized native parsing:
191
+
192
+ ```typescript
193
+ // Extract only the fields you need (faster for large JSON)
194
+ const { id, status } = await client.url.api.getJsonFields<{
195
+ id: number;
196
+ status: string;
197
+ }>(["id", "status"]);
198
+
199
+ console.log(id, status); // Only these fields are extracted
200
+ ```
201
+
202
+ **Performance:**
203
+
204
+ | Method | Use Case | Speed |
205
+ | -------------------------------- | -------------------- | ------------------------------ |
206
+ | `response.body.json()` | Need full object | Standard |
207
+ | `getJsonFields(["field1", ...])` | Need specific fields | **2-4x faster** for large JSON |
208
+
209
+ > 💡 **Tip:** Use `getJsonFields()` when you have large JSON payloads but only need a few fields.
210
+
211
+ ### Response Properties
212
+
213
+ ```typescript
214
+ const response = await client.url.api.get({ path: "/users" });
215
+
216
+ console.log(response.status); // 200
217
+ console.log(response.ok); // true
218
+ console.log(response.headers); // { "content-type": "application/json", ... }
219
+ console.log(response.redirected); // false
220
+ ```
221
+
222
+ ---
223
+
224
+ ## 💾 Caching
225
+
226
+ Enable caching for instant responses on repeated requests:
227
+
228
+ ### Enable Caching
229
+
230
+ ```typescript
231
+ const client = new JirenClient({
232
+ targets: {
233
+ api: {
234
+ url: "https://api.example.com",
235
+ cache: true, // ← Enable caching (60s default)
236
+ },
237
+ },
238
+ });
239
+ ```
240
+
241
+ ### Custom Cache Duration
242
+
243
+ ```typescript
244
+ const client = new JirenClient({
245
+ targets: {
246
+ api: {
247
+ url: "https://api.example.com",
248
+ cache: { ttl: 300000 }, // 5 minutes
249
+ },
250
+ cdn: {
251
+ url: "https://cdn.example.com",
252
+ cache: { ttl: 3600000 }, // 1 hour
253
+ },
254
+ },
255
+ });
256
+ ```
257
+
258
+ ### Cache Performance
259
+
260
+ | Request Type | Speed | Improvement |
261
+ | -------------- | ------ | ------------------ |
262
+ | First request | ~150ms | - |
263
+ | Cached request | ~1-2ms | **100x faster** ⚡ |
264
+
265
+ ### 🚀 Performance Benchmark
266
+
267
+ See the [top of this README](#-performance-fastest-in-the-world) for detailed benchmark results. Jiren consistently wins on throughput and tail latency.
268
+
269
+ ### Refresh Cache
270
+
271
+ ```typescript
272
+ // Force refresh cached data
273
+ await client.url.api.prefetch({ path: "/users" });
274
+ ```
275
+
276
+ > 💡 **Tip:** Add `.cache/` to your `.gitignore`
277
+
278
+ ---
279
+
280
+ ## 📊 Progress Tracking
281
+
282
+ Track download progress in real-time with the `download()` method:
283
+
284
+ ### Basic Usage
285
+
286
+ ```typescript
287
+ const response = await client.url.cdn.download({
288
+ path: "/large-file.zip",
289
+ onDownloadProgress: (progress) => {
290
+ console.log(`${progress.percent}% complete`);
291
+ console.log(`Speed: ${(progress.speed / 1024 / 1024).toFixed(2)} MB/s`);
292
+ console.log(`ETA: ${(progress.eta / 1000).toFixed(1)}s remaining`);
293
+ },
294
+ });
295
+
296
+ const data = await response.body.arrayBuffer();
297
+ ```
298
+
299
+ ### Progress Event Properties
300
+
301
+ | Property | Type | Description |
302
+ | --------- | -------- | ----------------------------- |
303
+ | `loaded` | `number` | Bytes transferred so far |
304
+ | `total` | `number` | Total bytes (0 if unknown) |
305
+ | `percent` | `number` | Percentage complete (0-100) |
306
+ | `speed` | `number` | Transfer speed in bytes/sec |
307
+ | `eta` | `number` | Estimated time remaining (ms) |
308
+
309
+ ### Progress Bar Example
310
+
311
+ ```typescript
312
+ await client.url.cdn.download({
313
+ path: "/video.mp4",
314
+ onDownloadProgress: (p) => {
315
+ const bar = "█".repeat(p.percent / 2).padEnd(50, "░");
316
+ process.stdout.write(`\r[${bar}] ${p.percent}%`);
317
+ },
318
+ });
319
+ console.log("\n✅ Download complete!");
320
+ ```
321
+
322
+ > 💡 **Note:** For HTTPS, progress events are fired as chunks are received. For HTTP, native streaming is used.
323
+
324
+ ### Upload Progress
325
+
326
+ Track upload progress in real-time with the `upload()` method:
327
+
328
+ ```typescript
329
+ await client.url.api.upload({
330
+ method: "POST",
331
+ path: "/upload",
332
+ body: largeData, // string or object
333
+ onUploadProgress: (progress) => {
334
+ console.log(`${progress.percent}% uploaded`);
335
+ console.log(`Speed: ${(progress.speed / 1024).toFixed(1)} KB/s`);
336
+ },
337
+ });
338
+ ```
339
+
340
+ ### Upload Progress Bar Example
341
+
342
+ ```typescript
343
+ await client.url.api.upload({
344
+ method: "PUT",
345
+ path: "/files/data.json",
346
+ body: JSON.stringify(bigPayload),
347
+ onUploadProgress: (p) => {
348
+ const bar = "█".repeat(p.percent / 2).padEnd(50, "░");
349
+ process.stdout.write(
350
+ `\r[${bar}] ${p.percent}% @ ${(p.speed / 1024 / 1024).toFixed(1)} MB/s`
351
+ );
352
+ },
353
+ });
354
+ console.log("\n✅ Upload complete!");
355
+ ```
356
+
357
+ > 💡 **Performance:** For HTTP, native Zig streaming achieves **~540 MB/s** upload speeds. HTTPS fires initial (0%) and final (100%) events.
358
+
359
+ ---
360
+
361
+ ## ⏱️ Timeout Configuration
362
+
363
+ Set maximum wait time for requests to prevent hanging on slow or unresponsive servers:
364
+
365
+ ### Basic Usage
366
+
367
+ ```typescript
368
+ // Timeout after 5 seconds
369
+ const response = await client.url.api.get({
370
+ timeout: 5000, // milliseconds
371
+ });
372
+
373
+ // Also works with POST, PUT, etc.
374
+ await client.url.api.post({
375
+ body: { data: "value" },
376
+ timeout: 10000, // 10 second timeout
377
+ });
378
+ ```
379
+
380
+ ### Handling Timeout Errors
381
+
382
+ ```typescript
383
+ try {
384
+ const response = await client.url.api.get({
385
+ path: "/slow-endpoint",
386
+ timeout: 3000,
387
+ });
388
+ } catch (error) {
389
+ if (error.name === "TimeoutError") {
390
+ console.log("Request timed out!");
391
+ } else {
392
+ throw error;
393
+ }
394
+ }
395
+ ```
396
+
397
+ ### Behavior Notes
398
+
399
+ - Timeout is specified in **milliseconds**
400
+ - **TimeoutError** is thrown when the timeout is exceeded
401
+ - Timeout errors are **not retried** (even if retry is configured)
402
+ - If `timeout` is not set or is `0`, no timeout is applied
403
+
404
+ ---
405
+
406
+ ## 🔒 Anti-Bot Protection
407
+
408
+ Bypass Cloudflare and other bot protections:
409
+
410
+ ```typescript
411
+ const client = new JirenClient({
412
+ targets: {
413
+ protected: "https://protected-site.com",
414
+ },
415
+ antibot: true,
416
+ });
417
+
418
+ const response = await client.url.protected.get();
419
+ ```
420
+
421
+ ---
422
+
423
+ ## 🔄 Interceptors
424
+
425
+ Add middleware to modify requests/responses:
426
+
427
+ ### Add Authentication
428
+
429
+ ```typescript
430
+ const client = new JirenClient({
431
+ targets: { api: "https://api.example.com" },
432
+ interceptors: {
433
+ request: [
434
+ (ctx) => ({
435
+ ...ctx,
436
+ headers: {
437
+ ...ctx.headers,
438
+ Authorization: `Bearer ${getToken()}`,
439
+ },
440
+ }),
441
+ ],
442
+ },
443
+ });
444
+ ```
445
+
446
+ ### Log Responses
447
+
448
+ ```typescript
449
+ const client = new JirenClient({
450
+ targets: { api: "https://api.example.com" },
451
+ interceptors: {
452
+ response: [
453
+ (ctx) => {
454
+ console.log(`${ctx.response.status} ${ctx.request.url}`);
455
+ return ctx;
456
+ },
457
+ ],
458
+ },
459
+ });
460
+ ```
461
+
462
+ ### Handle Errors
463
+
464
+ ```typescript
465
+ const client = new JirenClient({
466
+ targets: { api: "https://api.example.com" },
467
+ interceptors: {
468
+ error: [
469
+ (error, ctx) => {
470
+ console.error(`Request failed: ${ctx.url}`);
471
+ },
472
+ ],
473
+ },
474
+ });
475
+ ```
476
+
477
+ ### Add Interceptors Later
478
+
479
+ ```typescript
480
+ client.use({
481
+ request: [
482
+ (ctx) => ({ ...ctx, headers: { ...ctx.headers, "X-Custom": "value" } }),
483
+ ],
484
+ });
485
+ ```
486
+
487
+ ---
488
+
489
+ ## 📊 Metrics
490
+
491
+ Track performance and cache efficiency:
492
+
493
+ ### Get Endpoint Metrics
494
+
495
+ ```typescript
496
+ const metrics = client.metrics.get("api");
497
+
498
+ console.log(metrics.requests.total); // Total requests made
499
+ console.log(metrics.timing.avgMs); // Average response time
500
+ console.log(metrics.cache.hitRate); // Cache hit percentage
501
+ ```
502
+
503
+ ### Get Global Metrics
504
+
505
+ ```typescript
506
+ const global = client.metrics.getGlobal();
507
+
508
+ console.log(global.totalRequests); // All requests
509
+ console.log(global.avgResponseTimeMs); // Average across all endpoints
510
+ console.log(global.overallCacheHitRate); // Overall cache performance
511
+ ```
512
+
513
+ ### Export & Reset
514
+
515
+ ```typescript
516
+ // Export as JSON
517
+ const json = client.metrics.export();
518
+
519
+ // Reset metrics
520
+ client.metrics.reset();
521
+ ```
522
+
523
+ ---
524
+
525
+ ## 🔷 TypeScript Support
526
+
527
+ ### Type-Safe Responses
528
+
529
+ ```typescript
530
+ interface User {
531
+ id: number;
532
+ name: string;
533
+ email: string;
534
+ }
535
+
536
+ // TypeScript knows the response type!
537
+ const user = await client.url.api.get<User>({
538
+ path: "/users/123",
539
+ responseType: "json",
540
+ });
541
+
542
+ console.log(user.name); // ✅ Autocomplete works!
543
+ ```
544
+
545
+ ### Typed URL Keys
546
+
547
+ ```typescript
548
+ const client = new JirenClient({
549
+ targets: {
550
+ api: "https://api.example.com",
551
+ cdn: "https://cdn.example.com",
552
+ },
553
+ });
554
+
555
+ client.url.api.get(); // ✅ Valid
556
+ client.url.cdn.get(); // ✅ Valid
557
+ client.url.foo.get(); // ❌ TypeScript error!
558
+ ```
559
+
560
+ ---
561
+
562
+ ## 📚 API Reference
563
+
564
+ ### Creating a Client
565
+
566
+ ```typescript
567
+ new JirenClient({
568
+ targets: {
569
+ // Simple URL
570
+ api: "https://api.example.com",
571
+
572
+ // With caching
573
+ cdn: {
574
+ url: "https://cdn.example.com",
575
+ cache: true, // or { ttl: 60000 }
576
+ },
577
+ },
578
+
579
+ // Optional settings
580
+ antibot: false, // Enable anti-bot protection
581
+ benchmark: false, // Benchmark mode
582
+ interceptors: {}, // Request/response interceptors
583
+ });
584
+ ```
585
+
586
+ ### Request Methods
587
+
588
+ | Method | Signature |
589
+ | ----------------- | --------------------------------------------------------- |
590
+ | `get()` | `get<T>(options?): Promise<Response<T>>` |
591
+ | `post()` | `post<T>(body?, options?): Promise<Response<T>>` |
592
+ | `put()` | `put<T>(body?, options?): Promise<Response<T>>` |
593
+ | `patch()` | `patch<T>(body?, options?): Promise<Response<T>>` |
594
+ | `delete()` | `delete<T>(body?, options?): Promise<Response<T>>` |
595
+ | `head()` | `head(options?): Promise<Response>` |
596
+ | `options()` | `options(options?): Promise<Response>` |
597
+ | `prefetch()` | `prefetch(options?): Promise<void>` |
598
+ | `download()` | `download<T>(options?): Promise<Response<T>>` |
599
+ | `getJsonFields()` | `getJsonFields<T>(fields, options?): Promise<Partial<T>>` |
600
+
601
+ ### Request Options
602
+
603
+ ```typescript
604
+ {
605
+ path?: string; // URL path to append
606
+ headers?: Record<string, string>; // Request headers
607
+ responseType?: "json" | "text"; // Auto-parse response
608
+ maxRedirects?: number; // Max redirects (default: 5)
609
+ }
610
+ ```
611
+
612
+ ### Response Object
613
+
614
+ ```typescript
615
+ {
616
+ url: string;
617
+ status: number;
618
+ statusText: string;
619
+ headers: Record<string, string>;
620
+ ok: boolean;
621
+ redirected: boolean;
622
+ body: {
623
+ json<T>(): Promise<T>;
624
+ text(): Promise<string>;
625
+ arrayBuffer(): Promise<ArrayBuffer>;
626
+ blob(): Promise<Blob>;
627
+ };
628
+ }
629
+ ```
630
+
631
+ ---
632
+
633
+ ## 💡 Examples
634
+
635
+ ### API Client Pattern
636
+
637
+ ```typescript
638
+ // lib/api.ts
639
+ import { JirenClient } from "jiren";
640
+
641
+ export const api = new JirenClient({
642
+ targets: {
643
+ backend: {
644
+ url: process.env.API_URL!,
645
+ cache: { ttl: 30000 },
646
+ },
647
+ },
648
+ interceptors: {
649
+ request: [
650
+ (ctx) => ({
651
+ ...ctx,
652
+ headers: {
653
+ ...ctx.headers,
654
+ Authorization: `Bearer ${getSession()?.token}`,
655
+ },
656
+ }),
657
+ ],
658
+ },
659
+ });
660
+
661
+ // Usage anywhere
662
+ import { api } from "@/lib/api";
663
+ const users = await api.url.backend.get({
664
+ path: "/users",
665
+ responseType: "json",
666
+ });
667
+ ```
668
+
669
+ ### React/Next.js Hook
670
+
671
+ ```typescript
672
+ function useApi<T>(path: string) {
673
+ const [data, setData] = useState<T | null>(null);
674
+ const [loading, setLoading] = useState(true);
675
+
676
+ useEffect(() => {
677
+ api.url.backend
678
+ .get<T>({ path, responseType: "json" })
679
+ .then(setData)
680
+ .finally(() => setLoading(false));
681
+ }, [path]);
682
+
683
+ return { data, loading };
684
+ }
685
+
686
+ // Usage
687
+ function UserList() {
688
+ const { data: users, loading } = useApi<User[]>("/users");
689
+ if (loading) return <Spinner />;
690
+ return (
691
+ <ul>
692
+ {users?.map((u) => (
693
+ <li key={u.id}>{u.name}</li>
694
+ ))}
695
+ </ul>
696
+ );
697
+ }
698
+ ```
699
+
700
+ ---
701
+
702
+ ## 🏗️ Framework Integration
703
+
704
+ ### Next.js (App Router)
705
+
706
+ To use Jiren in Next.js, add it to `serverExternalPackages` in `next.config.ts`:
707
+
708
+ ```typescript
709
+ import type { NextConfig } from "next";
710
+
711
+ const nextConfig: NextConfig = {
712
+ // Required: Treat Jiren and Koffi as external native packages
713
+ serverExternalPackages: ["jiren", "koffi"],
714
+ };
715
+
716
+ export default nextConfig;
717
+ ```
718
+
719
+ **Usage in API Routes:**
720
+
721
+ ```typescript
722
+ // app/api/data/route.ts
723
+ import { JirenClient } from "jiren";
724
+
725
+ const client = new JirenClient({
726
+ targets: [{ key: "api", url: "https://api.example.com" }],
727
+ });
728
+
729
+ export async function GET() {
730
+ const response = await client.url.api.get({ path: "/users" });
731
+ return Response.json(await response.body.json());
732
+ }
733
+ ```
734
+
735
+ ---
736
+
737
+ ## 📋 Requirements
738
+
739
+ - **Runtime**:
740
+ - **Bun** v1.0.0+
741
+ - **Node.js** v18.0.0+ (macOS/Linux)
742
+ - **OS**: macOS (ARM64/x64) or Linux (x64)
743
+
744
+ ---
745
+
746
+ ## 📄 License
747
+
748
+ MIT © VK
749
+
750
+ ---
751
+
752
+ ## 🤝 Contributing
753
+
754
+ Contributions welcome! Please open an issue or submit a pull request.
755
+
756
+ ---
757
+
758
+ ## 🆘 Support
759
+
760
+ - 📖 [Documentation](https://github.com/vikashkhati007/jiren)
761
+ - 🐛 [Issue Tracker](https://github.com/vikashkhati007/jiren/issues)
762
+ - 💬 [Discussions](https://github.com/vikashkhati007/jiren/discussions)
763
+
764
+ ---
765
+
766
+ <p align="center">
767
+ <strong>Made with ⚡ by VK</strong>
768
+ </p>