@igoforth/ws-rpc 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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +446 -0
  3. package/dist/adapters/client.d.ts +117 -0
  4. package/dist/adapters/client.js +241 -0
  5. package/dist/adapters/cloudflare-do.d.ts +72 -0
  6. package/dist/adapters/cloudflare-do.js +192 -0
  7. package/dist/adapters/index.d.ts +13 -0
  8. package/dist/adapters/index.js +16 -0
  9. package/dist/adapters/server.d.ts +10 -0
  10. package/dist/adapters/server.js +122 -0
  11. package/dist/adapters/types.d.ts +125 -0
  12. package/dist/adapters/types.js +3 -0
  13. package/dist/codecs/cbor.d.ts +16 -0
  14. package/dist/codecs/cbor.js +36 -0
  15. package/dist/codecs/factory.d.ts +3 -0
  16. package/dist/codecs/factory.js +3 -0
  17. package/dist/codecs/index.d.ts +5 -0
  18. package/dist/codecs/index.js +5 -0
  19. package/dist/codecs/json.d.ts +4 -0
  20. package/dist/codecs/json.js +4 -0
  21. package/dist/codecs/msgpack.d.ts +16 -0
  22. package/dist/codecs/msgpack.js +34 -0
  23. package/dist/codecs-BmYG2d_U.js +0 -0
  24. package/dist/default-BkrMd28n.js +253 -0
  25. package/dist/default-xDNNMrg0.d.ts +129 -0
  26. package/dist/durable-MZjkvyS6.js +165 -0
  27. package/dist/errors-5BfreE63.js +96 -0
  28. package/dist/errors.d.ts +69 -0
  29. package/dist/errors.js +7 -0
  30. package/dist/factory-3ziwTuZe.js +132 -0
  31. package/dist/factory-C1v0AEHY.d.ts +101 -0
  32. package/dist/index-Be7jjS77.d.ts +1 -0
  33. package/dist/index.d.ts +14 -0
  34. package/dist/index.js +14 -0
  35. package/dist/interface-C4S-WCqW.d.ts +120 -0
  36. package/dist/json-54Z2bIIs.d.ts +22 -0
  37. package/dist/json-Bshec-bZ.js +41 -0
  38. package/dist/memory-Bqb3KEVr.js +48 -0
  39. package/dist/memory-D1nGjzzH.d.ts +41 -0
  40. package/dist/multi-peer-BAi9yVzp.js +242 -0
  41. package/dist/peers/default.d.ts +8 -0
  42. package/dist/peers/default.js +8 -0
  43. package/dist/peers/durable.d.ts +136 -0
  44. package/dist/peers/durable.js +9 -0
  45. package/dist/peers/index.d.ts +10 -0
  46. package/dist/peers/index.js +9 -0
  47. package/dist/protocol-DA84zrc2.d.ts +211 -0
  48. package/dist/protocol-_mpoOPp6.js +192 -0
  49. package/dist/protocol.d.ts +6 -0
  50. package/dist/protocol.js +6 -0
  51. package/dist/reconnect-CGAA_1Gf.js +26 -0
  52. package/dist/reconnect-DbcN0R_1.d.ts +35 -0
  53. package/dist/schema-CN5HHHku.d.ts +108 -0
  54. package/dist/schema.d.ts +2 -0
  55. package/dist/schema.js +43 -0
  56. package/dist/server-zTjpJpoX.d.ts +209 -0
  57. package/dist/sql-CCjc6Bid.js +142 -0
  58. package/dist/sql-DPmHOeZy.d.ts +131 -0
  59. package/dist/storage/index.d.ts +8 -0
  60. package/dist/storage/index.js +7 -0
  61. package/dist/storage/interface.d.ts +3 -0
  62. package/dist/storage/interface.js +0 -0
  63. package/dist/storage/memory.d.ts +7 -0
  64. package/dist/storage/memory.js +6 -0
  65. package/dist/storage/sql.d.ts +7 -0
  66. package/dist/storage/sql.js +6 -0
  67. package/dist/types-Be-qmQu0.d.ts +111 -0
  68. package/dist/types-D_psiH09.js +13 -0
  69. package/dist/types.d.ts +7 -0
  70. package/dist/types.js +3 -0
  71. package/dist/utils/index.d.ts +2 -0
  72. package/dist/utils/index.js +3 -0
  73. package/dist/utils/reconnect.d.ts +2 -0
  74. package/dist/utils/reconnect.js +3 -0
  75. package/package.json +156 -0
  76. package/src/adapters/client.ts +396 -0
  77. package/src/adapters/cloudflare-do.ts +346 -0
  78. package/src/adapters/index.ts +16 -0
  79. package/src/adapters/multi-peer.ts +404 -0
  80. package/src/adapters/server.ts +192 -0
  81. package/src/adapters/types.ts +202 -0
  82. package/src/codecs/cbor.ts +42 -0
  83. package/src/codecs/factory.ts +210 -0
  84. package/src/codecs/index.ts +30 -0
  85. package/src/codecs/json.ts +42 -0
  86. package/src/codecs/msgpack.ts +36 -0
  87. package/src/errors.ts +105 -0
  88. package/src/index.ts +102 -0
  89. package/src/peers/default.ts +433 -0
  90. package/src/peers/durable.ts +280 -0
  91. package/src/peers/index.ts +13 -0
  92. package/src/protocol.ts +306 -0
  93. package/src/schema.ts +167 -0
  94. package/src/storage/index.ts +20 -0
  95. package/src/storage/interface.ts +146 -0
  96. package/src/storage/memory.ts +84 -0
  97. package/src/storage/sql.ts +266 -0
  98. package/src/types.ts +158 -0
  99. package/src/utils/index.ts +9 -0
  100. package/src/utils/reconnect.ts +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ian Goforth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,446 @@
