airdcpp-apisocket 2.4.5-beta.1 → 2.5.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/GUIDE.md +1 -1
  2. package/README.md +3 -2
  3. package/dist/ApiConstants.d.ts +6 -6
  4. package/dist/ApiConstants.js +7 -7
  5. package/dist/NodeSocket.d.ts +4 -4
  6. package/dist/NodeSocket.js +24 -24
  7. package/dist/Promise.d.ts +8 -8
  8. package/dist/Promise.js +26 -26
  9. package/dist/PublicHelpers.d.ts +2 -2
  10. package/dist/PublicHelpers.js +94 -99
  11. package/dist/PublicHelpers.js.map +1 -1
  12. package/dist/SocketBase.d.ts +4 -4
  13. package/dist/SocketBase.js +351 -343
  14. package/dist/SocketBase.js.map +1 -1
  15. package/dist/SocketLogger.d.ts +9 -9
  16. package/dist/SocketLogger.js +74 -74
  17. package/dist/SocketLogger.js.map +1 -1
  18. package/dist/SocketRequestHandler.d.ts +14 -14
  19. package/dist/SocketRequestHandler.js +168 -162
  20. package/dist/SocketRequestHandler.js.map +1 -1
  21. package/dist/SocketSubscriptionHandler.d.ts +11 -11
  22. package/dist/SocketSubscriptionHandler.js +161 -158
  23. package/dist/SocketSubscriptionHandler.js.map +1 -1
  24. package/dist/types/api.d.ts +30 -30
  25. package/dist/types/api.js +3 -3
  26. package/dist/types/api_internal.d.ts +24 -24
  27. package/dist/types/api_internal.js +2 -2
  28. package/dist/types/index.d.ts +7 -7
  29. package/dist/types/index.js +23 -23
  30. package/dist/types/logger.d.ts +6 -6
  31. package/dist/types/logger.js +2 -2
  32. package/dist/types/options.d.ts +31 -31
  33. package/dist/types/options.js +3 -3
  34. package/dist/types/public_helpers.d.ts +19 -14
  35. package/dist/types/public_helpers.js +2 -2
  36. package/dist/types/public_helpers_internal.d.ts +27 -25
  37. package/dist/types/public_helpers_internal.js +2 -2
  38. package/dist/types/requests.d.ts +14 -14
  39. package/dist/types/requests.js +2 -2
  40. package/dist/types/socket.d.ts +23 -23
  41. package/dist/types/socket.js +2 -2
  42. package/dist/types/subscriptions.d.ts +20 -20
  43. package/dist/types/subscriptions.js +2 -2
  44. package/dist/utils.d.ts +2 -2
  45. package/dist/utils.js +15 -15
  46. package/dist-es/ApiConstants.d.ts +6 -6
  47. package/dist-es/ApiConstants.js +5 -5
  48. package/dist-es/NodeSocket.d.ts +4 -4
  49. package/dist-es/NodeSocket.js +4 -4
  50. package/dist-es/Promise.d.ts +8 -8
  51. package/dist-es/Promise.js +24 -24
  52. package/dist-es/PublicHelpers.d.ts +2 -2
  53. package/dist-es/PublicHelpers.js +90 -95
  54. package/dist-es/PublicHelpers.js.map +1 -1
  55. package/dist-es/SocketBase.d.ts +4 -4
  56. package/dist-es/SocketBase.js +346 -338
  57. package/dist-es/SocketBase.js.map +1 -1
  58. package/dist-es/SocketLogger.d.ts +9 -9
  59. package/dist-es/SocketLogger.js +68 -68
  60. package/dist-es/SocketLogger.js.map +1 -1
  61. package/dist-es/SocketRequestHandler.d.ts +14 -14
  62. package/dist-es/SocketRequestHandler.js +163 -157
  63. package/dist-es/SocketRequestHandler.js.map +1 -1
  64. package/dist-es/SocketSubscriptionHandler.d.ts +11 -11
  65. package/dist-es/SocketSubscriptionHandler.js +156 -153
  66. package/dist-es/SocketSubscriptionHandler.js.map +1 -1
  67. package/dist-es/types/api.d.ts +30 -30
  68. package/dist-es/types/api.js +2 -2
  69. package/dist-es/types/api_internal.d.ts +24 -24
  70. package/dist-es/types/api_internal.js +1 -1
  71. package/dist-es/types/index.d.ts +7 -7
  72. package/dist-es/types/index.js +7 -7
  73. package/dist-es/types/logger.d.ts +6 -6
  74. package/dist-es/types/logger.js +1 -1
  75. package/dist-es/types/options.d.ts +31 -31
  76. package/dist-es/types/options.js +2 -2
  77. package/dist-es/types/public_helpers.d.ts +19 -14
  78. package/dist-es/types/public_helpers.js +1 -1
  79. package/dist-es/types/public_helpers_internal.d.ts +27 -25
  80. package/dist-es/types/public_helpers_internal.js +1 -1
  81. package/dist-es/types/requests.d.ts +14 -14
  82. package/dist-es/types/requests.js +1 -1
  83. package/dist-es/types/socket.d.ts +23 -23
  84. package/dist-es/types/socket.js +1 -1
  85. package/dist-es/types/subscriptions.d.ts +20 -20
  86. package/dist-es/types/subscriptions.js +1 -1
  87. package/dist-es/utils.d.ts +2 -2
  88. package/dist-es/utils.js +11 -11
  89. package/jest.config.js +0 -3
  90. package/package.json +4 -4
  91. package/src/PublicHelpers.ts +10 -9
  92. package/src/SocketLogger.ts +1 -1
  93. package/src/SocketRequestHandler.ts +2 -2
  94. package/src/tests/Socket.test.ts +4 -9
  95. package/src/tests/helpers.ts +7 -2
  96. package/src/tests/public_helpers.test.ts +4 -4
  97. package/src/types/public_helpers.ts +7 -1
  98. package/src/types/public_helpers_internal.ts +3 -1
  99. package/tsconfig.json +2 -3
