@rlanz/socket 0.0.1-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 (44) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +387 -0
  3. package/build/chunk-4UPUCRVG.js +1772 -0
  4. package/build/chunk-4UPUCRVG.js.map +1 -0
  5. package/build/chunk-GKAD2UOA.js +18 -0
  6. package/build/chunk-GKAD2UOA.js.map +1 -0
  7. package/build/chunk-HK7Z65DA.js +19 -0
  8. package/build/chunk-HK7Z65DA.js.map +1 -0
  9. package/build/chunk-XUDFDJME.js +42 -0
  10. package/build/chunk-XUDFDJME.js.map +1 -0
  11. package/build/index.d.ts +10 -0
  12. package/build/index.js +21 -0
  13. package/build/index.js.map +1 -0
  14. package/build/providers/socket_provider.d.ts +40 -0
  15. package/build/providers/socket_provider.js +132 -0
  16. package/build/providers/socket_provider.js.map +1 -0
  17. package/build/services/socket.d.ts +12 -0
  18. package/build/services/socket.js +10 -0
  19. package/build/services/socket.js.map +1 -0
  20. package/build/shared_types-Dw9AphfO.d.ts +21 -0
  21. package/build/socket_service-jxIaH5Rs.d.ts +144 -0
  22. package/build/src/client/index.d.ts +106 -0
  23. package/build/src/client/index.js +671 -0
  24. package/build/src/client/index.js.map +1 -0
  25. package/build/src/client/types.d.ts +101 -0
  26. package/build/src/client/types.js +1 -0
  27. package/build/src/client/types.js.map +1 -0
  28. package/build/src/decorators.d.ts +17 -0
  29. package/build/src/decorators.js +9 -0
  30. package/build/src/decorators.js.map +1 -0
  31. package/build/src/health_check.d.ts +18 -0
  32. package/build/src/health_check.js +7 -0
  33. package/build/src/health_check.js.map +1 -0
  34. package/build/src/otel.d.ts +31 -0
  35. package/build/src/otel.js +276 -0
  36. package/build/src/otel.js.map +1 -0
  37. package/build/src/types/tracing_channels.d.ts +40 -0
  38. package/build/src/types/tracing_channels.js +1 -0
  39. package/build/src/types/tracing_channels.js.map +1 -0
  40. package/build/src/types.d.ts +5 -0
  41. package/build/src/types.js +1 -0
  42. package/build/src/types.js.map +1 -0
  43. package/build/types-C0rDwbry.d.ts +393 -0
  44. package/package.json +105 -0
