@nymphjs/client 1.0.0-beta.95 → 1.0.0-beta.97

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/lib/PubSub.d.ts DELETED
@@ -1,63 +0,0 @@
1
- import Nymph from './Nymph';
2
- import type { NymphOptions, Options, Selector } from './Nymph.types';
3
- import type { EntityInstanceType } from './Entity';
4
- import type { EntityConstructor, EntityInterface } from './Entity.types';
5
- import type { PubSubCallbacks, PubSubConnectCallback, PubSubCountCallback, PubSubDisconnectCallback, PubSubEventType, PubSubRejectCallback, PubSubResolveCallback, PubSubErrorCallback, PubSubSubscribable, PubSubUpdate } from './PubSub.types';
6
- export default class PubSub {
7
- private nymph;
8
- private authToken;
9
- private switchToken;
10
- private connection;
11
- private waitForConnectionTimeout;
12
- private pubsubUrl;
13
- private WebSocket;
14
- private subscriptions;
15
- private connectCallbacks;
16
- private disconnectCallbacks;
17
- private errorCallbacks;
18
- private noConsole;
19
- constructor(nymphOptions: NymphOptions, nymph: Nymph);
20
- subscribeEntities<T extends EntityConstructor = EntityConstructor>(options: Options<T> & {
21
- return: 'guid';
22
- }, ...selectors: Selector[]): PubSubSubscribable<PubSubUpdate<string[]>>;
23
- subscribeEntities<T extends EntityConstructor = EntityConstructor>(options: Options<T>, ...selectors: Selector[]): PubSubSubscribable<PubSubUpdate<EntityInstanceType<T>[]>>;
24
- subscribeEntity<T extends EntityConstructor = EntityConstructor>(options: Options<T> & {
25
- return: 'guid';
26
- }, ...selectors: Selector[]): PubSubSubscribable<PubSubUpdate<string | null>>;
27
- subscribeEntity<T extends EntityConstructor = EntityConstructor>(options: Options<T>, ...selectors: Selector[]): PubSubSubscribable<PubSubUpdate<EntityInstanceType<T> | null>>;
28
- subscribeUID(name: string): (resolve?: PubSubResolveCallback<number> | undefined, reject?: PubSubRejectCallback | undefined, count?: PubSubCountCallback | undefined) => {
29
- unsubscribe: () => void;
30
- };
31
- subscribeWith<T extends EntityInterface>(entity: T, resolve?: PubSubResolveCallback<T> | undefined, reject?: PubSubRejectCallback | undefined, count?: PubSubCountCallback | undefined): PubSubSubscription<T>;
32
- connect(): void;
33
- close(): void;
34
- private _waitForConnection;
35
- private _attemptConnect;
36
- private _onopen;
37
- private _onmessage;
38
- private _onclose;
39
- private _send;
40
- isConnectionOpen(): boolean;
41
- isConnectionConnecting(): boolean;
42
- isConnection(): boolean;
43
- private _subscribeQuery;
44
- private _subscribeUID;
45
- private _sendQuery;
46
- private _sendUID;
47
- private _isCountSubscribedQuery;
48
- private _isCountSubscribedUID;
49
- private _unsubscribeQuery;
50
- private _unsubscribeUID;
51
- private _sendUnQuery;
52
- private _sendUnUID;
53
- updateArray(current: EntityInterface[], update: PubSubUpdate<EntityInterface[]>): void;
54
- on<T extends PubSubEventType>(event: T, callback: T extends 'connect' ? PubSubConnectCallback : T extends 'disconnect' ? PubSubDisconnectCallback : T extends 'error' ? PubSubErrorCallback : never): () => boolean;
55
- off<T extends PubSubEventType>(event: T, callback: T extends 'connect' ? PubSubConnectCallback : T extends 'disconnect' ? PubSubDisconnectCallback : T extends 'error' ? PubSubErrorCallback : never): boolean;
56
- authenticate(authToken: string | null, switchToken?: string | null): void;
57
- }
58
- export declare class PubSubSubscription<T> {
59
- query: string;
60
- callbacks: PubSubCallbacks<T>;
61
- unsubscribe: () => void;
62
- constructor(query: string, callbacks: PubSubCallbacks<T>, unsubscribe: () => void);
63
- }
package/lib/PubSub.js DELETED
@@ -1,596 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PubSubSubscription = void 0;
4
- const Nymph_1 = require("./Nymph");
5
- const utils_1 = require("./utils");
6
- const HttpRequester_1 = require("./HttpRequester");
7
- class PubSub {
8
- constructor(nymphOptions, nymph) {
9
- this.authToken = null;
10
- this.switchToken = null;
11
- this.subscriptions = {
12
- queries: {},
13
- uids: {},
14
- };
15
- this.connectCallbacks = [];
16
- this.disconnectCallbacks = [];
17
- this.errorCallbacks = [];
18
- this.noConsole = false;
19
- this.nymph = nymph;
20
- this.nymph.pubsub = this;
21
- this.pubsubUrl = nymphOptions.pubsubUrl;
22
- this.WebSocket = nymphOptions.WebSocket ?? WebSocket;
23
- this.noConsole = !!nymphOptions.noConsole;
24
- if (!this.WebSocket) {
25
- throw new Error('Nymph-PubSub requires WebSocket!');
26
- }
27
- if (typeof addEventListener !== 'undefined') {
28
- addEventListener('online', () => this.connect());
29
- }
30
- if (!nymphOptions.noAutoconnect &&
31
- (typeof navigator === 'undefined' || navigator.onLine)) {
32
- this.connect();
33
- }
34
- }
35
- subscribeEntities(options, ...selectors) {
36
- const query = [
37
- (0, utils_1.entityConstructorsToClassNames)(options),
38
- ...(0, utils_1.entityConstructorsToClassNames)(selectors),
39
- ];
40
- const jsonQuery = JSON.stringify(query);
41
- const subscribe = (resolve, reject, count) => {
42
- const callbacks = [resolve, reject, count];
43
- if (!this.isConnection()) {
44
- // Fall back to a regular query if we're not connected.
45
- this.nymph.getEntities(options, ...selectors).then(resolve, reject);
46
- }
47
- this._subscribeQuery(jsonQuery, callbacks);
48
- return new PubSubSubscription(jsonQuery, callbacks, () => {
49
- this._unsubscribeQuery(jsonQuery, callbacks);
50
- });
51
- };
52
- return subscribe;
53
- }
54
- subscribeEntity(options, ...selectors) {
55
- const query = [
56
- { ...(0, utils_1.entityConstructorsToClassNames)(options), limit: 1 },
57
- ...(0, utils_1.entityConstructorsToClassNames)(selectors),
58
- ];
59
- const jsonQuery = JSON.stringify(query);
60
- const subscribe = (resolve, reject, count) => {
61
- const newResolve = (args) => {
62
- if (!args.length) {
63
- if (resolve) {
64
- resolve(null);
65
- }
66
- }
67
- else {
68
- if (resolve) {
69
- resolve(args[0]);
70
- }
71
- }
72
- };
73
- const callbacks = [newResolve, reject, count];
74
- if (!this.isConnection()) {
75
- // Fall back to a regular query if we're not connected.
76
- this.nymph.getEntity(options, ...selectors).then(resolve, reject);
77
- }
78
- this._subscribeQuery(jsonQuery, callbacks);
79
- return new PubSubSubscription(jsonQuery, callbacks, () => {
80
- this._unsubscribeQuery(jsonQuery, callbacks);
81
- });
82
- };
83
- return subscribe;
84
- }
85
- subscribeUID(name) {
86
- const subscribe = (resolve, reject, count) => {
87
- const callbacks = [resolve, reject, count];
88
- if (!this.isConnection()) {
89
- // Fall back to a regular query if we're not connected.
90
- this.nymph.getUID(name).then(resolve, reject);
91
- }
92
- this._subscribeUID(name, callbacks);
93
- return {
94
- unsubscribe: () => {
95
- this._unsubscribeUID(name, callbacks);
96
- },
97
- };
98
- };
99
- return subscribe;
100
- }
101
- subscribeWith(entity, resolve, reject, count) {
102
- if (!entity.guid) {
103
- throw new Nymph_1.InvalidRequestError("You can't subscribe to an entity with no GUID.");
104
- }
105
- const query = [
106
- { class: entity.constructor.class, limit: 1 },
107
- { type: '&', guid: entity.guid },
108
- ];
109
- const jsonQuery = JSON.stringify(query);
110
- const newResolve = (args) => {
111
- if (Array.isArray(args)) {
112
- if (args.length) {
113
- entity.$init(args[0].toJSON());
114
- }
115
- else {
116
- entity.guid = null;
117
- }
118
- }
119
- else if ('removed' in args) {
120
- entity.guid = null;
121
- }
122
- else {
123
- entity.$init(args.data);
124
- }
125
- if (resolve) {
126
- resolve(entity);
127
- }
128
- };
129
- const callbacks = [newResolve, reject, count];
130
- this._subscribeQuery(jsonQuery, callbacks);
131
- return new PubSubSubscription(jsonQuery, callbacks, () => {
132
- this._unsubscribeQuery(jsonQuery, callbacks);
133
- });
134
- }
135
- connect() {
136
- // Are we already connected?
137
- if (this.connection &&
138
- (this.connection.readyState === this.WebSocket.OPEN ||
139
- this.connection.readyState === this.WebSocket.CONNECTING)) {
140
- return;
141
- }
142
- this._waitForConnection();
143
- this._attemptConnect();
144
- }
145
- close() {
146
- if (this.waitForConnectionTimeout) {
147
- clearTimeout(this.waitForConnectionTimeout);
148
- }
149
- if (!this.connection) {
150
- return;
151
- }
152
- this.connection.close(1000, 'Closure requested by application.');
153
- }
154
- _waitForConnection(attempts = 1) {
155
- // Wait 5 seconds, then check and attempt connection again if unsuccessful.
156
- // Keep repeating, adding attempts^2*5 seconds each time to a max of ten
157
- // minutes, until successful.
158
- this.waitForConnectionTimeout = setTimeout(() => {
159
- if (this.connection) {
160
- if (this.connection.readyState !== this.WebSocket.OPEN) {
161
- if (this.connection.readyState !== this.WebSocket.CONNECTING) {
162
- this.connection.close();
163
- this._waitForConnection(attempts + 1);
164
- this._attemptConnect();
165
- }
166
- else {
167
- this._waitForConnection(attempts + 1);
168
- }
169
- }
170
- }
171
- else {
172
- this._attemptConnect();
173
- }
174
- }, Math.max(Math.pow(attempts, 2) * 5000, 1000 * 60 * 10));
175
- }
176
- _attemptConnect() {
177
- // Attempt to connect.
178
- if (this.pubsubUrl != null) {
179
- this.connection = new this.WebSocket(this.pubsubUrl, 'nymph');
180
- this.connection.onopen = this._onopen.bind(this);
181
- this.connection.onmessage = this._onmessage.bind(this);
182
- }
183
- }
184
- _onopen() {
185
- if (typeof console !== 'undefined' && !this.noConsole) {
186
- console.log('Nymph-PubSub connection established!');
187
- }
188
- if (this.waitForConnectionTimeout) {
189
- clearTimeout(this.waitForConnectionTimeout);
190
- }
191
- for (let i = 0; i < this.connectCallbacks.length; i++) {
192
- const callback = this.connectCallbacks[i];
193
- if (callback) {
194
- callback();
195
- }
196
- }
197
- if (this.authToken != null) {
198
- this._send({
199
- action: 'authenticate',
200
- authToken: this.authToken,
201
- switchToken: this.switchToken,
202
- });
203
- }
204
- for (let query in this.subscriptions.queries) {
205
- if (!this.subscriptions.queries.hasOwnProperty(query)) {
206
- continue;
207
- }
208
- let count = false;
209
- for (let callbacks = 0; callbacks < this.subscriptions.queries[query].length; callbacks++) {
210
- if (this.subscriptions.queries[query][callbacks][2]) {
211
- count = true;
212
- break;
213
- }
214
- }
215
- this._sendQuery(query, count);
216
- }
217
- for (let name in this.subscriptions.uids) {
218
- if (!this.subscriptions.uids.hasOwnProperty(name)) {
219
- continue;
220
- }
221
- let count = false;
222
- for (let callbacks = 0; callbacks < this.subscriptions.uids[name].length; callbacks++) {
223
- if (this.subscriptions.uids[name][callbacks][2]) {
224
- count = true;
225
- break;
226
- }
227
- }
228
- this._sendUID(name, count);
229
- }
230
- if (this.connection) {
231
- this.connection.onclose = this._onclose.bind(this);
232
- }
233
- }
234
- _onmessage(e) {
235
- let data = JSON.parse(e.data);
236
- let subs = [];
237
- let set = 'set' in data && data.set;
238
- let count = 'count' in data;
239
- let error = 'error' in data;
240
- if (data.hasOwnProperty('query') &&
241
- this.subscriptions.queries.hasOwnProperty(data.query)) {
242
- subs = [...this.subscriptions.queries[data.query]];
243
- if (!count && !error) {
244
- for (let i = 0; i < subs.length; i++) {
245
- const callback = subs[i][0];
246
- if (typeof callback === 'function') {
247
- callback(set
248
- ? data.data.map((e) => this.nymph.initEntity(e))
249
- : data);
250
- }
251
- }
252
- }
253
- }
254
- else if (data.hasOwnProperty('uid') &&
255
- this.subscriptions.uids.hasOwnProperty(data.uid)) {
256
- subs = [...this.subscriptions.uids[data.uid]];
257
- if (!count && !error) {
258
- for (let i = 0; i < subs.length; i++) {
259
- const callback = subs[i][0];
260
- const errCallback = subs[i][1];
261
- if (set && data.data == null) {
262
- if (typeof errCallback === 'function') {
263
- errCallback(new HttpRequester_1.ClientError({ status: 404, statusText: 'Not Found' }, { textStatus: 'Not Found' }));
264
- }
265
- }
266
- else if (typeof callback === 'function') {
267
- if (set) {
268
- callback(data.data);
269
- }
270
- else {
271
- callback(data.value ?? null, data.event);
272
- }
273
- }
274
- }
275
- }
276
- }
277
- else if (error) {
278
- for (let i = 0; i < this.errorCallbacks.length; i++) {
279
- const callback = this.errorCallbacks[i];
280
- if (callback) {
281
- callback(data.error);
282
- }
283
- }
284
- return;
285
- }
286
- if (count) {
287
- for (let i = 0; i < subs.length; i++) {
288
- const callback = subs[i][2];
289
- if (typeof callback === 'function') {
290
- callback(data.count);
291
- }
292
- }
293
- }
294
- if (error) {
295
- for (let i = 0; i < subs.length; i++) {
296
- const callback = subs[i][1];
297
- if (typeof callback === 'function') {
298
- callback(data.error);
299
- }
300
- }
301
- }
302
- }
303
- _onclose(e) {
304
- if (typeof console !== 'undefined' && !this.noConsole) {
305
- console.log(`Nymph-PubSub connection closed: ${e.code} ${e.reason}`);
306
- }
307
- for (let i = 0; i < this.disconnectCallbacks.length; i++) {
308
- const callback = this.disconnectCallbacks[i];
309
- if (callback) {
310
- callback();
311
- }
312
- }
313
- if (e.code !== 1000 &&
314
- (typeof navigator === 'undefined' || navigator.onLine)) {
315
- if (this.connection) {
316
- this.connection.close();
317
- }
318
- this._waitForConnection();
319
- this._attemptConnect();
320
- }
321
- }
322
- _send(data) {
323
- if (this.connection) {
324
- this.connection.send(JSON.stringify(data));
325
- }
326
- }
327
- isConnectionOpen() {
328
- return !!(this.connection && this.connection.readyState === this.WebSocket.OPEN);
329
- }
330
- isConnectionConnecting() {
331
- return !!(this.connection &&
332
- this.connection.readyState === this.WebSocket.CONNECTING);
333
- }
334
- isConnection() {
335
- return this.isConnectionOpen() || this.isConnectionConnecting();
336
- }
337
- _subscribeQuery(query, callbacks) {
338
- let isNewSubscription = false;
339
- if (!this.subscriptions.queries.hasOwnProperty(query)) {
340
- this.subscriptions.queries[query] = [];
341
- isNewSubscription = true;
342
- }
343
- let isCountSubscribed = isNewSubscription
344
- ? false
345
- : this._isCountSubscribedQuery(query);
346
- this.subscriptions.queries[query].push(callbacks);
347
- if (this.isConnectionOpen()) {
348
- if (isNewSubscription) {
349
- this._sendQuery(query, !!callbacks[2]);
350
- }
351
- else if (!isCountSubscribed && callbacks[2]) {
352
- this._sendUnQuery(query);
353
- this._sendQuery(query, true);
354
- }
355
- }
356
- }
357
- _subscribeUID(name, callbacks) {
358
- let isNewSubscription = false;
359
- if (!this.subscriptions.uids.hasOwnProperty(name)) {
360
- this.subscriptions.uids[name] = [];
361
- isNewSubscription = true;
362
- }
363
- let isCountSubscribed = isNewSubscription
364
- ? false
365
- : this._isCountSubscribedUID(name);
366
- this.subscriptions.uids[name].push(callbacks);
367
- if (this.isConnectionOpen()) {
368
- if (isNewSubscription) {
369
- this._sendUID(name, !!callbacks[2]);
370
- }
371
- else if (!isCountSubscribed && callbacks[2]) {
372
- this._sendUnUID(name);
373
- this._sendUID(name, true);
374
- }
375
- }
376
- }
377
- _sendQuery(query, count) {
378
- this._send({
379
- action: 'subscribe',
380
- query,
381
- count,
382
- });
383
- }
384
- _sendUID(name, count) {
385
- this._send({
386
- action: 'subscribe',
387
- uid: name,
388
- count,
389
- });
390
- }
391
- _isCountSubscribedQuery(query) {
392
- if (!this.subscriptions.queries.hasOwnProperty(query)) {
393
- return false;
394
- }
395
- for (let callbacks = 0; callbacks < this.subscriptions.queries[query].length; callbacks++) {
396
- if (this.subscriptions.queries[query][callbacks][2]) {
397
- return true;
398
- }
399
- }
400
- return false;
401
- }
402
- _isCountSubscribedUID(name) {
403
- if (!this.subscriptions.uids.hasOwnProperty(name)) {
404
- return false;
405
- }
406
- for (let callbacks = 0; callbacks < this.subscriptions.uids[name].length; callbacks++) {
407
- if (this.subscriptions.uids[name][callbacks][2]) {
408
- return true;
409
- }
410
- }
411
- return false;
412
- }
413
- _unsubscribeQuery(query, callbacks) {
414
- if (!this.subscriptions.queries.hasOwnProperty(query)) {
415
- return;
416
- }
417
- const idx = this.subscriptions.queries[query].indexOf(callbacks);
418
- if (idx === -1) {
419
- return;
420
- }
421
- this.subscriptions.queries[query].splice(idx, 1);
422
- if (!this.subscriptions.queries[query].length) {
423
- delete this.subscriptions.queries[query];
424
- if (this.isConnectionOpen()) {
425
- this._sendUnQuery(query);
426
- }
427
- }
428
- }
429
- _unsubscribeUID(name, callbacks) {
430
- if (!this.subscriptions.uids.hasOwnProperty(name)) {
431
- return;
432
- }
433
- const idx = this.subscriptions.uids[name].indexOf(callbacks);
434
- if (idx === -1) {
435
- return;
436
- }
437
- this.subscriptions.uids[name].splice(idx, 1);
438
- if (!this.subscriptions.uids[name].length) {
439
- delete this.subscriptions.uids[name];
440
- if (this.isConnectionOpen()) {
441
- this._sendUnUID(name);
442
- }
443
- }
444
- }
445
- _sendUnQuery(query) {
446
- this._send({
447
- action: 'unsubscribe',
448
- query: query,
449
- });
450
- }
451
- _sendUnUID(name) {
452
- this._send({
453
- action: 'unsubscribe',
454
- uid: name,
455
- });
456
- }
457
- updateArray(current, update) {
458
- if (Array.isArray(update)) {
459
- const newArr = [...update];
460
- if (current.length === 0) {
461
- // This will happen on the first update from a subscribe.
462
- current.splice(0, 0, ...newArr);
463
- return;
464
- }
465
- const idMap = {};
466
- const newEntities = [];
467
- while (current.length) {
468
- const first = current.shift();
469
- if (!first) {
470
- continue;
471
- }
472
- const guid = first.guid;
473
- if (!guid) {
474
- newEntities.push(first);
475
- continue;
476
- }
477
- idMap[guid] = first;
478
- }
479
- for (let i = 0; i < newArr.length; i++) {
480
- const entity = newArr[i];
481
- const guid = entity.guid;
482
- if (guid == null) {
483
- continue;
484
- }
485
- if (!idMap.hasOwnProperty(guid)) {
486
- // It was added.
487
- current.push(entity);
488
- }
489
- else if (idMap[guid].mdate !== entity.mdate) {
490
- // It was modified.
491
- idMap[guid].$init(entity.toJSON());
492
- current.push(idMap[guid]);
493
- }
494
- else {
495
- // Item wasn't modified.
496
- current.push(idMap[guid]);
497
- }
498
- }
499
- current.splice(current.length, 0, ...newEntities);
500
- }
501
- else if (update != null && update.hasOwnProperty('query')) {
502
- if ('removed' in update) {
503
- for (let i = 0; i < current.length; i++) {
504
- if (current[i] != null && current[i].guid === update.removed) {
505
- current.splice(i, 1);
506
- return;
507
- }
508
- }
509
- }
510
- // Get the entity.
511
- let entity = null;
512
- if ('added' in update) {
513
- // Check for it in the array already.
514
- for (let i = 0; i < current.length; i++) {
515
- if (current[i] != null && current[i].guid === update.added) {
516
- entity = current.splice(i, 1)[0].$init(update.data);
517
- }
518
- }
519
- if (entity == null) {
520
- // A new entity.
521
- entity = this.nymph.initEntity(update.data);
522
- }
523
- }
524
- if ('updated' in update) {
525
- // Extract it from the array.
526
- for (let i = 0; i < current.length; i++) {
527
- if (current[i] != null && current[i].guid === update.updated) {
528
- entity = current.splice(i, 1)[0].$init(update.data);
529
- }
530
- }
531
- }
532
- const query = JSON.parse(update.query);
533
- if (entity != null) {
534
- // Insert the entity in order.
535
- const sort = 'sort' in query[0] ? query[0].sort : 'cdate';
536
- const reverse = query[0].hasOwnProperty('reverse')
537
- ? query[0].reverse
538
- : false;
539
- let i;
540
- if (reverse) {
541
- for (i = 0; ((current[i] ?? {})[sort] ?? 0) >= (entity[sort] ?? 0) &&
542
- i < current.length; i++)
543
- ;
544
- }
545
- else {
546
- for (i = 0; ((current[i] ?? {})[sort] ?? 0) < (entity[sort] ?? 0) &&
547
- i < current.length; i++)
548
- ;
549
- }
550
- current.splice(i, 0, entity);
551
- }
552
- }
553
- }
554
- on(event, callback) {
555
- const prop = (event + 'Callbacks');
556
- if (!(prop in this)) {
557
- throw new Error('Invalid event type.');
558
- }
559
- // @ts-ignore: The callback should always be the right type here.
560
- this[prop].push(callback);
561
- return () => this.off(event, callback);
562
- }
563
- off(event, callback) {
564
- const prop = (event + 'Callbacks');
565
- if (!(prop in this)) {
566
- return false;
567
- }
568
- // @ts-ignore: The callback should always be the right type here.
569
- const i = this[prop].indexOf(callback);
570
- if (i > -1) {
571
- this[prop].splice(i, 1);
572
- }
573
- return true;
574
- }
575
- authenticate(authToken, switchToken = null) {
576
- this.authToken = authToken;
577
- this.switchToken = switchToken;
578
- if (this.isConnectionOpen()) {
579
- this._send({
580
- action: 'authenticate',
581
- authToken: this.authToken,
582
- switchToken: this.switchToken,
583
- });
584
- }
585
- }
586
- }
587
- exports.default = PubSub;
588
- class PubSubSubscription {
589
- constructor(query, callbacks, unsubscribe) {
590
- this.query = query;
591
- this.callbacks = callbacks;
592
- this.unsubscribe = unsubscribe;
593
- }
594
- }
595
- exports.PubSubSubscription = PubSubSubscription;
596
- //# sourceMappingURL=PubSub.js.map