@@ -1,339 +1,347 @@
1
- import ApiConstants from './ApiConstants.js';
2
- import SocketLogger from './SocketLogger.js';
3
- import SocketSubscriptionHandler from './SocketSubscriptionHandler.js';
4
- import SocketRequestHandler from './SocketRequestHandler.js';
5
- import invariant from 'invariant';
6
- import Promise from './Promise.js';
7
- // CONSTANTS
8
- const defaultOptions = {
9
- autoReconnect: true,
10
- reconnectInterval: 10,
11
- userSession: false,
12
- };
13
- const ApiSocket = (userOptions, WebSocketImpl) => {
14
- const options = Object.assign(Object.assign({}, defaultOptions), userOptions);
15
- let ws = null;
16
- let authToken = null;
17
- let socket = null;
18
- let reconnectTimer;
19
- let forceNoAutoConnect = true;
20
- let connectedCallback = null;
21
- let sessionResetCallback = null;
22
- let disconnectedCallback = null;
23
- const logger = SocketLogger(options);
24
- const subscriptions = SocketSubscriptionHandler(() => socket, logger, options);
25
- const requests = SocketRequestHandler(() => socket, logger, options);
26
- invariant(userOptions.url, '"url" must be defined in settings object');
27
- const resetSession = () => {
28
- if (authToken) {
29
- if (sessionResetCallback) {
30
- sessionResetCallback();
31
- }
32
- authToken = null;
33
- }
34
- };
35
- const onClosed = (event) => {
36
- if (event.wasClean) {
37
- logger.info('Websocket was closed normally');
38
- }
39
- else {
40
- logger.error(`Websocket failed: ${event.reason} (code: ${event.code})`);
41
- }
42
- requests.onSocketDisconnected();
43
- subscriptions.onSocketDisconnected();
44
- ws = null;
45
- if (disconnectedCallback) {
46
- disconnectedCallback(event.reason, event.code, event.wasClean);
47
- }
48
- if (authToken && options.autoReconnect && !forceNoAutoConnect) {
49
- setTimeout(() => {
50
- if (forceNoAutoConnect) {
51
- return;
52
- }
53
- socket.reconnect()
54
- .catch((error) => {
55
- logger.error('Reconnect failed for a closed socket', error.message);
56
- });
57
- });
58
- }
59
- };
60
- const onMessage = (event) => {
61
- const messageObj = JSON.parse(event.data);
62
- if (messageObj.callback_id) {
63
- // Callback
64
- requests.handleMessage(messageObj);
65
- }
66
- else {
67
- // Listener message
68
- subscriptions.handleMessage(messageObj);
69
- }
70
- };
71
- const setSocketHandlers = () => {
72
- ws.onerror = (event) => {
73
- logger.error(`Websocket failed: ${event.reason}`);
74
- };
75
- ws.onclose = onClosed;
76
- ws.onmessage = onMessage;
77
- };
78
- // Connect handler for creation of new session
79
- const handlePasswordLogin = (username = options.username, password = options.password) => {
80
- if (!username) {
81
- throw '"username" option was not supplied for authentication';
82
- }
83
- if (!password) {
84
- throw '"password" option was not supplied for authentication';
85
- }
86
- const data = {
87
- username,
88
- password,
89
- grant_type: 'password',
90
- };
91
- return requests.postAuthenticate(ApiConstants.LOGIN_URL, data);
92
- };
93
- const handleRefreshTokenLogin = (refreshToken) => {
94
- if (!refreshToken) {
95
- throw '"refreshToken" option was not supplied for authentication';
96
- }
97
- const data = {
98
- refresh_token: refreshToken,
99
- grant_type: 'refresh_token',
100
- };
101
- return requests.postAuthenticate(ApiConstants.LOGIN_URL, data);
102
- };
103
- // Connect handler for associating socket with an existing session token
104
- const handleAuthorizeToken = () => {
105
- const data = {
106
- auth_token: authToken,
107
- };
108
- return requests.postAuthenticate(ApiConstants.CONNECT_URL, data);
109
- };
110
- // Called after a successful authentication request
111
- const onSocketAuthenticated = (data) => {
112
- if (!authToken) {
113
- // New session
114
- logger.info('Login succeed');
115
- authToken = data.auth_token;
116
- }
117
- else {
118
- // Existing session
119
- logger.info('Socket associated with an existing session');
120
- }
121
- if (connectedCallback) {
122
- // Catch separately as we don't want an infinite reconnect loop
123
- try {
124
- connectedCallback(data);
125
- }
126
- catch (e) {
127
- console.error('Error in socket connect handler', e.message);
128
- }
129
- requests.onSocketConnected();
130
- }
131
- };
132
- // Send API authentication and handle the result
133
- // Authentication handler should send the actual authentication request
134
- const authenticate = (resolve, reject, authenticationHandler, reconnectHandler) => {
135
- authenticationHandler()
136
- .then((data) => {
137
- onSocketAuthenticated(data);
138
- resolve(data);
139
- })
140
- .catch((error) => {
141
- if (error.code) {
142
- if (authToken && error.code === 400 && options.autoReconnect) {
143
- // The session was lost (most likely the client was restarted)
144
- logger.info('Session lost, re-sending credentials');
145
- resetSession();
146
- authenticate(resolve, reject, handlePasswordLogin, reconnectHandler);
147
- return;
148
- }
149
- else if (error.code === 401) {
150
- // Invalid credentials, reset the token if we were reconnecting to avoid an infinite loop
151
- resetSession();
152
- }
153
- // Authentication was rejected
154
- socket.disconnect(undefined, 'Authentication failed');
155
- }
156
- else {
157
- // Socket was disconnected during the authentication
158
- logger.info('Socket disconnected during authentication, reconnecting');
159
- reconnectHandler();
160
- return;
161
- }
162
- reject(error);
163
- });
164
- };
165
- // Authentication handler should send the actual authentication request
166
- const connectInternal = (resolve, reject, authenticationHandler, reconnectOnFailure = true) => {
167
- ws = new WebSocketImpl(options.url);
168
- const scheduleReconnect = () => {
169
- ws = null;
170
- if (!reconnectOnFailure) {
171
- reject('Cannot connect to the server');
172
- return;
173
- }
174
- reconnectTimer = setTimeout(() => {
175
- logger.info('Socket reconnecting');
176
- connectInternal(resolve, reject, authenticationHandler, reconnectOnFailure);
177
- }, options.reconnectInterval * 1000);
178
- };
179
- ws.onopen = () => {
180
- logger.info('Socket connected');
181
- setSocketHandlers();
182
- authenticate(resolve, reject, authenticationHandler, scheduleReconnect);
183
- };
184
- ws.onerror = (event) => {
185
- logger.error('Connecting socket failed');
186
- scheduleReconnect();
187
- };
188
- };
189
- // Authentication handler should send the actual authentication request
190
- const startConnect = (authenticationHandler, reconnectOnFailure) => {
191
- forceNoAutoConnect = false;
192
- return new Promise((resolve, reject) => {
193
- logger.info('Starting socket connect');
194
- connectInternal(resolve, reject, authenticationHandler, reconnectOnFailure);
195
- });
196
- };
197
- // Is the socket connected and authorized?
198
- const isConnected = () => {
199
- return !!(ws && ws.readyState === (ws.OPEN || 1) && authToken);
200
- };
201
- // Is the socket connected but not possibly authorized?
202
- const isConnecting = () => {
203
- return !!(ws && !isConnected());
204
- };
205
- // Socket exists
206
- const isActive = () => {
207
- return !!ws;
208
- };
209
- const disableReconnect = () => {
210
- clearTimeout(reconnectTimer);
211
- forceNoAutoConnect = true;
212
- };
213
- const waitDisconnected = (timeoutMs = 2000) => {
214
- const checkInterval = 50;
215
- const maxAttempts = timeoutMs > 0 ? timeoutMs / checkInterval : 0;
216
- return new Promise((resolve, reject) => {
217
- let attempts = 0;
218
- const wait = () => {
219
- if (isActive()) {
220
- if (attempts >= maxAttempts) {
221
- logger.error(`Socket disconnect timed out after ${timeoutMs} ms`);
222
- reject('Socket disconnect timed out');
223
- }
224
- else {
225
- setTimeout(wait, checkInterval);
226
- attempts++;
227
- }
228
- }
229
- else {
230
- resolve();
231
- }
232
- };
233
- wait();
234
- });
235
- };
236
- // Disconnects the socket but keeps the session token
237
- const disconnect = (autoConnect = false, reason = 'Manually disconnected by the client') => {
238
- if (!ws) {
239
- if (!forceNoAutoConnect) {
240
- if (!autoConnect) {
241
- logger.verbose('Disconnecting a closed socket with auto reconnect enabled (cancel reconnect)');
242
- disableReconnect();
243
- }
244
- else {
245
- logger.verbose('Attempting to disconnect a closed socket with auto reconnect enabled (continue connecting)');
246
- }
247
- }
248
- else {
249
- logger.warn('Attempting to disconnect a closed socket (ignore)');
250
- //throw 'Attempting to disconnect a closed socket';
251
- }
252
- return;
253
- }
254
- logger.info('Disconnecting socket');
255
- if (!autoConnect) {
256
- disableReconnect();
257
- }
258
- ws.close(1000, reason);
259
- };
260
- socket = Object.assign(Object.assign({
261
- // Start connect
262
- // Username and password are not required if those are available in socket options
263
- connect: (username, password, reconnectOnFailure = true) => {
264
- if (isActive()) {
265
- throw 'Connect may only be used for a closed socket';
266
- }
267
- resetSession();
268
- return startConnect(() => handlePasswordLogin(username, password), reconnectOnFailure);
269
- }, connectRefreshToken: (refreshToken, reconnectOnFailure = true) => {
270
- if (isActive()) {
271
- throw 'Connect may only be used for a closed socket';
272
- }
273
- resetSession();
274
- return startConnect(() => handleRefreshTokenLogin(refreshToken), reconnectOnFailure);
275
- },
276
- // Connect and attempt to associate the socket with an existing session
277
- reconnect: (token = undefined, reconnectOnFailure = true) => {
278
- if (isActive()) {
279
- throw 'Reconnect may only be used for a closed socket';
280
- }
281
- if (token) {
282
- authToken = token;
283
- }
284
- if (!authToken) {
285
- throw 'No session token available for reconnecting';
286
- }
287
- logger.info('Reconnecting socket');
288
- return startConnect(handleAuthorizeToken, reconnectOnFailure);
289
- },
290
- // Remove the associated API session and close the socket
291
- logout: () => {
292
- const resolver = Promise.pending();
293
- socket.delete(ApiConstants.LOGOUT_URL)
294
- .then((data) => {
295
- logger.info('Logout succeed');
296
- resetSession();
297
- resolver.resolve(data);
298
- // Don't fire the disconnected event before resolver actions are handled
299
- disconnect(undefined, 'Logged out');
300
- })
301
- .catch((error) => {
302
- logger.error('Logout failed', error);
303
- resolver.reject(error);
304
- });
305
- return resolver.promise;
306
- }, disconnect,
307
- isConnecting,
308
- isConnected,
309
- isActive,
310
- logger,
311
- waitDisconnected,
312
- // Function to call each time the socket has been connected (and authorized)
313
- set onConnected(handler) {
314
- connectedCallback = handler;
315
- },
316
- // Function to call each time the stored session token was reset (manual logout/rejected reconnect)
317
- set onSessionReset(handler) {
318
- sessionResetCallback = handler;
319
- },
320
- // Function to call each time the socket has been disconnected
321
- set onDisconnected(handler) {
322
- disconnectedCallback = handler;
323
- },
324
- get onConnected() {
325
- return connectedCallback;
326
- },
327
- get onSessionReset() {
328
- return sessionResetCallback;
329
- },
330
- get onDisconnected() {
331
- return disconnectedCallback;
332
- },
333
- get nativeSocket() {
334
- return ws;
335
- } }, subscriptions.socket), requests.socket);
336
- return socket;
337
- };
338
- export default ApiSocket;
1
+ import ApiConstants from './ApiConstants.js';
2
+ import SocketLogger from './SocketLogger.js';
3
+ import SocketSubscriptionHandler from './SocketSubscriptionHandler.js';
4
+ import SocketRequestHandler from './SocketRequestHandler.js';
5
+ import invariant from 'invariant';
6
+ import Promise from './Promise.js';
7
+ // CONSTANTS
8
+ const defaultOptions = {
9
+ autoReconnect: true,
10
+ reconnectInterval: 10,
11
+ userSession: false,
12
+ };
13
+ const ApiSocket = (userOptions, WebSocketImpl) => {
14
+ const options = {
15
+ ...defaultOptions,
16
+ ...userOptions
17
+ };
18
+ let ws = null;
19
+ let authToken = null;
20
+ let socket = null;
21
+ let reconnectTimer;
22
+ let forceNoAutoConnect = true;
23
+ let connectedCallback = null;
24
+ let sessionResetCallback = null;
25
+ let disconnectedCallback = null;
26
+ const logger = SocketLogger(options);
27
+ const subscriptions = SocketSubscriptionHandler(() => socket, logger, options);
28
+ const requests = SocketRequestHandler(() => socket, logger, options);
29
+ invariant(userOptions.url, '"url" must be defined in settings object');
30
+ const resetSession = () => {
31
+ if (authToken) {
32
+ if (sessionResetCallback) {
33
+ sessionResetCallback();
34
+ }
35
+ authToken = null;
36
+ }
37
+ };
38
+ const onClosed = (event) => {
39
+ if (event.wasClean) {
40
+ logger.info('Websocket was closed normally');
41
+ }
42
+ else {
43
+ logger.error(`Websocket failed: ${event.reason} (code: ${event.code})`);
44
+ }
45
+ requests.onSocketDisconnected();
46
+ subscriptions.onSocketDisconnected();
47
+ ws = null;
48
+ if (disconnectedCallback) {
49
+ disconnectedCallback(event.reason, event.code, event.wasClean);
50
+ }
51
+ if (authToken && options.autoReconnect && !forceNoAutoConnect) {
52
+ setTimeout(() => {
53
+ if (forceNoAutoConnect) {
54
+ return;
55
+ }
56
+ socket.reconnect()
57
+ .catch((error) => {
58
+ logger.error('Reconnect failed for a closed socket', error.message);
59
+ });
60
+ });
61
+ }
62
+ };
63
+ const onMessage = (event) => {
64
+ const messageObj = JSON.parse(event.data);
65
+ if (messageObj.callback_id) {
66
+ // Callback
67
+ requests.handleMessage(messageObj);
68
+ }
69
+ else {
70
+ // Listener message
71
+ subscriptions.handleMessage(messageObj);
72
+ }
73
+ };
74
+ const setSocketHandlers = () => {
75
+ ws.onerror = (event) => {
76
+ logger.error(`Websocket failed: ${event.reason}`);
77
+ };
78
+ ws.onclose = onClosed;
79
+ ws.onmessage = onMessage;
80
+ };
81
+ // Connect handler for creation of new session
82
+ const handlePasswordLogin = (username = options.username, password = options.password) => {
83
+ if (!username) {
84
+ throw '"username" option was not supplied for authentication';
85
+ }
86
+ if (!password) {
87
+ throw '"password" option was not supplied for authentication';
88
+ }
89
+ const data = {
90
+ username,
91
+ password,
92
+ grant_type: 'password',
93
+ };
94
+ return requests.postAuthenticate(ApiConstants.LOGIN_URL, data);
95
+ };
96
+ const handleRefreshTokenLogin = (refreshToken) => {
97
+ if (!refreshToken) {
98
+ throw '"refreshToken" option was not supplied for authentication';
99
+ }
100
+ const data = {
101
+ refresh_token: refreshToken,
102
+ grant_type: 'refresh_token',
103
+ };
104
+ return requests.postAuthenticate(ApiConstants.LOGIN_URL, data);
105
+ };
106
+ // Connect handler for associating socket with an existing session token
107
+ const handleAuthorizeToken = () => {
108
+ const data = {
109
+ auth_token: authToken,
110
+ };
111
+ return requests.postAuthenticate(ApiConstants.CONNECT_URL, data);
112
+ };
113
+ // Called after a successful authentication request
114
+ const onSocketAuthenticated = (data) => {
115
+ if (!authToken) {
116
+ // New session
117
+ logger.info('Login succeed');
118
+ authToken = data.auth_token;
119
+ }
120
+ else {
121
+ // Existing session
122
+ logger.info('Socket associated with an existing session');
123
+ }
124
+ if (connectedCallback) {
125
+ // Catch separately as we don't want an infinite reconnect loop
126
+ try {
127
+ connectedCallback(data);
128
+ }
129
+ catch (e) {
130
+ console.error('Error in socket connect handler', e.message);
131
+ }
132
+ requests.onSocketConnected();
133
+ }
134
+ };
135
+ // Send API authentication and handle the result
136
+ // Authentication handler should send the actual authentication request
137
+ const authenticate = (resolve, reject, authenticationHandler, reconnectHandler) => {
138
+ authenticationHandler()
139
+ .then((data) => {
140
+ onSocketAuthenticated(data);
141
+ resolve(data);
142
+ })
143
+ .catch((error) => {
144
+ if (error.code) {
145
+ if (authToken && error.code === 400 && options.autoReconnect) {
146
+ // The session was lost (most likely the client was restarted)
147
+ logger.info('Session lost, re-sending credentials');
148
+ resetSession();
149
+ authenticate(resolve, reject, handlePasswordLogin, reconnectHandler);
150
+ return;
151
+ }
152
+ else if (error.code === 401) {
153
+ // Invalid credentials, reset the token if we were reconnecting to avoid an infinite loop
154
+ resetSession();
155
+ }
156
+ // Authentication was rejected
157
+ socket.disconnect(undefined, 'Authentication failed');
158
+ }
159
+ else {
160
+ // Socket was disconnected during the authentication
161
+ logger.info('Socket disconnected during authentication, reconnecting');
162
+ reconnectHandler();
163
+ return;
164
+ }
165
+ reject(error);
166
+ });
167
+ };
168
+ // Authentication handler should send the actual authentication request
169
+ const connectInternal = (resolve, reject, authenticationHandler, reconnectOnFailure = true) => {
170
+ ws = new WebSocketImpl(options.url);
171
+ const scheduleReconnect = () => {
172
+ ws = null;
173
+ if (!reconnectOnFailure) {
174
+ reject('Cannot connect to the server');
175
+ return;
176
+ }
177
+ reconnectTimer = setTimeout(() => {
178
+ logger.info('Socket reconnecting');
179
+ connectInternal(resolve, reject, authenticationHandler, reconnectOnFailure);
180
+ }, options.reconnectInterval * 1000);
181
+ };
182
+ ws.onopen = () => {
183
+ logger.info('Socket connected');
184
+ setSocketHandlers();
185
+ authenticate(resolve, reject, authenticationHandler, scheduleReconnect);
186
+ };
187
+ ws.onerror = (event) => {
188
+ logger.error('Connecting socket failed');
189
+ scheduleReconnect();
190
+ };
191
+ };
192
+ // Authentication handler should send the actual authentication request
193
+ const startConnect = (authenticationHandler, reconnectOnFailure) => {
194
+ forceNoAutoConnect = false;
195
+ return new Promise((resolve, reject) => {
196
+ logger.info('Starting socket connect');
197
+ connectInternal(resolve, reject, authenticationHandler, reconnectOnFailure);
198
+ });
199
+ };
200
+ // Is the socket connected and authorized?
201
+ const isConnected = () => {
202
+ return !!(ws && ws.readyState === (ws.OPEN || 1) && authToken);
203
+ };
204
+ // Is the socket connected but not possibly authorized?
205
+ const isConnecting = () => {
206
+ return !!(ws && !isConnected());
207
+ };
208
+ // Socket exists
209
+ const isActive = () => {
210
+ return !!ws;
211
+ };
212
+ const disableReconnect = () => {
213
+ clearTimeout(reconnectTimer);
214
+ forceNoAutoConnect = true;
215
+ };
216
+ const waitDisconnected = (timeoutMs = 2000) => {
217
+ const checkInterval = 50;
218
+ const maxAttempts = timeoutMs > 0 ? timeoutMs / checkInterval : 0;
219
+ return new Promise((resolve, reject) => {
220
+ let attempts = 0;
221
+ const wait = () => {
222
+ if (isActive()) {
223
+ if (attempts >= maxAttempts) {
224
+ logger.error(`Socket disconnect timed out after ${timeoutMs} ms`);
225
+ reject('Socket disconnect timed out');
226
+ }
227
+ else {
228
+ setTimeout(wait, checkInterval);
229
+ attempts++;
230
+ }
231
+ }
232
+ else {
233
+ resolve();
234
+ }
235
+ };
236
+ wait();
237
+ });
238
+ };
239
+ // Disconnects the socket but keeps the session token
240
+ const disconnect = (autoConnect = false, reason = 'Manually disconnected by the client') => {
241
+ if (!ws) {
242
+ if (!forceNoAutoConnect) {
243
+ if (!autoConnect) {
244
+ logger.verbose('Disconnecting a closed socket with auto reconnect enabled (cancel reconnect)');
245
+ disableReconnect();
246
+ }
247
+ else {
248
+ logger.verbose('Attempting to disconnect a closed socket with auto reconnect enabled (continue connecting)');
249
+ }
250
+ }
251
+ else {
252
+ logger.warn('Attempting to disconnect a closed socket (ignore)');
253
+ //throw 'Attempting to disconnect a closed socket';
254
+ }
255
+ return;
256
+ }
257
+ logger.info('Disconnecting socket');
258
+ if (!autoConnect) {
259
+ disableReconnect();
260
+ }
261
+ ws.close(1000, reason);
262
+ };
263
+ socket = {
264
+ // Start connect
265
+ // Username and password are not required if those are available in socket options
266
+ connect: (username, password, reconnectOnFailure = true) => {
267
+ if (isActive()) {
268
+ throw 'Connect may only be used for a closed socket';
269
+ }
270
+ resetSession();
271
+ return startConnect(() => handlePasswordLogin(username, password), reconnectOnFailure);
272
+ },
273
+ connectRefreshToken: (refreshToken, reconnectOnFailure = true) => {
274
+ if (isActive()) {
275
+ throw 'Connect may only be used for a closed socket';
276
+ }
277
+ resetSession();
278
+ return startConnect(() => handleRefreshTokenLogin(refreshToken), reconnectOnFailure);
279
+ },
280
+ // Connect and attempt to associate the socket with an existing session
281
+ reconnect: (token = undefined, reconnectOnFailure = true) => {
282
+ if (isActive()) {
283
+ throw 'Reconnect may only be used for a closed socket';
284
+ }
285
+ if (token) {
286
+ authToken = token;
287
+ }
288
+ if (!authToken) {
289
+ throw 'No session token available for reconnecting';
290
+ }
291
+ logger.info('Reconnecting socket');
292
+ return startConnect(handleAuthorizeToken, reconnectOnFailure);
293
+ },
294
+ // Remove the associated API session and close the socket
295
+ logout: () => {
296
+ const resolver = Promise.pending();
297
+ socket.delete(ApiConstants.LOGOUT_URL)
298
+ .then((data) => {
299
+ logger.info('Logout succeed');
300
+ resetSession();
301
+ resolver.resolve(data);
302
+ // Don't fire the disconnected event before resolver actions are handled
303
+ disconnect(undefined, 'Logged out');
304
+ })
305
+ .catch((error) => {
306
+ logger.error('Logout failed', error);
307
+ resolver.reject(error);
308
+ });
309
+ return resolver.promise;
310
+ },
311
+ disconnect,
312
+ isConnecting,
313
+ isConnected,
314
+ isActive,
315
+ logger,
316
+ waitDisconnected,
317
+ // Function to call each time the socket has been connected (and authorized)
318
+ set onConnected(handler) {
319
+ connectedCallback = handler;
320
+ },
321
+ // Function to call each time the stored session token was reset (manual logout/rejected reconnect)
322
+ set onSessionReset(handler) {
323
+ sessionResetCallback = handler;
324
+ },
325
+ // Function to call each time the socket has been disconnected
326
+ set onDisconnected(handler) {
327
+ disconnectedCallback = handler;
328
+ },
329
+ get onConnected() {
330
+ return connectedCallback;
331
+ },
332
+ get onSessionReset() {
333
+ return sessionResetCallback;
334
+ },
335
+ get onDisconnected() {
336
+ return disconnectedCallback;
337
+ },
338
+ get nativeSocket() {
339
+ return ws;
340
+ },
341
+ ...subscriptions.socket,
342
+ ...requests.socket,
343
+ };
344
+ return socket;
345
+ };
346
+ export default ApiSocket;
339
347
  //# sourceMappingURL=SocketBase.js.map