@irpclib/irpc 1.0.0-beta.20 → 1.0.0-beta.21

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,52 +1,46 @@
1
1
  # @irpclib/irpc
2
2
 
3
- **Isomorphic Remote Procedure Call** - Call remote functions like local functions.
3
+ **Stop thinking about the network. Just call functions.**
4
4
 
5
- ```typescript
6
- // Instead of this:
7
- const response = await fetch('/api/hello');
8
- const data = await response.json();
5
+ IRPC makes remote function calls and reactive streaming look and feel like local functions. Declare once, implement on the server, call from the client — no routes, no endpoints, no WebSocket configuration.
9
6
 
10
- // Just do this:
7
+ ```typescript
11
8
  const message = await hello('John');
9
+
10
+ const call = loadDashboard('user-123');
11
+ call.subscribe(state => console.log(state.data));
12
12
  ```
13
13
 
14
14
  ---
15
15
 
16
- ## Why IRPC?
17
-
18
- **Beside the simplicity**, this is what you get:
19
-
20
- ### Benchmark Results
21
- **Scenario:** 100,000 users, 10 calls each (1,000,000 total calls)
16
+ ## Performance
22
17
 
23
18
  | Framework | Total Time | HTTP Requests | Speedup |
24
19
  |-----------|------------|---------------|---------|
25
- | **IRPC** | **3,617ms** | **100,000** | **6.96x** 🚀 |
20
+ | **IRPC** | **3,617ms** | **100,000** | **6.96x** |
26
21
  | Bun Native | 25,180ms | 1,000,000 | 1.00x |
27
22
  | Hono | 18,004ms | 1,000,000 | 1.40x |
28
23
  | Elysia | 36,993ms | 1,000,000 | 0.68x |
29
24
 
30
- **IRPC handled 1 million API calls in 3.6 seconds with 10x fewer HTTP connections.**
25
+ **1 million API calls in 3.6 seconds with 10x fewer HTTP connections.**
31
26
 
32
27
  ---
33
28
 
34
29
  ## Features
35
30
 
36
- - ✅ **6.96x faster** than traditional REST
37
- - ✅ **10x fewer HTTP connections** (automatic batching)
38
- - **Type-safe** (end-to-end TypeScript)
39
- - **Zero boilerplate** (no routes, no endpoints)
40
- - **Transport agnostic** (HTTP, WebSocket, etc.)
41
- - **Built-in caching** (configurable per-call)
42
- - **Retry & timeout** (automatic error handling)
31
+ - 6.96x faster than traditional REST APIs
32
+ - 10x fewer HTTP connections through automatic batching
33
+ - Native continuous reactive streaming via `RemoteState`
34
+ - End-to-end type safety with TypeScript
35
+ - Zero boilerplate no routes or endpoints
36
+ - Transport agnostic (HTTP, WebSocket, BroadcastChannel)
37
+ - Built-in caching configurable per function
38
+ - Automatic retry and timeout handling
43
39
 
44
40
  ---
45
41
 
46
42
  ## Quick Start
47
43
 
48
- ### Create New Project
49
-
50
44
  ```bash
51
45
  npx degit beerush/anchor/templates/irpc-bun-app my-api
52
46
  cd my-api
@@ -92,9 +86,18 @@ irpc.use(transport);
92
86
  import { irpc } from '../lib/module.js';
93
87
 
94
88
  export type HelloFn = (name: string) => Promise<string>;
89
+ export const hello = irpc.declare<HelloFn>({ name: 'hello' });
90
+ ```
95
91
 
96
- export const hello = irpc.declare<HelloFn>({
97
- name: 'hello'
92
+ ```typescript
93
+ // rpc/dashboard/index.ts
94
+ import { irpc } from '../lib/module.js';
95
+ import type { RemoteState } from '@irpclib/irpc';
96
+
97
+ export type LoadDashboardFn = (userId: string) => RemoteState<DashboardData>;
98
+ export const loadDashboard = irpc.declare<LoadDashboardFn>({
99
+ name: 'loadDashboard',
100
+ init: () => ({} as DashboardData), // Initial client-side state before server data arrives
98
101
  });
99
102
  ```
100
103
 
@@ -110,6 +113,22 @@ irpc.construct(hello, async (name) => {
110
113
  });
111
114
  ```
