extra-native-websocket 0.3.2 → 0.4.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 (58) hide show
  1. package/README.md +9 -4
  2. package/lib/{es2015/extra-native-websocket.d.ts → extra-native-websocket.d.ts} +5 -3
  3. package/lib/{es2018/extra-native-websocket.js → extra-native-websocket.js} +49 -25
  4. package/lib/extra-native-websocket.js.map +1 -0
  5. package/lib/index.d.ts +3 -0
  6. package/lib/index.js +4 -0
  7. package/lib/index.js.map +1 -0
  8. package/lib/utils/auto-reconnect-with-exponential-back-off.d.ts +8 -0
  9. package/lib/utils/auto-reconnect-with-exponential-back-off.js +47 -0
  10. package/lib/utils/auto-reconnect-with-exponential-back-off.js.map +1 -0
  11. package/lib/utils/auto-reconnect.d.ts +2 -0
  12. package/lib/utils/auto-reconnect.js +38 -0
  13. package/lib/utils/auto-reconnect.js.map +1 -0
  14. package/lib/utils/index.d.ts +2 -0
  15. package/lib/utils/index.js +3 -0
  16. package/lib/utils/index.js.map +1 -0
  17. package/lib/websocket-error.js +14 -0
  18. package/lib/websocket-error.js.map +1 -0
  19. package/package.json +36 -35
  20. package/src/extra-native-websocket.ts +49 -13
  21. package/src/index.ts +3 -3
  22. package/src/utils/auto-reconnect-with-exponential-back-off.ts +9 -2
  23. package/src/utils/auto-reconnect.ts +16 -5
  24. package/src/utils/index.ts +2 -2
  25. package/lib/es2015/extra-native-websocket.js +0 -118
  26. package/lib/es2015/extra-native-websocket.js.map +0 -1
  27. package/lib/es2015/index.d.ts +0 -3
  28. package/lib/es2015/index.js +0 -20
  29. package/lib/es2015/index.js.map +0 -1
  30. package/lib/es2015/utils/auto-reconnect-with-exponential-back-off.d.ts +0 -7
  31. package/lib/es2015/utils/auto-reconnect-with-exponential-back-off.js +0 -59
  32. package/lib/es2015/utils/auto-reconnect-with-exponential-back-off.js.map +0 -1
  33. package/lib/es2015/utils/auto-reconnect.d.ts +0 -2
  34. package/lib/es2015/utils/auto-reconnect.js +0 -49
  35. package/lib/es2015/utils/auto-reconnect.js.map +0 -1
  36. package/lib/es2015/utils/index.d.ts +0 -2
  37. package/lib/es2015/utils/index.js +0 -19
  38. package/lib/es2015/utils/index.js.map +0 -1
  39. package/lib/es2015/websocket-error.js +0 -18
  40. package/lib/es2015/websocket-error.js.map +0 -1
  41. package/lib/es2018/extra-native-websocket.d.ts +0 -29
  42. package/lib/es2018/extra-native-websocket.js.map +0 -1
  43. package/lib/es2018/index.d.ts +0 -3
  44. package/lib/es2018/index.js +0 -20
  45. package/lib/es2018/index.js.map +0 -1
  46. package/lib/es2018/utils/auto-reconnect-with-exponential-back-off.d.ts +0 -7
  47. package/lib/es2018/utils/auto-reconnect-with-exponential-back-off.js +0 -48
  48. package/lib/es2018/utils/auto-reconnect-with-exponential-back-off.js.map +0 -1
  49. package/lib/es2018/utils/auto-reconnect.d.ts +0 -2
  50. package/lib/es2018/utils/auto-reconnect.js +0 -38
  51. package/lib/es2018/utils/auto-reconnect.js.map +0 -1
  52. package/lib/es2018/utils/index.d.ts +0 -2
  53. package/lib/es2018/utils/index.js +0 -19
  54. package/lib/es2018/utils/index.js.map +0 -1
  55. package/lib/es2018/websocket-error.d.ts +0 -6
  56. package/lib/es2018/websocket-error.js +0 -18
  57. package/lib/es2018/websocket-error.js.map +0 -1
  58. /package/lib/{es2015/websocket-error.d.ts → websocket-error.d.ts} +0 -0
