@api.global/typedsocket 4.0.0 → 4.1.2

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.
@@ -1,11 +1,9 @@
1
1
  import * as plugins from './typedsocket.plugins.js';
2
- const publicRoleName = 'publicRoleName';
3
- const publicRolePass = 'publicRolePass';
2
+ const TAG_PREFIX = '__typedsocket_tag__';
4
3
  /**
5
4
  * Creates a wrapper around IWebSocketPeer for tag compatibility
6
5
  */
7
6
  function wrapSmartServePeer(peer) {
8
- const TAG_PREFIX = '__typedsocket_tag__';
9
7
  return {
10
8
  peer,
11
9
  async getTagById(tagId) {
@@ -18,72 +16,52 @@ function wrapSmartServePeer(peer) {
18
16
  };
19
17
  }
20
18
  export class TypedSocket {
21
- // STATIC
19
+ // ============================================================================
20
+ // STATIC METHODS
21
+ // ============================================================================
22
22
  /**
23
- * creates a typedsocket server
24
- * note: this will fail in browser environments as server libs are not bundled.
23
+ * Creates a TypedSocket client using native WebSocket.
24
+ * Works in both browser and Node.js environments.
25
+ *
26
+ * @param typedrouterArg - TypedRouter for handling server-initiated requests
27
+ * @param serverUrlArg - Server URL (e.g., 'http://localhost:3000' or 'wss://example.com')
28
+ * @param options - Connection options
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const typedRouter = new TypedRouter();
33
+ * const client = await TypedSocket.createClient(
34
+ * typedRouter,
35
+ * 'http://localhost:3000',
36
+ * { autoReconnect: true }
37
+ * );
38
+ * ```
25
39
  */
26
- static async createServer(typedrouterArg) {
27
- const smartsocketServer = new plugins.smartsocket.Smartsocket({
28
- alias: 'typedsocketServer',
29
- port: 3000,
30
- });
31
- smartsocketServer.socketFunctions.add(new plugins.smartsocket.SocketFunction({
32
- funcName: 'processMessage',
33
- funcDef: async (dataArg, socketConnectionArg) => {
34
- return typedrouterArg.routeAndAddResponse(dataArg);
35
- },
36
- }));
37
- const typedsocket = new TypedSocket('server', typedrouterArg, async (dataArg, targetConnectionArg) => {
38
- if (!targetConnectionArg) {
39
- if ((smartsocketServer.socketConnections.getArray().length = 1)) {
40
- console.log('Since no targetConnection was supplied and there is only one active one present, choosing that one automatically');
41
- targetConnectionArg = smartsocketServer.socketConnections.getArray()[0];
42
- }
43
- else {
44
- throw new Error('you need to specify the wanted targetConnection. Currently no target is selectable automatically.');
45
- }
46
- }
47
- const response = (await smartsocketServer.clientCall('processMessage', dataArg, targetConnectionArg));
48
- return response;
49
- }, smartsocketServer);
50
- await smartsocketServer.start();
51
- return typedsocket;
52
- }
53
- static async createClient(typedrouterArg, serverUrlArg, aliasArg = 'clientArg') {
54
- const domain = new plugins.smartstring.Domain(serverUrlArg);
55
- const socketOptions = {
56
- alias: aliasArg,
57
- port: domain.port || 3000,
58
- url: `${domain.nodeParsedUrl.protocol}//${domain.nodeParsedUrl.hostname}`,
40
+ static async createClient(typedrouterArg, serverUrlArg, options = {}) {
41
+ const defaultOptions = {
59
42
  autoReconnect: true,
43
+ maxRetries: 100,
44
+ initialBackoffMs: 1000,
45
+ maxBackoffMs: 60000,
60
46
  };
61
- console.log(`starting typedsocket with the following settings:`);
62
- console.log(socketOptions);
63
- const smartsocketClient = new plugins.smartsocket.SmartsocketClient(socketOptions);
64
- smartsocketClient.addSocketFunction(new plugins.smartsocket.SocketFunction({
65
- funcName: 'processMessage',
66
- funcDef: async (dataArg, socketConnectionArg) => {
67
- return typedrouterArg.routeAndAddResponse(dataArg);
68
- },
69
- }));
70
- const typedsocket = new TypedSocket('client', typedrouterArg, async (dataArg) => {
71
- const response = smartsocketClient.serverCall('processMessage', dataArg);
72
- return response;
73
- }, smartsocketClient);
74
- console.log(`typedsocket triggering smartsocket to connect...`);
75
- const before = Date.now();
76
- await smartsocketClient.connect();
77
- console.log(`typedsocket triggered smartsocket connected in ${Date.now() - before}ms!!!`);
78
- return typedsocket;
47
+ const opts = { ...defaultOptions, ...options };
48
+ const typedSocket = new TypedSocket('client', typedrouterArg);
49
+ typedSocket.clientOptions = opts;
50
+ typedSocket.serverUrl = serverUrlArg;
51
+ typedSocket.currentBackoff = opts.initialBackoffMs;
52
+ await typedSocket.connect();
53
+ return typedSocket;
79
54
  }
55
+ /**
56
+ * Returns the current window location origin URL.
57
+ * Useful in browser environments for connecting to the same origin.
58
+ */
80
59
  static { this.useWindowLocationOriginUrl = () => {
81
- const windowLocationResult = plugins.smarturl.Smarturl.createFromUrl(globalThis.location.origin).toString();
82
- return windowLocationResult;
60
+ return plugins.smarturl.Smarturl.createFromUrl(globalThis.location.origin).toString();
83
61
  }; }
84
62
  /**
85
63
  * Creates a TypedSocket server from an existing SmartServe instance.
86
- * Use this when you want TypedSocket to work with SmartServe's WebSocket handling.
64
+ * This is the only way to create a server-side TypedSocket.
87
65
  *
88
66
  * @param smartServeArg - SmartServe instance with typedRouter configured in websocket options
89
67
  * @param typedRouterArg - TypedRouter for handling requests (must match SmartServe's typedRouter)
@@ -104,179 +82,382 @@ export class TypedSocket {
104
82
  */
105
83
  static fromSmartServe(smartServeArg, typedRouterArg) {
106
84
  const connectionWrappers = new Map();
107
- // Create the postMethod for server-initiated requests
108
- const postMethod = async (dataArg, targetConnectionArg) => {
109
- if (!targetConnectionArg) {
110
- const allConnections = smartServeArg.getWebSocketConnections();
85
+ // Register built-in tag handlers
86
+ TypedSocket.registerTagHandlers(typedRouterArg);
87
+ const typedSocket = new TypedSocket('server', typedRouterArg);
88
+ typedSocket.smartServeRef = smartServeArg;
89
+ typedSocket.smartServeConnectionWrappers = connectionWrappers;
90
+ return typedSocket;
91
+ }
92
+ /**
93
+ * Registers built-in TypedHandlers for tag management
94
+ */
95
+ static registerTagHandlers(typedRouter) {
96
+ // Set tag handler
97
+ typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_setTag', async (data, meta) => {
98
+ const peer = meta?.localData?.peer;
99
+ if (!peer) {
100
+ console.warn('setTag: No peer found in request context');
101
+ return { success: false };
102
+ }
103
+ peer.tags.add(data.name);
104
+ peer.data.set(`${TAG_PREFIX}${data.name}`, data.payload);
105
+ return { success: true };
106
+ }));
107
+ // Remove tag handler
108
+ typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_removeTag', async (data, meta) => {
109
+ const peer = meta?.localData?.peer;
110
+ if (!peer) {
111
+ console.warn('removeTag: No peer found in request context');
112
+ return { success: false };
113
+ }
114
+ peer.tags.delete(data.name);
115
+ peer.data.delete(`${TAG_PREFIX}${data.name}`);
116
+ return { success: true };
117
+ }));
118
+ }
119
+ // ============================================================================
120
+ // CONSTRUCTOR
121
+ // ============================================================================
122
+ constructor(sideArg, typedrouterArg) {
123
+ // Connection status observable
124
+ this.statusSubject = new plugins.smartrx.rxjs.Subject();
125
+ this.connectionStatus = 'new';
126
+ // Client-specific properties
127
+ this.websocket = null;
128
+ this.clientOptions = null;
129
+ this.serverUrl = '';
130
+ this.retryCount = 0;
131
+ this.currentBackoff = 1000;
132
+ this.pendingRequests = new Map();
133
+ // Server-specific properties (SmartServe mode)
134
+ this.smartServeRef = null;
135
+ this.smartServeConnectionWrappers = new Map();
136
+ this.side = sideArg;
137
+ this.typedrouter = typedrouterArg;
138
+ }
139
+ // ============================================================================
140
+ // CLIENT METHODS
141
+ // ============================================================================
142
+ /**
143
+ * Connects the client to the server using native WebSocket
144
+ */
145
+ async connect() {
146
+ const done = plugins.smartpromise.defer();
147
+ this.updateStatus('connecting');
148
+ // Convert HTTP URL to WebSocket URL
149
+ const wsUrl = this.toWebSocketUrl(this.serverUrl);
150
+ console.log(`TypedSocket connecting to ${wsUrl}...`);
151
+ this.websocket = new WebSocket(wsUrl);
152
+ const connectionTimeout = setTimeout(() => {
153
+ if (this.connectionStatus !== 'connected') {
154
+ console.warn('TypedSocket connection timeout');
155
+ this.websocket?.close();
156
+ done.reject(new Error('Connection timeout'));
157
+ }
158
+ }, 10000);
159
+ this.websocket.onopen = () => {
160
+ clearTimeout(connectionTimeout);
161
+ console.log('TypedSocket connected!');
162
+ this.updateStatus('connected');
163
+ this.retryCount = 0;
164
+ this.currentBackoff = this.clientOptions?.initialBackoffMs ?? 1000;
165
+ done.resolve();
166
+ };
167
+ this.websocket.onmessage = async (event) => {
168
+ await this.handleMessage(event.data);
169
+ };
170
+ this.websocket.onclose = () => {
171
+ clearTimeout(connectionTimeout);
172
+ this.handleDisconnect();
173
+ };
174
+ this.websocket.onerror = (error) => {
175
+ console.error('TypedSocket WebSocket error:', error);
176
+ };
177
+ try {
178
+ await done.promise;
179
+ }
180
+ catch (err) {
181
+ clearTimeout(connectionTimeout);
182
+ if (this.clientOptions?.autoReconnect) {
183
+ await this.scheduleReconnect();
184
+ }
185
+ else {
186
+ throw err;
187
+ }
188
+ }
189
+ }
190
+ /**
191
+ * Converts an HTTP(S) URL to a WebSocket URL
192
+ */
193
+ toWebSocketUrl(url) {
194
+ const parsed = new URL(url);
195
+ const wsProtocol = parsed.protocol === 'https:' ? 'wss:' : 'ws:';
196
+ return `${wsProtocol}//${parsed.host}${parsed.pathname}`;
197
+ }
198
+ /**
199
+ * Handles incoming WebSocket messages
200
+ */
201
+ async handleMessage(data) {
202
+ try {
203
+ const messageText = typeof data === 'string' ? data : new TextDecoder().decode(data);
204
+ const message = plugins.smartjson.parse(messageText);
205
+ // Check if this is a response to a pending request
206
+ if (message.correlation?.id && this.pendingRequests.has(message.correlation.id)) {
207
+ const pending = this.pendingRequests.get(message.correlation.id);
208
+ this.pendingRequests.delete(message.correlation.id);
209
+ pending.resolve(message);
210
+ return;
211
+ }
212
+ // Server-initiated request - route through TypedRouter
213
+ const response = await this.typedrouter.routeAndAddResponse(message);
214
+ if (response && this.websocket?.readyState === WebSocket.OPEN) {
215
+ this.websocket.send(plugins.smartjson.stringify(response));
216
+ }
217
+ }
218
+ catch (err) {
219
+ console.error('TypedSocket failed to process message:', err);
220
+ }
221
+ }
222
+ /**
223
+ * Handles WebSocket disconnection
224
+ */
225
+ handleDisconnect() {
226
+ if (this.connectionStatus === 'disconnected') {
227
+ return; // Already handled
228
+ }
229
+ this.updateStatus('disconnected');
230
+ // Reject all pending requests — the connection is gone and they'll never receive a response
231
+ for (const [id, pending] of this.pendingRequests) {
232
+ pending.reject(new Error('TypedSocket disconnected'));
233
+ }
234
+ this.pendingRequests.clear();
235
+ if (this.clientOptions?.autoReconnect && this.retryCount < this.clientOptions.maxRetries) {
236
+ this.scheduleReconnect();
237
+ }
238
+ }
239
+ /**
240
+ * Schedules a reconnection attempt with exponential backoff
241
+ */
242
+ async scheduleReconnect() {
243
+ if (!this.clientOptions)
244
+ return;
245
+ this.updateStatus('reconnecting');
246
+ this.retryCount++;
247
+ // Exponential backoff with jitter
248
+ const jitter = this.currentBackoff * 0.2 * (Math.random() * 2 - 1);
249
+ const delay = Math.min(this.currentBackoff + jitter, this.clientOptions.maxBackoffMs);
250
+ console.log(`TypedSocket reconnecting in ${Math.round(delay)}ms (attempt ${this.retryCount}/${this.clientOptions.maxRetries})`);
251
+ await plugins.smartdelay.delayFor(delay);
252
+ // Increase backoff for next time
253
+ this.currentBackoff = Math.min(this.currentBackoff * 2, this.clientOptions.maxBackoffMs);
254
+ try {
255
+ await this.connect();
256
+ }
257
+ catch (err) {
258
+ console.error('TypedSocket reconnection failed:', err);
259
+ }
260
+ }
261
+ /**
262
+ * Updates connection status and notifies subscribers
263
+ */
264
+ updateStatus(status) {
265
+ if (this.connectionStatus !== status) {
266
+ this.connectionStatus = status;
267
+ this.statusSubject.next(status);
268
+ }
269
+ }
270
+ /**
271
+ * Sends a request to the server and waits for response (client-side)
272
+ */
273
+ async sendRequest(request) {
274
+ if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) {
275
+ throw new Error('WebSocket not connected');
276
+ }
277
+ return new Promise((resolve, reject) => {
278
+ const timeout = setTimeout(() => {
279
+ this.pendingRequests.delete(request.correlation.id);
280
+ reject(new Error('Request timeout'));
281
+ }, 30000);
282
+ this.pendingRequests.set(request.correlation.id, {
283
+ resolve: (response) => {
284
+ clearTimeout(timeout);
285
+ resolve(response);
286
+ },
287
+ reject: (error) => {
288
+ clearTimeout(timeout);
289
+ reject(error);
290
+ },
291
+ });
292
+ this.websocket.send(plugins.smartjson.stringify(request));
293
+ });
294
+ }
295
+ // ============================================================================
296
+ // PUBLIC API - SHARED
297
+ // ============================================================================
298
+ /**
299
+ * Creates a TypedRequest for the specified method.
300
+ * On clients, sends to the server.
301
+ * On servers, sends to the specified target connection.
302
+ */
303
+ createTypedRequest(methodName, targetConnection) {
304
+ const postMethod = async (requestDataArg) => {
305
+ if (this.side === 'client') {
306
+ return this.sendRequest(requestDataArg);
307
+ }
308
+ // Server-side: send to target connection
309
+ if (!this.smartServeRef) {
310
+ throw new Error('Server not initialized');
311
+ }
312
+ let target = targetConnection;
313
+ if (!target) {
314
+ const allConnections = this.smartServeRef.getWebSocketConnections();
111
315
  if (allConnections.length === 1) {
112
- console.log('Since no targetConnection was supplied and there is only one active one present, choosing that one automatically');
113
316
  const peer = allConnections[0];
114
- let wrapper = connectionWrappers.get(peer.id);
115
- if (!wrapper) {
116
- wrapper = wrapSmartServePeer(peer);
117
- connectionWrappers.set(peer.id, wrapper);
118
- }
119
- targetConnectionArg = wrapper;
317
+ target = this.getOrCreateWrapper(peer);
120
318
  }
121
319
  else if (allConnections.length === 0) {
122
320
  throw new Error('No WebSocket connections available');
123
321
  }
124
322
  else {
125
- throw new Error('you need to specify the wanted targetConnection. Currently no target is selectable automatically.');
323
+ throw new Error('Multiple connections available - specify targetConnection');
126
324
  }
127
325
  }
128
- // Register interest for the response using correlation ID
129
- const interest = await typedRouterArg.fireEventInterestMap.addInterest(dataArg.correlation.id, dataArg);
130
- // Send the request to the client
131
- targetConnectionArg.peer.send(plugins.smartjson.stringify(dataArg));
132
- // Wait for the response (TypedRouter will fulfill via routeAndAddResponse when response arrives)
133
- const response = await interest.interestFullfilled;
134
- return response;
326
+ // Register interest for response
327
+ const interest = await this.typedrouter.fireEventInterestMap.addInterest(requestDataArg.correlation.id, requestDataArg);
328
+ // Send request
329
+ target.peer.send(plugins.smartjson.stringify(requestDataArg));
330
+ // Wait for response
331
+ return await interest.interestFullfilled;
135
332
  };
136
- const typedSocket = new TypedSocket('server', typedRouterArg, postMethod, null // No smartsocket server/client when using SmartServe
137
- );
138
- typedSocket.smartServeRef = smartServeArg;
139
- typedSocket.smartServeConnectionWrappers = connectionWrappers;
140
- return typedSocket;
333
+ return new plugins.typedrequest.TypedRequest(new plugins.typedrequest.TypedTarget({ postMethod }), methodName);
334
+ }
335
+ /**
336
+ * Gets the current connection status
337
+ */
338
+ getStatus() {
339
+ return this.connectionStatus;
141
340
  }