112
115
 
116
+ ```typescript
117
+ // rpc/dashboard/constructor.ts
118
+ import { irpc } from '../lib/module.js';
119
+ import { loadDashboard } from './index.js';
120
+ import { stream } from '@irpclib/irpc';
121
+
122
+ irpc.construct(loadDashboard, (userId) => {
123
+ return stream((data, resolve) => {
124
+ const q1 = db.users.get(userId).then(res => data.user = res);
125
+ const q2 = db.sales.aggregate(userId).then(res => data.sales = res);
126
+
127
+ Promise.all([q1, q2]).then(() => resolve());
128
+ }, {});
129
+ });
130
+ ```
131
+
113
132
  ### 4. Setup Server
114
133
 
115
134
  ```typescript
@@ -118,7 +137,7 @@ import { setContextProvider } from '@irpclib/irpc';
118
137
  import { AsyncLocalStorage } from 'node:async_hooks';
119
138
  import { HTTPRouter } from '@irpclib/http';
120
139
  import { irpc, transport } from './lib/module.js';
121
- import './rpc/hello/constructor.js'; // Import handlers
140
+ import './rpc/hello/constructor.js';
122
141
 
123
142
  setContextProvider(new AsyncLocalStorage());
124
143
 
@@ -137,16 +156,54 @@ Bun.serve({
137
156
  ### 5. Use on Client
138
157
 
139
158
  ```typescript
159
+ // client.ts
140
160
  import { hello } from './rpc/hello/index.js';
161
+ import { loadDashboard } from './rpc/dashboard/index.js';
141
162
 
163
+ // Standard execution
142
164
  const message = await hello('John');
143
165
  console.log(message); // "Hello John"
166
+
167
+ // Stream subscription
168
+ const call = loadDashboard('user-123');
169
+ call.subscribe(state => console.log('Hydration state:', state.data));
144
170
  ```
145
171
 
146
172
  ---
147
173
 
148
174
  ## Advanced Features
149
175
 
176
+ ### Call Configuration (Available at All Levels)
177
+
178
+ Configure retry, timeout, and other call behaviors at **function**, **package**, or **transport** level:
179
+
180
+ ```typescript
181
+ // Function-level (highest priority)
182
+ const criticalFn = irpc.declare({
183
+ name: 'processPayment',
184
+ timeout: 30000, // 30s timeout
185
+ maxRetries: 5, // 5 retry attempts
186
+ retryMode: 'exponential',
187
+ });
188
+
189
+ // Package-level (medium priority)
190
+ const irpc = createPackage({
191
+ name: 'my-api',
192
+ timeout: 10000, // 10s default
193
+ maxRetries: 3, // 3 retry attempts
194
+ retryMode: 'linear',
195
+ });
196
+
197
+ // Transport-level (lowest priority)
198
+ const transport = new HTTPTransport({
199
+ endpoint: '/api',
200
+ timeout: 5000, // 5s fallback
201
+ maxRetries: 1, // 1 retry attempt
202
+ });
203
+ ```
204
+
205
+ **Priority Order:** Function → Package → Transport
206
+
150
207
  ### Caching
151
208
 
152
209
  ```typescript
@@ -156,15 +213,27 @@ export const getUser = irpc.declare<GetUserFn>({
156
213
  });
157
214
  ```
158
215
 
159
- ### Timeout
216
+ ### Coalesce
217
+
218
+ Combine multiple calls with identical arguments:
160
219
 
161
220
  ```typescript
162
- export const slowQuery = irpc.declare<SlowQueryFn>({
163
- name: 'slowQuery',
164
- timeout: 30000, // 30 second timeout
221
+ export const expensiveQuery = irpc.declare<ExpensiveQueryFn>({
222
+ name: 'expensiveQuery',
223
+ coalesce: true,
165
224
  });
166
225
  ```
167
226
 
227
+ ### Cache Invalidation
228
+
229
+ ```typescript
230
+ // Invalidate specific cache entry
231
+ irpc.invalidate(getUser, 'user-123');
232
+
233
+ // Invalidate all cache for a function
234
+ irpc.invalidate(getUser);
235
+ ```
236
+
168
237
  ### Validation (Optional Zod)
169
238
 
170
239
  ```typescript