@eleven-am/pondsocket-client 0.0.34 → 0.0.35

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/browser/client.js CHANGED
@@ -1,28 +1,9 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _PondClient_instances, _PondClient_channels, _PondClient_clearTimeouts, _PondClient_createPublisher, _PondClient_handleAcknowledge, _PondClient_handleUnauthorized, _PondClient_init;
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
3
  exports.PondClient = void 0;
16
- const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
17
- const channel_1 = require("../core/channel");
18
- const types_1 = require("../types");
19
- const DEFAULT_CONNECTION_TIMEOUT = 10000;
20
- const DEFAULT_MAX_RECONNECT_DELAY = 30000;
21
- class PondClient {
22
- constructor(endpoint, params = {}, options = {}) {
23
- var _a, _b;
24
- _PondClient_instances.add(this);
25
- _PondClient_channels.set(this, void 0);
4
+ const webSocketClient_1 = require("../core/webSocketClient");
5
+ class PondClient extends webSocketClient_1.WebSocketClient {
6
+ _resolveAddress(endpoint, params) {
26
7
  let address;
27
8
  try {
28
9
  address = new URL(endpoint);
@@ -32,164 +13,13 @@ class PondClient {
32
13
  address.pathname = endpoint;
33
14
  address.hash = '';
34
15
  }
35
- this._disconnecting = false;
36
- this._reconnectAttempts = 0;
37
16
  const query = new URLSearchParams(params);
38
17
  address.search = query.toString();
39
18
  const protocol = address.protocol === 'https:' ? 'wss:' : 'ws:';
40
19
  if (address.protocol !== 'wss:' && address.protocol !== 'ws:') {
41
20
  address.protocol = protocol;
42
21
  }
43
- this._address = address;
44
- this._options = {
45
- connectionTimeout: (_a = options.connectionTimeout) !== null && _a !== void 0 ? _a : DEFAULT_CONNECTION_TIMEOUT,
46
- maxReconnectDelay: (_b = options.maxReconnectDelay) !== null && _b !== void 0 ? _b : DEFAULT_MAX_RECONNECT_DELAY,
47
- pingInterval: options.pingInterval,
48
- };
49
- __classPrivateFieldSet(this, _PondClient_channels, new Map(), "f");
50
- this._broadcaster = new pondsocket_common_1.Subject();
51
- this._connectionState = new pondsocket_common_1.BehaviorSubject(types_1.ConnectionState.DISCONNECTED);
52
- this._errorSubject = new pondsocket_common_1.Subject();
53
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_init).call(this);
54
- }
55
- /**
56
- * @desc Connects to the server and returns the socket.
57
- */
58
- connect() {
59
- this._disconnecting = false;
60
- this._connectionState.publish(types_1.ConnectionState.CONNECTING);
61
- const socket = new WebSocket(this._address.toString());
62
- this._connectionTimeoutId = setTimeout(() => {
63
- if (socket.readyState === WebSocket.CONNECTING) {
64
- const error = new Error('Connection timeout');
65
- this._errorSubject.publish(error);
66
- socket.close();
67
- }
68
- }, this._options.connectionTimeout);
69
- socket.onopen = () => {
70
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_clearTimeouts).call(this);
71
- this._reconnectAttempts = 0;
72
- if (this._options.pingInterval) {
73
- this._pingIntervalId = setInterval(() => {
74
- if (socket.readyState === WebSocket.OPEN) {
75
- socket.send(JSON.stringify({ action: 'ping' }));
76
- }
77
- }, this._options.pingInterval);
78
- }
79
- };
80
- socket.onmessage = (message) => {
81
- const lines = message.data.trim().split('\n');
82
- for (const line of lines) {
83
- if (line.trim()) {
84
- const data = JSON.parse(line);
85
- const event = pondsocket_common_1.channelEventSchema.parse(data);
86
- this._broadcaster.publish(event);
87
- }
88
- }
89
- };
90
- socket.onerror = (event) => {
91
- const error = new Error('WebSocket error');
92
- this._errorSubject.publish(error);
93
- socket.close();
94
- };
95
- socket.onclose = () => {
96
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_clearTimeouts).call(this);
97
- this._connectionState.publish(types_1.ConnectionState.DISCONNECTED);
98
- if (this._disconnecting) {
99
- return;
100
- }
101
- const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), this._options.maxReconnectDelay);
102
- this._reconnectAttempts++;
103
- setTimeout(() => {
104
- this.connect();
105
- }, delay);
106
- };
107
- this._socket = socket;
108
- }
109
- /**
110
- * @desc Returns the current state of the socket.
111
- */
112
- getState() {
113
- return this._connectionState.value;
114
- }
115
- /**
116
- * @desc Disconnects the socket.
117
- */
118
- disconnect() {
119
- var _a;
120
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_clearTimeouts).call(this);
121
- this._disconnecting = true;
122
- this._connectionState.publish(types_1.ConnectionState.DISCONNECTED);
123
- (_a = this._socket) === null || _a === void 0 ? void 0 : _a.close();
124
- __classPrivateFieldGet(this, _PondClient_channels, "f").clear();
125
- }
126
- /**
127
- * @desc Creates a channel with the given name and params.
128
- * @param name - The name of the channel.
129
- * @param params - The params to send to the server.
130
- */
131
- createChannel(name, params) {
132
- const channel = __classPrivateFieldGet(this, _PondClient_channels, "f").get(name);
133
- if (channel && channel.channelState !== pondsocket_common_1.ChannelState.CLOSED) {
134
- return channel;
135
- }
136
- const publisher = __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_createPublisher).call(this);
137
- const newChannel = new channel_1.Channel(publisher, this._connectionState, name, params || {});
138
- __classPrivateFieldGet(this, _PondClient_channels, "f").set(name, newChannel);
139
- return newChannel;
140
- }
141
- /**
142
- * @desc Subscribes to the connection state.
143
- * @param callback - The callback to call when the state changes.
144
- */
145
- onConnectionChange(callback) {
146
- return this._connectionState.subscribe(callback);
147
- }
148
- /**
149
- * @desc Subscribes to connection errors.
150
- * @param callback - The callback to call when an error occurs.
151
- */
152
- onError(callback) {
153
- return this._errorSubject.subscribe(callback);
22
+ return address;
154
23
  }
