websocket-ts 1.1.0 → 2.1.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 (76) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +211 -138
  3. package/package.json +46 -33
  4. package/src/backoff/backoff.ts +26 -18
  5. package/src/backoff/constantbackoff.ts +38 -20
  6. package/src/backoff/exponentialbackoff.ts +78 -38
  7. package/src/backoff/linearbackoff.ts +88 -37
  8. package/src/index.ts +23 -9
  9. package/src/queue/array_queue.ts +41 -0
  10. package/src/queue/queue.ts +46 -0
  11. package/src/queue/ring_queue.ts +69 -0
  12. package/src/websocket.ts +487 -162
  13. package/src/websocket_buffer.ts +18 -0
  14. package/src/websocket_builder.ts +274 -0
  15. package/src/websocket_event.ts +88 -0
  16. package/src/websocket_options.ts +23 -0
  17. package/src/websocket_retry_options.ts +22 -0
  18. package/{tsconfig.json → tsconfig.cjs.json} +71 -71
  19. package/tsconfig.esm.json +71 -0
  20. package/jest.config.js +0 -8
  21. package/lib/backoff/backoff.d.ts +0 -18
  22. package/lib/backoff/backoff.d.ts.map +0 -1
  23. package/lib/backoff/backoff.js +0 -3
  24. package/lib/backoff/backoff.js.map +0 -1
  25. package/lib/backoff/constantbackoff.d.ts +0 -11
  26. package/lib/backoff/constantbackoff.d.ts.map +0 -1
  27. package/lib/backoff/constantbackoff.js +0 -20
  28. package/lib/backoff/constantbackoff.js.map +0 -1
  29. package/lib/backoff/exponentialbackoff.d.ts +0 -22
  30. package/lib/backoff/exponentialbackoff.d.ts.map +0 -1
  31. package/lib/backoff/exponentialbackoff.js +0 -35
  32. package/lib/backoff/exponentialbackoff.js.map +0 -1
  33. package/lib/backoff/linearbackoff.d.ts +0 -19
  34. package/lib/backoff/linearbackoff.d.ts.map +0 -1
  35. package/lib/backoff/linearbackoff.js +0 -34
  36. package/lib/backoff/linearbackoff.js.map +0 -1
  37. package/lib/buffer/buffer.d.ts +0 -41
  38. package/lib/buffer/buffer.d.ts.map +0 -1
  39. package/lib/buffer/buffer.js +0 -3
  40. package/lib/buffer/buffer.js.map +0 -1
  41. package/lib/buffer/lrubuffer.d.ts +0 -24
  42. package/lib/buffer/lrubuffer.d.ts.map +0 -1
  43. package/lib/buffer/lrubuffer.js +0 -76
  44. package/lib/buffer/lrubuffer.js.map +0 -1
  45. package/lib/buffer/timebuffer.d.ts +0 -25
  46. package/lib/buffer/timebuffer.d.ts.map +0 -1
  47. package/lib/buffer/timebuffer.js +0 -92
  48. package/lib/buffer/timebuffer.js.map +0 -1
  49. package/lib/index.d.ts +0 -10
  50. package/lib/index.d.ts.map +0 -1
  51. package/lib/index.js +0 -22
  52. package/lib/index.js.map +0 -1
  53. package/lib/websocket.d.ts +0 -47
  54. package/lib/websocket.d.ts.map +0 -1
  55. package/lib/websocket.js +0 -120
  56. package/lib/websocket.js.map +0 -1
  57. package/lib/websocketBuilder.d.ts +0 -32
  58. package/lib/websocketBuilder.d.ts.map +0 -1
  59. package/lib/websocketBuilder.js +0 -68
  60. package/lib/websocketBuilder.js.map +0 -1
  61. package/lib/wsbuilder.d.ts +0 -29
  62. package/lib/wsbuilder.d.ts.map +0 -1
  63. package/lib/wsbuilder.js +0 -88
  64. package/lib/wsbuilder.js.map +0 -1
  65. package/src/buffer/buffer.ts +0 -45
  66. package/src/buffer/lrubuffer.ts +0 -80
  67. package/src/buffer/timebuffer.ts +0 -105
  68. package/src/websocketBuilder.ts +0 -98
  69. package/test/backoff/constantbackoff.test.ts +0 -21
  70. package/test/backoff/exponentialbackoff.test.ts +0 -13
  71. package/test/backoff/linearbackoff.test.ts +0 -32
  72. package/test/buffer/common.ts +0 -10
  73. package/test/buffer/lrubuffer.test.ts +0 -128
  74. package/test/buffer/timebuffer.test.ts +0 -115
  75. package/test/websocket.test.ts +0 -341
  76. package/test/websocketBuilder.test.ts +0 -36
