@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
@@ -0,0 +1,120 @@
1
+ import { m as RpcSchema } from "./schema-CN5HHHku.js";
2
+
3
+ //#region src/storage/interface.d.ts
4
+
5
+ /**
6
+ * A pending RPC call awaiting a response
7
+ */
8
+ interface PendingCall {
9
+ /** Unique request ID */
10
+ id: string;
11
+ /** Remote method name */
12
+ method: string;
13
+ /** Serialized parameters */
14
+ params: unknown;
15
+ /** Method name on actor to call with response */
16
+ callback: string;
17
+ /** When the call was sent (Unix ms) */
18
+ sentAt: number;
19
+ /** When the call should timeout (Unix ms) */
20
+ timeoutAt: number;
21
+ }
22
+ /**
23
+ * Storage mode discriminant
24
+ */
25
+ type StorageMode = "sync" | "async";
26
+ /**
27
+ * Conditional return type based on storage mode
28
+ */
29
+ type MaybePromise<T, TMode extends StorageMode> = TMode extends "sync" ? T : Promise<T>;
30
+ /**
31
+ * Pending call storage interface
32
+ *
33
+ * Generic over sync/async mode to preserve type information about
34
+ * whether operations block or return promises.
35
+ *
36
+ * @typeParam TMode - 'sync' for synchronous storage (DO SQL/KV), 'async' for file/external
37
+ */
38
+ interface PendingCallStorage<TMode extends StorageMode = "async"> {
39
+ /** Storage mode discriminant for runtime checks */
40
+ readonly mode: TMode;
41
+ /**
42
+ * Save a pending call
43
+ */
44
+ save(call: PendingCall): MaybePromise<void, TMode>;
45
+ /**
46
+ * Get a pending call by ID
47
+ */
48
+ get(id: string): MaybePromise<PendingCall | null, TMode>;
49
+ /**
50
+ * Delete a pending call by ID
51
+ */
52
+ delete(id: string): MaybePromise<boolean, TMode>;
53
+ /**
54
+ * List all calls that have exceeded their timeout
55
+ */
56
+ listExpired(before: number): MaybePromise<PendingCall[], TMode>;
57
+ /**
58
+ * List all pending calls (for debugging/recovery)
59
+ */
60
+ listAll(): MaybePromise<PendingCall[], TMode>;
61
+ /**
62
+ * Delete all pending calls (for cleanup)
63
+ */
64
+ clear(): MaybePromise<void, TMode>;
65
+ }
66
+ /**
67
+ * Convenience alias for synchronous storage (DO SQL/KV)
68
+ */
69
+ type SyncPendingCallStorage = PendingCallStorage<"sync">;
70
+ /**
71
+ * Convenience alias for asynchronous storage (file, external KV)
72
+ */
73
+ type AsyncPendingCallStorage = PendingCallStorage<"async">;
74
+ interface IContinuationHandler<TRemoteSchema extends RpcSchema> {
75
+ /**
76
+ * Make a hibernation-safe RPC call using continuation-passing style
77
+ *
78
+ * Instead of returning a Promise, the result will be passed to the
79
+ * named callback method on the actor. This survives DO hibernation.
80
+ *
81
+ * @param method - Remote method to call
82
+ * @param params - Parameters for the method
83
+ * @param callback - Name of method on actor to call with result
84
+ * @param timeout - Optional timeout override (ms)
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * // Make the call
89
+ * peer.callWithCallback('executeOrder', { market, side }, 'onOrderExecuted');
90
+ *
91
+ * // Define the callback on your actor
92
+ * onOrderExecuted(result: OrderResult, context: CallContext) {
93
+ * console.log('Order executed:', result);
94
+ * console.log('Latency:', context.latencyMs, 'ms');
95
+ * }
96
+ * ```
97
+ */
98
+ callWithCallback<K extends keyof TRemoteSchema["methods"] & string>(method: K, params: unknown, callback: keyof this & string, timeout?: number): void;
99
+ /**
100
+ * Get all pending durable calls (for debugging/monitoring)
101
+ */
102
+ getPendingCalls(): PendingCall[];
103
+ /**
104
+ * Get expired calls that have exceeded their timeout
105
+ */
106
+ getExpiredCalls(): PendingCall[];
107
+ /**
108
+ * Clean up expired calls
109
+ *
110
+ * Call this periodically (e.g., on alarm) to remove stale calls.
111
+ * Returns the expired calls for optional error handling.
112
+ */
113
+ cleanupExpired(): PendingCall[];
114
+ /**
115
+ * Clear all pending durable calls
116
+ */
117
+ clearPendingCalls(): void;
118
+ }
119
+ //#endregion
120
+ export { PendingCallStorage as a, PendingCall as i, IContinuationHandler as n, StorageMode as o, MaybePromise as r, SyncPendingCallStorage as s, AsyncPendingCallStorage as t };
@@ -0,0 +1,22 @@
1
+ import { n as CodecFactory } from "./factory-C1v0AEHY.js";
2
+ import * as z from "zod";
3
+
4
+ //#region src/codecs/json.d.ts
5
+
6
+ /**
7
+ * Factory for creating JSON codecs with Zod schema validation
8
+ *
9
+ * @param schema - Zod schema for validation
10
+ * @param options - Optional codec configuration
11
+ * @returns A codec that encodes to JSON string and validates on decode
12
+ */
13
+ declare const createJsonCodec: CodecFactory<string>;
14
+ /**
15
+ * Default JSON codec for unknown values
16
+ *
17
+ * Use when you need to serialize arbitrary data without schema validation.
18
+ * The decoded value will be `unknown` and should be validated separately.
19
+ */
20
+ declare const JsonCodec: z.ZodCodec<z.ZodString, z.ZodUnknown>;
21
+ //#endregion
22
+ export { createJsonCodec as n, JsonCodec as t };
@@ -0,0 +1,41 @@
1
+ import { n as createStringCodecFactory } from "./factory-3ziwTuZe.js";
2
+ import * as z from "zod";
3
+
4
+ //#region src/codecs/json.ts
5
+ /**
6
+ * JSON Codec
7
+ *
8
+ * String-based codec using native JSON serialization.
9
+ * Suitable for simple data types (no Date, Map, Set, BigInt support).
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createJsonCodec } from "@igoforth/ws-rpc/codecs";
14
+ *
15
+ * const UserCodec = createJsonCodec(z.object({
16
+ * id: z.string(),
17
+ * name: z.string(),
18
+ * }));
19
+ *
20
+ * const encoded = UserCodec.encode({ id: "1", name: "John" });
21
+ * const decoded = UserCodec.decode(encoded);
22
+ * ```
23
+ */
24
+ /**
25
+ * Factory for creating JSON codecs with Zod schema validation
26
+ *
27
+ * @param schema - Zod schema for validation
28
+ * @param options - Optional codec configuration
29
+ * @returns A codec that encodes to JSON string and validates on decode
30
+ */
31
+ const createJsonCodec = createStringCodecFactory(JSON.stringify, JSON.parse, "json_string");
32
+ /**
33
+ * Default JSON codec for unknown values
34
+ *
35
+ * Use when you need to serialize arbitrary data without schema validation.
36
+ * The decoded value will be `unknown` and should be validated separately.
37
+ */
38
+ const JsonCodec = createJsonCodec(z.unknown());
39
+
40
+ //#endregion
41
+ export { createJsonCodec as n, JsonCodec as t };
@@ -0,0 +1,48 @@
1
+ //#region src/storage/memory.ts
2
+ /**
3
+ * In-memory pending call storage for testing
4
+ *
5
+ * Optionally round-trips params through a codec for consistency testing.
6
+ */
7
+ var MemoryPendingCallStorage = class {
8
+ mode = "sync";
9
+ calls = /* @__PURE__ */ new Map();
10
+ paramsCodec;
11
+ constructor(options) {
12
+ this.paramsCodec = options?.paramsCodec ?? null;
13
+ }
14
+ save(call) {
15
+ const params = this.paramsCodec ? this.paramsCodec.decode(this.paramsCodec.encode(call.params)) : call.params;
16
+ this.calls.set(call.id, {
17
+ ...call,
18
+ params
19
+ });
20
+ }
21
+ get(id) {
22
+ const call = this.calls.get(id);
23
+ return call ? { ...call } : null;
24
+ }
25
+ delete(id) {
26
+ return this.calls.delete(id);
27
+ }
28
+ listExpired(before) {
29
+ const expired = [];
30
+ for (const call of this.calls.values()) if (call.timeoutAt <= before) expired.push({ ...call });
31
+ return expired.sort((a, b) => a.timeoutAt - b.timeoutAt);
32
+ }
33
+ listAll() {
34
+ return [...this.calls.values()].map((c) => ({ ...c })).sort((a, b) => a.sentAt - b.sentAt);
35
+ }
36
+ clear() {
37
+ this.calls.clear();
38
+ }
39
+ /**
40
+ * Get the number of stored calls (for testing)
41
+ */
42
+ get size() {
43
+ return this.calls.size;
44
+ }
45
+ };
46
+
47
+ //#endregion
48
+ export { MemoryPendingCallStorage as t };
@@ -0,0 +1,41 @@
1
+ import { i as StringCodec } from "./factory-C1v0AEHY.js";
2
+ import { i as PendingCall, s as SyncPendingCallStorage } from "./interface-C4S-WCqW.js";
3
+
4
+ //#region src/storage/memory.d.ts
5
+
6
+ /**
7
+ * Options for memory pending call storage
8
+ */
9
+ interface MemoryPendingCallStorageOptions {
10
+ /**
11
+ * Codec for serializing/deserializing params
12
+ *
13
+ * While memory storage doesn't strictly need serialization,
14
+ * using a codec ensures consistency with SQL storage and
15
+ * validates that params can be round-tripped.
16
+ */
17
+ paramsCodec?: StringCodec;
18
+ }
19
+ /**
20
+ * In-memory pending call storage for testing
21
+ *
22
+ * Optionally round-trips params through a codec for consistency testing.
23
+ */
24
+ declare class MemoryPendingCallStorage implements SyncPendingCallStorage {
25
+ readonly mode: "sync";
26
+ private readonly calls;
27
+ private readonly paramsCodec;
28
+ constructor(options?: MemoryPendingCallStorageOptions);
29
+ save(call: PendingCall): void;
30
+ get(id: string): PendingCall | null;
31
+ delete(id: string): boolean;
32
+ listExpired(before: number): PendingCall[];
33
+ listAll(): PendingCall[];
34
+ clear(): void;
35
+ /**
36
+ * Get the number of stored calls (for testing)
37
+ */
38
+ get size(): number;
39
+ }
40
+ //#endregion
41
+ export { MemoryPendingCallStorageOptions as n, MemoryPendingCallStorage as t };
@@ -0,0 +1,242 @@
1
+ import { t as RpcPeer } from "./default-BkrMd28n.js";
2
+
3
+ //#region src/adapters/multi-peer.ts
4
+ /**
5
+ * Multi-Peer Base Class
6
+ *
7
+ * Abstract base class for adapters managing multiple RPC peers.
8
+ * Extended by RpcServer and Cloudflare DO adapter.
9
+ */
10
+ /**
11
+ * Abstract base class for multi-peer adapters
12
+ *
13
+ * Provides shared functionality for managing multiple RPC peers:
14
+ * - Driver for calling methods on multiple peers
15
+ * - Broadcast emit to all peers
16
+ * - Peer lookup by ID
17
+ * - Connection count/IDs
18
+ *
19
+ * @typeParam TLocalSchema - Schema for methods/events this side provides
20
+ * @typeParam TRemoteSchema - Schema for methods/events the remote side provides
21
+ * @typeParam TConnection - Connection type (IWebSocket, WebSocket, etc.)
22
+ */
23
+ var MultiPeerBase = class {
24
+ peers = /* @__PURE__ */ new Map();
25
+ /** Local schema */
26
+ localSchema;
27
+ /** Remote schema */
28
+ remoteSchema;
29
+ /** Implementation of local methods */
30
+ provider;
31
+ /** Default timeout for RPC calls */
32
+ timeout;
33
+ /** Lifecycle hooks */
34
+ hooks;
35
+ constructor(options) {
36
+ this.localSchema = options.localSchema;
37
+ this.remoteSchema = options.remoteSchema;
38
+ this.provider = options.provider;
39
+ this.timeout = options.timeout ?? 3e4;
40
+ this.hooks = options.hooks ?? {};
41
+ }
42
+ /**
43
+ * Create an RPC peer for a WebSocket connection.
44
+ * Subclasses can override to customize peer creation.
45
+ */
46
+ createPeer(ws) {
47
+ return new RpcPeer({
48
+ ws,
49
+ localSchema: this.localSchema,
50
+ remoteSchema: this.remoteSchema,
51
+ provider: this.provider,
52
+ onEvent: this.hooks.onEvent ? (event, data) => {
53
+ const peer = this.findPeerByWs(ws);
54
+ if (peer) this.hooks.onEvent(peer, event, data);
55
+ } : void 0,
56
+ timeout: this.timeout
57
+ });
58
+ }
59
+ /**
60
+ * Find peer by WebSocket (internal helper for event routing)
61
+ */
62
+ findPeerByWs(ws) {
63
+ for (const peer of this.peers.values()) if (peer.getWebSocket() === ws) return peer;
64
+ return null;
65
+ }
66
+ /**
67
+ * Add a peer (called by subclass when connection established)
68
+ */
69
+ addPeer(connection, peer) {
70
+ this.peers.set(connection, peer);
71
+ this.hooks.onConnect?.(peer);
72
+ }
73
+ /**
74
+ * Remove a peer (called by subclass when connection closes)
75
+ */
76
+ removePeer(connection) {
77
+ const peer = this.peers.get(connection);
78
+ if (peer) {
79
+ peer.close();
80
+ this.peers.delete(connection);
81
+ this.hooks.onDisconnect?.(peer);
82
+ return peer;
83
+ }
84
+ return null;
85
+ }
86
+ /**
87
+ * Get peer by connection object
88
+ */
89
+ getPeerFor(connection) {
90
+ return this.peers.get(connection) ?? null;
91
+ }
92
+ /**
93
+ * Get peer by ID
94
+ */
95
+ getPeer(id) {
96
+ for (const peer of this.peers.values()) if (peer.id === id) return peer;
97
+ return null;
98
+ }
99
+ /**
100
+ * Find peer entry by ID (internal - includes connection)
101
+ */
102
+ findPeerEntry(id) {
103
+ for (const [connection, peer] of this.peers) if (peer.id === id) return {
104
+ peer,
105
+ connection
106
+ };
107
+ return null;
108
+ }
109
+ /**
110
+ * Get all peers
111
+ */
112
+ getPeers() {
113
+ return this.peers.values();
114
+ }
115
+ /**
116
+ * Get all open peer entries (internal)
117
+ */
118
+ getOpenEntries() {
119
+ const result = [];
120
+ for (const [connection, peer] of this.peers) if (peer.isOpen) result.push({
121
+ peer,
122
+ connection
123
+ });
124
+ return result;
125
+ }
126
+ /**
127
+ * Get count of open connections
128
+ */
129
+ getConnectionCount() {
130
+ let count = 0;
131
+ for (const peer of this.peers.values()) if (peer.isOpen) count++;
132
+ return count;
133
+ }
134
+ /**
135
+ * Get all open peer IDs
136
+ */
137
+ getConnectionIds() {
138
+ const ids = [];
139
+ for (const peer of this.peers.values()) if (peer.isOpen) ids.push(peer.id);
140
+ return ids;
141
+ }
142
+ /**
143
+ * Driver for calling remote methods on connected peers
144
+ *
145
+ * @returns MultiDriver proxy for calling methods on all or specific peers
146
+ */
147
+ get driver() {
148
+ return this.createMultiDriver();
149
+ }
150
+ /**
151
+ * Emit an event to connected peers
152
+ *
153
+ * @param event - Event name from local schema
154
+ * @param data - Event data matching the schema
155
+ * @param ids - Optional array of peer IDs to emit to (broadcasts to all if omitted)
156
+ */
157
+ emit(event, data, ids) {
158
+ const validPeers = ids ? this.peers.values().filter((p) => ids.includes(p.id) && p.isOpen) : this.peers.values().filter((p) => p.isOpen);
159
+ for (const peer of validPeers) peer.emit(event, data);
160
+ }
161
+ /**
162
+ * Close a specific peer by ID
163
+ *
164
+ * @param id - Peer ID to close
165
+ * @returns true if peer was found and closed, false otherwise
166
+ */
167
+ closePeer(id) {
168
+ const entry = this.findPeerEntry(id);
169
+ if (entry) {
170
+ entry.peer.close();
171
+ this.peers.delete(entry.connection);
172
+ this.hooks.onDisconnect?.(entry.peer);
173
+ return true;
174
+ }
175
+ return false;
176
+ }
177
+ /**
178
+ * Close all peers
179
+ */
180
+ closeAll() {
181
+ for (const peer of this.peers.values()) {
182
+ peer.close();
183
+ this.hooks.onDisconnect?.(peer);
184
+ }
185
+ this.peers.clear();
186
+ this.hooks.onClose?.();
187
+ }
188
+ /**
189
+ * Create a driver proxy for calling remote methods on multiple peers
190
+ */
191
+ createMultiDriver() {
192
+ const methods = this.remoteSchema.methods ?? {};
193
+ const driver = {};
194
+ for (const methodName of Object.keys(methods)) driver[methodName] = async (input, options) => {
195
+ return this.callMethod(methodName, input, options);
196
+ };
197
+ return driver;
198
+ }
199
+ /**
200
+ * Call a method on multiple peers with timeout handling
201
+ *
202
+ * @param method - Method name to call
203
+ * @param input - Method input parameters
204
+ * @param options - Call options including target peer IDs and timeout
205
+ * @returns Array of results from each peer (success or error)
206
+ */
207
+ async callMethod(method, input, options) {
208
+ const ids = options?.ids;
209
+ const timeout = options?.timeout ?? this.timeout;
210
+ let targetPeers;
211
+ if (ids === void 0) targetPeers = Array.from(this.peers.values()).filter((p) => p.isOpen);
212
+ else if (typeof ids === "string") {
213
+ const peer = this.getPeer(ids);
214
+ targetPeers = peer?.isOpen ? [peer] : [];
215
+ } else targetPeers = ids.map((id) => this.getPeer(id)).filter((p) => p?.isOpen === true);
216
+ const promises = targetPeers.map(async (peer) => {
217
+ try {
218
+ const callPromise = peer.driver[method](input);
219
+ const value = await Promise.race([callPromise, new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`Timeout after ${timeout}ms`)), timeout))]);
220
+ return {
221
+ id: peer.id,
222
+ result: {
223
+ success: true,
224
+ value
225
+ }
226
+ };
227
+ } catch (error) {
228
+ return {
229
+ id: peer.id,
230
+ result: {
231
+ success: false,
232
+ error: error instanceof Error ? error : new Error(String(error))
233
+ }
234
+ };
235
+ }
236
+ });
237
+ return Promise.all(promises);
238
+ }
239
+ };
240
+
241
+ //#endregion
242
+ export { MultiPeerBase as t };
@@ -0,0 +1,8 @@
1
+ import "../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 "../types-Be-qmQu0.js";
7
+ import { n as RpcPeerOptions, t as RpcPeer } from "../default-xDNNMrg0.js";
8
+ export { RpcPeer, RpcPeerOptions };
@@ -0,0 +1,8 @@
1
+ import "../factory-3ziwTuZe.js";
2
+ import "../json-Bshec-bZ.js";
3
+ import "../codecs-BmYG2d_U.js";
4
+ import "../protocol-_mpoOPp6.js";
5
+ import "../errors-5BfreE63.js";
6
+ import { t as RpcPeer } from "../default-BkrMd28n.js";
7
+
8
+ export { RpcPeer };
@@ -0,0 +1,136 @@
1
+ import { m as RpcSchema } from "../schema-CN5HHHku.js";
2
+ import "../factory-C1v0AEHY.js";
3
+ import "../json-54Z2bIIs.js";
4
+ import "../index-Be7jjS77.js";
5
+ import { g as WireInput } from "../protocol-DA84zrc2.js";
6
+ import "../types-Be-qmQu0.js";
7
+ import { n as RpcPeerOptions, t as RpcPeer } from "../default-xDNNMrg0.js";
8
+ import { i as PendingCall, s as SyncPendingCallStorage } from "../interface-C4S-WCqW.js";
9
+
10
+ //#region src/peers/durable.d.ts
11
+
12
+ /**
13
+ * Options for creating a DurableRpcPeer
14
+ */
15
+ interface DurableRpcPeerOptions<TActor> {
16
+ /** Synchronous storage for persisting pending calls */
17
+ storage: SyncPendingCallStorage;
18
+ /** The actor instance (for resolving callback methods) */
19
+ actor: TActor;
20
+ /** Default timeout for continuation-based calls (ms) */
21
+ durableTimeout?: number;
22
+ }
23
+ /**
24
+ * Context passed to callback methods along with the result
25
+ */
26
+ interface CallContext {
27
+ /** The original pending call */
28
+ call: PendingCall;
29
+ /** Time from send to response (ms) */
30
+ latencyMs: number;
31
+ }
32
+ /**
33
+ * Durable RPC Peer
34
+ *
35
+ * Extends RpcPeer to add:
36
+ * - Hibernation-safe continuation-based calls via `callWithCallback`
37
+ * - Automatic recovery of pending calls after hibernation
38
+ * - Timeout cleanup for stale calls
39
+ */
40
+ declare class DurableRpcPeer<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema, TActor> extends RpcPeer<TLocalSchema, TRemoteSchema> {
41
+ private readonly storage;
42
+ private readonly actor;
43
+ private readonly durableTimeout;
44
+ private durableRequestCounter;
45
+ /**
46
+ * Create a durable RPC peer
47
+ *
48
+ * @param options - Combined RPC peer and durable options
49
+ */
50
+ constructor(options: RpcPeerOptions<TLocalSchema, TRemoteSchema> & DurableRpcPeerOptions<TActor>);
51
+ /**
52
+ * Make a hibernation-safe RPC call using continuation-passing style
53
+ *
54
+ * Instead of returning a Promise, the result will be passed to the
55
+ * named callback method on the actor. This survives DO hibernation.
56
+ *
57
+ * @param method - Remote method to call
58
+ * @param params - Parameters for the method
59
+ * @param callback - Name of method on actor to call with result
60
+ * @param timeout - Optional timeout override (ms)
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * // Make the call
65
+ * peer.callWithCallback('executeOrder', { market, side }, 'onOrderExecuted');
66
+ *
67
+ * // Define the callback on your actor
68
+ * onOrderExecuted(result: OrderResult, context: CallContext) {
69
+ * console.log('Order executed:', result);
70
+ * console.log('Latency:', context.latencyMs, 'ms');
71
+ * }
72
+ * ```
73
+ */
74
+ callWithCallback<K extends keyof TRemoteSchema["methods"] & string>(method: K, params: unknown, callback: keyof TActor & string, timeout?: number): void;
75
+ /**
76
+ * Handle an incoming WebSocket message
77
+ *
78
+ * Checks durable storage for continuation-based calls before
79
+ * delegating to the base class for promise-based calls.
80
+ *
81
+ * @param data - Raw WebSocket message data
82
+ */
83
+ handleMessage(data: WireInput): void;
84
+ /**
85
+ * Get all pending durable calls (for debugging/monitoring)
86
+ *
87
+ * @returns Array of all pending calls
88
+ */
89
+ getPendingCalls(): PendingCall[];
90
+ /**
91
+ * Get expired calls that have exceeded their timeout
92
+ *
93
+ * @returns Array of calls that have exceeded their timeout
94
+ */
95
+ getExpiredCalls(): PendingCall[];
96
+ /**
97
+ * Clean up expired calls
98
+ *
99
+ * Call this periodically (e.g., on alarm) to remove stale calls.
100
+ *
101
+ * @returns The expired calls that were removed (for optional error handling)
102
+ */
103
+ cleanupExpired(): PendingCall[];
104
+ /**
105
+ * Clear all pending durable calls
106
+ */
107
+ clearPendingCalls(): void;
108
+ }
109
+ /**
110
+ * Create a factory function for DurableRpcPeer instances
111
+ *
112
+ * Pre-configures the durable storage and actor, returning a function
113
+ * that only needs RPC options to create a new peer.
114
+ *
115
+ * @param durableOptions - Durable configuration (storage, actor, timeout)
116
+ * @returns Factory function that creates DurableRpcPeer instances
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const createPeer = createDurableRpcPeerFactory({
121
+ * storage: new SqlPendingCallStorage(sql),
122
+ * actor: this,
123
+ * });
124
+ *
125
+ * // Later, create peers for each connection
126
+ * const peer = createPeer({
127
+ * ws,
128
+ * localSchema,
129
+ * remoteSchema,
130
+ * provider,
131
+ * });
132
+ * ```
133
+ */
134
+ declare const createDurableRpcPeerFactory: <TActor>(durableOptions: DurableRpcPeerOptions<TActor>) => <TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema>(rpcOptions: RpcPeerOptions<TLocalSchema, TRemoteSchema>) => DurableRpcPeer<TLocalSchema, TRemoteSchema, TActor>;
135
+ //#endregion
136
+ export { CallContext, DurableRpcPeer, DurableRpcPeerOptions, createDurableRpcPeerFactory };
@@ -0,0 +1,9 @@
1
+ import "../factory-3ziwTuZe.js";
2
+ import "../json-Bshec-bZ.js";
3
+ import "../codecs-BmYG2d_U.js";
4
+ import "../protocol-_mpoOPp6.js";
5
+ import "../errors-5BfreE63.js";
6
+ import "../default-BkrMd28n.js";
7
+ import { n as createDurableRpcPeerFactory, t as DurableRpcPeer } from "../durable-MZjkvyS6.js";
8
+
9
+ export { DurableRpcPeer, createDurableRpcPeerFactory };
@@ -0,0 +1,10 @@
1
+ import "../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 "../types-Be-qmQu0.js";
7
+ import { n as RpcPeerOptions, t as RpcPeer } from "../default-xDNNMrg0.js";
8
+ import "../interface-C4S-WCqW.js";
9
+ import { CallContext, DurableRpcPeer, DurableRpcPeerOptions } from "./durable.js";
10
+ export { type CallContext, DurableRpcPeer, type DurableRpcPeerOptions, RpcPeer, type RpcPeerOptions };