1
+ # @igoforth/ws-rpc
2
+
3
+ [![CI](https://github.com/igoforth/ws-rpc/actions/workflows/ci.yml/badge.svg)](https://github.com/igoforth/ws-rpc/actions/workflows/ci.yml)
4
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
5
+ [![Node](https://img.shields.io/badge/Node.js-18+-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ Bidirectional RPC over WebSocket with Zod schema validation and full TypeScript inference.
9
+
10
+ ## Features
11
+
12
+ - **Bidirectional RPC** - Both client and server can call methods on each other
13
+ - **Schema-first** - Define your API with Zod schemas, get full TypeScript inference
14
+ - **Multiple codecs** - JSON (built-in), MessagePack, and CBOR support
15
+ - **Cloudflare Durable Objects** - First-class support with hibernation-safe persistence
16
+ - **Auto-reconnect** - Client automatically reconnects with exponential backoff
17
+ - **Fire-and-forget events** - Decoupled from request/response pattern
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @igoforth/ws-rpc zod
23
+ # or
24
+ pnpm add @igoforth/ws-rpc zod
25
+ ```
26
+
27
+ ### Optional codecs
28
+
29
+ ```bash
30
+ # MessagePack (faster, smaller)
31
+ pnpm add @msgpack/msgpack
32
+
33
+ # CBOR (binary, compact)
34
+ pnpm add cbor-x
35
+ ```
36
+
37
+ ### Cloudflare Durable Objects
38
+
39
+ ```bash
40
+ pnpm add @cloudflare/actors
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ### 1. Define your schema
46
+
47
+ ```typescript
48
+ import { z } from "zod";
49
+ import { method, event, type RpcSchema } from "@igoforth/ws-rpc/schema";
50
+
51
+ // Server schema - methods the server implements
52
+ export const ServerSchema = {
53
+ methods: {
54
+ getUser: method({
55
+ input: z.object({ id: z.string() }),
56
+ output: z.object({ name: z.string(), email: z.string() }),
57
+ }),
58
+ createOrder: method({
59
+ input: z.object({ product: z.string(), quantity: z.number() }),
60
+ output: z.object({ orderId: z.string() }),
61
+ }),
62
+ },
63
+ events: {
64
+ orderUpdated: event({
65
+ data: z.object({ orderId: z.string(), status: z.string() }),
66
+ }),
67
+ },
68
+ } satisfies RpcSchema;
69
+
70
+ // Client schema - methods the client implements (for bidirectional RPC)
71
+ export const ClientSchema = {
72
+ methods: {
73
+ ping: method({
74
+ input: z.object({}),
75
+ output: z.object({ pong: z.boolean() }),
76
+ }),
77
+ },
78
+ events: {},
79
+ } satisfies RpcSchema;
80
+ ```
81
+
82
+ ### 2. Create a client
83
+
84
+ ```typescript
85
+ import { RpcClient } from "@igoforth/ws-rpc/adapters/client";
86
+ import { ServerSchema, ClientSchema } from "./schemas";
87
+
88
+ const client = new RpcClient({
89
+ url: "wss://your-server.com/ws",
90
+ localSchema: ClientSchema,
91
+ remoteSchema: ServerSchema,
92
+ provider: {
93
+ // Implement methods the server can call on us
94
+ ping: async () => ({ pong: true }),
95
+ },
96
+ reconnect: {
97
+ initialDelay: 1000,
98
+ maxDelay: 30000,
99
+ maxAttempts: 10,
100
+ },
101
+ autoConnect: true, // Connect immediately (or call client.connect() manually)
102
+ onConnect: () => console.log("Connected"),
103
+ onDisconnect: (code, reason) => console.log("Disconnected:", code, reason),
104
+ });
105
+
106
+ // Call server methods with full type safety
107
+ const user = await client.driver.getUser({ id: "123" });
108
+ console.log(user.name, user.email);
109
+
110
+ const order = await client.driver.createOrder({ product: "widget", quantity: 5 });
111
+ console.log(order.orderId);
112
+
113
+ // Emit events to the server
114
+ client.emit("someEvent", { data: "value" });
115
+
116
+ // Disconnect when done
117
+ client.disconnect();
118
+ ```
119
+
120
+ ### 3. Create a server (Node.js)
121
+
122
+ ```typescript
123
+ import { WebSocketServer } from "ws";
124
+ import { RpcServer } from "@igoforth/ws-rpc/adapters/server";
125
+ import { ServerSchema, ClientSchema } from "./schemas";
126
+
127
+ const server = new RpcServer({
128
+ wss: { port: 8080 },
129
+ WebSocketServer,
130
+ localSchema: ServerSchema,
131
+ remoteSchema: ClientSchema,
132
+ provider: {
133
+ getUser: async ({ id }) => {
134
+ return { name: "John Doe", email: "john@example.com" };
135
+ },
136
+ createOrder: async ({ product, quantity }) => {
137
+ return { orderId: crypto.randomUUID() };
138
+ },
139
+ },
140
+ hooks: {
141
+ onConnect: (peer) => {
142
+ console.log(`Client ${peer.id} connected`);
143
+
144
+ // Call methods on this specific client
145
+ peer.driver.ping({}).then((result) => {
146
+ console.log("Client responded:", result.pong);
147
+ });
148
+ },
149
+ onDisconnect: (peer) => {
150
+ console.log(`Client ${peer.id} disconnected`);
151
+ },
152
+ onError: (peer, error) => {
153
+ console.error(`Error from ${peer?.id}:`, error);
154
+ },
155
+ },
156
+ });
157
+
158
+ // Emit to all connected clients
159
+ server.emit("orderUpdated", { orderId: "123", status: "shipped" });
160
+
161
+ // Emit to specific clients by ID
162
+ server.emit("orderUpdated", { orderId: "456", status: "delivered" }, ["peer-id-1", "peer-id-2"]);
163
+
164
+ // Call methods on all clients
165
+ const results = await server.driver.ping({});
166
+ for (const { id, result } of results) {
167
+ if (result.success) {
168
+ console.log(`Peer ${id}:`, result.value);
169
+ }
170
+ }
171
+
172
+ // Get connection info
173
+ console.log("Connected clients:", server.getConnectionCount());
174
+ console.log("Client IDs:", server.getConnectionIds());
175
+
176
+ // Close a specific client
177
+ server.closePeer("peer-id", 1000, "Goodbye");
178
+
179
+ // Graceful shutdown
180
+ process.on("SIGTERM", () => server.close());
181
+ ```
182
+
183
+ ### 4. Cloudflare Durable Object
184
+
185
+ ```typescript
186
+ import { Actor } from "@cloudflare/actors";
187
+ import { withRpc } from "@igoforth/ws-rpc/adapters/cloudflare-do";
188
+ import { ServerSchema, ClientSchema } from "./schemas";
189
+
190
+ // The mixin adds RPC capabilities to your Actor
191
+ // Your class must implement the methods defined in localSchema
192
+ export class GameRoom extends withRpc(Actor, {
193
+ localSchema: ServerSchema,
194
+ remoteSchema: ClientSchema,
195
+ }) {
196
+ private gameState = { players: [] as string[] };
197
+
198
+ // Implement methods from ServerSchema
199
+ async getUser({ id }: { id: string }) {
200
+ return { name: `Player ${id}`, email: `${id}@game.com` };
201
+ }
202
+
203
+ async createOrder({ product, quantity }: { product: string; quantity: number }) {
204
+ return { orderId: crypto.randomUUID() };
205
+ }
206
+
207
+ // Use this.driver to call methods on connected clients
208
+ async notifyAllPlayers() {
209
+ // Call ping on all connected clients
210
+ const results = await this.driver.ping({});
211
+ console.log("Ping results:", results);
212
+ }
213
+
214
+ // Use this.emit to send events to clients
215
+ broadcastUpdate() {
216
+ this.emit("orderUpdated", { orderId: "123", status: "updated" });
217
+ }
218
+
219
+ // Check connection status
220
+ getPlayerCount() {
221
+ return this.getConnectionCount();
222
+ }
223
+ }
224
+ ```
225
+
226
+ ## API Reference
227
+
228
+ ### Schema Definition
229
+
230
+ ```typescript
231
+ import { method, event } from "@igoforth/ws-rpc/schema";
232
+ import { z } from "zod";
233
+
234
+ // Define a method with input/output validation
235
+ const myMethod = method({
236
+ input: z.object({ /* ... */ }),
237
+ output: z.object({ /* ... */ }),
238
+ });
239
+
240
+ // Define an event (fire-and-forget)
241
+ const myEvent = event({
242
+ data: z.object({ /* ... */ }),
243
+ });
244
+
245
+ // Combine into a schema
246
+ const MySchema = {
247
+ methods: { myMethod },
248
+ events: { myEvent },
249
+ } satisfies RpcSchema;
250
+ ```
251
+
252
+ ### Type Inference
253
+
254
+ ```typescript
255
+ import type { Provider, Driver, InferInput, InferOutput } from "@igoforth/ws-rpc/schema";
256
+
257
+ // Get the provider type (what you implement)
258
+ type MyProvider = Provider<typeof MySchema>;
259
+
260
+ // Get the driver type (what you call)
261
+ type MyDriver = Driver<typeof MySchema>;
262
+
263
+ // Get input/output types for a specific method
264
+ type MyMethodInput = InferInput<typeof MySchema["methods"]["myMethod"]>;
265
+ type MyMethodOutput = InferOutput<typeof MySchema["methods"]["myMethod"]>;
266
+ ```
267
+
268
+ ### Codecs
269
+
270
+ ```typescript
271
+ import { createMsgpackCodec } from "@igoforth/ws-rpc/codecs/msgpack";
272
+ import { createCborCodec } from "@igoforth/ws-rpc/codecs/cbor";
273
+ import { createJsonCodec } from "@igoforth/ws-rpc/codecs/json";
274
+
275
+ // JSON (default)
276
+ const jsonCodec = createJsonCodec(z.unknown());
277
+
278
+ // MessagePack (requires @msgpack/msgpack)
279
+ const msgpackCodec = createMsgpackCodec(z.unknown());
280
+
281
+ // CBOR (requires cbor-x)
282
+ const cborCodec = createCborCodec(z.unknown());
283
+ ```
284
+
285
+ ### Error Handling
286
+
287
+ ```typescript
288
+ import {
289
+ RpcError,
290
+ RpcTimeoutError,
291
+ RpcRemoteError,
292
+ RpcConnectionClosed,
293
+ RpcValidationError,
294
+ RpcMethodNotFoundError,
295
+ } from "@igoforth/ws-rpc/errors";
296
+
297
+ try {
298
+ await client.driver.someMethod({ /* ... */ });
299
+ } catch (error) {
300
+ if (error instanceof RpcTimeoutError) {
301
+ console.log(`Request '${error.method}' timed out after ${error.timeoutMs}ms`);
302
+ } else if (error instanceof RpcValidationError) {
303
+ console.log("Invalid input/output:", error.message);
304
+ } else if (error instanceof RpcRemoteError) {
305
+ console.log("Server error:", error.message, error.code);
306
+ } else if (error instanceof RpcMethodNotFoundError) {
307
+ console.log(`Method '${error.method}' not found`);
308
+ } else if (error instanceof RpcConnectionClosed) {
309
+ console.log("Connection closed");
310
+ }
311
+ }
312
+ ```
313
+
314
+ ### Client Options
315
+
316
+ ```typescript
317
+ const client = new RpcClient({
318
+ url: "wss://...",
319
+ localSchema: MyLocalSchema,
320
+ remoteSchema: MyRemoteSchema,
321
+ provider: { /* method implementations */ },
322
+
323
+ // Reconnection options (set to false to disable)
324
+ reconnect: {
325
+ initialDelay: 1000, // First retry delay (ms)
326
+ maxDelay: 30000, // Maximum retry delay (ms)
327
+ backoffMultiplier: 2, // Exponential backoff multiplier
328
+ maxAttempts: 0, // Max attempts (0 = unlimited)
329
+ jitter: 0.1, // Random jitter factor (0-1)
330
+ },
331
+
332
+ // Request timeout (ms)
333
+ timeout: 30000,
334
+
335
+ // Auto-connect on creation (default: false)
336
+ autoConnect: true,
337
+
338
+ // WebSocket options
339
+ protocols: ["v1"], // Subprotocols
340
+ headers: { Authorization: "Bearer ..." }, // Headers (Node.js/Bun only)
341
+
342
+ // Event handlers
343
+ onConnect: () => console.log("Connected"),
344
+ onDisconnect: (code, reason) => console.log("Disconnected"),
345
+ onReconnect: (attempt, delay) => console.log(`Reconnecting in ${delay}ms`),
346
+ onReconnectFailed: () => console.log("Reconnection failed"),
347
+ onEvent: (event, data) => console.log("Event:", event, data),
348
+ });
349
+
350
+ // Connection state
351
+ client.state; // "disconnected" | "connecting" | "connected" | "reconnecting"
352
+ client.isConnected; // boolean
353
+ ```
354
+
355
+ ## Hibernation-Safe Durable Objects
356
+
357
+ For Cloudflare Durable Objects that need hibernation-safe outgoing calls, use `DurableRpcPeer` with continuation-passing style:
358
+
359
+ ```typescript
360
+ import { DurableRpcPeer } from "@igoforth/ws-rpc/peer";
361
+ import { SqlPendingCallStorage } from "@igoforth/ws-rpc/storage";
362
+
363
+ class MyDO extends Actor<Env> {
364
+ private peer!: DurableRpcPeer<LocalSchema, RemoteSchema, this>;
365
+
366
+ onWebSocketConnect(ws: WebSocket) {
367
+ this.peer = new DurableRpcPeer({
368
+ ws,
369
+ localSchema: LocalSchema,
370
+ remoteSchema: RemoteSchema,
371
+ provider: this,
372
+ storage: new SqlPendingCallStorage(this.ctx.storage.sql),
373
+ actor: this,
374
+ });
375
+ }
376
+
377
+ onWebSocketMessage(ws: WebSocket, message: string | ArrayBuffer) {
378
+ this.peer.handleMessage(message);
379
+ }
380
+
381
+ async doSomething() {
382
+ // Promise-based (NOT hibernation-safe - pending if DO hibernates)
383
+ const result = await this.peer.driver.someMethod({ data: "value" });
384
+
385
+ // Continuation-based (hibernation-safe)
386
+ this.peer.callWithCallback("someMethod", { data: "value" }, "onResult");
387
+ }
388
+
389
+ // Callback receives result even after hibernation
390
+ onResult(result: SomeResult, context: CallContext) {
391
+ console.log("Result:", result);
392
+ console.log("Latency:", context.latencyMs, "ms");
393
+ }
394
+ }
395
+ ```
396
+
397
+ ## Performance
398
+
399
+ Real WebSocket RPC round-trip benchmarks (localhost, Node.js):
400
+
401
+ **Wire sizes:**
402
+ | Payload | JSON | MessagePack | CBOR |
403
+ |---------|------|-------------|------|
404
+ | Small | 93 B | 71 B | 112 B |
405
+ | Medium | 3.5 KB | 2.1 KB | 1.4 KB |
406
+ | Large | 24.5 KB | 19.6 KB | 14.1 KB |
407
+
408
+ **Throughput (ops/sec):**
409
+ | Payload | JSON | MessagePack | CBOR |
410
+ |---------|------|-------------|------|
411
+ | Small | 1,371 | 2,208 | **2,423** |
412
+ | Medium | 2,218 | 2,221 | **2,249** |
413
+ | Large | 1,334 | 1,245 | **1,562** |
414
+
415
+ CBOR provides the best balance of speed and wire size for most payloads. MessagePack excels with smaller payloads. JSON is the most portable but largest.
416
+
417
+ Run benchmarks yourself: `pnpm bench`
418
+
419
+ ## Multi-Peer Driver Results
420
+
421
+ When calling methods via `server.driver` or `this.driver` in a Durable Object, results are returned as an array:
422
+
423
+ ```typescript
424
+ // Call all connected peers
425
+ const results = await server.driver.getData({});
426
+
427
+ // Each result contains the peer ID and success/error
428
+ for (const { id, result } of results) {
429
+ if (result.success) {
430
+ console.log(`Peer ${id} returned:`, result.value);
431
+ } else {
432
+ console.error(`Peer ${id} failed:`, result.error.message);
433
+ }
434
+ }
435
+
436
+ // Call specific peers
437
+ const singleResult = await server.driver.getData({}, { ids: "peer-123" });
438
+ const multiResult = await server.driver.getData({}, {
439
+ ids: ["peer-1", "peer-2"],
440
+ timeout: 5000,
441
+ });
442
+ ```
443
+
444
+ ## License
445
+
446
+ MIT
@@ -0,0 +1,117 @@
1
+ import { a as InferEventData, h as StringKeys, m as RpcSchema, n as EventDef, p as Provider, t as Driver } from "../schema-CN5HHHku.js";
2
+ import "../factory-C1v0AEHY.js";
3
+ import "../json-54Z2bIIs.js";
4
+ import "../index-Be7jjS77.js";
5
+ import "../protocol-DA84zrc2.js";
6
+ import { a as IRpcOptions, c as WebSocketOptions, o as IWebSocket } from "../types-Be-qmQu0.js";
7
+ import "../default-xDNNMrg0.js";
8
+ import { t as ReconnectOptions } from "../reconnect-DbcN0R_1.js";
9
+ import { IAdapterHooks, IConnectionAdapter } from "./types.js";
10
+
11
+ //#region src/adapters/client.d.ts
12
+
13
+ /**
14
+ * Options for creating an RpcClient
15
+ */
16
+ interface RpcClientOptions<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema> extends IAdapterHooks<TRemoteSchema>, IRpcOptions<TLocalSchema, TRemoteSchema> {
17
+ /** WebSocket URL to connect to */
18
+ url: string;
19
+ /** Implementation of local methods */
20
+ provider: Provider<TLocalSchema>;
21
+ /** Auto-reconnect options (set to false to disable) */
22
+ reconnect?: ReconnectOptions | false;
23
+ /** Automatically connect when client is created (default: false) */
24
+ autoConnect?: boolean;
25
+ /** WebSocket subprotocols */
26
+ protocols?: string | string[];
27
+ /** HTTP headers for WebSocket upgrade request (Bun/Node.js only) */
28
+ headers?: Record<string, string>;
29
+ /** Custom WebSocket constructor (defaults to global WebSocket) */
30
+ WebSocket?: new (url: string, options?: string | string[] | WebSocketOptions) => IWebSocket;
31
+ }
32
+ /**
33
+ * Connection state
34
+ */
35
+ type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting";
36
+ /**
37
+ * RPC Client with auto-reconnect
38
+ *
39
+ * Manages WebSocket connection lifecycle and provides RPC capabilities.
40
+ */
41
+ declare class RpcClient<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema> implements IConnectionAdapter<TLocalSchema, TRemoteSchema> {
42
+ readonly localSchema: TLocalSchema;
43
+ readonly remoteSchema: TRemoteSchema;
44
+ readonly provider: Provider<TLocalSchema>;
45
+ readonly hooks: IAdapterHooks<TRemoteSchema>;
46
+ private readonly url;
47
+ private readonly reconnectOptions;
48
+ private readonly defaultTimeout;
49
+ private readonly protocols;
50
+ private readonly headers;
51
+ private readonly WebSocketImpl;
52
+ private ws;
53
+ private peer;
54
+ private _state;
55
+ private reconnectAttempt;
56
+ private reconnectTimeout;
57
+ private intentionalClose;
58
+ constructor(options: RpcClientOptions<TLocalSchema, TRemoteSchema>);
59
+ /**
60
+ * Current connection state
61
+ */
62
+ get state(): ConnectionState;
63
+ /**
64
+ * Whether the client is currently connected
65
+ */
66
+ get isConnected(): boolean;
67
+ /**
68
+ * Get the driver for calling remote methods
69
+ *
70
+ * @returns Driver proxy for calling remote methods
71
+ * @throws Error if not connected
72
+ */
73
+ get driver(): Driver<TRemoteSchema>;
74
+ /**
75
+ * Emit an event to the server (fire-and-forget)
76
+ *
77
+ * @param event - Event name from local schema
78
+ * @param data - Event data matching the schema
79
+ */
80
+ emit<K extends StringKeys<TLocalSchema["events"]>>(event: K, data: TLocalSchema["events"] extends Record<string, EventDef> ? InferEventData<TLocalSchema["events"][K]> : never): void;
81
+ /**
82
+ * Connect to the WebSocket server
83
+ *
84
+ * @returns Promise that resolves when connected
85
+ * @throws Error if connection fails
86
+ */
87
+ connect(): Promise<void>;
88
+ /**
89
+ * Disconnect from the server
90
+ *
91
+ * @param code - WebSocket close code (default: 1000)
92
+ * @param reason - Close reason message (default: "Client disconnect")
93
+ */
94
+ disconnect(code?: number, reason?: string): void;
95
+ /**
96
+ * Handle WebSocket open event
97
+ */
98
+ private handleOpen;
99
+ /**
100
+ * Handle WebSocket close event
101
+ */
102
+ private handleClose;
103
+ /**
104
+ * Schedule a reconnection attempt
105
+ */
106
+ private scheduleReconnect;
107
+ /**
108
+ * Attempt to reconnect
109
+ */
110
+ private attemptReconnect;
111
+ /**
112
+ * Cancel any pending reconnection
113
+ */
114
+ private cancelReconnect;
115
+ }
116
+ //#endregion
117
+ export { ConnectionState, RpcClient, RpcClientOptions };