package/README.md CHANGED
@@ -46,15 +46,19 @@ class ExtraNativeWebSocket extends Emitter<{
46
46
  /**
47
47
  * @throws {WebSocketError}
48
48
  */
49
- connect(): Promise<void>
49
+ connect(signal?: AbortSignal): Promise<void>
50
50
  close(code?: number, reason?: string): Promise<void>
51
- send(data: unknown): void
51
+ send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void
52
52
  }
53
53
  ```
54
54
 
55
55
  ### autoReconnect
56
56
  ```ts
57
- function autoReconnect(ws: ExtraNativeWebSocket, timeout?: number): () => void
57
+ function autoReconnect(
58
+ ws: ExtraNativeWebSocket
59
+ , reconnectTimeout?: number = 0
60
+ , connectTimeout?: number
61
+ ): () => void
58
62
  ```
59
63
 
60
64
  ### autoReconnectWithExponentialBackOff
@@ -63,9 +67,10 @@ function autoReonnectWithExponentialBackOff(
63
67
  ws: ExtraWebSocket
64
68
  , options: {
65
69
  baseTimeout: number
66
- maxTimeout?: number
70
+ maxTimeout?: number = Infinity
67
71
  factor?: number = 2
68
72
  jitter?: boolean = true
73
+ connectTimeout?: number
69
74
  }
70
75
  ): () => void
71
76
  ```
@@ -9,6 +9,7 @@ export declare enum State {
9
9
  Connected = 2,
10
10
  Closing = 3
11
11
  }
12
+ type Data = string | ArrayBufferLike | Blob | ArrayBufferView;
12
13
  export declare class ExtraNativeWebSocket extends Emitter<{
13
14
  open: [event: Event];
14
15
  message: [event: MessageEvent];
@@ -18,12 +19,13 @@ export declare class ExtraNativeWebSocket extends Emitter<{
18
19
  private createWebSocket;
19
20
  private instance?;
20
21
  private binaryType;
21
- protected unsentMessages: Queue<string | ArrayBufferLike | ArrayBufferView | Blob>;
22
+ protected unsentMessages: Queue<Data>;
22
23
  constructor(createWebSocket: () => WebSocket);
23
24
  getState(): State;
24
25
  getBinaryType(): BinaryType;
25
26
  setBinaryType(val: BinaryType): void;
26
- connect(): Promise<void>;
27
+ connect(signal?: AbortSignal): Promise<void>;
27
28
  close(code?: number, reason?: string): Promise<void>;
28
- send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;
29
+ send(data: Data): void;
29
30
  }
31
+ export {};
@@ -1,21 +1,19 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExtraNativeWebSocket = exports.State = exports.BinaryType = void 0;
4
- const prelude_1 = require("@blackglory/prelude");
5
- const websocket_error_1 = require("./websocket-error");
6
- const structures_1 = require("@blackglory/structures");
7
- var BinaryType;
1
+ import { assert } from '@blackglory/prelude';
2
+ import { WebSocketError } from './websocket-error.js';
3
+ import { Queue, Emitter } from '@blackglory/structures';
4
+ import { SyncDestructor } from 'extra-defer';
5
+ export var BinaryType;
8
6
  (function (BinaryType) {
9
7
  BinaryType[BinaryType["Blob"] = 0] = "Blob";
10
8
  BinaryType[BinaryType["ArrayBuffer"] = 1] = "ArrayBuffer";
11
- })(BinaryType = exports.BinaryType || (exports.BinaryType = {}));
12
- var State;
9
+ })(BinaryType || (BinaryType = {}));
10
+ export var State;
13
11
  (function (State) {
14
12
  State[State["Closed"] = 0] = "Closed";
15
13
  State[State["Connecting"] = 1] = "Connecting";
16
14
  State[State["Connected"] = 2] = "Connected";
17
15
  State[State["Closing"] = 3] = "Closing";
18
- })(State = exports.State || (exports.State = {}));
16
+ })(State || (State = {}));
19
17
  var ReadyState;
