reconnecting-eventsource 1.2.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/build/esm/reconnecting-eventsource.d.ts +42 -0
- package/build/esm/reconnecting-eventsource.js +248 -0
- package/build/esm/reconnecting-eventsource.js.map +1 -0
- package/build/esnext/reconnecting-eventsource.d.ts +42 -0
- package/{src → build/esnext}/reconnecting-eventsource.js +50 -66
- package/build/esnext/reconnecting-eventsource.js.map +1 -0
- package/build/src/reconnecting-eventsource.d.ts +42 -0
- package/build/src/reconnecting-eventsource.js +172 -0
- package/build/src/reconnecting-eventsource.js.map +1 -0
- package/dist/ReconnectingEventSource.min.js +2 -1
- package/dist/ReconnectingEventSource.min.js.map +1 -0
- package/package.json +39 -23
- package/.eslintignore +0 -1
- package/.eslintrc.json +0 -13
- package/.travis.yml +0 -10
- package/dist/ReconnectingEventSource.js +0 -1
- package/lib/index.js +0 -1
- package/reconnecting-eventsource.d.ts +0 -11
- package/src/index-umd.js +0 -2
- package/src/index.js +0 -2
- package/test.js +0 -108
- package/tsconfig.json +0 -8
- package/webpack.config.js +0 -111
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ npm install reconnecting-eventsource
|
|
|
23
23
|
In a browser environment, bring this in using:
|
|
24
24
|
|
|
25
25
|
```html
|
|
26
|
-
<script src="/node_modules/reconnecting-eventsource/dist/ReconnectingEventSource
|
|
26
|
+
<script src="/node_modules/reconnecting-eventsource/dist/ReconnectingEventSource.min.js"></script>
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
(You are free to copy this file out of `node_modules` if you wish)
|
|
@@ -48,11 +48,12 @@ Like the [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventS
|
|
|
48
48
|
// the maximum time to wait before attempting to reconnect in ms, default `3000`
|
|
49
49
|
// note: wait time is randomised to prevent all clients from attempting to reconnect simultaneously
|
|
50
50
|
max_retry_time: 3000,
|
|
51
|
-
}
|
|
52
51
|
|
|
52
|
+
// underlying EventSource class, default `EventSource`
|
|
53
|
+
eventSourceClass: EventSource,
|
|
54
|
+
}
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
|
|
56
57
|
## Building from source
|
|
57
58
|
|
|
58
59
|
If you wish to build this project, check out this repository and modify the source files in `src/`. Then, run the following command:
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export interface ReconnectingEventSourceInit extends EventSourceInit {
|
|
3
|
+
max_retry_time?: number;
|
|
4
|
+
eventSourceClass?: typeof EventSource;
|
|
5
|
+
lastEventId?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class EventSourceNotAvailableError extends Error {
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
declare type Listeners = {
|
|
11
|
+
[K in keyof EventSourceEventMap]: ((this: EventSource, ev: EventSourceEventMap[K]) => any)[];
|
|
12
|
+
};
|
|
13
|
+
export default class ReconnectingEventSource implements EventSource {
|
|
14
|
+
readonly _configuration: ReconnectingEventSourceInit | undefined;
|
|
15
|
+
readonly CONNECTING = 0;
|
|
16
|
+
readonly OPEN = 1;
|
|
17
|
+
readonly CLOSED = 2;
|
|
18
|
+
_eventSource: EventSource | null;
|
|
19
|
+
_lastEventId: string | null;
|
|
20
|
+
_timer: NodeJS.Timer | null;
|
|
21
|
+
_listeners: Listeners;
|
|
22
|
+
_onevent_wrapped: (this: EventSource, ev: Event) => any;
|
|
23
|
+
readyState: 0 | 1 | 2;
|
|
24
|
+
url: string;
|
|
25
|
+
withCredentials: boolean;
|
|
26
|
+
readonly max_retry_time: number;
|
|
27
|
+
eventSourceClass: typeof EventSource;
|
|
28
|
+
constructor(url: string | URL, configuration?: ReconnectingEventSourceInit);
|
|
29
|
+
dispatchEvent(event: Event): boolean;
|
|
30
|
+
_start(): void;
|
|
31
|
+
_onopen(event: Event): void;
|
|
32
|
+
_onerror(event: Event): void;
|
|
33
|
+
_onevent(event: Event): void;
|
|
34
|
+
onopen(event: Event): void;
|
|
35
|
+
onerror(event: Event): void;
|
|
36
|
+
onmessage(event: MessageEvent): void;
|
|
37
|
+
close(): void;
|
|
38
|
+
addEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
39
|
+
removeEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=reconnecting-eventsource.d.ts.map
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// MIT License:
|
|
2
|
+
//
|
|
3
|
+
// Copyright (C) 2022 Fanout, Inc.
|
|
4
|
+
//
|
|
5
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
// of this software and associated documentation files (the "Software"), to
|
|
7
|
+
// deal in the Software without restriction, including without limitation the
|
|
8
|
+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
9
|
+
// sell copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
// furnished to do so, subject to the following conditions:
|
|
11
|
+
//
|
|
12
|
+
// The above copyright notice and this permission notice shall be included in
|
|
13
|
+
// all copies or substantial portions of the Software.
|
|
14
|
+
//
|
|
15
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
21
|
+
// IN THE SOFTWARE.
|
|
22
|
+
var __extends = (this && this.__extends) || (function () {
|
|
23
|
+
var extendStatics = function (d, b) {
|
|
24
|
+
extendStatics = Object.setPrototypeOf ||
|
|
25
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
26
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
27
|
+
return extendStatics(d, b);
|
|
28
|
+
};
|
|
29
|
+
return function (d, b) {
|
|
30
|
+
if (typeof b !== "function" && b !== null)
|
|
31
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
32
|
+
extendStatics(d, b);
|
|
33
|
+
function __() { this.constructor = d; }
|
|
34
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
var __values = (this && this.__values) || function(o) {
|
|
38
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
39
|
+
if (m) return m.call(o);
|
|
40
|
+
if (o && typeof o.length === "number") return {
|
|
41
|
+
next: function () {
|
|
42
|
+
if (o && i >= o.length) o = void 0;
|
|
43
|
+
return { value: o && o[i++], done: !o };
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
47
|
+
};
|
|
48
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
49
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
50
|
+
if (!m) return o;
|
|
51
|
+
var i = m.call(o), r, ar = [], e;
|
|
52
|
+
try {
|
|
53
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
54
|
+
}
|
|
55
|
+
catch (error) { e = { error: error }; }
|
|
56
|
+
finally {
|
|
57
|
+
try {
|
|
58
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
59
|
+
}
|
|
60
|
+
finally { if (e) throw e.error; }
|
|
61
|
+
}
|
|
62
|
+
return ar;
|
|
63
|
+
};
|
|
64
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
65
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
66
|
+
if (ar || !(i in from)) {
|
|
67
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
68
|
+
ar[i] = from[i];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
72
|
+
};
|
|
73
|
+
var EventSourceNotAvailableError = /** @class */ (function (_super) {
|
|
74
|
+
__extends(EventSourceNotAvailableError, _super);
|
|
75
|
+
function EventSourceNotAvailableError() {
|
|
76
|
+
return _super.call(this, 'EventSource not available.\n' +
|
|
77
|
+
'Consider loading an EventSource polyfill and making it available globally as EventSource, ' +
|
|
78
|
+
'or passing one in as eventSourceClass to the ReconnectingEventSource constructor.') || this;
|
|
79
|
+
}
|
|
80
|
+
return EventSourceNotAvailableError;
|
|
81
|
+
}(Error));
|
|
82
|
+
export { EventSourceNotAvailableError };
|
|
83
|
+
var ReconnectingEventSource = /** @class */ (function () {
|
|
84
|
+
function ReconnectingEventSource(url, configuration) {
|
|
85
|
+
var _this = this;
|
|
86
|
+
this.CONNECTING = 0;
|
|
87
|
+
this.OPEN = 1;
|
|
88
|
+
this.CLOSED = 2;
|
|
89
|
+
this._configuration = configuration != null ? Object.assign({}, configuration) : undefined;
|
|
90
|
+
this.withCredentials = false;
|
|
91
|
+
this._eventSource = null;
|
|
92
|
+
this._lastEventId = null;
|
|
93
|
+
this._timer = null;
|
|
94
|
+
this._listeners = {
|
|
95
|
+
open: [],
|
|
96
|
+
error: [],
|
|
97
|
+
message: [],
|
|
98
|
+
};
|
|
99
|
+
this.url = url.toString();
|
|
100
|
+
this.readyState = this.CONNECTING;
|
|
101
|
+
this.max_retry_time = 3000;
|
|
102
|
+
this.eventSourceClass = globalThis.EventSource;
|
|
103
|
+
if (this._configuration != null) {
|
|
104
|
+
if (this._configuration.lastEventId) {
|
|
105
|
+
this._lastEventId = this._configuration.lastEventId;
|
|
106
|
+
delete this._configuration['lastEventId'];
|
|
107
|
+
}
|
|
108
|
+
if (this._configuration.max_retry_time) {
|
|
109
|
+
this.max_retry_time = this._configuration.max_retry_time;
|
|
110
|
+
delete this._configuration['max_retry_time'];
|
|
111
|
+
}
|
|
112
|
+
if (this._configuration.eventSourceClass) {
|
|
113
|
+
this.eventSourceClass = this._configuration.eventSourceClass;
|
|
114
|
+
delete this._configuration['eventSourceClass'];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (this.eventSourceClass == null || typeof this.eventSourceClass !== 'function') {
|
|
118
|
+
throw new EventSourceNotAvailableError();
|
|
119
|
+
}
|
|
120
|
+
this._onevent_wrapped = function (event) { _this._onevent(event); };
|
|
121
|
+
this._start();
|
|
122
|
+
}
|
|
123
|
+
ReconnectingEventSource.prototype.dispatchEvent = function (event) {
|
|
124
|
+
throw new Error("Method not implemented.");
|
|
125
|
+
};
|
|
126
|
+
ReconnectingEventSource.prototype._start = function () {
|
|
127
|
+
var e_1, _a;
|
|
128
|
+
var _this = this;
|
|
129
|
+
var url = this.url;
|
|
130
|
+
if (this._lastEventId) {
|
|
131
|
+
if (url.indexOf('?') === -1) {
|
|
132
|
+
url += '?';
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
url += '&';
|
|
136
|
+
}
|
|
137
|
+
url += 'lastEventId=' + encodeURIComponent(this._lastEventId);
|
|
138
|
+
}
|
|
139
|
+
this._eventSource = new this.eventSourceClass(url, this._configuration);
|
|
140
|
+
this._eventSource.onopen = function (event) { _this._onopen(event); };
|
|
141
|
+
this._eventSource.onerror = function (event) { _this._onerror(event); };
|
|
142
|
+
this._eventSource.onmessage = function (event) { _this.onmessage(event); };
|
|
143
|
+
try {
|
|
144
|
+
// apply listen types
|
|
145
|
+
for (var _b = __values(Object.keys(this._listeners)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
146
|
+
var type = _c.value;
|
|
147
|
+
this._eventSource.addEventListener(type, this._onevent_wrapped);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
151
|
+
finally {
|
|
152
|
+
try {
|
|
153
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
154
|
+
}
|
|
155
|
+
finally { if (e_1) throw e_1.error; }
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
ReconnectingEventSource.prototype._onopen = function (event) {
|
|
159
|
+
if (this.readyState === 0) {
|
|
160
|
+
this.readyState = 1;
|
|
161
|
+
this.onopen(event);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
ReconnectingEventSource.prototype._onerror = function (event) {
|
|
165
|
+
var _this = this;
|
|
166
|
+
if (this.readyState === 1) {
|
|
167
|
+
this.readyState = 0;
|
|
168
|
+
this.onerror(event);
|
|
169
|
+
}
|
|
170
|
+
if (this._eventSource) {
|
|
171
|
+
if (this._eventSource.readyState === 2) {
|
|
172
|
+
// reconnect with new object
|
|
173
|
+
this._eventSource.close();
|
|
174
|
+
this._eventSource = null;
|
|
175
|
+
// reconnect after random timeout < max_retry_time
|
|
176
|
+
var timeout = Math.round(this.max_retry_time * Math.random());
|
|
177
|
+
this._timer = setTimeout(function () { return _this._start(); }, timeout);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
ReconnectingEventSource.prototype._onevent = function (event) {
|
|
182
|
+
var e_2, _a;
|
|
183
|
+
if (event instanceof MessageEvent) {
|
|
184
|
+
this._lastEventId = event.lastEventId;
|
|
185
|
+
}
|
|
186
|
+
var listenersForType = this._listeners[event.type];
|
|
187
|
+
if (listenersForType != null) {
|
|
188
|
+
try {
|
|
189
|
+
// operate on a copy
|
|
190
|
+
for (var _b = __values(__spreadArray([], __read(listenersForType), false)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
191
|
+
var listener = _c.value;
|
|
192
|
+
listener.call(this, event);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
196
|
+
finally {
|
|
197
|
+
try {
|
|
198
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
199
|
+
}
|
|
200
|
+
finally { if (e_2) throw e_2.error; }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (event.type === 'message') {
|
|
204
|
+
this.onmessage(event);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
ReconnectingEventSource.prototype.onopen = function (event) {
|
|
208
|
+
// may be overridden
|
|
209
|
+
};
|
|
210
|
+
ReconnectingEventSource.prototype.onerror = function (event) {
|
|
211
|
+
// may be overridden
|
|
212
|
+
};
|
|
213
|
+
ReconnectingEventSource.prototype.onmessage = function (event) {
|
|
214
|
+
// may be overridden
|
|
215
|
+
};
|
|
216
|
+
ReconnectingEventSource.prototype.close = function () {
|
|
217
|
+
if (this._timer) {
|
|
218
|
+
clearTimeout(this._timer);
|
|
219
|
+
this._timer = null;
|
|
220
|
+
}
|
|
221
|
+
if (this._eventSource) {
|
|
222
|
+
this._eventSource.close();
|
|
223
|
+
this._eventSource = null;
|
|
224
|
+
}
|
|
225
|
+
this.readyState = 2;
|
|
226
|
+
};
|
|
227
|
+
ReconnectingEventSource.prototype.addEventListener = function (type, callback, options) {
|
|
228
|
+
// We don't support options at the moment
|
|
229
|
+
if (this._listeners[type] == null) {
|
|
230
|
+
this._listeners[type] = [];
|
|
231
|
+
if (this._eventSource != null) {
|
|
232
|
+
this._eventSource.addEventListener(type, this._onevent_wrapped);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
var listenersForType = this._listeners[type];
|
|
236
|
+
if (!listenersForType.includes(callback)) {
|
|
237
|
+
this._listeners[type] = __spreadArray(__spreadArray([], __read(listenersForType), false), [callback], false);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
ReconnectingEventSource.prototype.removeEventListener = function (type, callback, options) {
|
|
241
|
+
// We don't support options at the moment
|
|
242
|
+
var listenersForType = this._listeners[type];
|
|
243
|
+
this._listeners[type] = listenersForType.filter(function (l) { return l !== callback; });
|
|
244
|
+
};
|
|
245
|
+
return ReconnectingEventSource;
|
|
246
|
+
}());
|
|
247
|
+
export default ReconnectingEventSource;
|
|
248
|
+
//# sourceMappingURL=reconnecting-eventsource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconnecting-eventsource.js","sourceRoot":"","sources":["../../src/reconnecting-eventsource.ts"],"names":[],"mappings":"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","sourcesContent":["// MIT License:\n//\n// Copyright (C) 2022 Fanout, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n// IN THE SOFTWARE.\n\nexport interface ReconnectingEventSourceInit extends EventSourceInit {\n // the maximum time to wait before attempting to reconnect in ms, default `3000`\n // note: wait time is randomised to prevent all clients from attempting to reconnect simultaneously\n max_retry_time?: number;\n\n // the EventSource class to wrap. This allows the use of a polyfill or alternate\n // implementation instead of the platform-provided EventSource class.\n eventSourceClass?: typeof EventSource;\n\n // the last event\n lastEventId?: string;\n}\n\nexport class EventSourceNotAvailableError extends Error {\n constructor() {\n super(\n 'EventSource not available.\\n' +\n 'Consider loading an EventSource polyfill and making it available globally as EventSource, ' +\n 'or passing one in as eventSourceClass to the ReconnectingEventSource constructor.'\n );\n }\n}\n\ntype Listeners = {\n [K in keyof EventSourceEventMap]: ((this: EventSource, ev: EventSourceEventMap[K]) => any)[];\n};\n\nexport default class ReconnectingEventSource implements EventSource {\n\n readonly _configuration: ReconnectingEventSourceInit | undefined;\n readonly CONNECTING = 0;\n readonly OPEN = 1;\n readonly CLOSED = 2;\n\n _eventSource: EventSource | null;\n _lastEventId: string | null;\n _timer: NodeJS.Timer | null;\n _listeners: Listeners;\n _onevent_wrapped: (this: EventSource, ev: Event) => any;\n\n readyState: 0 | 1 | 2;\n url: string;\n withCredentials: boolean;\n\n readonly max_retry_time: number;\n eventSourceClass: typeof EventSource;\n\n constructor(url: string | URL, configuration?: ReconnectingEventSourceInit) {\n this._configuration = configuration != null ? Object.assign({}, configuration) : undefined;\n this.withCredentials = false;\n\n this._eventSource = null;\n this._lastEventId = null;\n this._timer = null;\n this._listeners = {\n open: [],\n error: [],\n message: [],\n };\n\n this.url = url.toString();\n this.readyState = this.CONNECTING;\n this.max_retry_time = 3000;\n this.eventSourceClass = globalThis.EventSource;\n\n if (this._configuration != null) {\n if (this._configuration.lastEventId) {\n this._lastEventId = this._configuration.lastEventId;\n delete this._configuration['lastEventId'];\n }\n\n if (this._configuration.max_retry_time) {\n this.max_retry_time = this._configuration.max_retry_time;\n delete this._configuration['max_retry_time'];\n }\n\n if (this._configuration.eventSourceClass) {\n this.eventSourceClass = this._configuration.eventSourceClass;\n delete this._configuration['eventSourceClass'];\n }\n }\n\n if(this.eventSourceClass == null || typeof this.eventSourceClass !== 'function') {\n throw new EventSourceNotAvailableError();\n }\n\n this._onevent_wrapped = (event) => { this._onevent(event); };\n\n this._start();\n }\n\n dispatchEvent(event: Event): boolean {\n throw new Error(\"Method not implemented.\");\n }\n\n _start() {\n let url = this.url;\n\n if (this._lastEventId) {\n if (url.indexOf('?') === -1) {\n url += '?';\n } else {\n url += '&';\n }\n url += 'lastEventId=' + encodeURIComponent(this._lastEventId);\n }\n\n this._eventSource = new this.eventSourceClass(url, this._configuration);\n\n this._eventSource.onopen = (event) => { this._onopen(event); };\n this._eventSource.onerror = (event) => { this._onerror(event); };\n this._eventSource.onmessage = (event) => { this.onmessage(event); };\n\n // apply listen types\n for (const type of Object.keys(this._listeners)) {\n this._eventSource.addEventListener(type, this._onevent_wrapped);\n }\n }\n\n _onopen(event: Event) {\n if (this.readyState === 0) {\n this.readyState = 1;\n this.onopen(event);\n }\n }\n\n _onerror(event: Event) {\n if (this.readyState === 1) {\n this.readyState = 0;\n this.onerror(event);\n }\n\n if (this._eventSource) {\n if(this._eventSource.readyState === 2) {\n // reconnect with new object\n this._eventSource.close();\n this._eventSource = null;\n\n // reconnect after random timeout < max_retry_time\n const timeout = Math.round(this.max_retry_time * Math.random());\n this._timer = setTimeout(() => this._start(), timeout);\n }\n }\n }\n\n _onevent(event: Event) {\n if (event instanceof MessageEvent) {\n this._lastEventId = event.lastEventId;\n }\n\n const listenersForType = this._listeners[event.type as keyof typeof this._listeners] as ((this:EventSource, ev: Event) => any)[];\n if (listenersForType != null) {\n // operate on a copy\n for (const listener of [...listenersForType]) {\n listener.call(this, event);\n }\n }\n\n if (event.type === 'message') {\n this.onmessage(event as MessageEvent);\n }\n }\n\n onopen(event: Event) {\n // may be overridden\n }\n\n onerror(event: Event) {\n // may be overridden\n }\n\n onmessage(event: MessageEvent) {\n // may be overridden\n }\n\n close() {\n if (this._timer) {\n clearTimeout(this._timer);\n this._timer = null;\n }\n\n if (this._eventSource) {\n this._eventSource.close();\n this._eventSource = null;\n }\n\n this.readyState = 2;\n }\n\n addEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions) {\n // We don't support options at the moment\n\n if (this._listeners[type] == null) {\n this._listeners[type] = [];\n if (this._eventSource != null) {\n this._eventSource.addEventListener(type, this._onevent_wrapped);\n }\n }\n\n const listenersForType = this._listeners[type];\n if (!listenersForType.includes(callback)) {\n this._listeners[type] = [...listenersForType, callback] as Listeners[typeof type];\n }\n }\n\n removeEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions) {\n // We don't support options at the moment\n\n const listenersForType = this._listeners[type];\n this._listeners[type] = listenersForType.filter(l => l !== callback) as Listeners[typeof type];\n }\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export interface ReconnectingEventSourceInit extends EventSourceInit {
|
|
3
|
+
max_retry_time?: number;
|
|
4
|
+
eventSourceClass?: typeof EventSource;
|
|
5
|
+
lastEventId?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class EventSourceNotAvailableError extends Error {
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
declare type Listeners = {
|
|
11
|
+
[K in keyof EventSourceEventMap]: ((this: EventSource, ev: EventSourceEventMap[K]) => any)[];
|
|
12
|
+
};
|
|
13
|
+
export default class ReconnectingEventSource implements EventSource {
|
|
14
|
+
readonly _configuration: ReconnectingEventSourceInit | undefined;
|
|
15
|
+
readonly CONNECTING = 0;
|
|
16
|
+
readonly OPEN = 1;
|
|
17
|
+
readonly CLOSED = 2;
|
|
18
|
+
_eventSource: EventSource | null;
|
|
19
|
+
_lastEventId: string | null;
|
|
20
|
+
_timer: NodeJS.Timer | null;
|
|
21
|
+
_listeners: Listeners;
|
|
22
|
+
_onevent_wrapped: (this: EventSource, ev: Event) => any;
|
|
23
|
+
readyState: 0 | 1 | 2;
|
|
24
|
+
url: string;
|
|
25
|
+
withCredentials: boolean;
|
|
26
|
+
readonly max_retry_time: number;
|
|
27
|
+
eventSourceClass: typeof EventSource;
|
|
28
|
+
constructor(url: string | URL, configuration?: ReconnectingEventSourceInit);
|
|
29
|
+
dispatchEvent(event: Event): boolean;
|
|
30
|
+
_start(): void;
|
|
31
|
+
_onopen(event: Event): void;
|
|
32
|
+
_onerror(event: Event): void;
|
|
33
|
+
_onevent(event: Event): void;
|
|
34
|
+
onopen(event: Event): void;
|
|
35
|
+
onerror(event: Event): void;
|
|
36
|
+
onmessage(event: MessageEvent): void;
|
|
37
|
+
close(): void;
|
|
38
|
+
addEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
39
|
+
removeEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=reconnecting-eventsource.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// MIT License:
|
|
2
2
|
//
|
|
3
|
-
// Copyright (C)
|
|
3
|
+
// Copyright (C) 2022 Fanout, Inc.
|
|
4
4
|
//
|
|
5
5
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
// of this software and associated documentation files (the "Software"), to
|
|
@@ -19,165 +19,149 @@
|
|
|
19
19
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
20
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
21
21
|
// IN THE SOFTWARE.
|
|
22
|
-
|
|
22
|
+
export class EventSourceNotAvailableError extends Error {
|
|
23
|
+
constructor() {
|
|
24
|
+
super('EventSource not available.\n' +
|
|
25
|
+
'Consider loading an EventSource polyfill and making it available globally as EventSource, ' +
|
|
26
|
+
'or passing one in as eventSourceClass to the ReconnectingEventSource constructor.');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
23
29
|
export default class ReconnectingEventSource {
|
|
24
|
-
|
|
25
30
|
constructor(url, configuration) {
|
|
26
|
-
this.
|
|
27
|
-
|
|
31
|
+
this.CONNECTING = 0;
|
|
32
|
+
this.OPEN = 1;
|
|
33
|
+
this.CLOSED = 2;
|
|
34
|
+
this._configuration = configuration != null ? Object.assign({}, configuration) : undefined;
|
|
35
|
+
this.withCredentials = false;
|
|
28
36
|
this._eventSource = null;
|
|
29
37
|
this._lastEventId = null;
|
|
30
38
|
this._timer = null;
|
|
31
|
-
this._listeners = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
this._listeners = {
|
|
40
|
+
open: [],
|
|
41
|
+
error: [],
|
|
42
|
+
message: [],
|
|
43
|
+
};
|
|
44
|
+
this.url = url.toString();
|
|
45
|
+
this.readyState = this.CONNECTING;
|
|
35
46
|
this.max_retry_time = 3000;
|
|
36
|
-
|
|
47
|
+
this.eventSourceClass = globalThis.EventSource;
|
|
37
48
|
if (this._configuration != null) {
|
|
38
49
|
if (this._configuration.lastEventId) {
|
|
39
50
|
this._lastEventId = this._configuration.lastEventId;
|
|
40
51
|
delete this._configuration['lastEventId'];
|
|
41
52
|
}
|
|
42
|
-
|
|
43
53
|
if (this._configuration.max_retry_time) {
|
|
44
54
|
this.max_retry_time = this._configuration.max_retry_time;
|
|
45
55
|
delete this._configuration['max_retry_time'];
|
|
46
56
|
}
|
|
57
|
+
if (this._configuration.eventSourceClass) {
|
|
58
|
+
this.eventSourceClass = this._configuration.eventSourceClass;
|
|
59
|
+
delete this._configuration['eventSourceClass'];
|
|
60
|
+
}
|
|
47
61
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
if (this.eventSourceClass == null || typeof this.eventSourceClass !== 'function') {
|
|
63
|
+
throw new EventSourceNotAvailableError();
|
|
64
|
+
}
|
|
65
|
+
this._onevent_wrapped = (event) => { this._onevent(event); };
|
|
51
66
|
this._start();
|
|
52
67
|
}
|
|
53
|
-
|
|
68
|
+
dispatchEvent(event) {
|
|
69
|
+
throw new Error("Method not implemented.");
|
|
70
|
+
}
|
|
54
71
|
_start() {
|
|
55
72
|
let url = this.url;
|
|
56
|
-
|
|
57
73
|
if (this._lastEventId) {
|
|
58
74
|
if (url.indexOf('?') === -1) {
|
|
59
75
|
url += '?';
|
|
60
|
-
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
61
78
|
url += '&';
|
|
62
79
|
}
|
|
63
80
|
url += 'lastEventId=' + encodeURIComponent(this._lastEventId);
|
|
64
81
|
}
|
|
65
|
-
|
|
66
|
-
this._eventSource =
|
|
67
|
-
|
|
68
|
-
this._eventSource.
|
|
69
|
-
this._eventSource.onerror = event => { this._onerror(event); };
|
|
70
|
-
this._eventSource.onmessage = event => { this.onmessage(event); };
|
|
71
|
-
|
|
82
|
+
this._eventSource = new this.eventSourceClass(url, this._configuration);
|
|
83
|
+
this._eventSource.onopen = (event) => { this._onopen(event); };
|
|
84
|
+
this._eventSource.onerror = (event) => { this._onerror(event); };
|
|
85
|
+
this._eventSource.onmessage = (event) => { this.onmessage(event); };
|
|
72
86
|
// apply listen types
|
|
73
87
|
for (const type of Object.keys(this._listeners)) {
|
|
74
88
|
this._eventSource.addEventListener(type, this._onevent_wrapped);
|
|
75
89
|
}
|
|
76
90
|
}
|
|
77
|
-
|
|
78
91
|
_onopen(event) {
|
|
79
92
|
if (this.readyState === 0) {
|
|
80
93
|
this.readyState = 1;
|
|
81
94
|
this.onopen(event);
|
|
82
95
|
}
|
|
83
96
|
}
|
|
84
|
-
|
|
85
97
|
_onerror(event) {
|
|
86
98
|
if (this.readyState === 1) {
|
|
87
99
|
this.readyState = 0;
|
|
88
100
|
this.onerror(event);
|
|
89
101
|
}
|
|
90
|
-
|
|
91
102
|
if (this._eventSource) {
|
|
92
|
-
if(this._eventSource.readyState === 2) {
|
|
103
|
+
if (this._eventSource.readyState === 2) {
|
|
93
104
|
// reconnect with new object
|
|
94
105
|
this._eventSource.close();
|
|
95
106
|
this._eventSource = null;
|
|
96
|
-
|
|
97
107
|
// reconnect after random timeout < max_retry_time
|
|
98
108
|
const timeout = Math.round(this.max_retry_time * Math.random());
|
|
99
109
|
this._timer = setTimeout(() => this._start(), timeout);
|
|
100
110
|
}
|
|
101
111
|
}
|
|
102
112
|
}
|
|
103
|
-
|
|
104
113
|
_onevent(event) {
|
|
105
|
-
if (event
|
|
114
|
+
if (event instanceof MessageEvent) {
|
|
106
115
|
this._lastEventId = event.lastEventId;
|
|
107
116
|
}
|
|
108
|
-
|
|
109
117
|
const listenersForType = this._listeners[event.type];
|
|
110
118
|
if (listenersForType != null) {
|
|
111
119
|
// operate on a copy
|
|
112
120
|
for (const listener of [...listenersForType]) {
|
|
113
|
-
listener(event);
|
|
121
|
+
listener.call(this, event);
|
|
114
122
|
}
|
|
115
123
|
}
|
|
116
|
-
|
|
117
124
|
if (event.type === 'message') {
|
|
118
125
|
this.onmessage(event);
|
|
119
126
|
}
|
|
120
127
|
}
|
|
121
|
-
|
|
122
128
|
onopen(event) {
|
|
123
129
|
// may be overridden
|
|
124
130
|
}
|
|
125
|
-
|
|
126
131
|
onerror(event) {
|
|
127
132
|
// may be overridden
|
|
128
133
|
}
|
|
129
|
-
|
|
130
134
|
onmessage(event) {
|
|
131
135
|
// may be overridden
|
|
132
136
|
}
|
|
133
|
-
|
|
134
137
|
close() {
|
|
135
138
|
if (this._timer) {
|
|
136
139
|
clearTimeout(this._timer);
|
|
137
140
|
this._timer = null;
|
|
138
141
|
}
|
|
139
|
-
|
|
140
142
|
if (this._eventSource) {
|
|
141
143
|
this._eventSource.close();
|
|
142
144
|
this._eventSource = null;
|
|
143
145
|
}
|
|
144
|
-
|
|
145
146
|
this.readyState = 2;
|
|
146
147
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (!(type in this._listeners)) {
|
|
148
|
+
addEventListener(type, callback, options) {
|
|
149
|
+
// We don't support options at the moment
|
|
150
|
+
if (this._listeners[type] == null) {
|
|
152
151
|
this._listeners[type] = [];
|
|
153
|
-
if (this._eventSource) {
|
|
152
|
+
if (this._eventSource != null) {
|
|
154
153
|
this._eventSource.addEventListener(type, this._onevent_wrapped);
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
|
-
|
|
158
156
|
const listenersForType = this._listeners[type];
|
|
159
157
|
if (!listenersForType.includes(callback)) {
|
|
160
158
|
this._listeners[type] = [...listenersForType, callback];
|
|
161
159
|
}
|
|
162
160
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
if (type in this._listeners) {
|
|
168
|
-
|
|
169
|
-
const listenersForType = this._listeners[type];
|
|
170
|
-
|
|
171
|
-
const updatedListenersForType = listenersForType.filter(l => l !== callback);
|
|
172
|
-
|
|
173
|
-
if (updatedListenersForType.length > 0) {
|
|
174
|
-
this._listeners[type] = updatedListenersForType;
|
|
175
|
-
} else {
|
|
176
|
-
delete this._listeners[type];
|
|
177
|
-
if (this._eventSource) {
|
|
178
|
-
this._eventSource.removeEventListener(type, this._onevent_wrapped);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
161
|
+
removeEventListener(type, callback, options) {
|
|
162
|
+
// We don't support options at the moment
|
|
163
|
+
const listenersForType = this._listeners[type];
|
|
164
|
+
this._listeners[type] = listenersForType.filter(l => l !== callback);
|
|
182
165
|
}
|
|
183
166
|
}
|
|
167
|
+
//# sourceMappingURL=reconnecting-eventsource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconnecting-eventsource.js","sourceRoot":"","sources":["../../src/reconnecting-eventsource.ts"],"names":[],"mappings":"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","sourcesContent":["// MIT License:\n//\n// Copyright (C) 2022 Fanout, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n// IN THE SOFTWARE.\n\nexport interface ReconnectingEventSourceInit extends EventSourceInit {\n // the maximum time to wait before attempting to reconnect in ms, default `3000`\n // note: wait time is randomised to prevent all clients from attempting to reconnect simultaneously\n max_retry_time?: number;\n\n // the EventSource class to wrap. This allows the use of a polyfill or alternate\n // implementation instead of the platform-provided EventSource class.\n eventSourceClass?: typeof EventSource;\n\n // the last event\n lastEventId?: string;\n}\n\nexport class EventSourceNotAvailableError extends Error {\n constructor() {\n super(\n 'EventSource not available.\\n' +\n 'Consider loading an EventSource polyfill and making it available globally as EventSource, ' +\n 'or passing one in as eventSourceClass to the ReconnectingEventSource constructor.'\n );\n }\n}\n\ntype Listeners = {\n [K in keyof EventSourceEventMap]: ((this: EventSource, ev: EventSourceEventMap[K]) => any)[];\n};\n\nexport default class ReconnectingEventSource implements EventSource {\n\n readonly _configuration: ReconnectingEventSourceInit | undefined;\n readonly CONNECTING = 0;\n readonly OPEN = 1;\n readonly CLOSED = 2;\n\n _eventSource: EventSource | null;\n _lastEventId: string | null;\n _timer: NodeJS.Timer | null;\n _listeners: Listeners;\n _onevent_wrapped: (this: EventSource, ev: Event) => any;\n\n readyState: 0 | 1 | 2;\n url: string;\n withCredentials: boolean;\n\n readonly max_retry_time: number;\n eventSourceClass: typeof EventSource;\n\n constructor(url: string | URL, configuration?: ReconnectingEventSourceInit) {\n this._configuration = configuration != null ? Object.assign({}, configuration) : undefined;\n this.withCredentials = false;\n\n this._eventSource = null;\n this._lastEventId = null;\n this._timer = null;\n this._listeners = {\n open: [],\n error: [],\n message: [],\n };\n\n this.url = url.toString();\n this.readyState = this.CONNECTING;\n this.max_retry_time = 3000;\n this.eventSourceClass = globalThis.EventSource;\n\n if (this._configuration != null) {\n if (this._configuration.lastEventId) {\n this._lastEventId = this._configuration.lastEventId;\n delete this._configuration['lastEventId'];\n }\n\n if (this._configuration.max_retry_time) {\n this.max_retry_time = this._configuration.max_retry_time;\n delete this._configuration['max_retry_time'];\n }\n\n if (this._configuration.eventSourceClass) {\n this.eventSourceClass = this._configuration.eventSourceClass;\n delete this._configuration['eventSourceClass'];\n }\n }\n\n if(this.eventSourceClass == null || typeof this.eventSourceClass !== 'function') {\n throw new EventSourceNotAvailableError();\n }\n\n this._onevent_wrapped = (event) => { this._onevent(event); };\n\n this._start();\n }\n\n dispatchEvent(event: Event): boolean {\n throw new Error(\"Method not implemented.\");\n }\n\n _start() {\n let url = this.url;\n\n if (this._lastEventId) {\n if (url.indexOf('?') === -1) {\n url += '?';\n } else {\n url += '&';\n }\n url += 'lastEventId=' + encodeURIComponent(this._lastEventId);\n }\n\n this._eventSource = new this.eventSourceClass(url, this._configuration);\n\n this._eventSource.onopen = (event) => { this._onopen(event); };\n this._eventSource.onerror = (event) => { this._onerror(event); };\n this._eventSource.onmessage = (event) => { this.onmessage(event); };\n\n // apply listen types\n for (const type of Object.keys(this._listeners)) {\n this._eventSource.addEventListener(type, this._onevent_wrapped);\n }\n }\n\n _onopen(event: Event) {\n if (this.readyState === 0) {\n this.readyState = 1;\n this.onopen(event);\n }\n }\n\n _onerror(event: Event) {\n if (this.readyState === 1) {\n this.readyState = 0;\n this.onerror(event);\n }\n\n if (this._eventSource) {\n if(this._eventSource.readyState === 2) {\n // reconnect with new object\n this._eventSource.close();\n this._eventSource = null;\n\n // reconnect after random timeout < max_retry_time\n const timeout = Math.round(this.max_retry_time * Math.random());\n this._timer = setTimeout(() => this._start(), timeout);\n }\n }\n }\n\n _onevent(event: Event) {\n if (event instanceof MessageEvent) {\n this._lastEventId = event.lastEventId;\n }\n\n const listenersForType = this._listeners[event.type as keyof typeof this._listeners] as ((this:EventSource, ev: Event) => any)[];\n if (listenersForType != null) {\n // operate on a copy\n for (const listener of [...listenersForType]) {\n listener.call(this, event);\n }\n }\n\n if (event.type === 'message') {\n this.onmessage(event as MessageEvent);\n }\n }\n\n onopen(event: Event) {\n // may be overridden\n }\n\n onerror(event: Event) {\n // may be overridden\n }\n\n onmessage(event: MessageEvent) {\n // may be overridden\n }\n\n close() {\n if (this._timer) {\n clearTimeout(this._timer);\n this._timer = null;\n }\n\n if (this._eventSource) {\n this._eventSource.close();\n this._eventSource = null;\n }\n\n this.readyState = 2;\n }\n\n addEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions) {\n // We don't support options at the moment\n\n if (this._listeners[type] == null) {\n this._listeners[type] = [];\n if (this._eventSource != null) {\n this._eventSource.addEventListener(type, this._onevent_wrapped);\n }\n }\n\n const listenersForType = this._listeners[type];\n if (!listenersForType.includes(callback)) {\n this._listeners[type] = [...listenersForType, callback] as Listeners[typeof type];\n }\n }\n\n removeEventListener<K extends keyof EventSourceEventMap>(type: K, callback: (this: EventSource, ev: EventSourceEventMap[K]) => any, options?: boolean | AddEventListenerOptions) {\n // We don't support options at the moment\n\n const listenersForType = this._listeners[type];\n this._listeners[type] = listenersForType.filter(l => l !== callback) as Listeners[typeof type];\n }\n}\n"]}
|