@schukai/monster 3.2.0 → 3.3.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/package.json +1 -1
- package/source/data/datasource/websocket.mjs +139 -206
- package/source/net/webconnect/message.mjs +55 -0
- package/source/net/webconnect.mjs +346 -0
- package/source/types/observablequeue.mjs +110 -0
- package/source/types/proxyobserver.mjs +2 -2
- package/source/types/uniquequeue.mjs +9 -6
- package/source/types/version.mjs +1 -1
- package/test/cases/data/datasource/websocket.mjs +118 -33
- package/test/cases/monster.mjs +1 -1
- package/test/cases/net/webconnect/message.mjs +50 -0
- package/test/cases/net/webconnect.mjs +116 -0
- package/test/cases/types/observablequeue.mjs +17 -0
- package/test/cases/types/queue.mjs +4 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright schukai GmbH and contributors 2022. All Rights Reserved.
|
|
3
|
+
* Node module: @schukai/monster
|
|
4
|
+
* This file is licensed under the AGPLv3 License.
|
|
5
|
+
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {instanceSymbol} from "../constants.mjs";
|
|
9
|
+
import {isInteger, isString, isObject} from "../types/is.mjs";
|
|
10
|
+
import {BaseWithOptions} from "../types/basewithoptions.mjs";
|
|
11
|
+
import {ObservableQueue} from "../types/observablequeue.mjs";
|
|
12
|
+
import {Message} from "./webconnect/message.mjs";
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export {WebConnect}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @private
|
|
19
|
+
* @type {Symbol}
|
|
20
|
+
*/
|
|
21
|
+
const receiveQueueSymbol = Symbol("receiveQueue");
|
|
22
|
+
/**
|
|
23
|
+
* @private
|
|
24
|
+
* @type {Symbol}
|
|
25
|
+
*/
|
|
26
|
+
const sendQueueSymbol = Symbol("sendQueue");
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @private
|
|
30
|
+
* @type {Symbol}
|
|
31
|
+
*
|
|
32
|
+
* hint: this name is used in the tests. if you want to change it, please change it in the tests as well.
|
|
33
|
+
*/
|
|
34
|
+
const connectionSymbol = Symbol("connection");
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @private
|
|
38
|
+
* @type {symbol}
|
|
39
|
+
*/
|
|
40
|
+
const manualCloseSymbol = Symbol("manualClose");
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @private
|
|
44
|
+
* @see https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
|
|
45
|
+
* @type {{"1000": string, "1011": string, "1010": string, "1008": string, "1007": string, "1006": string, "1005": string, "1004": string, "1015": string, "1003": string, "1002": string, "1001": string, "1009": string}}
|
|
46
|
+
*/
|
|
47
|
+
const connectionStatusCode = {
|
|
48
|
+
1000: "Normal closure",
|
|
49
|
+
1001: "Going away",
|
|
50
|
+
1002: "Protocol error",
|
|
51
|
+
1003: "Unsupported data",
|
|
52
|
+
1004: "Reserved",
|
|
53
|
+
1005: "No status code",
|
|
54
|
+
1006: "Connection closed abnormally",
|
|
55
|
+
1007: "Invalid frame payload data",
|
|
56
|
+
1008: "Policy violation",
|
|
57
|
+
1009: "Message too big",
|
|
58
|
+
1010: "Mandatory extension",
|
|
59
|
+
1011: "Internal server error",
|
|
60
|
+
1015: "TLS handshake"
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @private
|
|
65
|
+
* @this {WebConnect}
|
|
66
|
+
* @throws {Error} No url defined for websocket datasource.
|
|
67
|
+
*/
|
|
68
|
+
function connectServer(resolve, reject) {
|
|
69
|
+
const self = this;
|
|
70
|
+
|
|
71
|
+
const url = self.getOption('url');
|
|
72
|
+
if (!url) {
|
|
73
|
+
reject('No url defined for webconnect.');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let promiseAllredyResolved = false;
|
|
78
|
+
|
|
79
|
+
let connectionTimeout = self.getOption('connection.timeout');
|
|
80
|
+
if (!isInteger(connectionTimeout) || connectionTimeout < 100) {
|
|
81
|
+
connectionTimeout = 5000;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setTimeout(() => {
|
|
85
|
+
if (promiseAllredyResolved) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
reject(new Error("Connection timeout"));
|
|
89
|
+
}, connectionTimeout);
|
|
90
|
+
|
|
91
|
+
let reconnectTimeout = self.getOption('connection.reconnect.timeout');
|
|
92
|
+
if (!isInteger(reconnectTimeout) || reconnectTimeout < 1000) reconnectTimeout = 1000;
|
|
93
|
+
let reconnectAttempts = self.getOption('connection.reconnect.attempts');
|
|
94
|
+
if (!isInteger(reconnectAttempts) || reconnectAttempts < 1) reconnectAttempts = 1;
|
|
95
|
+
let reconnectEnabled = self.getOption('connection.reconnect.enabled');
|
|
96
|
+
if (reconnectEnabled !== true) reconnectEnabled = false;
|
|
97
|
+
|
|
98
|
+
self[manualCloseSymbol] = false;
|
|
99
|
+
self[connectionSymbol].reconnectCounter++;
|
|
100
|
+
|
|
101
|
+
if (self[connectionSymbol].socket && self[connectionSymbol].socket.readyState < 2) {
|
|
102
|
+
self[connectionSymbol].socket.close();
|
|
103
|
+
}
|
|
104
|
+
self[connectionSymbol].socket = null;
|
|
105
|
+
self[connectionSymbol].socket = new WebSocket(url);
|
|
106
|
+
|
|
107
|
+
self[connectionSymbol].socket.onmessage = function (event) {
|
|
108
|
+
if (event.data instanceof Blob) {
|
|
109
|
+
const reader = new FileReader();
|
|
110
|
+
reader.addEventListener("loadend", function () {
|
|
111
|
+
self[receiveQueueSymbol].add(new Message(reader.result))
|
|
112
|
+
});
|
|
113
|
+
reader.readAsText(new Message(event.data));
|
|
114
|
+
} else {
|
|
115
|
+
self[receiveQueueSymbol].add(Message.fromJSON(event.data));
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
self[connectionSymbol].socket.onopen = function () {
|
|
120
|
+
self[connectionSymbol].reconnectCounter = 0;
|
|
121
|
+
if (typeof resolve === 'function' && !promiseAllredyResolved) {
|
|
122
|
+
promiseAllredyResolved = true;
|
|
123
|
+
resolve();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
self[connectionSymbol].socket.close = function (event) {
|
|
128
|
+
|
|
129
|
+
if (self[manualCloseSymbol]) {
|
|
130
|
+
self[manualCloseSymbol] = false;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (reconnectEnabled && this[connectionSymbol].reconnectCounter < reconnectAttempts) {
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
self.connect();
|
|
137
|
+
}, reconnectTimeout * this[connectionSymbol].reconnectCounter);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
self[connectionSymbol].socket.onerror = (error) => {
|
|
143
|
+
|
|
144
|
+
if (reconnectEnabled && self[connectionSymbol].reconnectCounter < reconnectAttempts) {
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
self.connect();
|
|
147
|
+
}, reconnectTimeout * this[connectionSymbol].reconnectCounter);
|
|
148
|
+
} else {
|
|
149
|
+
if (typeof reject === 'function' && !promiseAllredyResolved) {
|
|
150
|
+
promiseAllredyResolved = true;
|
|
151
|
+
reject(error);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The RestAPI is a class that enables a REST API server.
|
|
160
|
+
*
|
|
161
|
+
* @externalExample ../../../example/data/storage/restapi.mjs
|
|
162
|
+
* @license AGPLv3
|
|
163
|
+
* @since 3.1.0
|
|
164
|
+
* @copyright schukai GmbH
|
|
165
|
+
* @memberOf Monster.Data.Datasource
|
|
166
|
+
* @summary The LocalStorage class encapsulates the access to data objects.
|
|
167
|
+
*/
|
|
168
|
+
class WebConnect extends BaseWithOptions {
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
*
|
|
172
|
+
* @param {Object} [options] options contains definitions for the datasource.
|
|
173
|
+
*/
|
|
174
|
+
constructor(options) {
|
|
175
|
+
|
|
176
|
+
if (isString(options)) {
|
|
177
|
+
options = {url: options};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
super(options);
|
|
181
|
+
|
|
182
|
+
this[receiveQueueSymbol] = new ObservableQueue();
|
|
183
|
+
this[sendQueueSymbol] = new ObservableQueue();
|
|
184
|
+
|
|
185
|
+
this[connectionSymbol] = {};
|
|
186
|
+
this[connectionSymbol].socket = null;
|
|
187
|
+
this[connectionSymbol].reconnectCounter = 0;
|
|
188
|
+
this[manualCloseSymbol] = false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
*
|
|
193
|
+
* @returns {Promise}
|
|
194
|
+
*/
|
|
195
|
+
connect() {
|
|
196
|
+
const self = this;
|
|
197
|
+
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
connectServer.call(this, resolve, reject);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @returns {boolean}
|
|
205
|
+
*/
|
|
206
|
+
isConnected() {
|
|
207
|
+
return this[connectionSymbol]?.socket?.readyState === 1;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* This method is called by the `instanceof` operator.
|
|
212
|
+
* @returns {symbol}
|
|
213
|
+
*/
|
|
214
|
+
static get [instanceSymbol]() {
|
|
215
|
+
return Symbol.for("@schukai/monster/net/webconnect");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @property {string} url=undefined Defines the resource that you wish to fetch.
|
|
220
|
+
* @property {Object} connection
|
|
221
|
+
* @property {Object} connection.timeout=5000 Defines the timeout for the connection.
|
|
222
|
+
* @property {Number} connection.reconnect.timeout The timeout in milliseconds for the reconnect.
|
|
223
|
+
* @property {Number} connection.reconnect.attempts The maximum number of reconnects.
|
|
224
|
+
* @property {Bool} connection.reconnect.enabled If the reconnect is enabled.
|
|
225
|
+
*/
|
|
226
|
+
get defaults() {
|
|
227
|
+
return Object.assign({}, super.defaults, {
|
|
228
|
+
url: undefined,
|
|
229
|
+
connection: {
|
|
230
|
+
timeout: 5000,
|
|
231
|
+
reconnect: {
|
|
232
|
+
timeout: 1000,
|
|
233
|
+
attempts: 1,
|
|
234
|
+
enabled: false,
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* This method closes the connection.
|
|
242
|
+
*
|
|
243
|
+
* @param {Number} [code=1000] The close code.
|
|
244
|
+
* @param {String} [reason=""] The close reason.
|
|
245
|
+
* @returns {Promise}
|
|
246
|
+
* @see https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
|
|
247
|
+
*/
|
|
248
|
+
close(statusCode, reason ) {
|
|
249
|
+
if (!isInteger(statusCode) || statusCode < 1000 || statusCode > 4999) {
|
|
250
|
+
statusCode = 1000;
|
|
251
|
+
}
|
|
252
|
+
if (!isString(reason)) {
|
|
253
|
+
reason = '';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return new Promise((resolve, reject) => {
|
|
257
|
+
try {
|
|
258
|
+
this[manualCloseSymbol] = true;
|
|
259
|
+
if (this[connectionSymbol].socket) {
|
|
260
|
+
this[connectionSymbol].socket.close(statusCode, reason);
|
|
261
|
+
}
|
|
262
|
+
} catch (error) {
|
|
263
|
+
reject(error);
|
|
264
|
+
}
|
|
265
|
+
resolve();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Polls the receive queue for new messages.
|
|
272
|
+
*
|
|
273
|
+
* @returns {Message}
|
|
274
|
+
*/
|
|
275
|
+
poll() {
|
|
276
|
+
return this[receiveQueueSymbol].poll();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Are there any messages in the receive queue?
|
|
281
|
+
*
|
|
282
|
+
* @returns {boolean}
|
|
283
|
+
*/
|
|
284
|
+
dataReceived() {
|
|
285
|
+
return !this[receiveQueueSymbol].isEmpty();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get Message from the receive queue, but do not remove it.
|
|
290
|
+
*
|
|
291
|
+
* @returns {Object}
|
|
292
|
+
*/
|
|
293
|
+
peek() {
|
|
294
|
+
return this[receiveQueueSymbol].peek();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Attach a new observer
|
|
299
|
+
*
|
|
300
|
+
* @param {Observer} observer
|
|
301
|
+
* @returns {ProxyObserver}
|
|
302
|
+
*/
|
|
303
|
+
attachObserver(observer) {
|
|
304
|
+
this[receiveQueueSymbol].attachObserver(observer);
|
|
305
|
+
return this;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Detach a observer
|
|
310
|
+
*
|
|
311
|
+
* @param {Observer} observer
|
|
312
|
+
* @returns {ProxyObserver}
|
|
313
|
+
*/
|
|
314
|
+
detachObserver(observer) {
|
|
315
|
+
this[receiveQueueSymbol].detachObserver(observer);
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @param {Observer} observer
|
|
321
|
+
* @returns {boolean}
|
|
322
|
+
*/
|
|
323
|
+
containsObserver(observer) {
|
|
324
|
+
return this[receiveQueueSymbol].containsObserver(observer);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* @param {Message|Object} message
|
|
329
|
+
* @return {Promise}
|
|
330
|
+
*/
|
|
331
|
+
send(message) {
|
|
332
|
+
const self = this;
|
|
333
|
+
|
|
334
|
+
return new Promise((resolve, reject) => {
|
|
335
|
+
|
|
336
|
+
if (self[connectionSymbol].socket.readyState !== 1) {
|
|
337
|
+
reject('the socket is not ready');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
self[connectionSymbol].socket.send(JSON.stringify(message))
|
|
341
|
+
resolve();
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
}
|
|
346
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright schukai GmbH and contributors 2022. All Rights Reserved.
|
|
3
|
+
* Node module: @schukai/monster
|
|
4
|
+
* This file is licensed under the AGPLv3 License.
|
|
5
|
+
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {Queue} from './queue.mjs';
|
|
9
|
+
import {instanceSymbol, internalSymbol} from '../constants.mjs';
|
|
10
|
+
import {ObserverList} from "./observerlist.mjs";
|
|
11
|
+
|
|
12
|
+
export {ObservableQueue};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* An observable queue is a list of items that are processed one after another (first in, first out).
|
|
16
|
+
*
|
|
17
|
+
* `Queue.add()` and `Queue.clear()` notify all observers.
|
|
18
|
+
*
|
|
19
|
+
* @externalExample ../../example/types/queue.mjs
|
|
20
|
+
* @license AGPLv3
|
|
21
|
+
* @since 3.3.0
|
|
22
|
+
* @copyright schukai GmbH
|
|
23
|
+
* @memberOf Monster.Types
|
|
24
|
+
* @summary An observable Queue (Fifo)
|
|
25
|
+
*/
|
|
26
|
+
class ObservableQueue extends Queue {
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
constructor() {
|
|
32
|
+
super();
|
|
33
|
+
this[internalSymbol]= {
|
|
34
|
+
observers: new ObserverList()
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* This method is called by the `instanceof` operator.
|
|
40
|
+
* @returns {symbol}
|
|
41
|
+
* @since 2.1.0
|
|
42
|
+
*/
|
|
43
|
+
static get [instanceSymbol]() {
|
|
44
|
+
return Symbol.for("@schukai/monster/types/observablequeue");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Add a new element to the end of the queue.
|
|
49
|
+
*
|
|
50
|
+
* @param {*} value
|
|
51
|
+
* @returns {Queue}
|
|
52
|
+
*/
|
|
53
|
+
add(value) {
|
|
54
|
+
super.add(value);
|
|
55
|
+
this.notifyObservers();
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* remove all entries
|
|
61
|
+
*
|
|
62
|
+
* @returns {Queue}
|
|
63
|
+
*/
|
|
64
|
+
clear() {
|
|
65
|
+
super.clear();
|
|
66
|
+
this.notifyObservers();
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Attach a new observer
|
|
72
|
+
*
|
|
73
|
+
* @param {Observer} observer
|
|
74
|
+
* @returns {ProxyObserver}
|
|
75
|
+
*/
|
|
76
|
+
attachObserver(observer) {
|
|
77
|
+
this[internalSymbol].observers.attach(observer)
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Detach a observer
|
|
83
|
+
*
|
|
84
|
+
* @param {Observer} observer
|
|
85
|
+
* @returns {ProxyObserver}
|
|
86
|
+
*/
|
|
87
|
+
detachObserver(observer) {
|
|
88
|
+
this[internalSymbol].observers.detach(observer)
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Notify all observer
|
|
94
|
+
*
|
|
95
|
+
* @returns {Promise}
|
|
96
|
+
*/
|
|
97
|
+
notifyObservers() {
|
|
98
|
+
return this[internalSymbol].observers.notify(this);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @param {Observer} observer
|
|
103
|
+
* @returns {boolean}
|
|
104
|
+
*/
|
|
105
|
+
containsObserver(observer) {
|
|
106
|
+
return this[internalSymbol].observers.contains(observer)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
}
|
|
@@ -61,9 +61,9 @@ export {ProxyObserver}
|
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
64
|
+
* Get the real object
|
|
65
65
|
*
|
|
66
|
-
*
|
|
66
|
+
* Changes to this object are not noticed by the observers, so you can make a large number of changes and inform the observers later.
|
|
67
67
|
*
|
|
68
68
|
* @returns {object}
|
|
69
69
|
*/
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {Queue} from "./queue.mjs";
|
|
9
|
+
import {internalSymbol} from "../constants.mjs";
|
|
9
10
|
import {validateObject} from "./validate.mjs";
|
|
10
11
|
|
|
11
12
|
export {UniqueQueue}
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
+
* An UniqueQueue is a queue that contains items only once.
|
|
15
16
|
*
|
|
16
17
|
* @license AGPLv3
|
|
17
18
|
* @since 1.4.0
|
|
@@ -26,7 +27,9 @@ export {UniqueQueue}
|
|
|
26
27
|
*/
|
|
27
28
|
constructor() {
|
|
28
29
|
super();
|
|
29
|
-
this
|
|
30
|
+
this[internalSymbol]={
|
|
31
|
+
unique : new WeakSet()
|
|
32
|
+
};
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
@@ -40,8 +43,8 @@ export {UniqueQueue}
|
|
|
40
43
|
|
|
41
44
|
validateObject(value);
|
|
42
45
|
|
|
43
|
-
if (!this.unique.has(value)) {
|
|
44
|
-
this.unique.add(value);
|
|
46
|
+
if (!this[internalSymbol].unique.has(value)) {
|
|
47
|
+
this[internalSymbol].unique.add(value);
|
|
45
48
|
super.add(value);
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -55,7 +58,7 @@ export {UniqueQueue}
|
|
|
55
58
|
*/
|
|
56
59
|
clear() {
|
|
57
60
|
super.clear();
|
|
58
|
-
this.unique = new WeakSet;
|
|
61
|
+
this[internalSymbol].unique = new WeakSet;
|
|
59
62
|
return this;
|
|
60
63
|
}
|
|
61
64
|
|
|
@@ -71,7 +74,7 @@ export {UniqueQueue}
|
|
|
71
74
|
return undefined;
|
|
72
75
|
}
|
|
73
76
|
let value = this.data.shift();
|
|
74
|
-
this.unique.delete(value);
|
|
77
|
+
this[internalSymbol].unique.delete(value);
|
|
75
78
|
return value;
|
|
76
79
|
}
|
|
77
80
|
|
package/source/types/version.mjs
CHANGED