20
18
  (function (ReadyState) {
21
19
  ReadyState[ReadyState["CONNECTING"] = 0] = "CONNECTING";
@@ -23,12 +21,12 @@ var ReadyState;
23
21
  ReadyState[ReadyState["CLOSING"] = 2] = "CLOSING";
24
22
  ReadyState[ReadyState["CLOSED"] = 3] = "CLOSED";
25
23
  })(ReadyState || (ReadyState = {}));
26
- class ExtraNativeWebSocket extends structures_1.Emitter {
24
+ export class ExtraNativeWebSocket extends Emitter {
27
25
  constructor(createWebSocket) {
28
26
  super();
29
27
  this.createWebSocket = createWebSocket;
30
28
  this.binaryType = BinaryType.Blob;
31
- this.unsentMessages = new structures_1.Queue();
29
+ this.unsentMessages = new Queue();
32
30
  }
33
31
  getState() {
34
32
  if (this.instance) {
@@ -61,27 +59,54 @@ class ExtraNativeWebSocket extends structures_1.Emitter {
61
59
  }
62
60
  }
63
61
  }
64
- connect() {
62
+ connect(signal) {
65
63
  return new Promise((resolve, reject) => {
66
- (0, prelude_1.assert)(this.getState() === State.Closed, 'WebSocket is not closed');
64
+ signal === null || signal === void 0 ? void 0 : signal.throwIfAborted();
65
+ assert(this.getState() === State.Closed, 'WebSocket is not closed');
67
66
  const self = this;
68
- const ws = this.instance = this.createWebSocket();
67
+ const ws = this.createWebSocket();
68
+ this.instance = ws;
69
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', abortListener, { once: true });
70
+ const destructor = new SyncDestructor();
69
71
  ws.addEventListener('error', errorListener, { once: true });
70
- ws.addEventListener('open', event => this.emit('open', event));
71
- ws.addEventListener('message', event => this.emit('message', event));
72
- ws.addEventListener('error', event => this.emit('error', event));
73
- ws.addEventListener('close', event => this.emit('close', event));
72
+ destructor.defer(() => ws.removeEventListener('error', errorListener));
73
+ {
74
+ const listener = (event) => this.emit('open', event);
75
+ ws.addEventListener('open', listener);
76
+ destructor.defer(() => ws.removeEventListener('open', listener));
77
+ }
78
+ {
79
+ const listener = (event) => this.emit('message', event);
80
+ ws.addEventListener('message', listener);
81
+ destructor.defer(() => ws.removeEventListener('message', listener));
82
+ }
83
+ {
84
+ const listener = (event) => this.emit('error', event);
85
+ ws.addEventListener('error', listener);
86
+ destructor.defer(() => ws.removeEventListener('error', listener));
87
+ }
88
+ {
89
+ const listener = (event) => this.emit('close', event);
90
+ ws.addEventListener('close', listener);
91
+ destructor.defer(() => ws.removeEventListener('close', listener));
92
+ }
74
93
  this.setBinaryType(this.binaryType);
75
94
  ws.addEventListener('open', openListener, { once: true });
95
+ function abortListener() {
96
+ assert(signal);
97
+ destructor.execute();
98
+ ws.close();
99
+ reject(signal.reason);
100
+ }
76
101
  function errorListener(event) {
77
102
  ws.addEventListener('close', closeListener, { once: true });
78
- }
79
- function closeListener(event) {
80
- reject(new websocket_error_1.WebSocketError(event.code, event.reason));
103
+ function closeListener(event) {
104
+ destructor.execute();
105
+ reject(new WebSocketError(event.code, event.reason));
106
+ }
81
107
  }
82
108
  function openListener(event) {
83
109
  ws.removeEventListener('error', errorListener);
84
- ws.removeEventListener('close', closeListener);
85
110
  for (let size = self.unsentMessages.size; size--;) {
86
111
  self.send(self.unsentMessages.dequeue());
87
112
  }
@@ -91,7 +116,7 @@ class ExtraNativeWebSocket extends structures_1.Emitter {
91
116
  }
92
117
  close(code, reason) {
93
118
  return new Promise(resolve => {
94
- (0, prelude_1.assert)(this.instance, 'WebSocket is not created');
119
+ assert(this.instance, 'WebSocket is not created');
95
120
  switch (this.getState()) {
96
121
  case State.Closed:
97
122
  resolve();
@@ -114,5 +139,4 @@ class ExtraNativeWebSocket extends structures_1.Emitter {
114
139
  }
115
140
  }
116
141
  }
117
- exports.ExtraNativeWebSocket = ExtraNativeWebSocket;
118
142
  //# sourceMappingURL=extra-native-websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extra-native-websocket.js","sourceRoot":"","sources":["../src/extra-native-websocket.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './extra-native-websocket.js';
2
+ export * from './websocket-error.js';
3
+ export * from './utils/index.js';
package/lib/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './extra-native-websocket.js';
2
+ export * from './websocket-error.js';
3
+ export * from './utils/index.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { ExtraNativeWebSocket } from "../extra-native-websocket.js";
2
+ export declare function autoReconnectWithExponentialBackOff(ws: ExtraNativeWebSocket, { baseTimeout, maxTimeout, factor, jitter, connectTimeout }: {
3
+ baseTimeout: number;
4
+ maxTimeout?: number;
5
+ factor?: number;
6
+ jitter?: boolean;
7
+ connectTimeout?: number;
8
+ }): () => void;
@@ -0,0 +1,47 @@
1
+ import { State } from "../extra-native-websocket.js";
2
+ import { calculateExponentialBackoffTimeout } from 'extra-timers';
3
+ import { pass } from '@blackglory/prelude';
4
+ import { delay } from 'extra-promise';
5
+ import { waitForFunction } from '@blackglory/wait-for';
6
+ import { AbortController, timeoutSignal } from 'extra-abort';
7
+ export function autoReconnectWithExponentialBackOff(ws, { baseTimeout, maxTimeout = Infinity, factor = 2, jitter = true, connectTimeout }) {
8
+ const controller = new AbortController();
9
+ const removeErrorListener = ws.on('error', pass);
10
+ let removeCloseListener = ws.once('close', closeListener);
11
+ return () => {
12
+ controller.abort();
13
+ removeCloseListener();
14
+ removeErrorListener();
15
+ };
16
+ async function closeListener() {
17
+ let retries = 0;
18
+ while (true) {
19
+ if (controller.signal.aborted)
20
+ return;
21
+ await delay(calculateExponentialBackoffTimeout({
22
+ retries,
23
+ baseTimeout,
24
+ maxTimeout,
25
+ factor,
26
+ jitter
27
+ }));
28
+ if (controller.signal.aborted)
29
+ return;
30
+ try {
31
+ await waitForFunction(() => ws.getState() === State.Closed);
32
+ await ws.connect(connectTimeout
33
+ ? timeoutSignal(connectTimeout)
34
+ : undefined);
35
+ if (controller.signal.aborted)
36
+ return;
37
+ removeCloseListener = ws.once('close', closeListener);
38
+ break;
39
+ }
40
+ catch (_a) {
41
+ retries++;
42
+ pass();
43
+ }
44
+ }
45
+ }
46
+ }
47
+ //# sourceMappingURL=auto-reconnect-with-exponential-back-off.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-reconnect-with-exponential-back-off.js","sourceRoot":"","sources":["../../src/utils/auto-reconnect-with-exponential-back-off.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,EAAE,qCAAsC;AAC5E,OAAO,EAAE,kCAAkC,EAAE,MAAM,cAAc,CAAA;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE5D,MAAM,UAAU,mCAAmC,CACjD,EAAwB,EACxB,EACE,WAAW,EACX,UAAU,GAAG,QAAQ,EACrB,MAAM,GAAG,CAAC,EACV,MAAM,GAAG,IAAI,EACb,cAAc,EAOf;IAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IAGxC,MAAM,mBAAmB,GAAG,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAChD,IAAI,mBAAmB,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;IAEzD,OAAO,GAAG,EAAE;QACV,UAAU,CAAC,KAAK,EAAE,CAAA;QAClB,mBAAmB,EAAE,CAAA;QACrB,mBAAmB,EAAE,CAAA;IACvB,CAAC,CAAA;IAED,KAAK,UAAU,aAAa;QAC1B,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAM;YAErC,MAAM,KAAK,CAAC,kCAAkC,CAAC;gBAC7C,OAAO;gBACP,WAAW;gBACX,UAAU;gBACV,MAAM;gBACN,MAAM;aACP,CAAC,CAAC,CAAA;YACH,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAM;YAErC,IAAI,CAAC;gBACH,MAAM,eAAe,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,KAAK,CAAC,MAAM,CAAC,CAAA;gBAC3D,MAAM,EAAE,CAAC,OAAO,CACd,cAAc;oBAChB,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC;oBAC/B,CAAC,CAAC,SAAS,CACV,CAAA;gBACD,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;oBAAE,OAAM;gBAErC,mBAAmB,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;gBACrD,MAAK;YACP,CAAC;YAAC,WAAM,CAAC;gBACP,OAAO,EAAE,CAAA;gBACT,IAAI,EAAE,CAAA;YACR,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { ExtraNativeWebSocket } from "../extra-native-websocket.js";
2
+ export declare function autoReconnect(ws: ExtraNativeWebSocket, reconnectTimeout?: number, connectTimeout?: number): () => void;
@@ -0,0 +1,38 @@
1
+ import { State } from "../extra-native-websocket.js";
2
+ import { delay } from 'extra-promise';
3
+ import { AbortController, timeoutSignal } from 'extra-abort';
4
+ import { pass } from '@blackglory/prelude';
5
+ import { waitForFunction } from '@blackglory/wait-for';
6
+ export function autoReconnect(ws, reconnectTimeout = 0, connectTimeout) {
7
+ const controller = new AbortController();
8
+ const removeErrorListener = ws.on('error', pass);
9
+ let removeCloseListener = ws.once('close', closeListener);
10
+ return () => {
11
+ controller.abort();
12
+ removeCloseListener();
13
+ removeErrorListener();
14
+ };
15
+ async function closeListener() {
16
+ while (true) {
17
+ if (controller.signal.aborted)
18
+ return;
19
+ await delay(reconnectTimeout);
20
+ if (controller.signal.aborted)
21
+ return;
22
+ try {
23
+ await waitForFunction(() => ws.getState() === State.Closed);
24
+ await ws.connect(connectTimeout
25
+ ? timeoutSignal(connectTimeout)
26
+ : undefined);
27
+ if (controller.signal.aborted)
28
+ return;
29
+ removeCloseListener = ws.once('close', closeListener);
30
+ break;
31
+ }
32
+ catch (_a) {
33
+ pass();
34
+ }
35
+ }
36
+ }
37
+ }
38
+ //# sourceMappingURL=auto-reconnect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-reconnect.js","sourceRoot":"","sources":["../../src/utils/auto-reconnect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,EAAE,qCAAsC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,MAAM,UAAU,aAAa,CAC3B,EAAwB,EACxB,mBAA2B,CAAC,EAC5B,cAAuB;IAEvB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IAGxC,MAAM,mBAAmB,GAAG,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAChD,IAAI,mBAAmB,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;IAEzD,OAAO,GAAG,EAAE;QACV,UAAU,CAAC,KAAK,EAAE,CAAA;QAClB,mBAAmB,EAAE,CAAA;QACrB,mBAAmB,EAAE,CAAA;IACvB,CAAC,CAAA;IAED,KAAK,UAAU,aAAa;QAC1B,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAM;YAErC,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAA;YAC7B,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAM;YAErC,IAAI,CAAC;gBACH,MAAM,eAAe,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,KAAK,CAAC,MAAM,CAAC,CAAA;gBAC3D,MAAM,EAAE,CAAC,OAAO,CACd,cAAc;oBAChB,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC;oBAC/B,CAAC,CAAC,SAAS,CACV,CAAA;gBACD,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;oBAAE,OAAM;gBAErC,mBAAmB,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;gBACrD,MAAK;YACP,CAAC;YAAC,WAAM,CAAC;gBACP,IAAI,EAAE,CAAA;YACR,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './auto-reconnect.js';
2
+ export * from './auto-reconnect-with-exponential-back-off.js';
@@ -0,0 +1,3 @@
1
+ export * from './auto-reconnect.js';
2
+ export * from './auto-reconnect-with-exponential-back-off.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,+CAA+C,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { CustomError } from '@blackglory/errors';
2
+ export class WebSocketError extends CustomError {
3
+ constructor(code, reason) {
4
+ if (reason) {
5
+ super(`${code}: ${reason}`);
6
+ }
7
+ else {
8
+ super(`${code}`);
9
+ }
10
+ this.code = code;
11
+ this.reason = reason;
12
+ }
13
+ }
14
+ //# sourceMappingURL=websocket-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-error.js","sourceRoot":"","sources":["../src/websocket-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,MAAM,OAAO,cAAe,SAAQ,WAAW;IAI7C,YAAY,IAAY,EAAE,MAAc;QACtC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,GAAG,IAAI,KAAK,MAAM,EAAE,CAAC,CAAA;QAC7B,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC,CAAA;QAClB,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF"}
package/package.json CHANGED
@@ -1,66 +1,67 @@
1
1
  {
2
2
  "name": "extra-native-websocket",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
7
7
  "lib",
8
8
  "src"
9
9
  ],
10
- "main": "lib/es2018/index.js",
11
- "types": "lib/es2018/index.d.ts",
10
+ "type": "module",
11
+ "main": "lib/index.js",
12
+ "types": "lib/index.d.ts",
12
13
  "repository": "git@github.com:BlackGlory/extra-native-websocket.git",
13
14
  "author": "BlackGlory <woshenmedoubuzhidao@blackglory.me>",
14
15
  "license": "MIT",
15
16
  "sideEffects": false,
17
+ "engines": {
18
+ "node": ">=18.17.0"
19
+ },
16
20
  "scripts": {
17
21
  "prepare": "ts-patch install -s",
18
22
  "lint": "eslint --ext .js,.jsx,.ts,.tsx --quiet src __tests__",
19
- "test": "jest --runInBand --no-cache --config jest.config.js",
20
- "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
21
- "test:coverage": "jest --coverage --config jest.config.js",
23
+ "test": "vitest --run",
22
24
  "prepublishOnly": "run-s prepare clean build",
23
- "clean": "run-p clean:*",
24
- "clean:build": "rimraf lib",
25
- "build": "run-p build:*",
26
- "build:es2015": "tsc --project tsconfig.build.json --module commonjs --target es2015 --outDir lib/es2015",
27
- "build:es2018": "tsc --project tsconfig.build.json --module commonjs --target es2018 --outDir lib/es2018",
25
+ "clean": "rimraf lib",
26
+ "build": "tsc --project tsconfig.build.json --outDir lib",
28
27
  "release": "standard-version"
29
28
  },
30
29
  "husky": {
31
30
  "hooks": {
32
- "pre-commit": "run-s prepare lint build",
31
+ "pre-commit": "run-s prepare lint test build",
33
32
  "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
34
33
  }
35
34
  },
36
35
  "devDependencies": {
37
- "@commitlint/cli": "^17.0.2",
38
- "@commitlint/config-conventional": "^17.0.2",
39
- "@types/jest": "^27.5.1",
40
- "@types/ws": "^8.5.3",
41
- "@typescript-eslint/eslint-plugin": "^5.27.1",
42
- "@typescript-eslint/parser": "^5.27.1",
43
- "eslint": "^8.17.0",
36
+ "@commitlint/cli": "^18.4.3",
37
+ "@commitlint/config-conventional": "^18.4.3",
38
+ "@types/ws": "^8.5.10",
39
+ "@typescript-eslint/eslint-plugin": "^6.13.2",
40
+ "@typescript-eslint/parser": "^6.13.2",
41
+ "cross-env": "^7.0.3",
42
+ "eslint": "^8.55.0",
44
43
  "husky": "4",
45
- "jest": "^28.1.1",
46
- "jest-environment-jsdom": "^28.1.1",
44
+ "jsdom": "^23.0.1",
47
45
  "npm-run-all": "^4.1.5",
48
- "return-style": "^1.0.0",
49
- "rimraf": "^3.0.2",
46
+ "return-style": "^3.0.1",
47
+ "rimraf": "^5.0.5",
50
48
  "standard-version": "^9.5.0",
51
- "ts-jest": "^28.0.4",
52
- "ts-patch": "^2.0.1",
53
- "tslib": "^2.4.0",
54
- "typescript": "^4.7.3",
55
- "typescript-transform-paths": "^3.3.1",
56
- "ws": "^8.7.0"
49
+ "ts-patch": "^3.1.1",
50
+ "tslib": "^2.6.2",
51
+ "typescript": "^5.3.3",
52
+ "typescript-transform-paths": "^3.4.6",
53
+ "vite": "^5.0.7",
54
+ "vite-tsconfig-paths": "^4.2.2",
55
+ "vitest": "^1.0.4",
56
+ "ws": "^8.14.2"
57
57
  },
58
58
  "dependencies": {
59
- "@blackglory/errors": "^2.2.1",
60
- "@blackglory/prelude": "^0.1.1",
61
- "@blackglory/structures": "^0.6.0",
62
- "@blackglory/wait-for": "^0.5.0",
63
- "extra-abort": "^0.1.2",
64
- "extra-promise": "^2.0.0"
59
+ "@blackglory/errors": "^3.0.3",
60
+ "@blackglory/prelude": "^0.3.4",
61
+ "@blackglory/structures": "^0.13.4",
62
+ "@blackglory/wait-for": "^0.7.4",
63
+ "extra-abort": "^0.3.7",
64
+ "extra-defer": "^0.3.0",
65
+ "extra-promise": "^6.0.8"
65
66
  }
66
67
  }
@@ -1,6 +1,7 @@
1
1
  import { assert } from '@blackglory/prelude'
2
- import { WebSocketError } from './websocket-error'
2
+ import { WebSocketError } from './websocket-error.js'
3
3
  import { Queue, Emitter } from '@blackglory/structures'
4
+ import { SyncDestructor } from 'extra-defer'
4
5
 
5
6
  export enum BinaryType {
6
7
  Blob
@@ -21,6 +22,8 @@ enum ReadyState {
21
22
  , CLOSED = 3
22
23
  }
23
24
 
25
+ type Data = string | ArrayBufferLike | Blob | ArrayBufferView
26
+
24
27
  export class ExtraNativeWebSocket extends Emitter<{
25
28
  open: [event: Event]
26
29
  message: [event: MessageEvent]
@@ -29,7 +32,7 @@ export class ExtraNativeWebSocket extends Emitter<{
29
32
  }> {
30
33
  private instance?: WebSocket
31
34
  private binaryType: BinaryType = BinaryType.Blob
32
- protected unsentMessages = new Queue<string | ArrayBufferLike | Blob | ArrayBufferView>()
35
+ protected unsentMessages = new Queue<Data>()
33
36
 
34
37
  constructor(private createWebSocket: () => WebSocket) {
35
38
  super()
@@ -72,35 +75,68 @@ export class ExtraNativeWebSocket extends Emitter<{
72
75
  /**
73
76
  * @throws {WebSocketError}
74
77
  */
75
- connect(): Promise<void> {
78
+ connect(signal?: AbortSignal): Promise<void> {
76
79
  return new Promise((resolve, reject) => {
80
+ signal?.throwIfAborted()
77
81
  assert(this.getState() === State.Closed, 'WebSocket is not closed')
78
82
 
79
83
  const self = this
80
- const ws = this.instance = this.createWebSocket()
84
+ const ws = this.createWebSocket()
85
+ this.instance = ws
86
+
87
+ signal?.addEventListener('abort', abortListener, { once: true })
81
88
 
89
+ const destructor = new SyncDestructor()
82
90
  ws.addEventListener('error', errorListener, { once: true })
91
+ destructor.defer(() => ws.removeEventListener('error', errorListener))
83
92
 
84
- ws.addEventListener('open', event => this.emit('open', event))
85
- ws.addEventListener('message', event => this.emit('message', event))
86
- ws.addEventListener('error', event => this.emit('error', event))
87
- ws.addEventListener('close', event => this.emit('close', event))
93
+ {
94
+ const listener = (event: Event) => this.emit('open', event)
95
+ ws.addEventListener('open', listener)
96
+ destructor.defer(() => ws.removeEventListener('open', listener))
97
+ }
98
+ {
99
+ const listener = (event: MessageEvent) => this.emit('message', event)
100
+ ws.addEventListener('message', listener)
101
+ destructor.defer(() => ws.removeEventListener('message', listener))
102
+ }
103
+ {
104
+ const listener = (event: Event) => this.emit('error', event)
105
+ ws.addEventListener('error', listener)
106
+ destructor.defer(() => ws.removeEventListener('error', listener))
107
+ }
108
+ {
109
+ const listener = (event: CloseEvent) => this.emit('close', event)
110
+ ws.addEventListener('close', listener)
111
+ destructor.defer(() => ws.removeEventListener('close', listener))
112
+ }
88
113
 
89
114
  this.setBinaryType(this.binaryType)
90
115
 
91
116
  ws.addEventListener('open', openListener, { once: true })
92
117
 
118
+ function abortListener(): void {
119
+ assert(signal)
120
+
121
+ destructor.execute()
122
+ ws.close()
123
+
124
+ reject(signal.reason)
125
+ }
126
+
93
127
  function errorListener(event: Event): void {
94
128
  ws.addEventListener('close', closeListener, { once: true })
95
- }
96
129
 
97
- function closeListener(event: CloseEvent): void {
98
- reject(new WebSocketError(event.code, event.reason))
130
+ function closeListener(event: CloseEvent): void {
131
+ destructor.execute()
132
+
133
+ reject(new WebSocketError(event.code, event.reason))
134
+ }
99
135
  }
100
136
 
101
137
  function openListener(event: Event): void {
102
138
  ws.removeEventListener('error', errorListener)
103
- ws.removeEventListener('close', closeListener)
139
+
104
140
  for (let size = self.unsentMessages.size; size--;) {
105
141
  self.send(self.unsentMessages.dequeue()!)
106
142
  }
@@ -127,7 +163,7 @@ export class ExtraNativeWebSocket extends Emitter<{
127
163
  })
128
164
  }
129
165
 
130
- send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void {
166
+ send(data: Data): void {
131
167
  if (this.getState() === State.Connected) {
132
168
  this.instance!.send(data)
133
169
  } else {
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './extra-native-websocket'
2
- export * from './websocket-error'
3
- export * from './utils'
1
+ export * from './extra-native-websocket.js'
2
+ export * from './websocket-error.js'
3
+ export * from './utils/index.js'
@@ -1,8 +1,9 @@
1
- import { ExtraNativeWebSocket, State } from '@src/extra-native-websocket'
1
+ import { ExtraNativeWebSocket, State } from '@src/extra-native-websocket.js'
2
2
  import { calculateExponentialBackoffTimeout } from 'extra-timers'
3
3
  import { pass } from '@blackglory/prelude'
4
4
  import { delay } from 'extra-promise'
5
5
  import { waitForFunction } from '@blackglory/wait-for'
6
+ import { AbortController, timeoutSignal } from 'extra-abort'
6
7
 
7
8
  export function autoReconnectWithExponentialBackOff(
8
9
  ws: ExtraNativeWebSocket
@@ -11,11 +12,13 @@ export function autoReconnectWithExponentialBackOff(
11
12
  , maxTimeout = Infinity
12
13
  , factor = 2
13
14
  , jitter = true
15
+ , connectTimeout
14
16
  }: {
15
17
  baseTimeout: number
16
18
  maxTimeout?: number
17
19
  factor?: number
18
20
  jitter?: boolean
21
+ connectTimeout?: number
19
22
  }
20
23
  ): () => void {
21
24
  const controller = new AbortController()
@@ -46,7 +49,11 @@ export function autoReconnectWithExponentialBackOff(
46
49
 
47
50
  try {
48
51
  await waitForFunction(() => ws.getState() === State.Closed)
49
- await ws.connect()
52
+ await ws.connect(
53
+ connectTimeout
54
+ ? timeoutSignal(connectTimeout)
55
+ : undefined
56
+ )
50
57
  if (controller.signal.aborted) return
51
58
 
52
59
  removeCloseListener = ws.once('close', closeListener)