@@ -1,38 +1,78 @@
1
- import {Backoff} from "./backoff";
2
-
3
- /**
4
- * ExponentialBackoff doubles the backoff with every step until a maximum
5
- * is reached. This is modelled after the binary exponential-backoff algo-
6
- * rithm used in computer-networking.
7
- *
8
- * The calculation-specification is:
9
- * backoff = k * 2^s with s in [1, expMax].
10
- *
11
- * Example: for initial=100, expMax=7 the ExponentialBackoff will pro-
12
- * duce the backoff-series [100, 200, 400, 800, 1600, 3200, 6400].
13
- */
14
- export class ExponentialBackoff implements Backoff {
15
- private readonly initial: number;
16
- private readonly expMax: number;
17
- private expCurrent: number;
18
- private current: number;
19
-
20
- constructor(initial: number, expMax: number) {
21
- this.initial = initial;
22
- this.expMax = expMax;
23
- this.expCurrent = 1;
24
- this.current = this.initial;
25
- }
26
-
27
- next(): number {
28
- const backoff = this.current;
29
- if (this.expMax > this.expCurrent++)
30
- this.current = this.current * 2;
31
- return backoff;
32
- }
33
-
34
- reset() {
35
- this.expCurrent = 1;
36
- this.current = this.initial;
37
- }
38
- }
1
+ import { Backoff } from "./backoff";
2
+
3
+ /**
4
+ * ExponentialBackoff increases the backoff-time exponentially.
5
+ * An optional maximum can be provided as an upper bound to the
6
+ * exponent and thus to the returned backoff.
7
+ *
8
+ * The series can be described as ('i' is the current step/retry):
9
+ * backoff = base * 2^i | without bound
10
+ * backoff = base * 2^min(i, expMax) | with bound
11
+ *
12
+ * Example:
13
+ *
14
+ * 1) Without bound:
15
+ * base = 1000, expMax = undefined
16
+ * backoff = 1000 * 2^0 = 1000 // first retry
17
+ * backoff = 1000 * 2^1 = 2000 // second retry
18
+ * backoff = 1000 * 2^2 = 4000 // ...doubles with every retry
19
+ * backoff = 1000 * 2^3 = 8000
20
+ * backoff = 1000 * 2^4 = 16000
21
+ * ... // and so on
22
+ *
23
+ * 2) With bound:
24
+ * base = 1000, expMax = 3
25
+ * backoff = 1000 * 2^0 = 1000 // first retry
26
+ * backoff = 1000 * 2^1 = 2000 // second retry
27
+ * backoff = 1000 * 2^2 = 4000 // third retry
28
+ * backoff = 1000 * 2^3 = 8000 // maximum reached, don't increase further
29
+ * backoff = 1000 * 2^3 = 8000
30
+ * backoff = 1000 * 2^3 = 8000
31
+ * ... // and so on
32
+ */
33
+ export class ExponentialBackoff implements Backoff {
34
+ private readonly base: number;
35
+ private readonly expMax?: number;
36
+ private i: number;
37
+ private _retries: number = 0;
38
+
39
+ /**
40
+ * Creates a new ExponentialBackoff.
41
+ * @param base the base of the exponentiation
42
+ * @param expMax the maximum exponent, no bound if undefined
43
+ */
44
+ constructor(base: number, expMax?: number) {
45
+ if (!Number.isInteger(base) || base < 0) {
46
+ throw new Error("Base must be a positive integer or zero");
47
+ }
48
+ if (expMax !== undefined && (!Number.isInteger(expMax) || expMax < 0)) {
49
+ throw new Error("ExpMax must be a undefined, a positive integer or zero");
50
+ }
51
+
52
+ this.base = base;
53
+ this.expMax = expMax;
54
+ this.i = 0;
55
+ }
56
+
57
+ get retries() {
58
+ return this._retries;
59
+ }
60
+
61
+ get current(): number {
62
+ return this.base * Math.pow(2, this.i);
63
+ }
64
+
65
+ next(): number {
66
+ this._retries++;
67
+ this.i =
68
+ this.expMax === undefined
69
+ ? this.i + 1
70
+ : Math.min(this.i + 1, this.expMax);
71
+ return this.current;
72
+ }
73
+
74
+ reset(): void {
75
+ this._retries = 0;
76
+ this.i = 0;
77
+ }
78
+ }
@@ -1,37 +1,88 @@
1
- import {Backoff} from "./backoff";
2
-
3
- /**
4
- * LinearBackoff increases the backoff-time by a constant number with
5
- * every step. An optional maximum can be provided as an upper bound
6
- * to the returned backoff.
7
- *
8
- * Example: for initial=0, increment=2000, maximum=8000 the Linear-
9
- * Backoff will produce the series [0, 2000, 4000, 6000, 8000].
10
- */
11
- export class LinearBackoff implements Backoff {
12
- private readonly initial: number;
13
- private readonly increment: number;
14
- private readonly maximum?: number;
15
- private current: number;
16
-
17
- constructor(initial: number, increment: number, maximum?: number) {
18
- this.initial = initial;
19
- this.increment = increment;
20
- this.maximum = maximum;
21
- this.current = this.initial;
22
- }
23
-
24
- next() {
25
- const backoff = this.current;
26
- const next = this.current + this.increment;
27
- if (this.maximum === undefined)
28
- this.current = next;
29
- else if (next <= this.maximum)
30
- this.current = next;
31
- return backoff;
32
- }
33
-
34
- reset() {
35
- this.current = this.initial;
36
- }
37
- }
1
+ import { Backoff } from "./backoff";
2
+
3
+ /**
4
+ * LinearBackoff returns a backoff-time that is incremented by a fixed amount
5
+ * with every step/retry. An optional maximum can be provided as an upper bound
6
+ * to the returned backoff.
7
+ *
8
+ * The series can be described as ('i' is the current step/retry):
9
+ * backoff = initial + increment * i | without bound
10
+ * backoff = initial + increment * min(i, max) | with bound
11
+ *
12
+ * Example:
13
+ *
14
+ * 1) Without bound:
15
+ * initial = 1000, increment = 1000
16
+ * backoff = 1000 + 1000 * 0 = 1000 // first retry
17
+ * backoff = 1000 + 1000 * 1 = 2000 // second retry
18
+ * backoff = 1000 + 1000 * 2 = 3000 // ...increases by 'increment' with every retry
19
+ * backoff = 1000 + 1000 * 3 = 4000
20
+ * backoff = 1000 + 1000 * 4 = 5000
21
+ * ... // and so on
22
+ *
23
+ * 2) With bound:
24
+ * initial = 1000, increment = 1000, max = 5000
25
+ * backoff = 1000 + 1000 * 0 = 1000 // first retry
26
+ * backoff = 1000 + 1000 * 1 = 2000 // second retry
27
+ * backoff = 1000 + 1000 * 2 = 3000 // third retry
28
+ * backoff = 1000 + 1000 * 3 = 4000 // fourth retry
29
+ * backoff = 1000 + 1000 * 4 = 5000 // maximum reached, don't increase further
30
+ * backoff = 1000 + 1000 * 4 = 5000
31
+ * backoff = 1000 + 1000 * 4 = 5000
32
+ * ... // and so on
33
+ */
34
+ export class LinearBackoff implements Backoff {
35
+ private readonly initial: number;
36
+ private readonly increment: number;
37
+ private readonly max?: number;
38
+ private i: number = 0;
39
+ private _retries: number = 0;
40
+
41
+ /**
42
+ * Creates a new LinearBackoff.
43
+ * @param initial the initial backoff-time in milliseconds
44
+ * @param increment the amount to increment the backoff-time with every step (in milliseconds)
45
+ * @param max the maximum backoff-time (in milliseconds), no bound if undefined
46
+ */
47
+ constructor(initial: number, increment: number, max?: number) {
48
+ if (initial < 0) {
49
+ throw new Error("Initial must be a positive number or zero");
50
+ }
51
+ if (increment < 0) {
52
+ throw new Error("Increment must be a positive number or zero");
53
+ }
54
+ if (max !== undefined && max < 0) {
55
+ throw new Error("Max must be undefined, a positive number or zero");
56
+ }
57
+ if (max !== undefined && max < initial) {
58
+ throw new Error(
59
+ "Max must be undefined or greater than or equal to initial",
60
+ );
61
+ }
62
+
63
+ this.initial = initial;
64
+ this.increment = increment;
65
+ this.max = max;
66
+ }
67
+
68
+ get retries() {
69
+ return this._retries;
70
+ }
71
+
72
+ get current(): number {
73
+ return this.max === undefined
74
+ ? this.initial + this.increment * this.i
75
+ : Math.min(this.initial + this.increment * this.i, this.max);
76
+ }
77
+
78
+ next(): number {
79
+ this._retries++;
80
+ this.i++;
81
+ return this.current;
82
+ }
83
+
84
+ reset(): void {
85
+ this._retries = 0;
86
+ this.i = 0;
87
+ }
88
+ }
package/src/index.ts CHANGED
@@ -1,9 +1,23 @@
1
- export * from './backoff/backoff';
2
- export * from './backoff/constantbackoff'
3
- export * from './backoff/exponentialbackoff'
4
- export * from './backoff/linearbackoff'
5
- export * from './buffer/buffer';
6
- export * from './buffer/lrubuffer'
7
- export * from './buffer/timebuffer'
8
- export * from './websocket';
9
- export * from './websocketBuilder';
1
+ export { Backoff } from "./backoff/backoff";
2
+ export { ConstantBackoff } from "./backoff/constantbackoff";
3
+ export { ExponentialBackoff } from "./backoff/exponentialbackoff";
4
+ export { LinearBackoff } from "./backoff/linearbackoff";
5
+ export { Queue } from "./queue/queue";
6
+ export { ArrayQueue } from "./queue/array_queue";
7
+ export { RingQueue } from "./queue/ring_queue";
8
+ export { Websocket } from "./websocket";
9
+ export { WebsocketBuffer } from "./websocket_buffer";
10
+ export { WebsocketBuilder } from "./websocket_builder";
11
+ export {
12
+ WebsocketEvent,
13
+ RetryEventDetail,
14
+ ReconnectEventDetail,
15
+ WebsocketEventMap,
16
+ WebsocketEventListener,
17
+ WebsocketEventListenerParams,
18
+ WebsocketEventListenerOptions,
19
+ WebsocketEventListenerWithOptions,
20
+ WebsocketEventListeners,
21
+ } from "./websocket_event";
22
+ export { WebsocketOptions } from "./websocket_options";
23
+ export { WebsocketConnectionRetryOptions } from "./websocket_retry_options";
@@ -0,0 +1,41 @@
1
+ import { Queue } from "./queue";
2
+
3
+ /**
4
+ * An array queue is a queue that has an unbounded capacity. Reading from an array queue
5
+ * will return the oldest element and effectively remove it from the queue.
6
+ */
7
+ export class ArrayQueue<E> implements Queue<E> {
8
+ private readonly elements: E[];
9
+
10
+ constructor() {
11
+ this.elements = [];
12
+ }
13
+
14
+ add(element: E): void {
15
+ this.elements.push(element);
16
+ }
17
+
18
+ clear() {
19
+ this.elements.length = 0;
20
+ }
21
+
22
+ forEach(fn: (element: E) => unknown) {
23
+ this.elements.forEach(fn);
24
+ }
25
+
26
+ length(): number {
27
+ return this.elements.length;
28
+ }
29
+
30
+ isEmpty(): boolean {
31
+ return this.elements.length === 0;
32
+ }
33
+
34
+ peek(): E | undefined {
35
+ return this.elements[0];
36
+ }
37
+
38
+ read(): E | undefined {
39
+ return this.elements.shift();
40
+ }
41
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * A queue holds elements until they are read. The order in which elements are
3
+ * read is determined by the implementation of the queue.
4
+ */
5
+ export interface Queue<E> {
6
+ /**
7
+ * Adds an element to the queue.
8
+ * @param element the element to add
9
+ */
10
+ add(element: E): void;
11
+
12
+ /**
13
+ * Clears the queue, removing all elements.
14
+ */
15
+ clear(): void;
16
+
17
+ /**
18
+ * Calls the given function for each element in the queue.
19
+ * @param fn the function to call
20
+ */
21
+ forEach(fn: (element: E) => unknown): void;
22
+
23
+ /**
24
+ * Number of elements in the queue.
25
+ * @return the number of elements in the queue
26
+ */
27
+ length(): number;
28
+
29
+ /**
30
+ * Whether the queue is empty.
31
+ * @return true if the queue is empty, false otherwise
32
+ */
33
+ isEmpty(): boolean;
34
+
35
+ /**
36
+ * Returns the next element in the queue without removing it.
37
+ * @return the next element in the queue, or undefined if the queue is empty
38
+ */
39
+ peek(): E | undefined;
40
+
41
+ /**
42
+ * Removes and returns the next element in the queue.
43
+ * @return the next element in the queue, or undefined if the queue is empty
44
+ */
45
+ read(): E | undefined;
46
+ }
@@ -0,0 +1,69 @@
1
+ import { Queue } from "./queue";
2
+
3
+ /**
4
+ * A ring queue is a queue that has a fixed capacity. When the queue is full, the oldest element is
5
+ * removed to make room for the new element. Reading from a ring queue will return the oldest
6
+ * element and effectively remove it from the queue.
7
+ */
8
+ export class RingQueue<E> implements Queue<E> {
9
+ private readonly elements: E[];
10
+ private head: number; // index of the next position to write to
11
+ private tail: number; // index of the next position to read from
12
+
13
+ constructor(capacity: number) {
14
+ if (!Number.isInteger(capacity) || capacity <= 0) {
15
+ throw new Error("Capacity must be a positive integer");
16
+ }
17
+
18
+ this.elements = new Array<E>(capacity + 1); // +1 to distinguish between full and empty
19
+ this.head = 0;
20
+ this.tail = 0;
21
+ }
22
+
23
+ add(element: E): void {
24
+ this.elements[this.head] = element;
25
+ this.head = (this.head + 1) % this.elements.length;
26
+ if (this.head === this.tail) {
27
+ this.tail = (this.tail + 1) % this.elements.length;
28
+ }
29
+ }
30
+
31
+ clear() {
32
+ this.head = 0;
33
+ this.tail = 0;
34
+ }
35
+
36
+ forEach(fn: (element: E) => unknown) {
37
+ for (
38
+ let i = this.tail;
39
+ i !== this.head;
40
+ i = (i + 1) % this.elements.length
41
+ ) {
42
+ fn(this.elements[i]);
43
+ }
44
+ }
45
+
46
+ length(): number {
47
+ return this.tail === this.head
48
+ ? 0
49
+ : this.tail < this.head
50
+ ? this.head - this.tail
51
+ : this.elements.length - this.tail + this.head;
52
+ }
53
+
54
+ isEmpty(): boolean {
55
+ return this.head === this.tail;
56
+ }
57
+
58
+ peek(): E | undefined {
59
+ return this.isEmpty() ? undefined : this.elements[this.tail];
60
+ }
61
+
62
+ read(): E | undefined {
63
+ const e = this.peek();
64
+ if (e !== undefined) {
65
+ this.tail = (this.tail + 1) % this.elements.length;
66
+ }
67
+ return e;
68
+ }
69
+ }