@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.
- package/LICENSE +21 -0
- package/README.md +446 -0
- package/dist/adapters/client.d.ts +117 -0
- package/dist/adapters/client.js +241 -0
- package/dist/adapters/cloudflare-do.d.ts +72 -0
- package/dist/adapters/cloudflare-do.js +192 -0
- package/dist/adapters/index.d.ts +13 -0
- package/dist/adapters/index.js +16 -0
- package/dist/adapters/server.d.ts +10 -0
- package/dist/adapters/server.js +122 -0
- package/dist/adapters/types.d.ts +125 -0
- package/dist/adapters/types.js +3 -0
- package/dist/codecs/cbor.d.ts +16 -0
- package/dist/codecs/cbor.js +36 -0
- package/dist/codecs/factory.d.ts +3 -0
- package/dist/codecs/factory.js +3 -0
- package/dist/codecs/index.d.ts +5 -0
- package/dist/codecs/index.js +5 -0
- package/dist/codecs/json.d.ts +4 -0
- package/dist/codecs/json.js +4 -0
- package/dist/codecs/msgpack.d.ts +16 -0
- package/dist/codecs/msgpack.js +34 -0
- package/dist/codecs-BmYG2d_U.js +0 -0
- package/dist/default-BkrMd28n.js +253 -0
- package/dist/default-xDNNMrg0.d.ts +129 -0
- package/dist/durable-MZjkvyS6.js +165 -0
- package/dist/errors-5BfreE63.js +96 -0
- package/dist/errors.d.ts +69 -0
- package/dist/errors.js +7 -0
- package/dist/factory-3ziwTuZe.js +132 -0
- package/dist/factory-C1v0AEHY.d.ts +101 -0
- package/dist/index-Be7jjS77.d.ts +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +14 -0
- package/dist/interface-C4S-WCqW.d.ts +120 -0
- package/dist/json-54Z2bIIs.d.ts +22 -0
- package/dist/json-Bshec-bZ.js +41 -0
- package/dist/memory-Bqb3KEVr.js +48 -0
- package/dist/memory-D1nGjzzH.d.ts +41 -0
- package/dist/multi-peer-BAi9yVzp.js +242 -0
- package/dist/peers/default.d.ts +8 -0
- package/dist/peers/default.js +8 -0
- package/dist/peers/durable.d.ts +136 -0
- package/dist/peers/durable.js +9 -0
- package/dist/peers/index.d.ts +10 -0
- package/dist/peers/index.js +9 -0
- package/dist/protocol-DA84zrc2.d.ts +211 -0
- package/dist/protocol-_mpoOPp6.js +192 -0
- package/dist/protocol.d.ts +6 -0
- package/dist/protocol.js +6 -0
- package/dist/reconnect-CGAA_1Gf.js +26 -0
- package/dist/reconnect-DbcN0R_1.d.ts +35 -0
- package/dist/schema-CN5HHHku.d.ts +108 -0
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +43 -0
- package/dist/server-zTjpJpoX.d.ts +209 -0
- package/dist/sql-CCjc6Bid.js +142 -0
- package/dist/sql-DPmHOeZy.d.ts +131 -0
- package/dist/storage/index.d.ts +8 -0
- package/dist/storage/index.js +7 -0
- package/dist/storage/interface.d.ts +3 -0
- package/dist/storage/interface.js +0 -0
- package/dist/storage/memory.d.ts +7 -0
- package/dist/storage/memory.js +6 -0
- package/dist/storage/sql.d.ts +7 -0
- package/dist/storage/sql.js +6 -0
- package/dist/types-Be-qmQu0.d.ts +111 -0
- package/dist/types-D_psiH09.js +13 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +3 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/reconnect.d.ts +2 -0
- package/dist/utils/reconnect.js +3 -0
- package/package.json +156 -0
- package/src/adapters/client.ts +396 -0
- package/src/adapters/cloudflare-do.ts +346 -0
- package/src/adapters/index.ts +16 -0
- package/src/adapters/multi-peer.ts +404 -0
- package/src/adapters/server.ts +192 -0
- package/src/adapters/types.ts +202 -0
- package/src/codecs/cbor.ts +42 -0
- package/src/codecs/factory.ts +210 -0
- package/src/codecs/index.ts +30 -0
- package/src/codecs/json.ts +42 -0
- package/src/codecs/msgpack.ts +36 -0
- package/src/errors.ts +105 -0
- package/src/index.ts +102 -0
- package/src/peers/default.ts +433 -0
- package/src/peers/durable.ts +280 -0
- package/src/peers/index.ts +13 -0
- package/src/protocol.ts +306 -0
- package/src/schema.ts +167 -0
- package/src/storage/index.ts +20 -0
- package/src/storage/interface.ts +146 -0
- package/src/storage/memory.ts +84 -0
- package/src/storage/sql.ts +266 -0
- package/src/types.ts +158 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/reconnect.ts +51 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { a as InferEventData, h as StringKeys, m as RpcSchema, n as EventDef, p as Provider } from "./schema-CN5HHHku.js";
|
|
2
|
+
import { a as IRpcOptions, o as IWebSocket, r as IMinWebSocket, s as IWebSocketServer, u as WebSocketServerOptions } from "./types-Be-qmQu0.js";
|
|
3
|
+
import { t as RpcPeer } from "./default-xDNNMrg0.js";
|
|
4
|
+
import { IMultiAdapterHooks, IMultiConnectionAdapter, MultiDriver } from "./adapters/types.js";
|
|
5
|
+
|
|
6
|
+
//#region src/adapters/multi-peer.d.ts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Options for creating a MultiPeerBase subclass
|
|
10
|
+
*/
|
|
11
|
+
interface MultiPeerOptions<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema> {
|
|
12
|
+
/** Schema defining local methods we implement */
|
|
13
|
+
localSchema: TLocalSchema;
|
|
14
|
+
/** Schema defining remote methods we can call */
|
|
15
|
+
remoteSchema: TRemoteSchema;
|
|
16
|
+
/** Implementation of local methods */
|
|
17
|
+
provider: Provider<TLocalSchema>;
|
|
18
|
+
/** Default timeout for RPC calls in ms */
|
|
19
|
+
timeout?: number;
|
|
20
|
+
/** Lifecycle hooks */
|
|
21
|
+
hooks?: IMultiAdapterHooks<TLocalSchema, TRemoteSchema>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Abstract base class for multi-peer adapters
|
|
25
|
+
*
|
|
26
|
+
* Provides shared functionality for managing multiple RPC peers:
|
|
27
|
+
* - Driver for calling methods on multiple peers
|
|
28
|
+
* - Broadcast emit to all peers
|
|
29
|
+
* - Peer lookup by ID
|
|
30
|
+
* - Connection count/IDs
|
|
31
|
+
*
|
|
32
|
+
* @typeParam TLocalSchema - Schema for methods/events this side provides
|
|
33
|
+
* @typeParam TRemoteSchema - Schema for methods/events the remote side provides
|
|
34
|
+
* @typeParam TConnection - Connection type (IWebSocket, WebSocket, etc.)
|
|
35
|
+
*/
|
|
36
|
+
declare abstract class MultiPeerBase<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema, TConnection> implements IMultiConnectionAdapter<TLocalSchema, TRemoteSchema> {
|
|
37
|
+
protected readonly peers: Map<TConnection, RpcPeer<TLocalSchema, TRemoteSchema>>;
|
|
38
|
+
/** Local schema */
|
|
39
|
+
readonly localSchema: TLocalSchema;
|
|
40
|
+
/** Remote schema */
|
|
41
|
+
readonly remoteSchema: TRemoteSchema;
|
|
42
|
+
/** Implementation of local methods */
|
|
43
|
+
readonly provider: Provider<TLocalSchema>;
|
|
44
|
+
/** Default timeout for RPC calls */
|
|
45
|
+
readonly timeout: number;
|
|
46
|
+
/** Lifecycle hooks */
|
|
47
|
+
readonly hooks: IMultiAdapterHooks<TLocalSchema, TRemoteSchema>;
|
|
48
|
+
constructor(options: MultiPeerOptions<TLocalSchema, TRemoteSchema>);
|
|
49
|
+
/**
|
|
50
|
+
* Create an RPC peer for a WebSocket connection.
|
|
51
|
+
* Subclasses can override to customize peer creation.
|
|
52
|
+
*/
|
|
53
|
+
protected createPeer(ws: IMinWebSocket): RpcPeer<TLocalSchema, TRemoteSchema>;
|
|
54
|
+
/**
|
|
55
|
+
* Find peer by WebSocket (internal helper for event routing)
|
|
56
|
+
*/
|
|
57
|
+
private findPeerByWs;
|
|
58
|
+
/**
|
|
59
|
+
* Add a peer (called by subclass when connection established)
|
|
60
|
+
*/
|
|
61
|
+
protected addPeer(connection: TConnection, peer: RpcPeer<TLocalSchema, TRemoteSchema>): void;
|
|
62
|
+
/**
|
|
63
|
+
* Remove a peer (called by subclass when connection closes)
|
|
64
|
+
*/
|
|
65
|
+
protected removePeer(connection: TConnection): RpcPeer<TLocalSchema, TRemoteSchema> | null;
|
|
66
|
+
/**
|
|
67
|
+
* Get peer by connection object
|
|
68
|
+
*/
|
|
69
|
+
getPeerFor(connection: TConnection): RpcPeer<TLocalSchema, TRemoteSchema> | null;
|
|
70
|
+
/**
|
|
71
|
+
* Get peer by ID
|
|
72
|
+
*/
|
|
73
|
+
getPeer(id: string): RpcPeer<TLocalSchema, TRemoteSchema> | null;
|
|
74
|
+
/**
|
|
75
|
+
* Find peer entry by ID (internal - includes connection)
|
|
76
|
+
*/
|
|
77
|
+
protected findPeerEntry(id: string): {
|
|
78
|
+
peer: RpcPeer<TLocalSchema, TRemoteSchema>;
|
|
79
|
+
connection: TConnection;
|
|
80
|
+
} | null;
|
|
81
|
+
/**
|
|
82
|
+
* Get all peers
|
|
83
|
+
*/
|
|
84
|
+
getPeers(): IterableIterator<RpcPeer<TLocalSchema, TRemoteSchema>>;
|
|
85
|
+
/**
|
|
86
|
+
* Get all open peer entries (internal)
|
|
87
|
+
*/
|
|
88
|
+
protected getOpenEntries(): Array<{
|
|
89
|
+
peer: RpcPeer<TLocalSchema, TRemoteSchema>;
|
|
90
|
+
connection: TConnection;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Get count of open connections
|
|
94
|
+
*/
|
|
95
|
+
getConnectionCount(): number;
|
|
96
|
+
/**
|
|
97
|
+
* Get all open peer IDs
|
|
98
|
+
*/
|
|
99
|
+
getConnectionIds(): string[];
|
|
100
|
+
/**
|
|
101
|
+
* Driver for calling remote methods on connected peers
|
|
102
|
+
*
|
|
103
|
+
* @returns MultiDriver proxy for calling methods on all or specific peers
|
|
104
|
+
*/
|
|
105
|
+
get driver(): MultiDriver<TRemoteSchema>;
|
|
106
|
+
/**
|
|
107
|
+
* Emit an event to connected peers
|
|
108
|
+
*
|
|
109
|
+
* @param event - Event name from local schema
|
|
110
|
+
* @param data - Event data matching the schema
|
|
111
|
+
* @param ids - Optional array of peer IDs to emit to (broadcasts to all if omitted)
|
|
112
|
+
*/
|
|
113
|
+
emit<K extends StringKeys<TLocalSchema["events"]>>(event: K, data: TLocalSchema["events"] extends Record<string, EventDef> ? InferEventData<TLocalSchema["events"][K]> : never, ids?: string[]): void;
|
|
114
|
+
/**
|
|
115
|
+
* Close a specific peer by ID
|
|
116
|
+
*
|
|
117
|
+
* @param id - Peer ID to close
|
|
118
|
+
* @returns true if peer was found and closed, false otherwise
|
|
119
|
+
*/
|
|
120
|
+
closePeer(id: string): boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Close all peers
|
|
123
|
+
*/
|
|
124
|
+
protected closeAll(): void;
|
|
125
|
+
/**
|
|
126
|
+
* Create a driver proxy for calling remote methods on multiple peers
|
|
127
|
+
*/
|
|
128
|
+
private createMultiDriver;
|
|
129
|
+
/**
|
|
130
|
+
* Call a method on multiple peers with timeout handling
|
|
131
|
+
*
|
|
132
|
+
* @param method - Method name to call
|
|
133
|
+
* @param input - Method input parameters
|
|
134
|
+
* @param options - Call options including target peer IDs and timeout
|
|
135
|
+
* @returns Array of results from each peer (success or error)
|
|
136
|
+
*/
|
|
137
|
+
private callMethod;
|
|
138
|
+
}
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/adapters/server.d.ts
|
|
141
|
+
/**
|
|
142
|
+
* Options for creating an RpcServer
|
|
143
|
+
*/
|
|
144
|
+
interface RpcServerOptions<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema> extends IRpcOptions<TLocalSchema, TRemoteSchema> {
|
|
145
|
+
/** Implementation of local methods */
|
|
146
|
+
provider: Provider<TLocalSchema>;
|
|
147
|
+
/** WebSocket server instance or options to create one */
|
|
148
|
+
wss: IWebSocketServer | WebSocketServerOptions;
|
|
149
|
+
/** WebSocket server constructor (defaults to require('ws').WebSocketServer) */
|
|
150
|
+
WebSocketServer?: new (options: WebSocketServerOptions) => IWebSocketServer;
|
|
151
|
+
/** Lifecycle hooks */
|
|
152
|
+
hooks?: IMultiAdapterHooks<TLocalSchema, TRemoteSchema>;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* RPC Server
|
|
156
|
+
*
|
|
157
|
+
* Manages WebSocket server and client connections with RPC capabilities.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* import { WebSocketServer } from "ws";
|
|
162
|
+
* import { RpcServer } from "@igoforth/ws-rpc/adapters/server";
|
|
163
|
+
*
|
|
164
|
+
* const server = new RpcServer({
|
|
165
|
+
* wss: { port: 8080 },
|
|
166
|
+
* WebSocketServer,
|
|
167
|
+
* localSchema: ServerSchema,
|
|
168
|
+
* remoteSchema: ClientSchema,
|
|
169
|
+
* provider: {
|
|
170
|
+
* getUser: async ({ id }) => ({ name: "John", email: "john@example.com" }),
|
|
171
|
+
* },
|
|
172
|
+
* hooks: {
|
|
173
|
+
* onConnect: (peer) => {
|
|
174
|
+
* console.log(`Client ${peer.id} connected`);
|
|
175
|
+
* peer.driver.ping({}).then(console.log);
|
|
176
|
+
* },
|
|
177
|
+
* onDisconnect: (peer) => console.log(`Client ${peer.id} disconnected`),
|
|
178
|
+
* },
|
|
179
|
+
* });
|
|
180
|
+
*
|
|
181
|
+
* // Emit to all clients
|
|
182
|
+
* server.emit("orderUpdated", { orderId: "123", status: "shipped" });
|
|
183
|
+
*
|
|
184
|
+
* // Graceful shutdown
|
|
185
|
+
* process.on("SIGTERM", () => server.close());
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
declare class RpcServer<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema> extends MultiPeerBase<TLocalSchema, TRemoteSchema, IWebSocket> {
|
|
189
|
+
private readonly wss;
|
|
190
|
+
constructor(options: RpcServerOptions<TLocalSchema, TRemoteSchema>);
|
|
191
|
+
private handleConnection;
|
|
192
|
+
/**
|
|
193
|
+
* Close a peer connection with WebSocket close code/reason
|
|
194
|
+
*
|
|
195
|
+
* @param id - Peer ID to close
|
|
196
|
+
* @param code - WebSocket close code (default: 1000)
|
|
197
|
+
* @param reason - Close reason message (default: "Server disconnect")
|
|
198
|
+
* @returns true if peer was found and closed, false otherwise
|
|
199
|
+
*/
|
|
200
|
+
closePeer(id: string, code?: number, reason?: string): boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Close the server and all client connections
|
|
203
|
+
*
|
|
204
|
+
* @param callback - Optional callback invoked when server is closed
|
|
205
|
+
*/
|
|
206
|
+
close(callback?: (err?: Error) => void): void;
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
export { RpcServerOptions as n, MultiPeerBase as r, RpcServer as t };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { n as createJsonCodec } from "./json-Bshec-bZ.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/storage/sql.ts
|
|
5
|
+
/**
|
|
6
|
+
* SQL Pending Call Storage
|
|
7
|
+
*
|
|
8
|
+
* Synchronous storage implementation using Durable Object SQL storage.
|
|
9
|
+
* Calls are persisted to SQLite and survive hibernation.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Table name for pending calls
|
|
13
|
+
*/
|
|
14
|
+
const TABLE_NAME = "_rpc_pending_calls";
|
|
15
|
+
/**
|
|
16
|
+
* Default codec for params serialization (JSON)
|
|
17
|
+
*/
|
|
18
|
+
const defaultParamsCodec = createJsonCodec(z.unknown());
|
|
19
|
+
/**
|
|
20
|
+
* SQL-backed pending call storage for Durable Objects
|
|
21
|
+
*
|
|
22
|
+
* Uses synchronous SQLite operations available in DO context.
|
|
23
|
+
*/
|
|
24
|
+
var SqlPendingCallStorage = class {
|
|
25
|
+
mode = "sync";
|
|
26
|
+
sql;
|
|
27
|
+
paramsCodec;
|
|
28
|
+
initialized = false;
|
|
29
|
+
/**
|
|
30
|
+
* Create a SQL-backed pending call storage
|
|
31
|
+
*
|
|
32
|
+
* @param sql - Durable Object SQL storage instance
|
|
33
|
+
* @param options - Optional configuration including custom params codec
|
|
34
|
+
*/
|
|
35
|
+
constructor(sql, options) {
|
|
36
|
+
this.sql = sql;
|
|
37
|
+
this.paramsCodec = options?.paramsCodec ?? defaultParamsCodec;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Ensure table exists (lazy initialization)
|
|
41
|
+
*/
|
|
42
|
+
ensureTable() {
|
|
43
|
+
if (this.initialized) return;
|
|
44
|
+
this.sql.exec(`
|
|
45
|
+
CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
|
|
46
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
47
|
+
method TEXT NOT NULL,
|
|
48
|
+
params TEXT NOT NULL,
|
|
49
|
+
callback TEXT NOT NULL,
|
|
50
|
+
sent_at INTEGER NOT NULL,
|
|
51
|
+
timeout_at INTEGER NOT NULL
|
|
52
|
+
)
|
|
53
|
+
`);
|
|
54
|
+
this.sql.exec(`
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_${TABLE_NAME}_timeout
|
|
56
|
+
ON ${TABLE_NAME}(timeout_at)
|
|
57
|
+
`);
|
|
58
|
+
this.initialized = true;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Save a pending call to storage
|
|
62
|
+
*
|
|
63
|
+
* @param call - The pending call to persist
|
|
64
|
+
*/
|
|
65
|
+
save(call) {
|
|
66
|
+
this.ensureTable();
|
|
67
|
+
const encodedParams = this.paramsCodec.encode(call.params);
|
|
68
|
+
this.sql.exec(`INSERT OR REPLACE INTO ${TABLE_NAME}
|
|
69
|
+
(id, method, params, callback, sent_at, timeout_at)
|
|
70
|
+
VALUES (?, ?, ?, ?, ?, ?)`, call.id, call.method, encodedParams, call.callback, call.sentAt, call.timeoutAt);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get a pending call by ID
|
|
74
|
+
*
|
|
75
|
+
* @param id - The unique request ID
|
|
76
|
+
* @returns The pending call or null if not found
|
|
77
|
+
*/
|
|
78
|
+
get(id) {
|
|
79
|
+
this.ensureTable();
|
|
80
|
+
const row = [...this.sql.exec(`SELECT * FROM ${TABLE_NAME} WHERE id = ?`, id)][0];
|
|
81
|
+
if (!row) return null;
|
|
82
|
+
return this.rowToCall(row);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Delete a pending call by ID
|
|
86
|
+
*
|
|
87
|
+
* @param id - The unique request ID
|
|
88
|
+
* @returns true if the call existed and was deleted
|
|
89
|
+
*/
|
|
90
|
+
delete(id) {
|
|
91
|
+
this.ensureTable();
|
|
92
|
+
const exists = this.get(id) !== null;
|
|
93
|
+
if (exists) this.sql.exec(`DELETE FROM ${TABLE_NAME} WHERE id = ?`, id);
|
|
94
|
+
return exists;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* List all calls that have exceeded their timeout
|
|
98
|
+
*
|
|
99
|
+
* @param before - Unix timestamp (ms); returns calls with timeoutAt <= before
|
|
100
|
+
* @returns Array of expired pending calls ordered by timeout
|
|
101
|
+
*/
|
|
102
|
+
listExpired(before) {
|
|
103
|
+
this.ensureTable();
|
|
104
|
+
return [...this.sql.exec(`SELECT * FROM ${TABLE_NAME} WHERE timeout_at <= ? ORDER BY timeout_at ASC`, before)].map((row) => this.rowToCall(row));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* List all pending calls
|
|
108
|
+
*
|
|
109
|
+
* @returns Array of all pending calls ordered by sent time
|
|
110
|
+
*/
|
|
111
|
+
listAll() {
|
|
112
|
+
this.ensureTable();
|
|
113
|
+
return [...this.sql.exec(`SELECT * FROM ${TABLE_NAME} ORDER BY sent_at ASC`)].map((row) => this.rowToCall(row));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Delete all pending calls
|
|
117
|
+
*/
|
|
118
|
+
clear() {
|
|
119
|
+
this.ensureTable();
|
|
120
|
+
this.sql.exec(`DELETE FROM ${TABLE_NAME}`);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Convert a database row to a PendingCall
|
|
124
|
+
*
|
|
125
|
+
* @param row - Database row with call data
|
|
126
|
+
* @returns Deserialized pending call
|
|
127
|
+
*/
|
|
128
|
+
rowToCall(row) {
|
|
129
|
+
const params = this.paramsCodec.decode(row.params);
|
|
130
|
+
return {
|
|
131
|
+
id: row.id,
|
|
132
|
+
method: row.method,
|
|
133
|
+
params,
|
|
134
|
+
callback: row.callback,
|
|
135
|
+
sentAt: row.sent_at,
|
|
136
|
+
timeoutAt: row.timeout_at
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
export { SqlPendingCallStorage as t };
|
|
@@ -0,0 +1,131 @@
|
|
|
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/sql.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* SQL storage value types (matches Cloudflare SqlStorageValue)
|
|
8
|
+
*/
|
|
9
|
+
type SqlStorageValue = ArrayBuffer | string | number | null;
|
|
10
|
+
/**
|
|
11
|
+
* Cursor returned by SqlStorage.exec()
|
|
12
|
+
*
|
|
13
|
+
* Compatible with Cloudflare's SqlStorageCursor.
|
|
14
|
+
*/
|
|
15
|
+
interface SqlStorageCursor<T extends Record<string, SqlStorageValue>> extends Iterable<T> {
|
|
16
|
+
next(): {
|
|
17
|
+
done?: false;
|
|
18
|
+
value: T;
|
|
19
|
+
} | {
|
|
20
|
+
done: true;
|
|
21
|
+
value?: never;
|
|
22
|
+
};
|
|
23
|
+
toArray(): T[];
|
|
24
|
+
one(): T;
|
|
25
|
+
readonly rowsRead: number;
|
|
26
|
+
readonly rowsWritten: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Minimal SqlStorage interface for Durable Object SQL
|
|
30
|
+
*
|
|
31
|
+
* Compatible with `DurableObjectState.storage.sql` in Cloudflare Workers.
|
|
32
|
+
*/
|
|
33
|
+
interface SqlStorage {
|
|
34
|
+
exec<T extends Record<string, SqlStorageValue>>(query: string, ...bindings: unknown[]): SqlStorageCursor<T>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Options for SQL pending call storage
|
|
38
|
+
*/
|
|
39
|
+
interface SqlPendingCallStorageOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Codec for serializing/deserializing params
|
|
42
|
+
*
|
|
43
|
+
* Use a custom codec to support additional JavaScript types like
|
|
44
|
+
* Date, Map, Set, BigInt, etc.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import superjson from "superjson";
|
|
49
|
+
* import { createStringCodecFactory } from "@igoforth/ws-rpc/codecs";
|
|
50
|
+
*
|
|
51
|
+
* const superJsonCodec = createStringCodecFactory(
|
|
52
|
+
* superjson.stringify,
|
|
53
|
+
* superjson.parse,
|
|
54
|
+
* "superjson"
|
|
55
|
+
* );
|
|
56
|
+
*
|
|
57
|
+
* const storage = new SqlPendingCallStorage(sql, {
|
|
58
|
+
* paramsCodec: superJsonCodec(z.unknown()),
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
paramsCodec?: StringCodec;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* SQL-backed pending call storage for Durable Objects
|
|
66
|
+
*
|
|
67
|
+
* Uses synchronous SQLite operations available in DO context.
|
|
68
|
+
*/
|
|
69
|
+
declare class SqlPendingCallStorage implements SyncPendingCallStorage {
|
|
70
|
+
readonly mode: "sync";
|
|
71
|
+
private readonly sql;
|
|
72
|
+
private readonly paramsCodec;
|
|
73
|
+
private initialized;
|
|
74
|
+
/**
|
|
75
|
+
* Create a SQL-backed pending call storage
|
|
76
|
+
*
|
|
77
|
+
* @param sql - Durable Object SQL storage instance
|
|
78
|
+
* @param options - Optional configuration including custom params codec
|
|
79
|
+
*/
|
|
80
|
+
constructor(sql: SqlStorage, options?: SqlPendingCallStorageOptions);
|
|
81
|
+
/**
|
|
82
|
+
* Ensure table exists (lazy initialization)
|
|
83
|
+
*/
|
|
84
|
+
private ensureTable;
|
|
85
|
+
/**
|
|
86
|
+
* Save a pending call to storage
|
|
87
|
+
*
|
|
88
|
+
* @param call - The pending call to persist
|
|
89
|
+
*/
|
|
90
|
+
save(call: PendingCall): void;
|
|
91
|
+
/**
|
|
92
|
+
* Get a pending call by ID
|
|
93
|
+
*
|
|
94
|
+
* @param id - The unique request ID
|
|
95
|
+
* @returns The pending call or null if not found
|
|
96
|
+
*/
|
|
97
|
+
get(id: string): PendingCall | null;
|
|
98
|
+
/**
|
|
99
|
+
* Delete a pending call by ID
|
|
100
|
+
*
|
|
101
|
+
* @param id - The unique request ID
|
|
102
|
+
* @returns true if the call existed and was deleted
|
|
103
|
+
*/
|
|
104
|
+
delete(id: string): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* List all calls that have exceeded their timeout
|
|
107
|
+
*
|
|
108
|
+
* @param before - Unix timestamp (ms); returns calls with timeoutAt <= before
|
|
109
|
+
* @returns Array of expired pending calls ordered by timeout
|
|
110
|
+
*/
|
|
111
|
+
listExpired(before: number): PendingCall[];
|
|
112
|
+
/**
|
|
113
|
+
* List all pending calls
|
|
114
|
+
*
|
|
115
|
+
* @returns Array of all pending calls ordered by sent time
|
|
116
|
+
*/
|
|
117
|
+
listAll(): PendingCall[];
|
|
118
|
+
/**
|
|
119
|
+
* Delete all pending calls
|
|
120
|
+
*/
|
|
121
|
+
clear(): void;
|
|
122
|
+
/**
|
|
123
|
+
* Convert a database row to a PendingCall
|
|
124
|
+
*
|
|
125
|
+
* @param row - Database row with call data
|
|
126
|
+
* @returns Deserialized pending call
|
|
127
|
+
*/
|
|
128
|
+
private rowToCall;
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
export { SqlStorageCursor as i, SqlPendingCallStorageOptions as n, SqlStorage as r, SqlPendingCallStorage 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 { a as PendingCallStorage, i as PendingCall, o as StorageMode, r as MaybePromise, s as SyncPendingCallStorage, t as AsyncPendingCallStorage } from "../interface-C4S-WCqW.js";
|
|
6
|
+
import { n as MemoryPendingCallStorageOptions, t as MemoryPendingCallStorage } from "../memory-D1nGjzzH.js";
|
|
7
|
+
import { n as SqlPendingCallStorageOptions, t as SqlPendingCallStorage } from "../sql-DPmHOeZy.js";
|
|
8
|
+
export { type AsyncPendingCallStorage, type MaybePromise, MemoryPendingCallStorage, type MemoryPendingCallStorageOptions, type PendingCall, type PendingCallStorage, SqlPendingCallStorage, type SqlPendingCallStorageOptions, type StorageMode, type SyncPendingCallStorage };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import "../factory-3ziwTuZe.js";
|
|
2
|
+
import "../json-Bshec-bZ.js";
|
|
3
|
+
import "../codecs-BmYG2d_U.js";
|
|
4
|
+
import { t as MemoryPendingCallStorage } from "../memory-Bqb3KEVr.js";
|
|
5
|
+
import { t as SqlPendingCallStorage } from "../sql-CCjc6Bid.js";
|
|
6
|
+
|
|
7
|
+
export { MemoryPendingCallStorage, SqlPendingCallStorage };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import "../schema-CN5HHHku.js";
|
|
2
|
+
import { a as PendingCallStorage, i as PendingCall, n as IContinuationHandler, o as StorageMode, r as MaybePromise, s as SyncPendingCallStorage, t as AsyncPendingCallStorage } from "../interface-C4S-WCqW.js";
|
|
3
|
+
export { AsyncPendingCallStorage, IContinuationHandler, MaybePromise, PendingCall, PendingCallStorage, StorageMode, SyncPendingCallStorage };
|
|
File without changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import "../schema-CN5HHHku.js";
|
|
2
|
+
import "../factory-C1v0AEHY.js";
|
|
3
|
+
import "../json-54Z2bIIs.js";
|
|
4
|
+
import "../index-Be7jjS77.js";
|
|
5
|
+
import "../interface-C4S-WCqW.js";
|
|
6
|
+
import { n as MemoryPendingCallStorageOptions, t as MemoryPendingCallStorage } from "../memory-D1nGjzzH.js";
|
|
7
|
+
export { MemoryPendingCallStorage, MemoryPendingCallStorageOptions };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import "../schema-CN5HHHku.js";
|
|
2
|
+
import "../factory-C1v0AEHY.js";
|
|
3
|
+
import "../json-54Z2bIIs.js";
|
|
4
|
+
import "../index-Be7jjS77.js";
|
|
5
|
+
import "../interface-C4S-WCqW.js";
|
|
6
|
+
import { i as SqlStorageCursor, n as SqlPendingCallStorageOptions, r as SqlStorage, t as SqlPendingCallStorage } from "../sql-DPmHOeZy.js";
|
|
7
|
+
export { SqlPendingCallStorage, SqlPendingCallStorageOptions, SqlStorage, SqlStorageCursor };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { i as EventHandler, m as RpcSchema, p as Provider, r as EventEmitter } from "./schema-CN5HHHku.js";
|
|
2
|
+
import { g as WireInput } from "./protocol-DA84zrc2.js";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WebSocket ready state constants type
|
|
8
|
+
*/
|
|
9
|
+
interface WebSocketReadyState {
|
|
10
|
+
CONNECTING: 0;
|
|
11
|
+
OPEN: 1;
|
|
12
|
+
CLOSING: 2;
|
|
13
|
+
CLOSED: 3;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* WebSocket ready states
|
|
17
|
+
*/
|
|
18
|
+
declare const WebSocketReadyState: WebSocketReadyState;
|
|
19
|
+
/**
|
|
20
|
+
* Minimal WebSocket interface for sending and receiving
|
|
21
|
+
*/
|
|
22
|
+
interface IMinWebSocket {
|
|
23
|
+
send(data: string | ArrayBuffer | Uint8Array): void;
|
|
24
|
+
close(code?: number, reason?: string): void;
|
|
25
|
+
readonly readyState: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extended WebSocket interface with events
|
|
29
|
+
*/
|
|
30
|
+
interface IWebSocket extends IMinWebSocket {
|
|
31
|
+
send(data: string | ArrayBuffer): void;
|
|
32
|
+
addEventListener?(type: "open" | "close" | "message" | "error", listener: (event: unknown) => void): void;
|
|
33
|
+
removeEventListener?(type: "open" | "close" | "message" | "error", listener: (event: unknown) => void): void;
|
|
34
|
+
onopen?: ((event: unknown) => void) | null;
|
|
35
|
+
onclose?: ((event: unknown) => void) | null;
|
|
36
|
+
onmessage?: ((event: unknown) => void) | null;
|
|
37
|
+
onerror?: ((event: unknown) => void) | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* WebSocket constructor options (Bun-compatible)
|
|
41
|
+
*/
|
|
42
|
+
interface WebSocketOptions {
|
|
43
|
+
protocols?: string | string[];
|
|
44
|
+
headers?: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Minimal WebSocket server interface
|
|
48
|
+
*/
|
|
49
|
+
interface IWebSocketServer {
|
|
50
|
+
on(event: "connection", listener: (ws: IWebSocket) => void): this;
|
|
51
|
+
on(event: "close", listener: () => void): this;
|
|
52
|
+
on(event: "error", listener: (error: Error) => void): this;
|
|
53
|
+
close(callback?: (err?: Error) => void): void;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* WebSocket server constructor options
|
|
57
|
+
*/
|
|
58
|
+
interface WebSocketServerOptions {
|
|
59
|
+
port?: number;
|
|
60
|
+
host?: string;
|
|
61
|
+
path?: string;
|
|
62
|
+
server?: unknown;
|
|
63
|
+
noServer?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Base RPC Options used across Peers and Adapters
|
|
67
|
+
*/
|
|
68
|
+
interface IRpcOptions<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema> {
|
|
69
|
+
/** Schema defining local methods we implement */
|
|
70
|
+
readonly localSchema: TLocalSchema;
|
|
71
|
+
/** Schema defining remote methods we can call */
|
|
72
|
+
readonly remoteSchema: TRemoteSchema;
|
|
73
|
+
/** Default timeout for RPC calls in ms */
|
|
74
|
+
readonly timeout?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Interface for types that provide RPC method implementations
|
|
78
|
+
*
|
|
79
|
+
* @typeParam TLocalSchema - Schema defining local methods
|
|
80
|
+
*/
|
|
81
|
+
interface IMethodController<TLocalSchema extends RpcSchema> {
|
|
82
|
+
/** Implementation of local methods */
|
|
83
|
+
readonly provider: Provider<TLocalSchema>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Interface for types that can emit and receive events
|
|
87
|
+
*
|
|
88
|
+
* @typeParam TLocalSchema - Schema defining local events we can emit
|
|
89
|
+
* @typeParam TRemoteSchema - Schema defining remote events we receive
|
|
90
|
+
* @typeParam EmitArgs - Additional arguments for emit (e.g., peer IDs)
|
|
91
|
+
* @typeParam EventArgs - Additional arguments for event handler
|
|
92
|
+
*/
|
|
93
|
+
interface IEventController<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema, EmitArgs extends any[] = [], EventArgs extends any[] = []> {
|
|
94
|
+
/** Emit an event to the connected peer */
|
|
95
|
+
emit: EventEmitter<TLocalSchema, EmitArgs>;
|
|
96
|
+
/** Called when receiving an event from the connected peer */
|
|
97
|
+
onEvent?: EventHandler<TRemoteSchema, EventArgs>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Base interface for RPC connections (1-1)
|
|
101
|
+
*
|
|
102
|
+
* Implemented by RpcPeer.
|
|
103
|
+
*/
|
|
104
|
+
interface IRpcConnection<TLocalSchema extends RpcSchema, TRemoteSchema extends RpcSchema> extends IRpcOptions<TLocalSchema, TRemoteSchema>, IMethodController<TLocalSchema>, IEventController<TLocalSchema, TRemoteSchema> {
|
|
105
|
+
/** Timeout for RPC calls in ms */
|
|
106
|
+
readonly timeout: number;
|
|
107
|
+
/** Handle an incoming WebSocket message */
|
|
108
|
+
handleMessage(data: WireInput): void;
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { IRpcOptions as a, WebSocketOptions as c, IRpcConnection as i, WebSocketReadyState as l, IMethodController as n, IWebSocket as o, IMinWebSocket as r, IWebSocketServer as s, IEventController as t, WebSocketServerOptions as u };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
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 { a as IRpcOptions, c as WebSocketOptions, i as IRpcConnection, l as WebSocketReadyState, n as IMethodController, o as IWebSocket, r as IMinWebSocket, s as IWebSocketServer, t as IEventController, u as WebSocketServerOptions } from "./types-Be-qmQu0.js";
|
|
7
|
+
export { IEventController, IMethodController, IMinWebSocket, IRpcConnection, IRpcOptions, IWebSocket, IWebSocketServer, WebSocketOptions, WebSocketReadyState, WebSocketServerOptions };
|
package/dist/types.js
ADDED