142
- get eventSubject() {
143
- if (this.smartServeRef) {
144
- // SmartServe doesn't provide an eventSubject, return a new Subject
145
- // In SmartServe mode, connection events are handled via onConnectionOpen/onConnectionClose hooks
146
- console.warn('eventSubject is not fully supported in SmartServe mode. Use SmartServe hooks instead.');
147
- return new plugins.smartrx.rxjs.Subject();
341
+ /**
342
+ * Stops the TypedSocket client or cleans up server state
343
+ */
344
+ async stop() {
345
+ if (this.side === 'client') {
346
+ if (this.clientOptions) {
347
+ this.clientOptions.autoReconnect = false;
348
+ }
349
+ if (this.websocket) {
350
+ this.websocket.close();
351
+ this.websocket = null;
352
+ }
353
+ this.pendingRequests.clear();
354
+ }
355
+ else {
356
+ // Server mode - just clear wrappers (SmartServe manages its own lifecycle)
357
+ this.smartServeConnectionWrappers.clear();
148
358
  }
149
- return this.socketServerOrClient.eventSubject;
150
359
  }
151
- constructor(sideArg, typedrouterArg, postMethodArg, socketServerOrClientArg) {
152
- this.smartServeConnectionWrappers = new Map();
153
- this.side = sideArg;
154
- this.typedrouter = typedrouterArg;
155
- this.postMethod = postMethodArg;
156
- this.socketServerOrClient = socketServerOrClientArg;
360
+ // ============================================================================
361
+ // CLIENT-ONLY METHODS
362
+ // ============================================================================
363
+ /**
364
+ * Sets a tag on this client connection.
365
+ * Tags are stored on the server and can be used for filtering.
366
+ * @client-only
367
+ */
368
+ async setTag(name, payload) {
369
+ if (this.side !== 'client') {
370
+ throw new Error('setTag is only available on clients');
371
+ }
372
+ const request = this.createTypedRequest('__typedsocket_setTag');
373
+ const response = await request.fire({ name, payload });
374
+ if (!response.success) {
375
+ throw new Error('Failed to set tag on server');
376
+ }
157
377
  }
158
- addTag(nameArg, payloadArg) {
159
- if (this.side === 'client' &&
160
- this.socketServerOrClient instanceof plugins.smartsocket.SmartsocketClient) {
161
- this.socketServerOrClient.socketConnection.addTag({
162
- id: nameArg,
163
- payload: payloadArg,
164
- });
378
+ /**
379
+ * Removes a tag from this client connection.
380
+ * @client-only
381
+ */
382
+ async removeTag(name) {
383
+ if (this.side !== 'client') {
384
+ throw new Error('removeTag is only available on clients');
165
385
  }
166
- else {
167
- throw new Error('tagging is only supported on clients');
386
+ const request = this.createTypedRequest('__typedsocket_removeTag');
387
+ const response = await request.fire({ name });
388
+ if (!response.success) {
389
+ throw new Error('Failed to remove tag on server');
168
390
  }
169
391
  }
170
- createTypedRequest(methodName, targetConnection) {
171
- const typedrequest = new plugins.typedrequest.TypedRequest(new plugins.typedrequest.TypedTarget({
172
- postMethod: async (requestDataArg) => {
173
- const result = await this.postMethod(requestDataArg, targetConnection);
174
- return result;
175
- },
176
- }), methodName);
177
- return typedrequest;
392
+ // ============================================================================
393
+ // SERVER-ONLY METHODS
394
+ // ============================================================================
395
+ /**
396
+ * Gets or creates a connection wrapper for a peer
397
+ */
398
+ getOrCreateWrapper(peer) {
399
+ let wrapper = this.smartServeConnectionWrappers.get(peer.id);
400
+ if (!wrapper) {
401
+ wrapper = wrapSmartServePeer(peer);
402
+ this.smartServeConnectionWrappers.set(peer.id, wrapper);
403
+ }
404
+ return wrapper;
178
405
  }
179
406
  /**
180
- * returns all matching target connections
181
- * Works with both Smartsocket and SmartServe backends
182
- * @param asyncFindFuncArg - async filter function
183
- * @returns array of matching connections
407
+ * Finds all connections matching the filter function.
408
+ * @server-only
184
409
  */
185
410
  async findAllTargetConnections(asyncFindFuncArg) {
186
- // SmartServe mode
187
- if (this.smartServeRef) {
188
- const matchingConnections = [];
189
- for (const peer of this.smartServeRef.getWebSocketConnections()) {
190
- let wrapper = this.smartServeConnectionWrappers.get(peer.id);
191
- if (!wrapper) {
192
- wrapper = wrapSmartServePeer(peer);
193
- this.smartServeConnectionWrappers.set(peer.id, wrapper);
194
- }
195
- if (await asyncFindFuncArg(wrapper)) {
196
- matchingConnections.push(wrapper);
197
- }
198
- }
199
- return matchingConnections;
411
+ if (this.side !== 'server' || !this.smartServeRef) {
412
+ throw new Error('findAllTargetConnections is only available on servers');
200
413
  }
201
- // Smartsocket mode
202
- if (this.socketServerOrClient instanceof plugins.smartsocket.Smartsocket) {
203
- const matchingSockets = [];
204
- for (const socketConnection of this.socketServerOrClient.socketConnections.getArray()) {
205
- if (await asyncFindFuncArg(socketConnection)) {
206
- matchingSockets.push(socketConnection);
207
- }
414
+ const matchingConnections = [];
415
+ for (const peer of this.smartServeRef.getWebSocketConnections()) {
416
+ const wrapper = this.getOrCreateWrapper(peer);
417
+ if (await asyncFindFuncArg(wrapper)) {
418
+ matchingConnections.push(wrapper);
208
419
  }
209
- return matchingSockets;
210
420
  }
211
- throw new Error('this method >>findTargetConnection<< is only available from the server');
421
+ return matchingConnections;
212
422
  }
213
423
  /**
214
- * returns a single target connection by returning the first one of all matching ones
215
- * @param asyncFindFuncArg
216
- * @returns
424
+ * Finds the first connection matching the filter function.
425
+ * @server-only
217
426
  */
218
427
  async findTargetConnection(asyncFindFuncArg) {
219
428
  const allMatching = await this.findAllTargetConnections(asyncFindFuncArg);
220
429
  return allMatching[0];
221
430
  }
222
431
  /**
223
- * Find all connections that have a specific tag
224
- * Works with both Smartsocket and SmartServe backends
432
+ * Finds all connections with the specified tag.
433
+ * @server-only
225
434
  */
226
435
  async findAllTargetConnectionsByTag(keyArg, payloadArg) {
227
- // SmartServe mode - use native filtering for better performance
228
- if (this.smartServeRef) {
229
- const peers = this.smartServeRef.getWebSocketConnectionsByTag(keyArg);
230
- const results = [];
231
- for (const peer of peers) {
232
- let wrapper = this.smartServeConnectionWrappers.get(peer.id);
233
- if (!wrapper) {
234
- wrapper = wrapSmartServePeer(peer);
235
- this.smartServeConnectionWrappers.set(peer.id, wrapper);
236
- }
237
- // If payload specified, also filter by payload stored in peer.data
238
- if (payloadArg !== undefined) {
239
- const tag = await wrapper.getTagById(keyArg);
240
- if (plugins.smartjson.stringify(tag?.payload) !== plugins.smartjson.stringify(payloadArg)) {
241
- continue;
242
- }
436
+ if (this.side !== 'server' || !this.smartServeRef) {
437
+ throw new Error('findAllTargetConnectionsByTag is only available on servers');
438
+ }
439
+ const peers = this.smartServeRef.getWebSocketConnectionsByTag(keyArg);
440
+ const results = [];
441
+ for (const peer of peers) {
442
+ const wrapper = this.getOrCreateWrapper(peer);
443
+ // If payload specified, also filter by payload
444
+ if (payloadArg !== undefined) {
445
+ const tag = await wrapper.getTagById(keyArg);
446
+ if (plugins.smartjson.stringify(tag?.payload) !== plugins.smartjson.stringify(payloadArg)) {
447
+ continue;
243
448
  }
244
- results.push(wrapper);
245
449
  }
246
- return results;
450
+ results.push(wrapper);
247
451
  }
248
- // Smartsocket mode - use existing logic
249
- return this.findAllTargetConnections(async (socketConnectionArg) => {
250
- let result;
251
- if (!payloadArg) {
252
- result = !!(await socketConnectionArg.getTagById(keyArg));
253
- }
254
- else {
255
- result = !!(plugins.smartjson.stringify((await socketConnectionArg.getTagById(keyArg))?.payload) ===
256
- plugins.smartjson.stringify(payloadArg));
257
- }
258
- return result;
259
- });
452
+ return results;
260
453
  }
261
454
  /**
262
- * Find a single connection by tag
455
+ * Finds the first connection with the specified tag.
456
+ * @server-only
263
457
  */
264
458
  async findTargetConnectionByTag(keyArg, payloadArg) {
265
459
  const allResults = await this.findAllTargetConnectionsByTag(keyArg, payloadArg);
266
460
  return allResults[0];
267
461
  }
268
- /**
269
- * Stop the TypedSocket server/client
270
- * Note: In SmartServe mode, SmartServe manages its own lifecycle
271
- */
272
- async stop() {
273
- if (this.smartServeRef) {
274
- // SmartServe manages its own lifecycle
275
- // Clear our connection wrappers
276
- this.smartServeConnectionWrappers.clear();
277
- return;
278
- }
279
- await this.socketServerOrClient.stop();
280
- }
281
462
  }
282
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWRzb2NrZXQuY2xhc3Nlcy50eXBlZHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3R5cGVkc29ja2V0LmNsYXNzZXMudHlwZWRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUVwRCxNQUFNLGNBQWMsR0FBRyxnQkFBZ0IsQ0FBQztBQUN4QyxNQUFNLGNBQWMsR0FBRyxnQkFBZ0IsQ0FBQztBQWF4Qzs7R0FFRztBQUNILFNBQVMsa0JBQWtCLENBQUMsSUFBNEI7SUFDdEQsTUFBTSxVQUFVLEdBQUcscUJBQXFCLENBQUM7SUFDekMsT0FBTztRQUNMLElBQUk7UUFDSixLQUFLLENBQUMsVUFBVSxDQUFDLEtBQWE7WUFDNUIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQzFCLE9BQU8sU0FBUyxDQUFDO1lBQ25CLENBQUM7WUFDRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLFVBQVUsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ2hDLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELE1BQU0sT0FBTyxXQUFXO0lBQ3RCLFNBQVM7SUFDVDs7O09BR0c7SUFDSSxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FDOUIsY0FBZ0Q7UUFFaEQsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDO1lBQzVELEtBQUssRUFBRSxtQkFBbUI7WUFDMUIsSUFBSSxFQUFFLElBQUk7U0FDWCxDQUFDLENBQUM7UUFFSCxpQkFBaUIsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUNuQyxJQUFJLE9BQU8sQ0FBQyxX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
463
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWRzb2NrZXQuY2xhc3Nlcy50eXBlZHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3R5cGVkc29ja2V0LmNsYXNzZXMudHlwZWRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUtwRCxNQUFNLFVBQVUsR0FBRyxxQkFBcUIsQ0FBQztBQW1DekM7O0dBRUc7QUFDSCxTQUFTLGtCQUFrQixDQUFDLElBQTRCO0lBQ3RELE9BQU87UUFDTCxJQUFJO1FBQ0osS0FBSyxDQUFDLFVBQVUsQ0FBQyxLQUFhO1lBQzVCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUMxQixPQUFPLFNBQVMsQ0FBQztZQUNuQixDQUFDO1lBQ0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxVQUFVLEdBQUcsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUN2RCxPQUFPLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUNoQyxDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLE9BQU8sV0FBVztJQUN0QiwrRUFBK0U7SUFDL0UsaUJBQWlCO0lBQ2pCLCtFQUErRTtJQUUvRTs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQkc7SUFDSSxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FDOUIsY0FBZ0QsRUFDaEQsWUFBb0IsRUFDcEIsVUFBcUMsRUFBRTtRQUV2QyxNQUFNLGNBQWMsR0FBd0M7WUFDMUQsYUFBYSxFQUFFLElBQUk7WUFDbkIsVUFBVSxFQUFFLEdBQUc7WUFDZixnQkFBZ0IsRUFBRSxJQUFJO1lBQ3RCLFlBQVksRUFBRSxLQUFLO1NBQ3BCLENBQUM7UUFDRixNQUFNLElBQUksR0FBRyxFQUFFLEdBQUcsY0FBYyxFQUFFLEdBQUcs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