teckos-client 0.2.5 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.js +456 -5
- package/dist/index.min.js +1 -0
- package/es/index.js +459 -0
- package/es/index.mjs +1 -0
- package/lib/index.js +484 -0
- package/package.json +61 -46
- package/src/ITeckosClient.js +2 -0
- package/src/ITeckosClient.js.map +1 -0
- package/src/ITeckosClient.ts +3 -3
- package/src/TeckosClient.js +235 -0
- package/src/TeckosClient.js.map +1 -0
- package/src/TeckosClient.ts +40 -32
- package/src/TeckosClientWithJWT.js +63 -0
- package/src/TeckosClientWithJWT.js.map +1 -0
- package/src/TeckosClientWithJWT.ts +8 -10
- package/src/index.js +8 -0
- package/src/index.js.map +1 -0
- package/src/types/ConnectionState.js +9 -0
- package/src/types/ConnectionState.js.map +1 -0
- package/src/types/Options.js +2 -0
- package/src/types/Options.js.map +1 -0
- package/src/types/Packet.js +2 -0
- package/src/types/Packet.js.map +1 -0
- package/src/types/PacketType.js +7 -0
- package/src/types/PacketType.js.map +1 -0
- package/src/types/SocketEvent.js +2 -0
- package/src/types/SocketEvent.js.map +1 -0
- package/src/types/index.js +4 -0
- package/src/types/index.js.map +1 -0
- package/src/util/Converter.js +6 -0
- package/src/util/Converter.js.map +1 -0
- package/src/util/SocketEventEmitter.js +99 -0
- package/src/util/SocketEventEmitter.js.map +1 -0
- package/src/util/formatProdErrorMessage.ts +16 -0
- package/{dist → types}/ITeckosClient.d.ts +3 -3
- package/{dist → types}/TeckosClient.d.ts +6 -6
- package/{dist → types}/TeckosClientWithJWT.d.ts +0 -0
- package/{dist → types}/index.d.ts +0 -0
- package/{dist → types}/types/ConnectionState.d.ts +0 -0
- package/{dist → types}/types/Options.d.ts +0 -0
- package/{dist → types}/types/Packet.d.ts +0 -0
- package/{dist → types}/types/PacketType.d.ts +0 -0
- package/{dist → types}/types/SocketEvent.d.ts +0 -0
- package/{dist → types}/types/index.d.ts +0 -0
- package/{dist → types}/util/Converter.d.ts +0 -0
- package/{dist → types}/util/SocketEventEmitter.d.ts +1 -1
- package/types/util/formatProdErrorMessage.d.ts +9 -0
- package/dist/teckos-client.cjs.development.js +0 -617
- package/dist/teckos-client.cjs.development.js.map +0 -1
- package/dist/teckos-client.cjs.production.min.js +0 -2
- package/dist/teckos-client.cjs.production.min.js.map +0 -1
- package/dist/teckos-client.esm.js +0 -614
- package/dist/teckos-client.esm.js.map +0 -1
package/es/index.js
ADDED
@@ -0,0 +1,459 @@
|
|
1
|
+
import * as IsomorphicWebSocket from 'isomorphic-ws';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
5
|
+
*
|
6
|
+
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
7
|
+
* during build.
|
8
|
+
* @param {number} code
|
9
|
+
*/
|
10
|
+
function formatProdErrorMessage(code) {
|
11
|
+
return `Minified Redux error #${code}; visit https://redux.js.org/Errors?code=${code} for the full message or ` + 'use the non-minified dev environment for full errors. ';
|
12
|
+
} // eslint-disable-next-line import/no-default-export
|
13
|
+
|
14
|
+
const enc = new TextEncoder();
|
15
|
+
const dec = new TextDecoder();
|
16
|
+
|
17
|
+
const encodePacket = packet => enc.encode(JSON.stringify(packet));
|
18
|
+
|
19
|
+
const decodePacket = buffer => JSON.parse(dec.decode(buffer).toString());
|
20
|
+
|
21
|
+
class SocketEventEmitter {
|
22
|
+
maxListeners = 50;
|
23
|
+
handlers = {};
|
24
|
+
addListener = (event, listener) => {
|
25
|
+
if (Object.keys(this.handlers).length === this.maxListeners) {
|
26
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(2) : 'Max listeners reached');
|
27
|
+
}
|
28
|
+
|
29
|
+
if (typeof listener !== 'function') {
|
30
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(3) : 'The given listener is not a function');
|
31
|
+
}
|
32
|
+
|
33
|
+
this.handlers[event] = this.handlers[event] || [];
|
34
|
+
this.handlers[event].push(listener);
|
35
|
+
return this;
|
36
|
+
};
|
37
|
+
once = (event, listener) => {
|
38
|
+
if (Object.keys(this.handlers).length === this.maxListeners) {
|
39
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(2) : 'Max listeners reached');
|
40
|
+
}
|
41
|
+
|
42
|
+
if (typeof listener !== 'function') {
|
43
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(3) : 'The given listener is not a function');
|
44
|
+
}
|
45
|
+
|
46
|
+
this.handlers[event] = this.handlers[event] || [];
|
47
|
+
|
48
|
+
const onceWrapper = () => {
|
49
|
+
listener();
|
50
|
+
this.off(event, onceWrapper);
|
51
|
+
};
|
52
|
+
|
53
|
+
this.handlers[event].push(onceWrapper);
|
54
|
+
return this;
|
55
|
+
};
|
56
|
+
removeListener = (event, listener) => {
|
57
|
+
if (this.handlers[event]) {
|
58
|
+
this.handlers[event] = this.handlers[event].filter(handler => handler !== listener);
|
59
|
+
}
|
60
|
+
|
61
|
+
return this;
|
62
|
+
};
|
63
|
+
off = (event, listener) => this.removeListener(event, listener);
|
64
|
+
removeAllListeners = event => {
|
65
|
+
if (event) {
|
66
|
+
delete this.handlers[event];
|
67
|
+
} else {
|
68
|
+
this.handlers = {};
|
69
|
+
}
|
70
|
+
|
71
|
+
return this;
|
72
|
+
};
|
73
|
+
setMaxListeners = n => {
|
74
|
+
this.maxListeners = n;
|
75
|
+
return this;
|
76
|
+
};
|
77
|
+
getMaxListeners = () => this.maxListeners;
|
78
|
+
listeners = event => {
|
79
|
+
if (this.handlers[event]) {
|
80
|
+
return [...this.handlers[event]];
|
81
|
+
}
|
82
|
+
|
83
|
+
return [];
|
84
|
+
};
|
85
|
+
rawListeners = event => [...this.handlers[event]];
|
86
|
+
listenerCount = event => {
|
87
|
+
if (this.handlers[event]) {
|
88
|
+
return Object.keys(this.handlers[event]).length;
|
89
|
+
}
|
90
|
+
|
91
|
+
return 0;
|
92
|
+
};
|
93
|
+
prependListener = (event, listener) => {
|
94
|
+
if (Object.keys(this.handlers).length === this.maxListeners) {
|
95
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(2) : 'Max listeners reached');
|
96
|
+
}
|
97
|
+
|
98
|
+
this.handlers[event] = this.handlers[event] || [];
|
99
|
+
this.handlers[event].unshift(listener);
|
100
|
+
return this;
|
101
|
+
};
|
102
|
+
prependOnceListener = (event, listener) => {
|
103
|
+
if (Object.keys(this.handlers).length === this.maxListeners) {
|
104
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(2) : 'Max listeners reached');
|
105
|
+
}
|
106
|
+
|
107
|
+
this.handlers[event] = this.handlers[event] || [];
|
108
|
+
|
109
|
+
const onceWrapper = () => {
|
110
|
+
listener();
|
111
|
+
this.off(event, onceWrapper);
|
112
|
+
};
|
113
|
+
|
114
|
+
this.handlers[event].unshift(onceWrapper);
|
115
|
+
return this;
|
116
|
+
};
|
117
|
+
eventNames = () => Object.keys(this.handlers);
|
118
|
+
on = (event, listener) => this.addListener(event, listener);
|
119
|
+
emit = (event, ...args) => {
|
120
|
+
const listeners = this.listeners(event);
|
121
|
+
|
122
|
+
if (listeners.length > 0) {
|
123
|
+
listeners.forEach(listener => {
|
124
|
+
if (listener) listener(args);
|
125
|
+
});
|
126
|
+
return true;
|
127
|
+
}
|
128
|
+
|
129
|
+
return false;
|
130
|
+
};
|
131
|
+
}
|
132
|
+
|
133
|
+
var PacketType;
|
134
|
+
|
135
|
+
(function (PacketType) {
|
136
|
+
PacketType[PacketType["EVENT"] = 0] = "EVENT";
|
137
|
+
PacketType[PacketType["ACK"] = 1] = "ACK";
|
138
|
+
})(PacketType || (PacketType = {}));
|
139
|
+
|
140
|
+
var ConnectionState;
|
141
|
+
|
142
|
+
(function (ConnectionState) {
|
143
|
+
ConnectionState["DISCONNECTED"] = "disconnected";
|
144
|
+
ConnectionState["CONNECTING"] = "connecting";
|
145
|
+
ConnectionState["CONNECTED"] = "connected";
|
146
|
+
ConnectionState["DISCONNECTING"] = "disconnecting";
|
147
|
+
})(ConnectionState || (ConnectionState = {}));
|
148
|
+
|
149
|
+
const DEFAULT_OPTIONS = {
|
150
|
+
reconnection: true,
|
151
|
+
reconnectionDelay: 1000,
|
152
|
+
reconnectionDelayMax: 5000,
|
153
|
+
reconnectionAttempts: Infinity,
|
154
|
+
randomizationFactor: 0.5,
|
155
|
+
timeout: 5000,
|
156
|
+
debug: false
|
157
|
+
};
|
158
|
+
|
159
|
+
class TeckosClient extends SocketEventEmitter {
|
160
|
+
url;
|
161
|
+
options;
|
162
|
+
ws;
|
163
|
+
currentReconnectDelay;
|
164
|
+
currentReconnectionAttempts = 0;
|
165
|
+
acks = new Map();
|
166
|
+
fnId = 0;
|
167
|
+
connectionTimeout;
|
168
|
+
reconnectionTimeout;
|
169
|
+
|
170
|
+
constructor(url, options) {
|
171
|
+
super();
|
172
|
+
this.options = { ...DEFAULT_OPTIONS,
|
173
|
+
...options
|
174
|
+
};
|
175
|
+
this.currentReconnectDelay = this.options.reconnectionDelay;
|
176
|
+
this.url = url;
|
177
|
+
}
|
178
|
+
|
179
|
+
attachHandler = () => {
|
180
|
+
if (this.ws) {
|
181
|
+
this.ws.onopen = this.handleOpen;
|
182
|
+
this.ws.onerror = this.handleError;
|
183
|
+
this.ws.onclose = this.handleClose;
|
184
|
+
this.ws.onmessage = this.handleMessage;
|
185
|
+
}
|
186
|
+
};
|
187
|
+
|
188
|
+
get webSocket() {
|
189
|
+
return this.ws;
|
190
|
+
}
|
191
|
+
|
192
|
+
connect = () => {
|
193
|
+
if (this.options.debug) console.log(`(teckos:client) Connecting to ${this.url}...`); // This will try to connect immediately
|
194
|
+
// eslint-disable-next-line new-cap
|
195
|
+
|
196
|
+
this.ws = new IsomorphicWebSocket.WebSocket(this.url); // Attach handlers
|
197
|
+
|
198
|
+
this.attachHandler(); // Handle timeout
|
199
|
+
|
200
|
+
this.connectionTimeout = setTimeout(() => {
|
201
|
+
if (this.ws && this.ws.readyState === 0
|
202
|
+
/* = CONNECTING */
|
203
|
+
) {
|
204
|
+
this.ws.close();
|
205
|
+
}
|
206
|
+
}, this.options.timeout);
|
207
|
+
};
|
208
|
+
reconnect = () => {
|
209
|
+
this.listeners('reconnect_attempt').forEach(listener => listener());
|
210
|
+
this.connect();
|
211
|
+
};
|
212
|
+
|
213
|
+
getConnectionState() {
|
214
|
+
if (this.ws) {
|
215
|
+
switch (this.ws.readyState) {
|
216
|
+
case 0
|
217
|
+
/* = CONNECTING */
|
218
|
+
:
|
219
|
+
return ConnectionState.CONNECTING;
|
220
|
+
|
221
|
+
case 1
|
222
|
+
/* = OPEN */
|
223
|
+
:
|
224
|
+
return ConnectionState.CONNECTED;
|
225
|
+
|
226
|
+
case 2
|
227
|
+
/* = CLOSING */
|
228
|
+
:
|
229
|
+
return ConnectionState.DISCONNECTING;
|
230
|
+
|
231
|
+
default:
|
232
|
+
/* 3 = CLOSED */
|
233
|
+
return ConnectionState.DISCONNECTED;
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
return ConnectionState.DISCONNECTED;
|
238
|
+
}
|
239
|
+
|
240
|
+
get state() {
|
241
|
+
return this.getConnectionState();
|
242
|
+
}
|
243
|
+
|
244
|
+
get connected() {
|
245
|
+
return this.getConnectionState() === ConnectionState.CONNECTED;
|
246
|
+
}
|
247
|
+
|
248
|
+
get disconnected() {
|
249
|
+
return this.getConnectionState() === ConnectionState.DISCONNECTED;
|
250
|
+
}
|
251
|
+
|
252
|
+
emit = (event, ...args) => {
|
253
|
+
args.unshift(event);
|
254
|
+
const packet = {
|
255
|
+
type: PacketType.EVENT,
|
256
|
+
data: args
|
257
|
+
};
|
258
|
+
|
259
|
+
if (typeof args[args.length - 1] === 'function') {
|
260
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
261
|
+
this.acks.set(this.fnId, args.pop());
|
262
|
+
packet.id = this.fnId;
|
263
|
+
this.fnId += 1;
|
264
|
+
}
|
265
|
+
|
266
|
+
return this.sendPackage(packet);
|
267
|
+
};
|
268
|
+
send = (...args) => {
|
269
|
+
args.unshift('message');
|
270
|
+
return this.sendPackage({
|
271
|
+
type: PacketType.EVENT,
|
272
|
+
data: args
|
273
|
+
});
|
274
|
+
};
|
275
|
+
sendPackage = packet => {
|
276
|
+
if (this.ws !== undefined && this.ws.readyState === 1
|
277
|
+
/* = OPEN */
|
278
|
+
) {
|
279
|
+
const buffer = encodePacket(packet);
|
280
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Send packet: ${JSON.stringify(packet)}`);
|
281
|
+
this.ws.send(buffer);
|
282
|
+
return true;
|
283
|
+
}
|
284
|
+
|
285
|
+
return false;
|
286
|
+
};
|
287
|
+
handleMessage = msg => {
|
288
|
+
const packet = typeof msg.data === 'string' ? JSON.parse(msg.data) : decodePacket(msg.data);
|
289
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Got packet: ${JSON.stringify(packet)}`);
|
290
|
+
|
291
|
+
if (packet.type === PacketType.EVENT) {
|
292
|
+
const event = packet.data[0];
|
293
|
+
const args = packet.data.slice(1);
|
294
|
+
|
295
|
+
if (event) {
|
296
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
297
|
+
this.listeners(event).forEach(listener => listener(...args));
|
298
|
+
} else {
|
299
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(0) : `(teckos-client) [${this.url}] Got invalid event message: ${JSON.stringify(msg.data)}`);
|
300
|
+
}
|
301
|
+
} else if (packet.type === PacketType.ACK && packet.id !== undefined) {
|
302
|
+
// Call assigned function
|
303
|
+
const ack = this.acks.get(packet.id);
|
304
|
+
|
305
|
+
if (typeof ack === 'function') {
|
306
|
+
ack.apply(this, packet.data);
|
307
|
+
this.acks.delete(packet.id);
|
308
|
+
}
|
309
|
+
} else {
|
310
|
+
throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(1) : `(teckos-client) [${this.url}] Got invalid message type: ${packet.type}`);
|
311
|
+
}
|
312
|
+
};
|
313
|
+
handleOpen = () => {
|
314
|
+
if (this.currentReconnectionAttempts > 0) {
|
315
|
+
// Reset reconnection settings to default
|
316
|
+
this.currentReconnectDelay = this.options.reconnectionDelay;
|
317
|
+
this.currentReconnectionAttempts = 0; // Inform listeners
|
318
|
+
|
319
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Reconnected!`); // eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
320
|
+
|
321
|
+
this.listeners('reconnect').forEach(listener => listener());
|
322
|
+
} // Inform listeners
|
323
|
+
|
324
|
+
|
325
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Connected!`);
|
326
|
+
this.listeners('connect').forEach(listener => listener());
|
327
|
+
};
|
328
|
+
handleError = error => {
|
329
|
+
if (this.handlers && this.handlers.error) {
|
330
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Got error from server: ${JSON.stringify(error)}`);
|
331
|
+
this.handlers.error.forEach(listener => listener(error));
|
332
|
+
}
|
333
|
+
};
|
334
|
+
handleClose = () => {
|
335
|
+
// Stop connection timeout
|
336
|
+
if (this.connectionTimeout) {
|
337
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
338
|
+
clearTimeout(this.connectionTimeout);
|
339
|
+
} // Stop reconnection timeout
|
340
|
+
|
341
|
+
|
342
|
+
if (this.reconnectionTimeout) {
|
343
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
344
|
+
clearTimeout(this.reconnectionTimeout);
|
345
|
+
} // Inform listeners
|
346
|
+
|
347
|
+
|
348
|
+
if (this.currentReconnectionAttempts > 0) {
|
349
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Reconnect #${this.currentReconnectionAttempts} failed!`);
|
350
|
+
this.listeners('reconnect_error').forEach(listener => {
|
351
|
+
if (listener) listener();
|
352
|
+
});
|
353
|
+
} else {
|
354
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Disconnected!`);
|
355
|
+
this.listeners('disconnect').forEach(listener => {
|
356
|
+
if (listener) listener();
|
357
|
+
});
|
358
|
+
}
|
359
|
+
|
360
|
+
if (this.options.reconnection) {
|
361
|
+
// Apply reconnection logic
|
362
|
+
this.currentReconnectionAttempts += 1;
|
363
|
+
|
364
|
+
if (this.options.reconnectionAttempts === Infinity || this.currentReconnectionAttempts <= this.options.reconnectionAttempts) {
|
365
|
+
const timeout = Math.min(this.options.reconnectionDelayMax, this.currentReconnectDelay); // Increase reconnection delay
|
366
|
+
|
367
|
+
this.currentReconnectDelay = Math.round(this.currentReconnectDelay + this.currentReconnectDelay * this.options.randomizationFactor);
|
368
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Try reconnecting (${this.currentReconnectionAttempts}/${this.options.reconnectionAttempts}) in ${timeout}ms to ${this.url}...`);
|
369
|
+
this.reconnectionTimeout = setTimeout(() => {
|
370
|
+
this.reconnect();
|
371
|
+
}, timeout);
|
372
|
+
} else {
|
373
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Reconnection maximum of ${this.options.reconnectionAttempts} reached`);
|
374
|
+
this.listeners('reconnect_failed').forEach(listener => listener());
|
375
|
+
}
|
376
|
+
}
|
377
|
+
};
|
378
|
+
close = () => {
|
379
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Closing connection (client-side)`);
|
380
|
+
|
381
|
+
if (this.ws !== undefined) {
|
382
|
+
this.ws.onclose = () => {};
|
383
|
+
|
384
|
+
this.ws.close();
|
385
|
+
this.listeners('disconnect').forEach(listener => listener());
|
386
|
+
}
|
387
|
+
};
|
388
|
+
disconnect = () => {
|
389
|
+
this.close();
|
390
|
+
};
|
391
|
+
}
|
392
|
+
|
393
|
+
/* eslint-disable no-console */
|
394
|
+
|
395
|
+
class TeckosClientWithJWT extends TeckosClient {
|
396
|
+
token;
|
397
|
+
initialData;
|
398
|
+
receivedReady = false; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
399
|
+
|
400
|
+
constructor(url, options, token, initialData) {
|
401
|
+
super(url, options);
|
402
|
+
this.token = token; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
403
|
+
|
404
|
+
this.initialData = initialData;
|
405
|
+
this.on('disconnect', () => {
|
406
|
+
this.receivedReady = false;
|
407
|
+
});
|
408
|
+
}
|
409
|
+
|
410
|
+
getConnectionState() {
|
411
|
+
if (this.ws) {
|
412
|
+
switch (this.ws.readyState) {
|
413
|
+
case IsomorphicWebSocket.WebSocket.OPEN:
|
414
|
+
if (this.receivedReady) {
|
415
|
+
return ConnectionState.CONNECTED;
|
416
|
+
}
|
417
|
+
|
418
|
+
return ConnectionState.CONNECTING;
|
419
|
+
|
420
|
+
case IsomorphicWebSocket.WebSocket.CONNECTING:
|
421
|
+
return ConnectionState.CONNECTING;
|
422
|
+
|
423
|
+
case IsomorphicWebSocket.WebSocket.CLOSING:
|
424
|
+
return ConnectionState.DISCONNECTING;
|
425
|
+
|
426
|
+
default:
|
427
|
+
return ConnectionState.DISCONNECTED;
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
return ConnectionState.DISCONNECTED;
|
432
|
+
}
|
433
|
+
|
434
|
+
handleReadyEvent = () => {
|
435
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Connected!`);
|
436
|
+
this.receivedReady = true;
|
437
|
+
|
438
|
+
if (this.currentReconnectionAttempts > 0) {
|
439
|
+
if (this.options.debug) console.log(`(teckos:client) [${this.url}] Reconnected!`);
|
440
|
+
this.listeners('reconnect').forEach(listener => listener()); // Reset reconnection settings to default
|
441
|
+
|
442
|
+
this.currentReconnectDelay = this.options.reconnectionDelay;
|
443
|
+
this.currentReconnectionAttempts = 0;
|
444
|
+
}
|
445
|
+
|
446
|
+
this.listeners('connect').forEach(listener => listener());
|
447
|
+
};
|
448
|
+
handleOpen = () => {
|
449
|
+
this.receivedReady = false;
|
450
|
+
this.once('ready', this.handleReadyEvent);
|
451
|
+
if (this.options.debug) console.log(`(teckos:client) Connection opened, sending token now`);
|
452
|
+
this.emit('token', {
|
453
|
+
token: this.token,
|
454
|
+
...this.initialData
|
455
|
+
});
|
456
|
+
};
|
457
|
+
}
|
458
|
+
|
459
|
+
export { ConnectionState, PacketType, TeckosClient, TeckosClientWithJWT };
|
package/es/index.mjs
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
function e(e){return`Minified Redux error #${e}; visit https://redux.js.org/Errors?code=${e} for the full message or use the non-minified dev environment for full errors. `}module.exports=require("ws");const t=new TextEncoder,n=new TextDecoder;var s,i;!function(e){e[e.EVENT=0]="EVENT",e[e.ACK=1]="ACK"}(s||(s={})),function(e){e.DISCONNECTED="disconnected",e.CONNECTING="connecting",e.CONNECTED="connected",e.DISCONNECTING="disconnecting"}(i||(i={}));const o={reconnection:!0,reconnectionDelay:1e3,reconnectionDelayMax:5e3,reconnectionAttempts:1/0,randomizationFactor:.5,timeout:5e3,debug:!1};class r extends class{maxListeners=50;handlers={};addListener=(t,n)=>{if(Object.keys(this.handlers).length===this.maxListeners)throw Error(e(2));if("function"!=typeof n)throw Error(e(3));return this.handlers[t]=this.handlers[t]||[],this.handlers[t].push(n),this};once=(t,n)=>{if(Object.keys(this.handlers).length===this.maxListeners)throw Error(e(2));if("function"!=typeof n)throw Error(e(3));this.handlers[t]=this.handlers[t]||[];const s=()=>{n(),this.off(t,s)};return this.handlers[t].push(s),this};removeListener=(e,t)=>(this.handlers[e]&&(this.handlers[e]=this.handlers[e].filter((e=>e!==t))),this);off=(e,t)=>this.removeListener(e,t);removeAllListeners=e=>(e?delete this.handlers[e]:this.handlers={},this);setMaxListeners=e=>(this.maxListeners=e,this);getMaxListeners=()=>this.maxListeners;listeners=e=>this.handlers[e]?[...this.handlers[e]]:[];rawListeners=e=>[...this.handlers[e]];listenerCount=e=>this.handlers[e]?Object.keys(this.handlers[e]).length:0;prependListener=(t,n)=>{if(Object.keys(this.handlers).length===this.maxListeners)throw Error(e(2));return this.handlers[t]=this.handlers[t]||[],this.handlers[t].unshift(n),this};prependOnceListener=(t,n)=>{if(Object.keys(this.handlers).length===this.maxListeners)throw Error(e(2));this.handlers[t]=this.handlers[t]||[];const s=()=>{n(),this.off(t,s)};return this.handlers[t].unshift(s),this};eventNames=()=>Object.keys(this.handlers);on=(e,t)=>this.addListener(e,t);emit=(e,...t)=>{const n=this.listeners(e);return n.length>0&&(n.forEach((e=>{e&&e(t)})),!0)}}{url;options;ws;currentReconnectDelay;currentReconnectionAttempts=0;acks=new Map;fnId=0;connectionTimeout;reconnectionTimeout;constructor(e,t){super(),this.options={...o,...t},this.currentReconnectDelay=this.options.reconnectionDelay,this.url=e}attachHandler=()=>{this.ws&&(this.ws.onopen=this.handleOpen,this.ws.onerror=this.handleError,this.ws.onclose=this.handleClose,this.ws.onmessage=this.handleMessage)};get webSocket(){return this.ws}connect=()=>{this.options.debug&&console.log(`(teckos:client) Connecting to ${this.url}...`),this.ws=new(void 0)(this.url),this.attachHandler(),this.connectionTimeout=setTimeout((()=>{this.ws&&0===this.ws.readyState&&this.ws.close()}),this.options.timeout)};reconnect=()=>{this.listeners("reconnect_attempt").forEach((e=>e())),this.connect()};getConnectionState(){if(this.ws)switch(this.ws.readyState){case 0:return i.CONNECTING;case 1:return i.CONNECTED;case 2:return i.DISCONNECTING;default:return i.DISCONNECTED}return i.DISCONNECTED}get state(){return this.getConnectionState()}get connected(){return this.getConnectionState()===i.CONNECTED}get disconnected(){return this.getConnectionState()===i.DISCONNECTED}emit=(e,...t)=>{t.unshift(e);const n={type:s.EVENT,data:t};return"function"==typeof t[t.length-1]&&(this.acks.set(this.fnId,t.pop()),n.id=this.fnId,this.fnId+=1),this.sendPackage(n)};send=(...e)=>(e.unshift("message"),this.sendPackage({type:s.EVENT,data:e}));sendPackage=e=>{if(void 0!==this.ws&&1===this.ws.readyState){const n=(e=>t.encode(JSON.stringify(e)))(e);return this.options.debug&&console.log(`(teckos:client) [${this.url}] Send packet: ${JSON.stringify(e)}`),this.ws.send(n),!0}return!1};handleMessage=t=>{const i="string"==typeof t.data?JSON.parse(t.data):JSON.parse(""+n.decode(t.data));if(this.options.debug&&console.log(`(teckos:client) [${this.url}] Got packet: ${JSON.stringify(i)}`),i.type===s.EVENT){const t=i.data[0],n=i.data.slice(1);if(!t)throw Error(e(0));this.listeners(t).forEach((e=>e(...n)))}else{if(i.type!==s.ACK||void 0===i.id)throw Error(e(1));{const e=this.acks.get(i.id);"function"==typeof e&&(e.apply(this,i.data),this.acks.delete(i.id))}}};handleOpen=()=>{this.currentReconnectionAttempts>0&&(this.currentReconnectDelay=this.options.reconnectionDelay,this.currentReconnectionAttempts=0,this.options.debug&&console.log(`(teckos:client) [${this.url}] Reconnected!`),this.listeners("reconnect").forEach((e=>e()))),this.options.debug&&console.log(`(teckos:client) [${this.url}] Connected!`),this.listeners("connect").forEach((e=>e()))};handleError=e=>{this.handlers&&this.handlers.error&&(this.options.debug&&console.log(`(teckos:client) [${this.url}] Got error from server: ${JSON.stringify(e)}`),this.handlers.error.forEach((t=>t(e))))};handleClose=()=>{if(this.connectionTimeout&&clearTimeout(this.connectionTimeout),this.reconnectionTimeout&&clearTimeout(this.reconnectionTimeout),this.currentReconnectionAttempts>0?(this.options.debug&&console.log(`(teckos:client) [${this.url}] Reconnect #${this.currentReconnectionAttempts} failed!`),this.listeners("reconnect_error").forEach((e=>{e&&e()}))):(this.options.debug&&console.log(`(teckos:client) [${this.url}] Disconnected!`),this.listeners("disconnect").forEach((e=>{e&&e()}))),this.options.reconnection)if(this.currentReconnectionAttempts+=1,this.options.reconnectionAttempts!==1/0&&this.currentReconnectionAttempts>this.options.reconnectionAttempts)this.options.debug&&console.log(`(teckos:client) [${this.url}] Reconnection maximum of ${this.options.reconnectionAttempts} reached`),this.listeners("reconnect_failed").forEach((e=>e()));else{const e=Math.min(this.options.reconnectionDelayMax,this.currentReconnectDelay);this.currentReconnectDelay=Math.round(this.currentReconnectDelay+this.currentReconnectDelay*this.options.randomizationFactor),this.options.debug&&console.log(`(teckos:client) [${this.url}] Try reconnecting (${this.currentReconnectionAttempts}/${this.options.reconnectionAttempts}) in ${e}ms to ${this.url}...`),this.reconnectionTimeout=setTimeout((()=>{this.reconnect()}),e)}};close=()=>{this.options.debug&&console.log(`(teckos:client) [${this.url}] Closing connection (client-side)`),void 0!==this.ws&&(this.ws.onclose=()=>{},this.ws.close(),this.listeners("disconnect").forEach((e=>e())))};disconnect=()=>{this.close()}}class c extends r{token;initialData;receivedReady=!1;constructor(e,t,n,s){super(e,t),this.token=n,this.initialData=s,this.on("disconnect",(()=>{this.receivedReady=!1}))}getConnectionState(){if(this.ws)switch(this.ws.readyState){case void 0:return this.receivedReady?i.CONNECTED:i.CONNECTING;case void 0:return i.CONNECTING;case void 0:return i.DISCONNECTING;default:return i.DISCONNECTED}return i.DISCONNECTED}handleReadyEvent=()=>{this.options.debug&&console.log(`(teckos:client) [${this.url}] Connected!`),this.receivedReady=!0,this.currentReconnectionAttempts>0&&(this.options.debug&&console.log(`(teckos:client) [${this.url}] Reconnected!`),this.listeners("reconnect").forEach((e=>e())),this.currentReconnectDelay=this.options.reconnectionDelay,this.currentReconnectionAttempts=0),this.listeners("connect").forEach((e=>e()))};handleOpen=()=>{this.receivedReady=!1,this.once("ready",this.handleReadyEvent),this.options.debug&&console.log("(teckos:client) Connection opened, sending token now"),this.emit("token",{token:this.token,...this.initialData})}}export{i as ConnectionState,s as PacketType,r as TeckosClient,c as TeckosClientWithJWT};
|