@@ -0,0 +1,671 @@
1
+ // src/client/channel.ts
2
+ var Channel = class {
3
+ /**
4
+ * Channel name.
5
+ */
6
+ name;
7
+ /**
8
+ * Socket client transport.
9
+ */
10
+ #transport;
11
+ /**
12
+ * Whether the channel should stay subscribed.
13
+ */
14
+ #subscribed = false;
15
+ #active = false;
16
+ /**
17
+ * Event handlers grouped by event type.
18
+ */
19
+ #eventHandlers = /* @__PURE__ */ new Map();
20
+ /**
21
+ * Current presence data.
22
+ */
23
+ #presence = null;
24
+ /**
25
+ * Present user IDs used to detect join and leave events.
26
+ */
27
+ #presentUserIds = /* @__PURE__ */ new Set();
28
+ /**
29
+ * Handler registered through .here().
30
+ */
31
+ #hereHandler = null;
32
+ /**
33
+ * Handler registered through .joining().
34
+ */
35
+ #joiningHandler = null;
36
+ /**
37
+ * Handler registered through .leaving().
38
+ */
39
+ #leavingHandler = null;
40
+ /**
41
+ * Internal transport handlers to clean up on unsubscribe.
42
+ */
43
+ #boundPresenceHandler = null;
44
+ #boundEventHandler = null;
45
+ #boundDisconnectHandler = null;
46
+ #listenersAttached = false;
47
+ #pendingSubscribe = null;
48
+ #subscribeToken = 0;
49
+ constructor(name, transport) {
50
+ this.name = name;
51
+ this.#transport = transport;
52
+ }
53
+ /**
54
+ * Whether the channel should stay subscribed.
55
+ */
56
+ get subscribed() {
57
+ return this.#subscribed;
58
+ }
59
+ /**
60
+ * Whether the channel is active on the server.
61
+ */
62
+ get active() {
63
+ return this.#active;
64
+ }
65
+ /**
66
+ * List of present users.
67
+ */
68
+ get users() {
69
+ return this.#presence?.users ?? [];
70
+ }
71
+ /**
72
+ * Number of present users.
73
+ */
74
+ get count() {
75
+ return this.#presence?.count ?? 0;
76
+ }
77
+ /**
78
+ * Registers a handler called with the present users.
79
+ * Called immediately on subscribe and after each presence change.
80
+ */
81
+ here(handler) {
82
+ this.#hereHandler = handler;
83
+ return this;
84
+ }
85
+ /**
86
+ * Registers a handler called when a user joins.
87
+ */
88
+ joining(handler) {
89
+ this.#joiningHandler = handler;
90
+ return this;
91
+ }
92
+ /**
93
+ * Registers a handler called when a user leaves.
94
+ */
95
+ leaving(handler) {
96
+ this.#leavingHandler = handler;
97
+ return this;
98
+ }
99
+ /**
100
+ * Listens for an event on this channel.
101
+ */
102
+ listen(event, handler) {
103
+ if (!this.#eventHandlers.has(event)) {
104
+ this.#eventHandlers.set(event, /* @__PURE__ */ new Set());
105
+ }
106
+ this.#eventHandlers.get(event).add(handler);
107
+ return this;
108
+ }
109
+ /**
110
+ * Removes an event listener.
111
+ */
112
+ stopListening(event, handler) {
113
+ if (handler) {
114
+ this.#eventHandlers.get(event)?.delete(handler);
115
+ } else {
116
+ this.#eventHandlers.delete(event);
117
+ }
118
+ return this;
119
+ }
120
+ /**
121
+ * Subscribes to the channel.
122
+ *
123
+ * client listeners -> subscribe ack -> active channel
124
+ * | | |
125
+ * v v v
126
+ * events ready presence sync send/listen
127
+ */
128
+ async subscribe(options = {}) {
129
+ this.#subscribed = true;
130
+ if (this.#pendingSubscribe) {
131
+ return this.#pendingSubscribe.promise;
132
+ }
133
+ if (this.#active) {
134
+ return this;
135
+ }
136
+ const timeout = options.timeout ?? 5e3;
137
+ if (!this.#listenersAttached) {
138
+ this.#setupSocketListeners();
139
+ }
140
+ const token = ++this.#subscribeToken;
141
+ let resolvePromise;
142
+ let rejectPromise;
143
+ const promise = new Promise((resolve2, reject2) => {
144
+ resolvePromise = resolve2;
145
+ rejectPromise = reject2;
146
+ });
147
+ this.#pendingSubscribe = {
148
+ promise,
149
+ resolve: resolvePromise,
150
+ reject: rejectPromise,
151
+ token
152
+ };
153
+ const { resolve, reject } = this.#pendingSubscribe;
154
+ const timer = setTimeout(() => {
155
+ if (token !== this.#subscribeToken) return;
156
+ this.#pendingSubscribe = null;
157
+ this.#resetConnectionState();
158
+ reject(new Error(`Subscribe timeout for channel: ${this.name}`));
159
+ }, timeout);
160
+ this.#transport.sendRequest({ type: "subscribe", channel: this.name }, timeout).then((response) => {
161
+ if (token !== this.#subscribeToken) return;
162
+ clearTimeout(timer);
163
+ this.#pendingSubscribe = null;
164
+ if (response.ok) {
165
+ this.#active = true;
166
+ const presenceData = response.data?.presenceData ?? response.presenceData;
167
+ if (presenceData) {
168
+ this.#handleInitialPresence(presenceData);
169
+ }
170
+ resolve(this);
171
+ } else {
172
+ this.#resetConnectionState();
173
+ reject(new Error(response.error ?? "Subscribe failed"));
174
+ }
175
+ }).catch((error) => {
176
+ if (token !== this.#subscribeToken) return;
177
+ clearTimeout(timer);
178
+ this.#pendingSubscribe = null;
179
+ this.#resetConnectionState();
180
+ reject(error instanceof Error ? error : new Error("Subscribe failed"));
181
+ });
182
+ return promise;
183
+ }
184
+ /**
185
+ * Unsubscribes from the channel.
186
+ */
187
+ async unsubscribe(options = {}) {
188
+ if (!this.#subscribed && !this.#active) return;
189
+ this.#subscribed = false;
190
+ this.#subscribeToken++;
191
+ if (this.#pendingSubscribe) {
192
+ this.#pendingSubscribe.reject(new Error(`Unsubscribed from channel: ${this.name}`));
193
+ this.#pendingSubscribe = null;
194
+ }
195
+ return new Promise((resolve) => {
196
+ const timeout = options.timeout ?? 5e3;
197
+ const timer = setTimeout(() => {
198
+ this.#cleanupTerminal();
199
+ resolve();
200
+ }, timeout);
201
+ this.#transport.sendRequest({ type: "unsubscribe", channel: this.name }, timeout).then(() => {
202
+ clearTimeout(timer);
203
+ this.#cleanupTerminal();
204
+ resolve();
205
+ }).catch(() => {
206
+ clearTimeout(timer);
207
+ this.#cleanupTerminal();
208
+ resolve();
209
+ });
210
+ });
211
+ }
212
+ /**
213
+ * Sends an event to the server.
214
+ */
215
+ send(event, data) {
216
+ if (!this.#active) {
217
+ console.warn(`Cannot send to channel ${this.name}: not subscribed`);
218
+ return this;
219
+ }
220
+ const payload = {
221
+ channel: this.name,
222
+ event,
223
+ data
224
+ };
225
+ this.#transport.send({ type: "message", ...payload });
226
+ return this;
227
+ }
228
+ /**
229
+ * Sends an event and waits for a response.
230
+ */
231
+ async sendWithAck(event, data) {
232
+ if (!this.#active) {
233
+ throw new Error(`Cannot send to channel ${this.name}: not subscribed`);
234
+ }
235
+ const payload = {
236
+ channel: this.name,
237
+ event,
238
+ data
239
+ };
240
+ const response = await this.#transport.sendRequest({
241
+ type: "message",
242
+ ...payload
243
+ });
244
+ if (!response?.ok) {
245
+ throw new Error(response?.error ?? `Channel handler failed: ${event}`);
246
+ }
247
+ return response.data;
248
+ }
249
+ /**
250
+ * Configures transport listeners.
251
+ */
252
+ #setupSocketListeners() {
253
+ this.#boundPresenceHandler = (data) => {
254
+ if (!data || typeof data !== "object") return;
255
+ this.#handlePresenceUpdate(data);
256
+ };
257
+ this.#transport.on(`channel:${this.name}:presence:update`, this.#boundPresenceHandler);
258
+ this.#boundEventHandler = (data) => {
259
+ if (!data || typeof data !== "object") return;
260
+ const payload = data;
261
+ if (!payload.event) return;
262
+ const handlers = this.#eventHandlers.get(payload.event);
263
+ handlers?.forEach((handler) => handler(payload.data));
264
+ };
265
+ this.#transport.on(`channel:${this.name}:event`, this.#boundEventHandler);
266
+ this.#boundDisconnectHandler = () => {
267
+ this.#resetConnectionState();
268
+ };
269
+ this.#transport.on("disconnect", this.#boundDisconnectHandler);
270
+ this.#listenersAttached = true;
271
+ }
272
+ /**
273
+ * Handles the initial presence snapshot.
274
+ */
275
+ #handleInitialPresence(data) {
276
+ this.#presence = data;
277
+ this.#presentUserIds = new Set(data.users.map((u) => u.id));
278
+ this.#hereHandler?.(data.users);
279
+ }
280
+ /**
281
+ * Handles a presence update.
282
+ *
283
+ * previous IDs current IDs
284
+ * | |
285
+ * +-- diff in -----+--> joining / leaving callbacks
286
+ */
287
+ #handlePresenceUpdate(data) {
288
+ const previousIds = this.#presentUserIds;
289
+ const currentIds = new Set(data.users.map((u) => u.id));
290
+ for (const user of data.users) {
291
+ if (!previousIds.has(user.id)) {
292
+ this.#joiningHandler?.(user);
293
+ }
294
+ }
295
+ if (this.#presence) {
296
+ for (const user of this.#presence.users) {
297
+ if (!currentIds.has(user.id)) {
298
+ this.#leavingHandler?.(user);
299
+ }
300
+ }
301
+ }
302
+ this.#presence = data;
303
+ this.#presentUserIds = currentIds;
304
+ this.#hereHandler?.(data.users);
305
+ }
306
+ #resetConnectionState() {
307
+ this.#active = false;
308
+ this.#presence = null;
309
+ this.#presentUserIds.clear();
310
+ }
311
+ #detachTransportListeners() {
312
+ if (this.#boundPresenceHandler) {
313
+ this.#transport.off(`channel:${this.name}:presence:update`, this.#boundPresenceHandler);
314
+ this.#boundPresenceHandler = null;
315
+ }
316
+ if (this.#boundEventHandler) {
317
+ this.#transport.off(`channel:${this.name}:event`, this.#boundEventHandler);
318
+ this.#boundEventHandler = null;
319
+ }
320
+ if (this.#boundDisconnectHandler) {
321
+ this.#transport.off("disconnect", this.#boundDisconnectHandler);
322
+ this.#boundDisconnectHandler = null;
323
+ }
324
+ this.#listenersAttached = false;
325
+ }
326
+ #clearUserCallbacks() {
327
+ this.#eventHandlers.clear();
328
+ this.#hereHandler = null;
329
+ this.#joiningHandler = null;
330
+ this.#leavingHandler = null;
331
+ }
332
+ /**
333
+ * Performs terminal cleanup after the user leaves or the socket is disposed.
334
+ */
335
+ #cleanupTerminal() {
336
+ this.#subscribed = false;
337
+ this.#resetConnectionState();
338
+ this.#detachTransportListeners();
339
+ this.#clearUserCallbacks();
340
+ }
341
+ };
342
+
343
+ // src/client/socket_session.ts
344
+ var ClientSocketSession = class {
345
+ #ws = null;
346
+ #state = "disconnected";
347
+ #connectPromise = null;
348
+ #cancelConnect = null;
349
+ #stateHandlers = /* @__PURE__ */ new Set();
350
+ #eventHandlers = /* @__PURE__ */ new Map();
351
+ #pendingRequests = /* @__PURE__ */ new Map();
352
+ #requestId = 0;
353
+ #reconnectAttempts = 0;
354
+ #reconnectTimer = null;
355
+ #manualDisconnect = false;
356
+ #buildUrl;
357
+ #createWebSocket;
358
+ #autoReconnect;
359
+ #reconnectDelay;
360
+ #reconnectMaxDelay;
361
+ #onConnected;
362
+ constructor(options) {
363
+ this.#buildUrl = options.buildUrl;
364
+ this.#createWebSocket = options.createWebSocket ?? ((url) => new WebSocket(url));
365
+ this.#autoReconnect = options.autoReconnect ?? true;
366
+ this.#reconnectDelay = Math.max(0, options.reconnectDelay ?? 250);
367
+ this.#reconnectMaxDelay = Math.max(this.#reconnectDelay, options.reconnectMaxDelay ?? 5e3);
368
+ this.#onConnected = options.onConnected;
369
+ }
370
+ get state() {
371
+ return this.#state;
372
+ }
373
+ get connected() {
374
+ return this.#state === "connected";
375
+ }
376
+ connect() {
377
+ if (this.#state === "connected") {
378
+ return Promise.resolve();
379
+ }
380
+ if (this.#connectPromise) {
381
+ return this.#connectPromise;
382
+ }
383
+ this.#manualDisconnect = false;
384
+ this.#setState("connecting");
385
+ const connectPromise = new Promise((resolve, reject) => {
386
+ const ws = this.#createWebSocket(this.#buildUrl());
387
+ this.#ws = ws;
388
+ let settled = false;
389
+ const cleanup = () => {
390
+ ws.removeEventListener("open", handleOpen);
391
+ ws.removeEventListener("error", handleError);
392
+ if (this.#connectPromise === connectPromise) {
393
+ this.#connectPromise = null;
394
+ }
395
+ if (this.#cancelConnect === cancelConnect) {
396
+ this.#cancelConnect = null;
397
+ }
398
+ };
399
+ const cancelConnect = (error) => {
400
+ if (settled) {
401
+ return;
402
+ }
403
+ settled = true;
404
+ cleanup();
405
+ reject(error);
406
+ };
407
+ const handleOpen = () => {
408
+ settled = true;
409
+ cleanup();
410
+ this.#reconnectAttempts = 0;
411
+ this.#setState("connected");
412
+ this.#emitLocal("connect");
413
+ this.#onConnected?.();
414
+ resolve();
415
+ };
416
+ const handleError = () => {
417
+ cancelConnect(new Error("WebSocket connection failed"));
418
+ if (this.#ws === ws) {
419
+ this.#setState("disconnected");
420
+ }
421
+ };
422
+ const handleClose = () => {
423
+ cancelConnect(new Error("WebSocket connection failed"));
424
+ if (this.#ws === ws) {
425
+ this.#handleClose();
426
+ }
427
+ };
428
+ this.#cancelConnect = cancelConnect;
429
+ ws.addEventListener("open", handleOpen);
430
+ ws.addEventListener("error", handleError);
431
+ ws.addEventListener("message", (event) => this.#handleIncoming(event.data));
432
+ ws.addEventListener("close", handleClose);
433
+ });
434
+ this.#connectPromise = connectPromise;
435
+ return connectPromise;
436
+ }
437
+ disconnect() {
438
+ this.#manualDisconnect = true;
439
+ if (this.#reconnectTimer) {
440
+ clearTimeout(this.#reconnectTimer);
441
+ this.#reconnectTimer = null;
442
+ }
443
+ this.#cancelConnect?.(new Error("Socket disconnected"));
444
+ this.#reconnectAttempts = 0;
445
+ this.#ws?.close();
446
+ this.#rejectPending(new Error("Socket disconnected"));
447
+ }
448
+ onStateChange(handler) {
449
+ this.#stateHandlers.add(handler);
450
+ return () => {
451
+ this.#stateHandlers.delete(handler);
452
+ };
453
+ }
454
+ on(event, handler) {
455
+ if (!this.#eventHandlers.has(event)) {
456
+ this.#eventHandlers.set(event, /* @__PURE__ */ new Set());
457
+ }
458
+ this.#eventHandlers.get(event).add(handler);
459
+ return () => {
460
+ this.off(event, handler);
461
+ };
462
+ }
463
+ off(event, handler) {
464
+ this.#eventHandlers.get(event)?.delete(handler);
465
+ }
466
+ send(message) {
467
+ if (this.#ws?.readyState !== WebSocket.OPEN) {
468
+ return;
469
+ }
470
+ this.#ws.send(JSON.stringify(message));
471
+ }
472
+ sendRequest(message, timeout = 5e3) {
473
+ if (this.#ws?.readyState !== WebSocket.OPEN) {
474
+ return Promise.reject(new Error("Socket is not connected"));
475
+ }
476
+ const id = String(++this.#requestId);
477
+ const payload = { id, ...message };
478
+ return new Promise((resolve, reject) => {
479
+ const timer = setTimeout(() => {
480
+ this.#pendingRequests.delete(id);
481
+ reject(new Error("Socket request timed out"));
482
+ }, timeout);
483
+ this.#pendingRequests.set(id, { resolve, reject, timer });
484
+ this.#ws.send(JSON.stringify(payload));
485
+ });
486
+ }
487
+ #handleIncoming(raw) {
488
+ const message = this.#parseMessage(raw);
489
+ if (!message) {
490
+ return;
491
+ }
492
+ if (message.type === "ack") {
493
+ this.#resolveAck(message);
494
+ return;
495
+ }
496
+ if (message.type === "event") {
497
+ if (message.channel) {
498
+ if (message.event === "presence:update") {
499
+ this.#emitLocal(`channel:${message.channel}:presence:update`, message.data);
500
+ return;
501
+ }
502
+ this.#emitLocal(`channel:${message.channel}:event`, {
503
+ event: message.event,
504
+ data: message.data
505
+ });
506
+ return;
507
+ }
508
+ this.#emitLocal(message.event, message.data);
509
+ }
510
+ }
511
+ #parseMessage(raw) {
512
+ try {
513
+ const data = typeof raw === "string" ? raw : String(raw);
514
+ const message = JSON.parse(data);
515
+ return message && typeof message === "object" ? message : null;
516
+ } catch {
517
+ return null;
518
+ }
519
+ }
520
+ #resolveAck(message) {
521
+ if (!message.id) {
522
+ return;
523
+ }
524
+ const pending = this.#pendingRequests.get(message.id);
525
+ if (!pending) {
526
+ return;
527
+ }
528
+ clearTimeout(pending.timer);
529
+ this.#pendingRequests.delete(message.id);
530
+ if (message.ok) {
531
+ pending.resolve({ ok: true, data: message.data });
532
+ } else {
533
+ pending.resolve({ ok: false, error: message.error });
534
+ }
535
+ }
536
+ #handleClose() {
537
+ const shouldEmitDisconnect = this.#state !== "disconnected";
538
+ this.#setState("disconnected");
539
+ if (shouldEmitDisconnect) {
540
+ this.#emitLocal("disconnect");
541
+ }
542
+ this.#rejectPending(new Error("Socket disconnected"));
543
+ this.#scheduleReconnect();
544
+ }
545
+ #scheduleReconnect() {
546
+ if (this.#manualDisconnect || !this.#autoReconnect || this.#reconnectTimer) {
547
+ return;
548
+ }
549
+ const delay = Math.min(
550
+ this.#reconnectDelay * 2 ** this.#reconnectAttempts,
551
+ this.#reconnectMaxDelay
552
+ );
553
+ this.#reconnectAttempts += 1;
554
+ this.#reconnectTimer = setTimeout(() => {
555
+ this.#reconnectTimer = null;
556
+ this.connect().catch(() => this.#handleClose());
557
+ }, delay);
558
+ }
559
+ #rejectPending(error) {
560
+ for (const [id, pending] of this.#pendingRequests) {
561
+ clearTimeout(pending.timer);
562
+ pending.reject(error);
563
+ this.#pendingRequests.delete(id);
564
+ }
565
+ }
566
+ #emitLocal(event, data) {
567
+ this.#eventHandlers.get(event)?.forEach((handler) => handler(data));
568
+ }
569
+ #setState(state) {
570
+ if (this.#state === state) {
571
+ return;
572
+ }
573
+ this.#state = state;
574
+ this.#stateHandlers.forEach((handler) => handler(state));
575
+ }
576
+ };
577
+
578
+ // src/client/socket.ts
579
+ var Socket = class {
580
+ #channels = /* @__PURE__ */ new Map();
581
+ #url;
582
+ #path;
583
+ #auth;
584
+ #session;
585
+ constructor(options = {}) {
586
+ const browserWindow = globalThis;
587
+ const browserOrigin = typeof globalThis === "object" && browserWindow.window?.location?.origin ? browserWindow.window.location.origin : "";
588
+ this.#url = options.url ?? browserOrigin;
589
+ this.#path = options.path ?? "/socket";
590
+ this.#auth = options.auth;
591
+ this.#session = new ClientSocketSession({
592
+ buildUrl: () => this.#buildUrl(),
593
+ autoReconnect: options.autoReconnect,
594
+ reconnectDelay: options.reconnectDelay,
595
+ reconnectMaxDelay: options.reconnectMaxDelay,
596
+ onConnected: () => {
597
+ void this.#resubscribeChannels();
598
+ }
599
+ });
600
+ }
601
+ get state() {
602
+ return this.#session.state;
603
+ }
604
+ get connected() {
605
+ return this.#session.connected;
606
+ }
607
+ get id() {
608
+ return void 0;
609
+ }
610
+ connect() {
611
+ return this.#session.connect();
612
+ }
613
+ disconnect() {
614
+ for (const channel of this.#channels.values()) {
615
+ channel.unsubscribe().catch(() => {
616
+ });
617
+ }
618
+ this.#channels.clear();
619
+ this.#session.disconnect();
620
+ }
621
+ channel(name) {
622
+ if (!this.#channels.has(name)) {
623
+ this.#channels.set(name, new Channel(name, this));
624
+ }
625
+ return this.#channels.get(name);
626
+ }
627
+ async leave(name) {
628
+ const channel = this.#channels.get(name);
629
+ if (channel) {
630
+ await channel.unsubscribe();
631
+ this.#channels.delete(name);
632
+ }
633
+ }
634
+ onStateChange(handler) {
635
+ return this.#session.onStateChange(handler);
636
+ }
637
+ on(event, handler) {
638
+ return this.#session.on(event, handler);
639
+ }
640
+ off(event, handler) {
641
+ this.#session.off(event, handler);
642
+ }
643
+ send(message) {
644
+ this.#session.send(message);
645
+ }
646
+ sendRequest(message, timeout = 5e3) {
647
+ return this.#session.sendRequest(message, timeout);
648
+ }
649
+ #buildUrl() {
650
+ const browserGlobal = globalThis;
651
+ const url = new URL(this.#url || browserGlobal.location?.origin || "http://localhost");
652
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
653
+ url.pathname = this.#path;
654
+ if (this.#auth) {
655
+ url.searchParams.set("auth", JSON.stringify(this.#auth));
656
+ }
657
+ return url.toString();
658
+ }
659
+ async #resubscribeChannels() {
660
+ for (const channel of this.#channels.values()) {
661
+ if (channel.subscribed && !channel.active) {
662
+ await channel.subscribe().catch(console.error);
663
+ }
664
+ }
665
+ }
666
+ };
667
+ export {
668
+ Channel,
669
+ Socket
670
+ };
671
+ //# sourceMappingURL=index.js.map