155
24
  }
156
25
  exports.PondClient = PondClient;
157
- _PondClient_channels = new WeakMap(), _PondClient_instances = new WeakSet(), _PondClient_clearTimeouts = function _PondClient_clearTimeouts() {
158
- if (this._connectionTimeoutId) {
159
- clearTimeout(this._connectionTimeoutId);
160
- this._connectionTimeoutId = undefined;
161
- }
162
- if (this._pingIntervalId) {
163
- clearInterval(this._pingIntervalId);
164
- this._pingIntervalId = undefined;
165
- }
166
- }, _PondClient_createPublisher = function _PondClient_createPublisher() {
167
- return (message) => {
168
- if (this._connectionState.value === types_1.ConnectionState.CONNECTED) {
169
- this._socket.send(JSON.stringify(message));
170
- }
171
- };
172
- }, _PondClient_handleAcknowledge = function _PondClient_handleAcknowledge(message) {
173
- var _a;
174
- const channel = (_a = __classPrivateFieldGet(this, _PondClient_channels, "f").get(message.channelName)) !== null && _a !== void 0 ? _a : new channel_1.Channel(__classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_createPublisher).call(this), this._connectionState, message.channelName, {});
175
- __classPrivateFieldGet(this, _PondClient_channels, "f").set(message.channelName, channel);
176
- channel.acknowledge(this._broadcaster);
177
- }, _PondClient_handleUnauthorized = function _PondClient_handleUnauthorized(message) {
178
- const channel = __classPrivateFieldGet(this, _PondClient_channels, "f").get(message.channelName);
179
- if (channel) {
180
- const payload = message.payload;
181
- channel.decline(payload);
182
- }
183
- }, _PondClient_init = function _PondClient_init() {
184
- this._broadcaster.subscribe((message) => {
185
- if (message.event === pondsocket_common_1.Events.ACKNOWLEDGE) {
186
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_handleAcknowledge).call(this, message);
187
- }
188
- else if (message.event === pondsocket_common_1.Events.UNAUTHORIZED) {
189
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_handleUnauthorized).call(this, message);
190
- }
191
- else if (message.event === pondsocket_common_1.Events.CONNECTION && message.action === pondsocket_common_1.ServerActions.CONNECT) {
192
- this._connectionState.publish(types_1.ConnectionState.CONNECTED);
193
- }
194
- });
195
- };
@@ -13,7 +13,6 @@ const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
13
13
  const client_1 = require("./client");
14
14
  const types_1 = require("../types");
