@camera.ui/rpc 1.0.1

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 ADDED
@@ -0,0 +1,3 @@
1
+ # @camera.ui/rpc
2
+
3
+ This is the Node implementation of the camera-ui-rpc library.
@@ -0,0 +1,106 @@
1
+ import type { RPCClient } from './client.js';
2
+ export interface ChannelMessage {
3
+ type: 'message' | 'close' | 'error';
4
+ data?: any;
5
+ error?: string;
6
+ sender?: string;
7
+ }
8
+ /**
9
+ * Bidirectional communication channel between RPC clients
10
+ */
11
+ export declare class Channel {
12
+ protected client: RPCClient;
13
+ protected channelId: string;
14
+ protected closed: boolean;
15
+ protected unsubscribe?: () => void;
16
+ protected initialized: boolean;
17
+ private handlers;
18
+ private closeHandlers;
19
+ private errorHandlers;
20
+ private subscriptions;
21
+ /**
22
+ * Check if channel is closed
23
+ */
24
+ get isClosed(): boolean;
25
+ /**
26
+ * Get the channel ID
27
+ */
28
+ get id(): string;
29
+ constructor(client: RPCClient, channelId: string);
30
+ /**
31
+ * Initialize the channel (called by RPCClient)
32
+ */
33
+ init(): Promise<void>;
34
+ /**
35
+ * Send data through the channel
36
+ */
37
+ send<TMessage = any>(data: TMessage): Promise<void>;
38
+ /**
39
+ * Send a request and wait for reply
40
+ */
41
+ request<TRequest = any, TResponse = any>(data: TRequest, timeout?: number): Promise<TResponse>;
42
+ /**
43
+ * Setup a request handler for this channel
44
+ */
45
+ onRequest<TRequest = any, TResponse = any>(handler: (data: TRequest) => Promise<TResponse> | TResponse): Promise<() => void>;
46
+ /**
47
+ * Listen for messages
48
+ */
49
+ on<TEvent = any>(event: 'message', handler: (data: TEvent) => void): void;
50
+ on(event: 'close', handler: () => void): void;
51
+ on(event: 'error', handler: (error: Error) => void): void;
52
+ /**
53
+ * Remove event listener
54
+ */
55
+ off<TEvent = any>(event: 'message', handler: (data: TEvent) => void): void;
56
+ off(event: 'close', handler: () => void): void;
57
+ off(event: 'error', handler: (error: Error) => void): void;
58
+ /**
59
+ * Close the channel gracefully
60
+ */
61
+ close(): Promise<void>;
62
+ private handlerChain;
63
+ private runHandler;
64
+ protected emit(event: string, data?: any): void;
65
+ protected handleClose(): void;
66
+ protected handleError(error: Error): void;
67
+ protected cleanup(): Promise<void>;
68
+ }
69
+ /**
70
+ * Private channel for 1:1 communication between two specific clients
71
+ */
72
+ export declare class PrivateChannel extends Channel {
73
+ private targetClientId;
74
+ private readonly clientId;
75
+ private remoteClientId?;
76
+ /**
77
+ * Get the remote client ID (if connected)
78
+ */
79
+ get remoteId(): string | undefined;
80
+ constructor(client: RPCClient, channelId: string, targetClientId: string);
81
+ /**
82
+ * Initialize private channel with handshake
83
+ */
84
+ init(): Promise<void>;
85
+ /**
86
+ * Send data through the private channel
87
+ */
88
+ send<TMessage = any>(data: TMessage): Promise<void>;
89
+ /**
90
+ * Send a request and wait for reply using native NATS request/reply
91
+ */
92
+ request<TRequest = any, TResponse = any>(data: TRequest, timeout?: number): Promise<TResponse>;
93
+ /**
94
+ * Setup a request handler for this private channel
95
+ */
96
+ onRequest<TRequest = any, TResponse = any>(handler: (data: TRequest) => Promise<TResponse> | TResponse): Promise<() => void>;
97
+ /**
98
+ * Close the private channel gracefully
99
+ */
100
+ close(): Promise<void>;
101
+ /**
102
+ * Check if channel is connected to a specific client
103
+ */
104
+ isConnectedTo(clientId: string): boolean;
105
+ private sendRaw;
106
+ }
@@ -0,0 +1,347 @@
1
+ import { isPromise } from './utils.js';
2
+ /**
3
+ * Bidirectional communication channel between RPC clients
4
+ */
5
+ export class Channel {
6
+ client;
7
+ channelId;
8
+ closed = false;
9
+ unsubscribe;
10
+ initialized = false;
11
+ // Return type is `void` (consumer-void) so handlers that incidentally
12
+ // return a value type-check. Runtime uses isPromise() on the actual
13
+ // returned value to detect async handlers and chain them.
14
+ handlers = new Map();
15
+ closeHandlers = new Set();
16
+ errorHandlers = new Set();
17
+ subscriptions = [];
18
+ /**
19
+ * Check if channel is closed
20
+ */
21
+ get isClosed() {
22
+ return this.closed;
23
+ }
24
+ /**
25
+ * Get the channel ID
26
+ */
27
+ get id() {
28
+ return this.channelId;
29
+ }
30
+ constructor(client, channelId) {
31
+ this.client = client;
32
+ this.channelId = channelId;
33
+ }
34
+ /**
35
+ * Initialize the channel (called by RPCClient)
36
+ */
37
+ async init() {
38
+ if (this.initialized) {
39
+ return;
40
+ }
41
+ this.initialized = true;
42
+ const subject = `channel.${this.channelId}`;
43
+ this.unsubscribe = await this.client.subscribe(subject, async (msg) => {
44
+ switch (msg.type) {
45
+ case 'message':
46
+ this.emit('message', msg.data);
47
+ break;
48
+ case 'close':
49
+ this.handleClose();
50
+ break;
51
+ case 'error':
52
+ this.handleError(new Error(msg.error ?? 'Channel error'));
53
+ break;
54
+ }
55
+ });
56
+ }
57
+ /**
58
+ * Send data through the channel
59
+ */
60
+ async send(data) {
61
+ if (this.closed) {
62
+ throw new Error('Channel is closed');
63
+ }
64
+ const msg = {
65
+ type: 'message',
66
+ data,
67
+ };
68
+ await this.client.publish(`channel.${this.channelId}`, msg);
69
+ }
70
+ /**
71
+ * Send a request and wait for reply
72
+ */
73
+ async request(data, timeout = 5000) {
74
+ if (this.closed) {
75
+ throw new Error('Channel is closed');
76
+ }
77
+ const subject = `channel.${this.channelId}.request`;
78
+ return this.client.request(subject, data, { timeout });
79
+ }
80
+ /**
81
+ * Setup a request handler for this channel
82
+ */
83
+ async onRequest(handler) {
84
+ const subject = `channel.${this.channelId}.request`;
85
+ const unsubscribe = this.client.onRequest(subject, handler);
86
+ this.subscriptions.push(unsubscribe);
87
+ return unsubscribe;
88
+ }
89
+ on(event, handler) {
90
+ if (event === 'close') {
91
+ this.closeHandlers.add(handler);
92
+ }
93
+ else if (event === 'error') {
94
+ this.errorHandlers.add(handler);
95
+ }
96
+ else {
97
+ if (!this.handlers.has(event)) {
98
+ this.handlers.set(event, new Set());
99
+ }
100
+ this.handlers.get(event).add(handler);
101
+ }
102
+ }
103
+ off(event, handler) {
104
+ if (event === 'close') {
105
+ this.closeHandlers.delete(handler);
106
+ }
107
+ else if (event === 'error') {
108
+ this.errorHandlers.delete(handler);
109
+ }
110
+ else {
111
+ this.handlers.get(event)?.delete(handler);
112
+ }
113
+ }
114
+ /**
115
+ * Close the channel gracefully
116
+ */
117
+ async close() {
118
+ if (this.closed)
119
+ return;
120
+ this.closed = true;
121
+ // Try to notify other side
122
+ try {
123
+ const msg = { type: 'close' };
124
+ await this.client.publish(`channel.${this.channelId}`, msg);
125
+ }
126
+ catch {
127
+ // Ignore publish errors during close
128
+ }
129
+ // Cleanup
130
+ await this.cleanup();
131
+ }
132
+ // Per-channel promise chain. Async handlers for message / close / error
133
+ // are serialized via this chain so dispatch stays ordered — matches
134
+ // Python's channel.py:_emit/_handle_close/_handle_error behavior.
135
+ // Sync handlers stay fire-and-forget (not chained, no overhead).
136
+ handlerChain = Promise.resolve();
137
+ runHandler(handler, arg, label) {
138
+ let result;
139
+ try {
140
+ result = handler(arg);
141
+ }
142
+ catch (error) {
143
+ console.error(`Error in ${label}:`, error);
144
+ return;
145
+ }
146
+ if (isPromise(result)) {
147
+ const pending = result;
148
+ this.handlerChain = this.handlerChain.then(() => pending).catch((error) => console.error(`Error in ${label}:`, error));
149
+ }
150
+ }
151
+ emit(event, data) {
152
+ const handlers = this.handlers.get(event);
153
+ if (!handlers)
154
+ return;
155
+ for (const handler of handlers) {
156
+ this.runHandler(handler, data, 'channel handler');
157
+ }
158
+ }
159
+ handleClose() {
160
+ if (this.closed)
161
+ return;
162
+ this.closed = true;
163
+ for (const handler of this.closeHandlers) {
164
+ this.runHandler(() => handler(), undefined, 'close handler');
165
+ }
166
+ this.cleanup().catch(console.error);
167
+ }
168
+ handleError(error) {
169
+ for (const handler of this.errorHandlers) {
170
+ this.runHandler(handler, error, 'error handler');
171
+ }
172
+ }
173
+ async cleanup() {
174
+ // Clear all handlers
175
+ this.handlers.clear();
176
+ this.closeHandlers.clear();
177
+ this.errorHandlers.clear();
178
+ // Clear subscriptions
179
+ await Promise.allSettled(this.subscriptions.map((unsub) => unsub));
180
+ // Unsubscribe from NATS
181
+ if (this.unsubscribe) {
182
+ try {
183
+ this.unsubscribe();
184
+ }
185
+ catch {
186
+ // Ignore unsubscribe errors
187
+ }
188
+ this.unsubscribe = undefined;
189
+ }
190
+ // Disconnect isolated client if present
191
+ const isolatedClient = this._isolatedClient;
192
+ if (isolatedClient) {
193
+ try {
194
+ await isolatedClient.disconnect();
195
+ }
196
+ catch {
197
+ // Ignore disconnect errors
198
+ }
199
+ }
200
+ }
201
+ }
202
+ /**
203
+ * Private channel for 1:1 communication between two specific clients
204
+ */
205
+ export class PrivateChannel extends Channel {
206
+ targetClientId;
207
+ clientId;
208
+ remoteClientId;
209
+ /**
210
+ * Get the remote client ID (if connected)
211
+ */
212
+ get remoteId() {
213
+ return this.remoteClientId;
214
+ }
215
+ constructor(client, channelId, targetClientId) {
216
+ super(client, channelId);
217
+ this.targetClientId = targetClientId;
218
+ // Use the original client name, not the isolated connection name
219
+ // When using isolated connections, the name includes suffixes like '-channel-secret-chat'
220
+ // We need to extract the original name to maintain consistent identity
221
+ const fullName = client.options.name ?? `client-${Date.now()}`;
222
+ // Extract base name by removing any suffixes added for isolated connections
223
+ this.clientId = fullName.replace(/-(channel|private)-.*$/, '');
224
+ }
225
+ /**
226
+ * Initialize private channel with handshake
227
+ */
228
+ async init() {
229
+ if (this.initialized) {
230
+ return;
231
+ }
232
+ this.initialized = true;
233
+ // Use a unique subject that includes channelId and both client IDs for true privacy
234
+ const sortedIds = [this.clientId, this.targetClientId].sort();
235
+ const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}`;
236
+ this.unsubscribe = await this.client.subscribe(subject, async (msg) => {
237
+ // Filter messages: only process if it's for us
238
+ if (msg.sender === this.clientId) {
239
+ // Skip our own messages
240
+ return;
241
+ }
242
+ if (msg.sender !== this.targetClientId) {
243
+ // Only accept messages from the target client
244
+ return;
245
+ }
246
+ if (!this.remoteClientId && msg.sender) {
247
+ // First message establishes the connection
248
+ this.remoteClientId = msg.sender;
249
+ }
250
+ if (this.remoteClientId && msg.sender !== this.remoteClientId) {
251
+ // After connection established, only accept from connected client
252
+ return;
253
+ }
254
+ switch (msg.type) {
255
+ case 'message':
256
+ // Filter out handshake messages
257
+ if (msg.data && typeof msg.data === 'object' && '__handshake' in msg.data) {
258
+ // Handshake received, connection established
259
+ return;
260
+ }
261
+ this.emit('message', msg.data);
262
+ break;
263
+ case 'close':
264
+ this.handleClose();
265
+ break;
266
+ case 'error':
267
+ this.handleError(new Error(msg.error ?? 'Channel error'));
268
+ break;
269
+ }
270
+ });
271
+ // Send initial handshake
272
+ try {
273
+ await this.sendRaw({
274
+ type: 'message',
275
+ data: { __handshake: true },
276
+ sender: this.clientId,
277
+ });
278
+ }
279
+ catch {
280
+ // Ignore handshake errors - connection might still work
281
+ }
282
+ }
283
+ /**
284
+ * Send data through the private channel
285
+ */
286
+ async send(data) {
287
+ if (this.closed) {
288
+ throw new Error('Channel is closed');
289
+ }
290
+ await this.sendRaw({
291
+ type: 'message',
292
+ data,
293
+ sender: this.clientId,
294
+ });
295
+ }
296
+ /**
297
+ * Send a request and wait for reply using native NATS request/reply
298
+ */
299
+ async request(data, timeout = 5000) {
300
+ if (this.closed) {
301
+ throw new Error('Channel is closed');
302
+ }
303
+ const sortedIds = [this.clientId, this.targetClientId].sort();
304
+ const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}.request`;
305
+ return this.client.request(subject, data, { timeout });
306
+ }
307
+ /**
308
+ * Setup a request handler for this private channel
309
+ */
310
+ async onRequest(handler) {
311
+ const sortedIds = [this.clientId, this.targetClientId].sort();
312
+ const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}.request`;
313
+ return this.client.onRequest(subject, handler);
314
+ }
315
+ /**
316
+ * Close the private channel gracefully
317
+ */
318
+ async close() {
319
+ if (this.closed)
320
+ return;
321
+ this.closed = true;
322
+ // Try to notify remote client, but don't fail if it errors
323
+ try {
324
+ await this.sendRaw({
325
+ type: 'close',
326
+ sender: this.clientId,
327
+ });
328
+ }
329
+ catch {
330
+ // Ignore send errors during close
331
+ }
332
+ await this.cleanup();
333
+ }
334
+ /**
335
+ * Check if channel is connected to a specific client
336
+ */
337
+ isConnectedTo(clientId) {
338
+ return this.remoteClientId === clientId;
339
+ }
340
+ async sendRaw(msg) {
341
+ // Use the same subject format as in init()
342
+ const sortedIds = [this.clientId, this.targetClientId].sort();
343
+ const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}`;
344
+ await this.client.publish(subject, msg);
345
+ }
346
+ }
347
+ //# sourceMappingURL=channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Message types for chunked transfers
3
+ */
4
+ export interface ChunkMessage {
5
+ id: string;
6
+ chunkIndex: number;
7
+ data: Uint8Array;
8
+ isLast: boolean;
9
+ }
10
+ /**
11
+ * Split data into chunks
12
+ */
13
+ export declare function createChunks(encoded: Uint8Array, chunkId: string, maxChunkSize: number): Generator<ChunkMessage>;
14
+ /**
15
+ * Reassemble chunks back into original data using a pre-allocated buffer.
16
+ * Chunks are written directly to the buffer - no intermediate Map storage.
17
+ */
18
+ export declare class ChunkAssembler {
19
+ readonly id: string;
20
+ private buffer;
21
+ private receivedChunks;
22
+ private totalChunks;
23
+ private chunkSize;
24
+ constructor(id: string, totalSize: number, totalChunks: number, chunkSize?: number);
25
+ /**
26
+ * Add a chunk to the assembler.
27
+ * Writes directly to the pre-allocated buffer.
28
+ * @returns true if all chunks are received
29
+ */
30
+ addChunk(chunk: ChunkMessage): boolean;
31
+ /**
32
+ * Check if all chunks have been received
33
+ */
34
+ isComplete(): boolean;
35
+ /**
36
+ * Get the reassembled data.
37
+ * Buffer is already complete, just decode - no copy needed.
38
+ */
39
+ getData<T = any>(): T;
40
+ /**
41
+ * Get progress information
42
+ */
43
+ getProgress(): {
44
+ received: number;
45
+ total: number;
46
+ percentage: number;
47
+ };
48
+ }
49
+ /**
50
+ * Manager for handling multiple chunk transfers
51
+ */
52
+ export declare class ChunkingManager {
53
+ private assemblers;
54
+ private completedCallbacks;
55
+ private errorCallbacks;
56
+ /**
57
+ * Start receiving chunks for a transfer.
58
+ * Pre-allocates buffer for direct chunk writing.
59
+ */
60
+ startReceiving(id: string, totalChunks: number, onComplete: (data: any) => void, onError: (error: Error) => void, totalSize: number, chunkSize?: number): void;
61
+ /**
62
+ * Process an incoming chunk
63
+ */
64
+ processChunk(chunk: ChunkMessage): void;
65
+ /**
66
+ * Cancel a transfer
67
+ */
68
+ cancel(id: string): void;
69
+ /**
70
+ * Get progress for a transfer
71
+ */
72
+ getProgress(id: string): {
73
+ received: number;
74
+ total: number;
75
+ percentage: number;
76
+ } | null;
77
+ }