15
15
  class MockWebSocket {
16
- // eslint-disable-next-line no-useless-constructor
17
16
  constructor(url) {
18
17
  this.url = url;
19
18
  this.send = jest.fn();
@@ -23,7 +22,6 @@ class MockWebSocket {
23
22
  }
24
23
  MockWebSocket.CONNECTING = 0;
25
24
  MockWebSocket.OPEN = 1;
26
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
27
25
  // @ts-expect-error
28
26
  global.WebSocket = MockWebSocket;
29
27
  describe('PondClient', () => {
@@ -92,7 +90,6 @@ describe('PondClient', () => {
92
90
  test('createChannel method should create a new channel or return an existing one', () => {
93
91
  const mockChannel = pondClient.createChannel('exampleChannel');
94
92
  const mockExistingChannel = pondClient.createChannel('exampleChannel');
95
- // eslint-disable-next-line @typescript-eslint/no-var-requires
96
93
  expect(mockChannel).toBeInstanceOf(require('../core/channel').Channel);
97
94
  expect(mockExistingChannel).toBe(mockChannel);
98
95
  });
@@ -104,7 +101,6 @@ describe('PondClient', () => {
104
101
  expect(mockCallback).toHaveBeenCalledWith(types_1.ConnectionState.CONNECTED);
105
102
  unsubscribe();
106
103
  pondClient['_connectionState'].publish(types_1.ConnectionState.DISCONNECTED);
107
- // Should not be called again after unsubscribe
108
104
  expect(mockCallback).toHaveBeenCalledTimes(1);
109
105
  });
110
106
  test('getState method should return the current state of the socket', () => {
@@ -1,28 +1,23 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
2
  var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
3
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
4
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
5
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
6
  };
13
- var _SSEClient_instances, _SSEClient_channels, _SSEClient_handleMessage, _SSEClient_clearTimeout, _SSEClient_createPublisher, _SSEClient_handleAcknowledge, _SSEClient_handleUnauthorized, _SSEClient_init;
7
+ var _SSEClient_instances, _SSEClient_handleMessage;
14
8
  Object.defineProperty(exports, "__esModule", { value: true });
15
9
  exports.SSEClient = void 0;
16
10
  const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
17
- const channel_1 = require("../core/channel");
11
+ const baseClient_1 = require("../core/baseClient");
18
12
  const types_1 = require("../types");
19
- const DEFAULT_CONNECTION_TIMEOUT = 10000;
20
- const DEFAULT_MAX_RECONNECT_DELAY = 30000;
21
- class SSEClient {
13
+ class SSEClient extends baseClient_1.BaseClient {
22
14
  constructor(endpoint, params = {}, options = {}) {
23
- var _a, _b;
15
+ super(endpoint, params, options);
24
16
  _SSEClient_instances.add(this);
25
- _SSEClient_channels.set(this, void 0);
17
+ this._postAddress = new URL(this._address.toString());
18
+ this._withCredentials = options.withCredentials;
19
+ }
20
+ _resolveAddress(endpoint, params) {
26
21
  let address;
27
22
  try {
28
23
  address = new URL(endpoint);
@@ -31,33 +26,20 @@ class SSEClient {
31
26
  address = new URL(window.location.toString());
32
27
  address.pathname = endpoint;
33
28
  }
34
- this._disconnecting = false;
35
- this._reconnectAttempts = 0;
36
29
  const query = new URLSearchParams(params);
37
30
  address.search = query.toString();
38
31
  if (address.protocol !== 'https:' && address.protocol !== 'http:') {
39
32
  address.protocol = window.location.protocol;
40
33
  }
41
- this._address = address;
42
- this._postAddress = new URL(address.toString());
43
- this._options = {
44
- connectionTimeout: (_a = options.connectionTimeout) !== null && _a !== void 0 ? _a : DEFAULT_CONNECTION_TIMEOUT,
45
- maxReconnectDelay: (_b = options.maxReconnectDelay) !== null && _b !== void 0 ? _b : DEFAULT_MAX_RECONNECT_DELAY,
46
- pingInterval: options.pingInterval,
47
- withCredentials: options.withCredentials,
48
- };
49
- __classPrivateFieldSet(this, _SSEClient_channels, new Map(), "f");
50
- this._broadcaster = new pondsocket_common_1.Subject();
51
- this._connectionState = new pondsocket_common_1.BehaviorSubject(types_1.ConnectionState.DISCONNECTED);
52
- this._errorSubject = new pondsocket_common_1.Subject();
53
- __classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_init).call(this);
34
+ return address;
54
35
  }
55
36
  connect() {
56
37
  var _a;
57
38
  this._disconnecting = false;
39
+ this._connectionId = undefined;
58
40
  this._connectionState.publish(types_1.ConnectionState.CONNECTING);
59
41
  const eventSource = new EventSource(this._address.toString(), {
60
- withCredentials: (_a = this._options.withCredentials) !== null && _a !== void 0 ? _a : false,
42
+ withCredentials: (_a = this._withCredentials) !== null && _a !== void 0 ? _a : false,
61
43
  });
62
44
  this._connectionTimeoutId = setTimeout(() => {
63
45
  if (eventSource.readyState === EventSource.CONNECTING) {
@@ -67,7 +49,7 @@ class SSEClient {
67
49
  }
68
50
  }, this._options.connectionTimeout);
69
51
  eventSource.onopen = () => {
70
- __classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_clearTimeout).call(this);
52
+ this._clearConnectionTimeout();
71
53
  this._reconnectAttempts = 0;
72
54
  };
73
55
  eventSource.onmessage = (event) => {
@@ -77,28 +59,18 @@ class SSEClient {
77
59
  const error = new Error('SSE connection error');
78
60
  this._errorSubject.publish(error);
79
61
  eventSource.close();
80
- __classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_clearTimeout).call(this);
62
+ this._clearConnectionTimeout();
81
63
  this._connectionState.publish(types_1.ConnectionState.DISCONNECTED);
82
- if (this._disconnecting) {
83
- return;
84
- }
85
- const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), this._options.maxReconnectDelay);
86
- this._reconnectAttempts++;
87
- setTimeout(() => {
88
- this.connect();
89
- }, delay);
64
+ this._scheduleReconnect();
90
65
  };
91
66
  this._eventSource = eventSource;
92
67
  }
93
- getState() {
94
- return this._connectionState.value;
95
- }
96
68
  getConnectionId() {
97
69
  return this._connectionId;
98
70
  }
99
71
  disconnect() {
100
72
  var _a;
101
- __classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_clearTimeout).call(this);
73
+ this._clearConnectionTimeout();
102
74
  this._disconnecting = true;
103
75
  this._connectionState.publish(types_1.ConnectionState.DISCONNECTED);
104
76
  if (this._connectionId) {
@@ -107,93 +79,46 @@ class SSEClient {
107
79
  headers: {
108
80
  'X-Connection-ID': this._connectionId,
109
81
  },
110
- credentials: this._options.withCredentials ? 'include' : 'same-origin',
82
+ credentials: this._withCredentials ? 'include' : 'same-origin',
111
83
  }).catch(() => {
112
84
  });
113
85
  }
114
86
  (_a = this._eventSource) === null || _a === void 0 ? void 0 : _a.close();
115
87
  this._connectionId = undefined;
116
- __classPrivateFieldGet(this, _SSEClient_channels, "f").clear();
117
- }
118
- createChannel(name, params) {
119
- const channel = __classPrivateFieldGet(this, _SSEClient_channels, "f").get(name);
120
- if (channel && channel.channelState !== pondsocket_common_1.ChannelState.CLOSED) {
121
- return channel;
122
- }
123
- const publisher = __classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_createPublisher).call(this);
124
- const newChannel = new channel_1.Channel(publisher, this._connectionState, name, params || {});
125
- __classPrivateFieldGet(this, _SSEClient_channels, "f").set(name, newChannel);
126
- return newChannel;
88
+ this._clearChannels();
127
89
  }
128
- onConnectionChange(callback) {
129
- return this._connectionState.subscribe(callback);
130
- }
131
- onError(callback) {
132
- return this._errorSubject.subscribe(callback);
90
+ _createPublisher() {
91
+ return (message) => {
92
+ if (this._connectionState.value === types_1.ConnectionState.CONNECTED && this._connectionId) {
93
+ fetch(this._postAddress.toString(), {
94
+ method: 'POST',
95
+ headers: {
96
+ 'Content-Type': 'application/json',
97
+ 'X-Connection-ID': this._connectionId,
98
+ },
99
+ body: JSON.stringify(message),
100
+ credentials: this._withCredentials ? 'include' : 'same-origin',
101
+ }).catch((err) => {
102
+ this._errorSubject.publish(err instanceof Error ? err : new Error('Failed to send message'));
103
+ });
104
+ }
105
+ };
133
106
  }
134
107
  }
135
108
  exports.SSEClient = SSEClient;
136
- _SSEClient_channels = new WeakMap(), _SSEClient_instances = new WeakSet(), _SSEClient_handleMessage = function _SSEClient_handleMessage(data) {
109
+ _SSEClient_instances = new WeakSet(), _SSEClient_handleMessage = function _SSEClient_handleMessage(data) {
137
110
  try {
138
- const lines = data.trim().split('\n');
139
- for (const line of lines) {
140
- if (line.trim()) {
141
- const parsed = JSON.parse(line);
142
- const event = pondsocket_common_1.channelEventSchema.parse(parsed);
143
- if (event.event === pondsocket_common_1.Events.CONNECTION && event.action === pondsocket_common_1.ServerActions.CONNECT) {
144
- if (event.payload && typeof event.payload === 'object' && 'connectionId' in event.payload) {
145
- this._connectionId = event.payload.connectionId;
146
- }
111
+ const events = this._parseMessages(data);
112
+ for (const event of events) {
113
+ if (event.event === pondsocket_common_1.Events.CONNECTION && event.action === pondsocket_common_1.ServerActions.CONNECT) {
114
+ if (event.payload && typeof event.payload === 'object' && 'connectionId' in event.payload) {
115
+ this._connectionId = event.payload.connectionId;
147
116
  }
148
- this._broadcaster.publish(event);
149
117
  }
118
+ this._broadcaster.publish(event);
150
119
  }
151
120
  }
152
121
  catch (e) {
153
122
  this._errorSubject.publish(e instanceof Error ? e : new Error('Failed to parse SSE message'));
154
123
  }
155
- }, _SSEClient_clearTimeout = function _SSEClient_clearTimeout() {
156
- if (this._connectionTimeoutId) {
157
- clearTimeout(this._connectionTimeoutId);
158
- this._connectionTimeoutId = undefined;
159
- }
160
- }, _SSEClient_createPublisher = function _SSEClient_createPublisher() {
161
- return (message) => {
162
- if (this._connectionState.value === types_1.ConnectionState.CONNECTED && this._connectionId) {
163
- fetch(this._postAddress.toString(), {
164
- method: 'POST',
165
- headers: {
166
- 'Content-Type': 'application/json',
167
- 'X-Connection-ID': this._connectionId,
168
- },
169
- body: JSON.stringify(message),
170
- credentials: this._options.withCredentials ? 'include' : 'same-origin',
171
- }).catch((err) => {
172
- this._errorSubject.publish(err instanceof Error ? err : new Error('Failed to send message'));
173
- });
174
- }
175
- };
176
- }, _SSEClient_handleAcknowledge = function _SSEClient_handleAcknowledge(message) {
177
- var _a;
178
- const channel = (_a = __classPrivateFieldGet(this, _SSEClient_channels, "f").get(message.channelName)) !== null && _a !== void 0 ? _a : new channel_1.Channel(__classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_createPublisher).call(this), this._connectionState, message.channelName, {});
179
- __classPrivateFieldGet(this, _SSEClient_channels, "f").set(message.channelName, channel);
180
- channel.acknowledge(this._broadcaster);
181
- }, _SSEClient_handleUnauthorized = function _SSEClient_handleUnauthorized(message) {
182
- const channel = __classPrivateFieldGet(this, _SSEClient_channels, "f").get(message.channelName);
183
- if (channel) {
184
- const payload = message.payload;
185
- channel.decline(payload);
186
- }
187
- }, _SSEClient_init = function _SSEClient_init() {
188
- this._broadcaster.subscribe((message) => {
189
- if (message.event === pondsocket_common_1.Events.ACKNOWLEDGE) {
190
- __classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_handleAcknowledge).call(this, message);
191
- }
192
- else if (message.event === pondsocket_common_1.Events.UNAUTHORIZED) {
193
- __classPrivateFieldGet(this, _SSEClient_instances, "m", _SSEClient_handleUnauthorized).call(this, message);
194
- }
195
- else if (message.event === pondsocket_common_1.Events.CONNECTION && message.action === pondsocket_common_1.ServerActions.CONNECT) {
196
- this._connectionState.publish(types_1.ConnectionState.CONNECTED);
197
- }
198
- });
199
124
  };
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _BaseClient_instances, _BaseClient_channels, _BaseClient_handleAcknowledge, _BaseClient_handleUnauthorized, _BaseClient_init;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.BaseClient = void 0;
16
+ const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
17
+ const channel_1 = require("./channel");
18
+ const types_1 = require("../types");
19
+ const DEFAULT_CONNECTION_TIMEOUT = 10000;
20
+ const DEFAULT_MAX_RECONNECT_DELAY = 30000;
21
+ class BaseClient {
22
+ constructor(endpoint, params = {}, options = {}) {
23
+ var _a, _b;
24
+ _BaseClient_instances.add(this);
25
+ _BaseClient_channels.set(this, void 0);
26
+ this._address = this._resolveAddress(endpoint, params);
27
+ this._disconnecting = false;
28
+ this._reconnectAttempts = 0;
29
+ this._options = {
30
+ connectionTimeout: (_a = options.connectionTimeout) !== null && _a !== void 0 ? _a : DEFAULT_CONNECTION_TIMEOUT,
31
+ maxReconnectDelay: (_b = options.maxReconnectDelay) !== null && _b !== void 0 ? _b : DEFAULT_MAX_RECONNECT_DELAY,
32
+ pingInterval: options.pingInterval,
33
+ };
34
+ __classPrivateFieldSet(this, _BaseClient_channels, new Map(), "f");
35
+ this._broadcaster = new pondsocket_common_1.Subject();
36
+ this._connectionState = new pondsocket_common_1.BehaviorSubject(types_1.ConnectionState.DISCONNECTED);
37
+ this._errorSubject = new pondsocket_common_1.Subject();
38
+ __classPrivateFieldGet(this, _BaseClient_instances, "m", _BaseClient_init).call(this);
39
+ }
40
+ _clearConnectionTimeout() {
41
+ if (this._connectionTimeoutId) {
42
+ clearTimeout(this._connectionTimeoutId);
43
+ this._connectionTimeoutId = undefined;
44
+ }
45
+ }
46
+ _scheduleReconnect() {
47
+ if (this._disconnecting) {
48
+ return;
49
+ }
50
+ const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), this._options.maxReconnectDelay);
51
+ this._reconnectAttempts++;
52
+ setTimeout(() => {
53
+ this.connect();
54
+ }, delay);
55
+ }
56
+ getState() {
57
+ return this._connectionState.value;
58
+ }
59
+ createChannel(name, params) {
60
+ const channel = __classPrivateFieldGet(this, _BaseClient_channels, "f").get(name);
61
+ if (channel && channel.channelState !== pondsocket_common_1.ChannelState.CLOSED) {
62
+ return channel;
63
+ }
64
+ const publisher = this._createPublisher();
65
+ const newChannel = new channel_1.Channel(publisher, this._connectionState, name, params || {});
66
+ __classPrivateFieldGet(this, _BaseClient_channels, "f").set(name, newChannel);
67
+ return newChannel;
68
+ }
69
+ onConnectionChange(callback) {
70
+ return this._connectionState.subscribe(callback);
71
+ }
72
+ onError(callback) {
73
+ return this._errorSubject.subscribe(callback);
74
+ }
75
+ _parseMessages(data) {
76
+ const events = [];
77
+ const lines = data.trim().split('\n');
78
+ for (const line of lines) {
79
+ if (line.trim()) {
80
+ const parsed = JSON.parse(line);
81
+ const event = pondsocket_common_1.channelEventSchema.parse(parsed);
82
+ events.push(event);
83
+ }
84
+ }
85
+ return events;
86
+ }
87
+ _clearChannels() {
88
+ __classPrivateFieldGet(this, _BaseClient_channels, "f").clear();
89
+ }
90
+ }
91
+ exports.BaseClient = BaseClient;
92
+ _BaseClient_channels = new WeakMap(), _BaseClient_instances = new WeakSet(), _BaseClient_handleAcknowledge = function _BaseClient_handleAcknowledge(message) {
93
+ const channel = __classPrivateFieldGet(this, _BaseClient_channels, "f").get(message.channelName);
94
+ if (!channel) {
95
+ return;
96
+ }
97
+ channel.acknowledge(this._broadcaster);
98
+ }, _BaseClient_handleUnauthorized = function _BaseClient_handleUnauthorized(message) {
99
+ const channel = __classPrivateFieldGet(this, _BaseClient_channels, "f").get(message.channelName);
100
+ if (channel) {
101
+ const payload = message.payload;
102
+ channel.decline(payload);
103
+ }
104
+ }, _BaseClient_init = function _BaseClient_init() {
105
+ this._broadcaster.subscribe((message) => {
106
+ if (message.event === pondsocket_common_1.Events.ACKNOWLEDGE) {
107
+ __classPrivateFieldGet(this, _BaseClient_instances, "m", _BaseClient_handleAcknowledge).call(this, message);
108
+ }
109
+ else if (message.event === pondsocket_common_1.Events.UNAUTHORIZED) {
110
+ __classPrivateFieldGet(this, _BaseClient_instances, "m", _BaseClient_handleUnauthorized).call(this, message);
111
+ }
112
+ else if (message.event === pondsocket_common_1.Events.CONNECTION && message.action === pondsocket_common_1.ServerActions.CONNECT) {
113
+ this._connectionState.publish(types_1.ConnectionState.CONNECTED);
114
+ }
115
+ });
116
+ };
package/core/channel.js CHANGED
@@ -10,13 +10,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _Channel_instances, _Channel_name, _Channel_queue, _Channel_presence, _Channel_presenceSub, _Channel_publisher, _Channel_joinParams, _Channel_receiver, _Channel_clientState, _Channel_joinState, _Channel_emptyQueue, _Channel_init, _Channel_onMessage, _Channel_publish, _Channel_subscribeToPresence;
13
+ var _Channel_instances, _Channel_name, _Channel_queue, _Channel_presence, _Channel_presenceSub, _Channel_publisher, _Channel_joinParams, _Channel_receiver, _Channel_clientState, _Channel_joinState, _Channel_maxQueueSize, _Channel_emptyQueue, _Channel_init, _Channel_onMessage, _Channel_publish, _Channel_subscribeToPresence;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.Channel = void 0;
16
16
  const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
17
17
  const types_1 = require("../types");
18
18
  class Channel {
19
- constructor(publisher, clientState, name, params) {
19
+ constructor(publisher, clientState, name, params, maxQueueSize = 100) {
20
20
  _Channel_instances.add(this);
21
21
  _Channel_name.set(this, void 0);
22
22
  _Channel_queue.set(this, void 0);
@@ -27,11 +27,13 @@ class Channel {
27
27
  _Channel_receiver.set(this, void 0);
28
28
  _Channel_clientState.set(this, void 0);
29
29
  _Channel_joinState.set(this, void 0);
30
+ _Channel_maxQueueSize.set(this, void 0);
30
31
  __classPrivateFieldSet(this, _Channel_name, name, "f");
31
32
  __classPrivateFieldSet(this, _Channel_queue, [], "f");
32
33
  __classPrivateFieldSet(this, _Channel_presence, [], "f");
33
34
  __classPrivateFieldSet(this, _Channel_joinParams, params, "f");
34
35
  __classPrivateFieldSet(this, _Channel_publisher, publisher, "f");
36
+ __classPrivateFieldSet(this, _Channel_maxQueueSize, maxQueueSize, "f");
35
37
  __classPrivateFieldSet(this, _Channel_clientState, clientState, "f");
36
38
  __classPrivateFieldSet(this, _Channel_receiver, new pondsocket_common_1.Subject(), "f");
37
39
  __classPrivateFieldSet(this, _Channel_joinState, new pondsocket_common_1.BehaviorSubject(pondsocket_common_1.ChannelState.IDLE), "f");
@@ -56,6 +58,9 @@ class Channel {
56
58
  * @param receiver - The receiver to subscribe to.
57
59
  */
58
60
  acknowledge(receiver) {
61
+ if (__classPrivateFieldGet(this, _Channel_joinState, "f").value === pondsocket_common_1.ChannelState.JOINED) {
62
+ return;
63
+ }
59
64
  __classPrivateFieldGet(this, _Channel_joinState, "f").publish(pondsocket_common_1.ChannelState.JOINED);
60
65
  __classPrivateFieldGet(this, _Channel_instances, "m", _Channel_init).call(this, receiver);
61
66
  __classPrivateFieldGet(this, _Channel_instances, "m", _Channel_emptyQueue).call(this);
@@ -198,20 +203,22 @@ class Channel {
198
203
  };
199
204
  __classPrivateFieldGet(this, _Channel_instances, "m", _Channel_publish).call(this, message);
200
205
  }
201
- /**
202
- * @desc Sends a message to the server and waits for a response.
203
- * @param sentEvent - The event to send.
204
- * @param payload - The message to send.
205
- */
206
- sendForResponse(sentEvent, payload) {
206
+ sendForResponse(sentEvent, payload, timeoutMs = 30000) {
207
207
  const requestId = (0, pondsocket_common_1.uuid)();
208
- return new Promise((resolve) => {
209
- const unsub = __classPrivateFieldGet(this, _Channel_instances, "m", _Channel_onMessage).call(this, (_, message, responseId) => {
208
+ return new Promise((resolve, reject) => {
209
+ const cleanup = { timer: undefined,
210
+ unsub: () => { } };
211
+ cleanup.unsub = __classPrivateFieldGet(this, _Channel_instances, "m", _Channel_onMessage).call(this, (_, message, responseId) => {
210
212
  if (requestId === responseId) {
213
+ clearTimeout(cleanup.timer);
211
214
  resolve(message);
212
- unsub();
215
+ cleanup.unsub();
213
216
  }
214
217
  });
218
+ cleanup.timer = setTimeout(() => {
219
+ cleanup.unsub();
220
+ reject(new Error(`sendForResponse timed out after ${timeoutMs}ms for event "${String(sentEvent)}"`));
221
+ }, timeoutMs);
215
222
  const message = {
216
223
  action: pondsocket_common_1.ClientActions.BROADCAST,
217
224
  channelName: __classPrivateFieldGet(this, _Channel_name, "f"),
@@ -224,7 +231,7 @@ class Channel {
224
231
  }
225
232
  }
226
233
  exports.Channel = Channel;
227
- _Channel_name = new WeakMap(), _Channel_queue = new WeakMap(), _Channel_presence = new WeakMap(), _Channel_presenceSub = new WeakMap(), _Channel_publisher = new WeakMap(), _Channel_joinParams = new WeakMap(), _Channel_receiver = new WeakMap(), _Channel_clientState = new WeakMap(), _Channel_joinState = new WeakMap(), _Channel_instances = new WeakSet(), _Channel_emptyQueue = function _Channel_emptyQueue() {
234
+ _Channel_name = new WeakMap(), _Channel_queue = new WeakMap(), _Channel_presence = new WeakMap(), _Channel_presenceSub = new WeakMap(), _Channel_publisher = new WeakMap(), _Channel_joinParams = new WeakMap(), _Channel_receiver = new WeakMap(), _Channel_clientState = new WeakMap(), _Channel_joinState = new WeakMap(), _Channel_maxQueueSize = new WeakMap(), _Channel_instances = new WeakSet(), _Channel_emptyQueue = function _Channel_emptyQueue() {
228
235
  __classPrivateFieldGet(this, _Channel_queue, "f")
229
236
  .forEach((message) => __classPrivateFieldGet(this, _Channel_publisher, "f").call(this, message));
230
237
  __classPrivateFieldSet(this, _Channel_queue, [], "f");
@@ -268,6 +275,9 @@ _Channel_name = new WeakMap(), _Channel_queue = new WeakMap(), _Channel_presence
268
275
  if (__classPrivateFieldGet(this, _Channel_joinState, "f").value === pondsocket_common_1.ChannelState.JOINED) {
269
276
  return __classPrivateFieldGet(this, _Channel_publisher, "f").call(this, data);
270
277
  }
278
+ if (__classPrivateFieldGet(this, _Channel_queue, "f").length >= __classPrivateFieldGet(this, _Channel_maxQueueSize, "f")) {
279
+ __classPrivateFieldGet(this, _Channel_queue, "f").shift();
280
+ }
271
281
  __classPrivateFieldGet(this, _Channel_queue, "f").push(data);
272
282
  }, _Channel_subscribeToPresence = function _Channel_subscribeToPresence(callback) {
273
283
  return __classPrivateFieldGet(this, _Channel_receiver, "f").subscribe((data) => {
@@ -685,6 +685,32 @@ describe('Channel', () => {
685
685
  });
686
686
  expect(specificMessageListener).not.toHaveBeenCalled();
687
687
  });
688
+ it('should handle decline by setting state to DECLINED and clearing queue', () => {
689
+ const { channel } = createChannel();
690
+ channel.sendMessage('queued', { data: 'test' });
691
+ channel.decline({ message: 'Not authorized', statusCode: 403 });
692
+ expect(channel.channelState).toBe(pondsocket_common_1.ChannelState.DECLINED);
693
+ });
694
+ it('should not re-join when already in JOINED state', () => {
695
+ const { channel, publisher, receiver } = createChannel();
696
+ channel.join();
697
+ channel.acknowledge(receiver);
698
+ expect(channel.channelState).toBe(pondsocket_common_1.ChannelState.JOINED);
699
+ publisher.mockClear();
700
+ channel.join();
701
+ expect(publisher).not.toHaveBeenCalled();
702
+ });
703
+ it('sendForResponse should reject with timeout error', () => __awaiter(void 0, void 0, void 0, function* () {
704
+ const publisher = jest.fn();
705
+ const state = new pondsocket_common_1.BehaviorSubject(types_1.ConnectionState.CONNECTED);
706
+ const receiver = new pondsocket_common_1.Subject();
707
+ const channel = new channel_1.Channel(publisher, state, 'test', {});
708
+ channel.join();
709
+ channel.acknowledge(receiver);
710
+ // @ts-expect-error - testing timeout behavior
711
+ const promise = channel.sendForResponse('timeout-event', { data: 'test' }, 100);
712
+ yield expect(promise).rejects.toThrow(/sendForResponse timed out after 100ms/);
713
+ }));
688
714
  it('should be able to wait for a message', () => __awaiter(void 0, void 0, void 0, function* () {
689
715
  const state = new pondsocket_common_1.BehaviorSubject(types_1.ConnectionState.CONNECTED);
690
716
  const receiver = new pondsocket_common_1.Subject();
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebSocketClient = void 0;
4
+ const baseClient_1 = require("./baseClient");
5
+ const types_1 = require("../types");
6
+ class WebSocketClient extends baseClient_1.BaseClient {
7
+ constructor() {
8
+ super(...arguments);
9
+ this._lastMessageTime = 0;
10
+ }
11
+ connect() {
12
+ this._disconnecting = false;
13
+ this._connectionState.publish(types_1.ConnectionState.CONNECTING);
14
+ const socket = new WebSocket(this._address.toString());
15
+ this._connectionTimeoutId = setTimeout(() => {
16
+ if (socket.readyState === WebSocket.CONNECTING) {
17
+ const error = new Error('Connection timeout');
18
+ this._errorSubject.publish(error);
19
+ socket.close();
20
+ }
21
+ }, this._options.connectionTimeout);
22
+ socket.onopen = () => {
23
+ this._clearConnectionTimeout();
24
+ this._clearPingInterval();
25
+ this._clearPongTimeout();
26
+ this._reconnectAttempts = 0;
27
+ this._lastMessageTime = Date.now();
28
+ if (this._options.pingInterval) {
29
+ this._pingIntervalId = setInterval(() => {
30
+ if (socket.readyState === WebSocket.OPEN) {
31
+ socket.send(JSON.stringify({ action: 'ping' }));
32
+ }
33
+ }, this._options.pingInterval);
34
+ this._schedulePongTimeout(socket);
35
+ }
36
+ };
37
+ socket.onmessage = (message) => {
38
+ this._lastMessageTime = Date.now();
39
+ const events = this._parseMessages(message.data);
40
+ for (const event of events) {
41
+ this._broadcaster.publish(event);
42
+ }
43
+ };
44
+ socket.onerror = () => {
45
+ const error = new Error('WebSocket error');
46
+ this._errorSubject.publish(error);
47
+ socket.close();
48
+ };
49
+ socket.onclose = () => {
50
+ this._clearConnectionTimeout();
51
+ this._clearPingInterval();
52
+ this._clearPongTimeout();
53
+ this._connectionState.publish(types_1.ConnectionState.DISCONNECTED);
54
+ this._scheduleReconnect();
55
+ };
56
+ this._socket = socket;
57
+ }
58
+ disconnect() {
59
+ var _a;
60
+ this._clearConnectionTimeout();
61
+ this._clearPingInterval();
62
+ this._clearPongTimeout();
63
+ this._disconnecting = true;
64
+ this._connectionState.publish(types_1.ConnectionState.DISCONNECTED);
65
+ (_a = this._socket) === null || _a === void 0 ? void 0 : _a.close();
66
+ this._clearChannels();
67
+ }
68
+ _createPublisher() {
69
+ return (message) => {
70
+ var _a;
71
+ if (this._connectionState.value === types_1.ConnectionState.CONNECTED) {
72
+ (_a = this._socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(message));
73
+ }
74
+ };
75
+ }
76
+ _clearPingInterval() {
77
+ if (this._pingIntervalId) {
78
+ clearInterval(this._pingIntervalId);
79
+ this._pingIntervalId = undefined;
80
+ }
81
+ }
82
+ _clearPongTimeout() {
83
+ if (this._pongTimeoutId) {
84
+ clearTimeout(this._pongTimeoutId);
85
+ this._pongTimeoutId = undefined;
86
+ }
87
+ }
88
+ _schedulePongTimeout(socket) {
89
+ this._clearPongTimeout();
90
+ const timeout = this._options.pingInterval * 2;
91
+ this._pongTimeoutId = setTimeout(() => {
92
+ if (Date.now() - this._lastMessageTime >= timeout) {
93
+ this._errorSubject.publish(new Error('Connection lost: no response from server'));
94
+ socket.close();
95
+ return;
96
+ }
97
+ this._schedulePongTimeout(socket);
98
+ }, timeout);
99
+ }
100
+ }
101
+ exports.WebSocketClient = WebSocketClient;
package/dist.d.ts CHANGED
@@ -102,7 +102,7 @@ declare class Channel<EventMap extends PondEventMap = PondEventMap, Presence ext
102
102
  * @param sentEvent - The event to send.
103
103
  * @param payload - The message to send.
104
104
  */
105
- sendForResponse<Event extends EventWithResponse<EventMap>> (sentEvent: Event, payload: PayloadForResponse<EventMap, Event>): Promise<ResponseForEvent<EventMap, Event>>;
105
+ sendForResponse<Event extends EventWithResponse<EventMap>> (sentEvent: Event, payload: PayloadForResponse<EventMap, Event>, timeoutMs?: number): Promise<ResponseForEvent<EventMap, Event>>;
106
106
  }
107
107
 
108
108
  declare class PondClient {
package/node/node.js CHANGED
@@ -1,85 +1,17 @@
1
1
  "use strict";
2
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
- };
7
- var _PondClient_instances, _PondClient_clearTimeouts;
8
2
  Object.defineProperty(exports, "__esModule", { value: true });
9
3
  exports.PondClient = void 0;
10
- const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
11
- const client_1 = require("../browser/client");
12
- const types_1 = require("../types");
13
- // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-require-imports
14
- const WebSocket = require('websocket').w3cwebsocket;
15
- class PondClient extends client_1.PondClient {
16
- constructor() {
17
- super(...arguments);
18
- _PondClient_instances.add(this);
19
- }
20
- /**
21
- * @desc Connects to the server and returns the socket.
22
- */
23
- connect() {
24
- this._disconnecting = false;
25
- this._connectionState.publish(types_1.ConnectionState.CONNECTING);
26
- const socket = new WebSocket(this._address.toString());
27
- this._connectionTimeoutId = setTimeout(() => {
28
- if (socket.readyState === WebSocket.CONNECTING) {
29
- const error = new Error('Connection timeout');
30
- this._errorSubject.publish(error);
31
- socket.close();
32
- }
33
- }, this._options.connectionTimeout);
34
- socket.onopen = () => {
35
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_clearTimeouts).call(this);
36
- this._reconnectAttempts = 0;
37
- if (this._options.pingInterval) {
38
- this._pingIntervalId = setInterval(() => {
39
- if (socket.readyState === WebSocket.OPEN) {
40
- socket.send(JSON.stringify({ action: 'ping' }));
41
- }
42
- }, this._options.pingInterval);
43
- }
44
- };
45
- socket.onmessage = (message) => {
46
- const lines = message.data.trim().split('\n');
47
- for (const line of lines) {
48
- if (line.trim()) {
49
- const data = JSON.parse(line);
50
- const event = pondsocket_common_1.channelEventSchema.parse(data);
51
- this._broadcaster.publish(event);
52
- }
53
- }
54
- };
55
- socket.onerror = () => {
56
- const error = new Error('WebSocket error');
57
- this._errorSubject.publish(error);
58
- socket.close();
59
- };
60
- socket.onclose = () => {
61
- __classPrivateFieldGet(this, _PondClient_instances, "m", _PondClient_clearTimeouts).call(this);
62
- this._connectionState.publish(types_1.ConnectionState.DISCONNECTED);
63
- if (this._disconnecting) {
64
- return;
65
- }
66
- const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), this._options.maxReconnectDelay);
67
- this._reconnectAttempts++;
68
- setTimeout(() => {
69
- this.connect();
70
- }, delay);
71
- };
72
- this._socket = socket;
4
+ const webSocketClient_1 = require("../core/webSocketClient");
5
+ class PondClient extends webSocketClient_1.WebSocketClient {
6
+ _resolveAddress(endpoint, params) {
7
+ const address = new URL(endpoint);
8
+ const query = new URLSearchParams(params);
9
+ address.search = query.toString();
10
+ const protocol = address.protocol === 'https:' ? 'wss:' : 'ws:';
11
+ if (address.protocol !== 'wss:' && address.protocol !== 'ws:') {
12
+ address.protocol = protocol;
13
+ }
14
+ return address;
73
15
  }
74
16
  }
75
17
  exports.PondClient = PondClient;
76
- _PondClient_instances = new WeakSet(), _PondClient_clearTimeouts = function _PondClient_clearTimeouts() {
77
- if (this._connectionTimeoutId) {
78
- clearTimeout(this._connectionTimeoutId);
79
- this._connectionTimeoutId = undefined;
80
- }
81
- if (this._pingIntervalId) {
82
- clearInterval(this._pingIntervalId);
83
- this._pingIntervalId = undefined;
84
- }
85
- };
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_1 = require("./node");
4
+ describe('PondClient (Node)', () => {
5
+ it('should resolve http endpoint to ws protocol', () => {
6
+ const client = new node_1.PondClient('http://localhost:3000/ws', { token: 'abc' });
7
+ const address = client._address;
8
+ expect(address.protocol).toBe('ws:');
9
+ expect(address.hostname).toBe('localhost');
10
+ expect(address.port).toBe('3000');
11
+ expect(address.pathname).toBe('/ws');
12
+ expect(address.searchParams.get('token')).toBe('abc');
13
+ });
14
+ it('should resolve https endpoint to wss protocol', () => {
15
+ const client = new node_1.PondClient('https://example.com/ws', {});
16
+ const address = client._address;
17
+ expect(address.protocol).toBe('wss:');
18
+ expect(address.hostname).toBe('example.com');
19
+ });
20
+ it('should keep ws protocol if already specified', () => {
21
+ const client = new node_1.PondClient('ws://localhost:3000/ws', {});
22
+ const address = client._address;
23
+ expect(address.protocol).toBe('ws:');
24
+ });
25
+ it('should keep wss protocol if already specified', () => {
26
+ const client = new node_1.PondClient('wss://example.com/ws', {});
27
+ const address = client._address;
28
+ expect(address.protocol).toBe('wss:');
29
+ });
30
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eleven-am/pondsocket-client",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "description": "PondSocket is a fast simple socket server",
5
5
  "keywords": [
6
6
  "socket",
@@ -30,18 +30,23 @@
30
30
  "pipeline": "npm run test && npm run build && npm run push"
31
31
  },
32
32
  "dependencies": {
33
- "@eleven-am/pondsocket-common": "^0.0.34",
34
- "websocket": "^1.0.35"
33
+ "@eleven-am/pondsocket-common": "^0.0.37"
35
34
  },
36
35
  "devDependencies": {
36
+ "@eslint/compat": "^2.0.2",
37
+ "@eslint/eslintrc": "^3.3.4",
38
+ "@eslint/js": "^9.39.3",
39
+ "@stylistic/eslint-plugin-ts": "^4.4.1",
37
40
  "@types/jest": "^30.0.0",
38
- "@types/websocket": "^1.0.10",
39
- "@typescript-eslint/eslint-plugin": "^8.49.0",
41
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
42
+ "@typescript-eslint/parser": "^8.56.1",
43
+ "eslint": "^9.39.3",
40
44
  "eslint-plugin-file-progress": "^3.0.2",
41
45
  "eslint-plugin-import": "^2.32.0",
46
+ "globals": "^17.4.0",
42
47
  "jest": "^30.2.0",
43
- "prettier": "^3.7.4",
44
- "supertest": "^7.1.4",
48
+ "prettier": "^3.8.1",
49
+ "supertest": "^7.2.2",
45
50
  "ts-jest": "^29.4.6",
46
51
  "ts-loader": "^9.5.4",
47
52
  "ts-node": "^10.9.2",
@@ -56,12 +61,25 @@
56
61
  "rootDir": "src",
57
62
  "testRegex": ".*\\.test\\.ts$",
58
63
  "transform": {
59
- "^.+\\.(t|j)s$": "ts-jest"
64
+ "^.+\\.(t|j)s$": [
65
+ "ts-jest",
66
+ {
67
+ "diagnostics": false
68
+ }
69
+ ]
60
70
  },
61
71
  "collectCoverageFrom": [
62
- "**/*.(t|j)s"
72
+ "**/*.(t|j)s",
73
+ "!**/*.test.ts",
74
+ "!**/*.d.ts",
75
+ "!**/index.ts",
76
+ "!**/index.d.ts",
77
+ "!**/dist.d.ts"
63
78
  ],
64
79
  "coverageDirectory": "../coverage",
65
- "testEnvironment": "node"
80
+ "testEnvironment": "node",
81
+ "moduleNameMapper": {
82
+ "^@eleven-am/pondsocket-common$": "<rootDir>/../../comnon/dist"
83
+ }
66
84
  }
67
85
  }