hyperstack-typescript 0.2.5 → 0.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/dist/index.d.ts +75 -37
- package/dist/index.esm.js +212 -185
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +214 -185
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { inflate } from 'pako';
|
|
2
|
+
|
|
1
3
|
const DEFAULT_MAX_ENTRIES_PER_VIEW = 10000;
|
|
2
4
|
const DEFAULT_CONFIG = {
|
|
3
5
|
reconnectIntervals: [1000, 2000, 4000, 8000, 16000],
|
|
@@ -13,16 +15,40 @@ class HyperStackError extends Error {
|
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
|
|
18
|
+
function isCompressedFrame(obj) {
|
|
19
|
+
return (typeof obj === 'object' &&
|
|
20
|
+
obj !== null &&
|
|
21
|
+
obj.compressed === 'gzip' &&
|
|
22
|
+
typeof obj.data === 'string');
|
|
23
|
+
}
|
|
24
|
+
function decompressGzip(base64Data) {
|
|
25
|
+
const binaryString = atob(base64Data);
|
|
26
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
27
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
28
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
29
|
+
}
|
|
30
|
+
const decompressed = inflate(bytes);
|
|
31
|
+
return new TextDecoder().decode(decompressed);
|
|
32
|
+
}
|
|
33
|
+
function parseAndDecompress(jsonString) {
|
|
34
|
+
const parsed = JSON.parse(jsonString);
|
|
35
|
+
if (isCompressedFrame(parsed)) {
|
|
36
|
+
const decompressedJson = decompressGzip(parsed.data);
|
|
37
|
+
const frame = JSON.parse(decompressedJson);
|
|
38
|
+
return frame;
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
16
42
|
function isSnapshotFrame(frame) {
|
|
17
43
|
return frame.op === 'snapshot';
|
|
18
44
|
}
|
|
19
45
|
function parseFrame(data) {
|
|
20
46
|
if (typeof data === 'string') {
|
|
21
|
-
return
|
|
47
|
+
return parseAndDecompress(data);
|
|
22
48
|
}
|
|
23
49
|
const decoder = new TextDecoder('utf-8');
|
|
24
50
|
const jsonString = decoder.decode(data);
|
|
25
|
-
return
|
|
51
|
+
return parseAndDecompress(jsonString);
|
|
26
52
|
}
|
|
27
53
|
async function parseFrameFromBlob(blob) {
|
|
28
54
|
const arrayBuffer = await blob.arrayBuffer();
|
|
@@ -119,6 +145,7 @@ class ConnectionManager {
|
|
|
119
145
|
this.notifyFrameHandlers(frame);
|
|
120
146
|
}
|
|
121
147
|
catch (error) {
|
|
148
|
+
console.error('[hyperstack] Error parsing frame:', error);
|
|
122
149
|
this.updateState('error', 'Failed to parse frame from server');
|
|
123
150
|
}
|
|
124
151
|
};
|
|
@@ -251,57 +278,6 @@ class ConnectionManager {
|
|
|
251
278
|
}
|
|
252
279
|
}
|
|
253
280
|
|
|
254
|
-
class ViewData {
|
|
255
|
-
constructor() {
|
|
256
|
-
this.entities = new Map();
|
|
257
|
-
this.accessOrder = [];
|
|
258
|
-
}
|
|
259
|
-
get(key) {
|
|
260
|
-
return this.entities.get(key);
|
|
261
|
-
}
|
|
262
|
-
set(key, value) {
|
|
263
|
-
if (!this.entities.has(key)) {
|
|
264
|
-
this.accessOrder.push(key);
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
this.touch(key);
|
|
268
|
-
}
|
|
269
|
-
this.entities.set(key, value);
|
|
270
|
-
}
|
|
271
|
-
delete(key) {
|
|
272
|
-
const idx = this.accessOrder.indexOf(key);
|
|
273
|
-
if (idx !== -1) {
|
|
274
|
-
this.accessOrder.splice(idx, 1);
|
|
275
|
-
}
|
|
276
|
-
return this.entities.delete(key);
|
|
277
|
-
}
|
|
278
|
-
has(key) {
|
|
279
|
-
return this.entities.has(key);
|
|
280
|
-
}
|
|
281
|
-
values() {
|
|
282
|
-
return this.entities.values();
|
|
283
|
-
}
|
|
284
|
-
keys() {
|
|
285
|
-
return this.entities.keys();
|
|
286
|
-
}
|
|
287
|
-
get size() {
|
|
288
|
-
return this.entities.size;
|
|
289
|
-
}
|
|
290
|
-
touch(key) {
|
|
291
|
-
const idx = this.accessOrder.indexOf(key);
|
|
292
|
-
if (idx !== -1) {
|
|
293
|
-
this.accessOrder.splice(idx, 1);
|
|
294
|
-
this.accessOrder.push(key);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
evictOldest() {
|
|
298
|
-
const oldest = this.accessOrder.shift();
|
|
299
|
-
if (oldest !== undefined) {
|
|
300
|
-
this.entities.delete(oldest);
|
|
301
|
-
}
|
|
302
|
-
return oldest;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
281
|
function isObject(item) {
|
|
306
282
|
return item !== null && typeof item === 'object' && !Array.isArray(item);
|
|
307
283
|
}
|
|
@@ -331,189 +307,234 @@ function deepMergeWithAppend(target, source, appendPaths, currentPath = '') {
|
|
|
331
307
|
}
|
|
332
308
|
return result;
|
|
333
309
|
}
|
|
334
|
-
class
|
|
335
|
-
constructor(config = {}) {
|
|
336
|
-
this.
|
|
337
|
-
this.updateCallbacks = new Set();
|
|
338
|
-
this.richUpdateCallbacks = new Set();
|
|
310
|
+
class FrameProcessor {
|
|
311
|
+
constructor(storage, config = {}) {
|
|
312
|
+
this.storage = storage;
|
|
339
313
|
this.maxEntriesPerView = config.maxEntriesPerView === undefined
|
|
340
314
|
? DEFAULT_MAX_ENTRIES_PER_VIEW
|
|
341
315
|
: config.maxEntriesPerView;
|
|
342
316
|
}
|
|
343
|
-
enforceMaxEntries(viewData) {
|
|
344
|
-
if (this.maxEntriesPerView === null)
|
|
345
|
-
return;
|
|
346
|
-
while (viewData.size > this.maxEntriesPerView) {
|
|
347
|
-
viewData.evictOldest();
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
317
|
handleFrame(frame) {
|
|
351
318
|
if (isSnapshotFrame(frame)) {
|
|
352
319
|
this.handleSnapshotFrame(frame);
|
|
353
|
-
return;
|
|
354
320
|
}
|
|
355
|
-
|
|
321
|
+
else {
|
|
322
|
+
this.handleEntityFrame(frame);
|
|
323
|
+
}
|
|
356
324
|
}
|
|
357
325
|
handleSnapshotFrame(frame) {
|
|
358
326
|
const viewPath = frame.entity;
|
|
359
|
-
let viewData = this.views.get(viewPath);
|
|
360
|
-
if (!viewData) {
|
|
361
|
-
viewData = new ViewData();
|
|
362
|
-
this.views.set(viewPath, viewData);
|
|
363
|
-
}
|
|
364
327
|
for (const entity of frame.data) {
|
|
365
|
-
const previousValue =
|
|
366
|
-
|
|
367
|
-
this.notifyUpdate(viewPath, entity.key, {
|
|
328
|
+
const previousValue = this.storage.get(viewPath, entity.key);
|
|
329
|
+
this.storage.set(viewPath, entity.key, entity.data);
|
|
330
|
+
this.storage.notifyUpdate(viewPath, entity.key, {
|
|
368
331
|
type: 'upsert',
|
|
369
332
|
key: entity.key,
|
|
370
333
|
data: entity.data,
|
|
371
334
|
});
|
|
372
|
-
this.
|
|
335
|
+
this.emitRichUpdate(viewPath, entity.key, previousValue, entity.data, 'upsert');
|
|
373
336
|
}
|
|
374
|
-
this.enforceMaxEntries(
|
|
337
|
+
this.enforceMaxEntries(viewPath);
|
|
375
338
|
}
|
|
376
339
|
handleEntityFrame(frame) {
|
|
377
340
|
const viewPath = frame.entity;
|
|
378
|
-
|
|
379
|
-
if (!viewData) {
|
|
380
|
-
viewData = new ViewData();
|
|
381
|
-
this.views.set(viewPath, viewData);
|
|
382
|
-
}
|
|
383
|
-
const previousValue = viewData.get(frame.key);
|
|
341
|
+
const previousValue = this.storage.get(viewPath, frame.key);
|
|
384
342
|
switch (frame.op) {
|
|
385
343
|
case 'create':
|
|
386
344
|
case 'upsert':
|
|
387
|
-
|
|
388
|
-
this.enforceMaxEntries(
|
|
389
|
-
this.notifyUpdate(viewPath, frame.key, {
|
|
345
|
+
this.storage.set(viewPath, frame.key, frame.data);
|
|
346
|
+
this.enforceMaxEntries(viewPath);
|
|
347
|
+
this.storage.notifyUpdate(viewPath, frame.key, {
|
|
390
348
|
type: 'upsert',
|
|
391
349
|
key: frame.key,
|
|
392
350
|
data: frame.data,
|
|
393
351
|
});
|
|
394
|
-
this.
|
|
352
|
+
this.emitRichUpdate(viewPath, frame.key, previousValue, frame.data, frame.op);
|
|
395
353
|
break;
|
|
396
354
|
case 'patch': {
|
|
397
|
-
const existing =
|
|
355
|
+
const existing = this.storage.get(viewPath, frame.key);
|
|
398
356
|
const appendPaths = frame.append ?? [];
|
|
399
357
|
const merged = existing
|
|
400
358
|
? deepMergeWithAppend(existing, frame.data, appendPaths)
|
|
401
359
|
: frame.data;
|
|
402
|
-
|
|
403
|
-
this.enforceMaxEntries(
|
|
404
|
-
this.notifyUpdate(viewPath, frame.key, {
|
|
360
|
+
this.storage.set(viewPath, frame.key, merged);
|
|
361
|
+
this.enforceMaxEntries(viewPath);
|
|
362
|
+
this.storage.notifyUpdate(viewPath, frame.key, {
|
|
405
363
|
type: 'patch',
|
|
406
364
|
key: frame.key,
|
|
407
365
|
data: frame.data,
|
|
408
366
|
});
|
|
409
|
-
this.
|
|
367
|
+
this.emitRichUpdate(viewPath, frame.key, previousValue, merged, 'patch', frame.data);
|
|
410
368
|
break;
|
|
411
369
|
}
|
|
412
370
|
case 'delete':
|
|
413
|
-
|
|
414
|
-
this.notifyUpdate(viewPath, frame.key, {
|
|
371
|
+
this.storage.delete(viewPath, frame.key);
|
|
372
|
+
this.storage.notifyUpdate(viewPath, frame.key, {
|
|
415
373
|
type: 'delete',
|
|
416
374
|
key: frame.key,
|
|
417
375
|
});
|
|
418
|
-
if (previousValue !==
|
|
419
|
-
|
|
376
|
+
if (previousValue !== null) {
|
|
377
|
+
const richUpdate = { type: 'deleted', key: frame.key, lastKnown: previousValue };
|
|
378
|
+
this.storage.notifyRichUpdate(viewPath, frame.key, richUpdate);
|
|
420
379
|
}
|
|
421
380
|
break;
|
|
422
381
|
}
|
|
423
382
|
}
|
|
424
|
-
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
383
|
+
emitRichUpdate(viewPath, key, before, after, _op, patch) {
|
|
384
|
+
const richUpdate = before === null
|
|
385
|
+
? { type: 'created', key, data: after }
|
|
386
|
+
: { type: 'updated', key, before, after, patch };
|
|
387
|
+
this.storage.notifyRichUpdate(viewPath, key, richUpdate);
|
|
388
|
+
}
|
|
389
|
+
enforceMaxEntries(viewPath) {
|
|
390
|
+
if (this.maxEntriesPerView === null)
|
|
391
|
+
return;
|
|
392
|
+
if (!this.storage.evictOldest)
|
|
393
|
+
return;
|
|
394
|
+
while (this.storage.size(viewPath) > this.maxEntriesPerView) {
|
|
395
|
+
this.storage.evictOldest(viewPath);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
class ViewData {
|
|
401
|
+
constructor() {
|
|
402
|
+
this.entities = new Map();
|
|
403
|
+
this.accessOrder = [];
|
|
404
|
+
}
|
|
405
|
+
get(key) {
|
|
406
|
+
return this.entities.get(key);
|
|
407
|
+
}
|
|
408
|
+
set(key, value) {
|
|
409
|
+
if (!this.entities.has(key)) {
|
|
410
|
+
this.accessOrder.push(key);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
this.touch(key);
|
|
414
|
+
}
|
|
415
|
+
this.entities.set(key, value);
|
|
416
|
+
}
|
|
417
|
+
delete(key) {
|
|
418
|
+
const idx = this.accessOrder.indexOf(key);
|
|
419
|
+
if (idx !== -1) {
|
|
420
|
+
this.accessOrder.splice(idx, 1);
|
|
421
|
+
}
|
|
422
|
+
return this.entities.delete(key);
|
|
423
|
+
}
|
|
424
|
+
has(key) {
|
|
425
|
+
return this.entities.has(key);
|
|
426
|
+
}
|
|
427
|
+
values() {
|
|
428
|
+
return this.entities.values();
|
|
429
|
+
}
|
|
430
|
+
keys() {
|
|
431
|
+
return this.entities.keys();
|
|
432
|
+
}
|
|
433
|
+
get size() {
|
|
434
|
+
return this.entities.size;
|
|
435
|
+
}
|
|
436
|
+
touch(key) {
|
|
437
|
+
const idx = this.accessOrder.indexOf(key);
|
|
438
|
+
if (idx !== -1) {
|
|
439
|
+
this.accessOrder.splice(idx, 1);
|
|
440
|
+
this.accessOrder.push(key);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
evictOldest() {
|
|
444
|
+
const oldest = this.accessOrder.shift();
|
|
445
|
+
if (oldest !== undefined) {
|
|
446
|
+
this.entities.delete(oldest);
|
|
447
|
+
}
|
|
448
|
+
return oldest;
|
|
449
|
+
}
|
|
450
|
+
clear() {
|
|
451
|
+
this.entities.clear();
|
|
452
|
+
this.accessOrder = [];
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
class MemoryAdapter {
|
|
456
|
+
constructor(_config = {}) {
|
|
457
|
+
this.views = new Map();
|
|
458
|
+
this.updateCallbacks = new Set();
|
|
459
|
+
this.richUpdateCallbacks = new Set();
|
|
429
460
|
}
|
|
430
461
|
get(viewPath, key) {
|
|
431
|
-
const
|
|
432
|
-
if (!
|
|
462
|
+
const view = this.views.get(viewPath);
|
|
463
|
+
if (!view)
|
|
433
464
|
return null;
|
|
434
|
-
const value =
|
|
465
|
+
const value = view.get(key);
|
|
435
466
|
return value !== undefined ? value : null;
|
|
436
467
|
}
|
|
468
|
+
getAll(viewPath) {
|
|
469
|
+
const view = this.views.get(viewPath);
|
|
470
|
+
if (!view)
|
|
471
|
+
return [];
|
|
472
|
+
return Array.from(view.values());
|
|
473
|
+
}
|
|
437
474
|
getAllSync(viewPath) {
|
|
438
|
-
const
|
|
439
|
-
if (!
|
|
475
|
+
const view = this.views.get(viewPath);
|
|
476
|
+
if (!view)
|
|
440
477
|
return undefined;
|
|
441
|
-
return Array.from(
|
|
478
|
+
return Array.from(view.values());
|
|
442
479
|
}
|
|
443
480
|
getSync(viewPath, key) {
|
|
444
|
-
const
|
|
445
|
-
if (!
|
|
481
|
+
const view = this.views.get(viewPath);
|
|
482
|
+
if (!view)
|
|
446
483
|
return undefined;
|
|
447
|
-
const value =
|
|
484
|
+
const value = view.get(key);
|
|
448
485
|
return value !== undefined ? value : null;
|
|
449
486
|
}
|
|
487
|
+
has(viewPath, key) {
|
|
488
|
+
return this.views.get(viewPath)?.has(key) ?? false;
|
|
489
|
+
}
|
|
450
490
|
keys(viewPath) {
|
|
451
|
-
const
|
|
452
|
-
if (!
|
|
491
|
+
const view = this.views.get(viewPath);
|
|
492
|
+
if (!view)
|
|
453
493
|
return [];
|
|
454
|
-
return Array.from(
|
|
494
|
+
return Array.from(view.keys());
|
|
455
495
|
}
|
|
456
496
|
size(viewPath) {
|
|
457
|
-
|
|
458
|
-
return viewData?.size ?? 0;
|
|
497
|
+
return this.views.get(viewPath)?.size ?? 0;
|
|
459
498
|
}
|
|
460
|
-
|
|
461
|
-
this.views.
|
|
499
|
+
set(viewPath, key, data) {
|
|
500
|
+
let view = this.views.get(viewPath);
|
|
501
|
+
if (!view) {
|
|
502
|
+
view = new ViewData();
|
|
503
|
+
this.views.set(viewPath, view);
|
|
504
|
+
}
|
|
505
|
+
view.set(key, data);
|
|
506
|
+
}
|
|
507
|
+
delete(viewPath, key) {
|
|
508
|
+
this.views.get(viewPath)?.delete(key);
|
|
462
509
|
}
|
|
463
|
-
|
|
464
|
-
|
|
510
|
+
clear(viewPath) {
|
|
511
|
+
if (viewPath) {
|
|
512
|
+
this.views.get(viewPath)?.clear();
|
|
513
|
+
this.views.delete(viewPath);
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
this.views.clear();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
evictOldest(viewPath) {
|
|
520
|
+
return this.views.get(viewPath)?.evictOldest();
|
|
465
521
|
}
|
|
466
522
|
onUpdate(callback) {
|
|
467
523
|
this.updateCallbacks.add(callback);
|
|
468
|
-
return () =>
|
|
469
|
-
this.updateCallbacks.delete(callback);
|
|
470
|
-
};
|
|
524
|
+
return () => this.updateCallbacks.delete(callback);
|
|
471
525
|
}
|
|
472
526
|
onRichUpdate(callback) {
|
|
473
527
|
this.richUpdateCallbacks.add(callback);
|
|
474
|
-
return () =>
|
|
475
|
-
this.richUpdateCallbacks.delete(callback);
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
subscribe(viewPath, callback) {
|
|
479
|
-
const handler = (path, _key, update) => {
|
|
480
|
-
if (path === viewPath) {
|
|
481
|
-
callback(update);
|
|
482
|
-
}
|
|
483
|
-
};
|
|
484
|
-
this.updateCallbacks.add(handler);
|
|
485
|
-
return () => {
|
|
486
|
-
this.updateCallbacks.delete(handler);
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
subscribeToKey(viewPath, key, callback) {
|
|
490
|
-
const handler = (path, updateKey, update) => {
|
|
491
|
-
if (path === viewPath && updateKey === key) {
|
|
492
|
-
callback(update);
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
this.updateCallbacks.add(handler);
|
|
496
|
-
return () => {
|
|
497
|
-
this.updateCallbacks.delete(handler);
|
|
498
|
-
};
|
|
528
|
+
return () => this.richUpdateCallbacks.delete(callback);
|
|
499
529
|
}
|
|
500
530
|
notifyUpdate(viewPath, key, update) {
|
|
501
531
|
for (const callback of this.updateCallbacks) {
|
|
502
532
|
callback(viewPath, key, update);
|
|
503
533
|
}
|
|
504
534
|
}
|
|
505
|
-
notifyRichUpdate(viewPath, key,
|
|
506
|
-
const richUpdate = before === undefined
|
|
507
|
-
? { type: 'created', key, data: after }
|
|
508
|
-
: { type: 'updated', key, before, after, patch };
|
|
509
|
-
for (const callback of this.richUpdateCallbacks) {
|
|
510
|
-
callback(viewPath, key, richUpdate);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
notifyRichDelete(viewPath, key, lastKnown) {
|
|
514
|
-
const richUpdate = { type: 'deleted', key, lastKnown };
|
|
535
|
+
notifyRichUpdate(viewPath, key, update) {
|
|
515
536
|
for (const callback of this.richUpdateCallbacks) {
|
|
516
|
-
callback(viewPath, key,
|
|
537
|
+
callback(viewPath, key, update);
|
|
517
538
|
}
|
|
518
539
|
}
|
|
519
540
|
}
|
|
@@ -569,12 +590,12 @@ class SubscriptionRegistry {
|
|
|
569
590
|
}
|
|
570
591
|
|
|
571
592
|
const MAX_QUEUE_SIZE = 1000;
|
|
572
|
-
function createUpdateStream(
|
|
593
|
+
function createUpdateStream(storage, subscriptionRegistry, subscription, keyFilter) {
|
|
573
594
|
return {
|
|
574
595
|
[Symbol.asyncIterator]() {
|
|
575
596
|
const queue = [];
|
|
576
597
|
let waitingResolve = null;
|
|
577
|
-
let
|
|
598
|
+
let unsubscribeStorage = null;
|
|
578
599
|
let unsubscribeRegistry = null;
|
|
579
600
|
let done = false;
|
|
580
601
|
const handler = (viewPath, key, update) => {
|
|
@@ -599,12 +620,12 @@ function createUpdateStream(store, subscriptionRegistry, subscription, keyFilter
|
|
|
599
620
|
}
|
|
600
621
|
};
|
|
601
622
|
const start = () => {
|
|
602
|
-
|
|
623
|
+
unsubscribeStorage = storage.onUpdate(handler);
|
|
603
624
|
unsubscribeRegistry = subscriptionRegistry.subscribe(subscription);
|
|
604
625
|
};
|
|
605
626
|
const cleanup = () => {
|
|
606
627
|
done = true;
|
|
607
|
-
|
|
628
|
+
unsubscribeStorage?.();
|
|
608
629
|
unsubscribeRegistry?.();
|
|
609
630
|
};
|
|
610
631
|
start();
|
|
@@ -633,12 +654,12 @@ function createUpdateStream(store, subscriptionRegistry, subscription, keyFilter
|
|
|
633
654
|
},
|
|
634
655
|
};
|
|
635
656
|
}
|
|
636
|
-
function createRichUpdateStream(
|
|
657
|
+
function createRichUpdateStream(storage, subscriptionRegistry, subscription, keyFilter) {
|
|
637
658
|
return {
|
|
638
659
|
[Symbol.asyncIterator]() {
|
|
639
660
|
const queue = [];
|
|
640
661
|
let waitingResolve = null;
|
|
641
|
-
let
|
|
662
|
+
let unsubscribeStorage = null;
|
|
642
663
|
let unsubscribeRegistry = null;
|
|
643
664
|
let done = false;
|
|
644
665
|
const handler = (viewPath, key, update) => {
|
|
@@ -663,12 +684,12 @@ function createRichUpdateStream(store, subscriptionRegistry, subscription, keyFi
|
|
|
663
684
|
}
|
|
664
685
|
};
|
|
665
686
|
const start = () => {
|
|
666
|
-
|
|
687
|
+
unsubscribeStorage = storage.onRichUpdate(handler);
|
|
667
688
|
unsubscribeRegistry = subscriptionRegistry.subscribe(subscription);
|
|
668
689
|
};
|
|
669
690
|
const cleanup = () => {
|
|
670
691
|
done = true;
|
|
671
|
-
|
|
692
|
+
unsubscribeStorage?.();
|
|
672
693
|
unsubscribeRegistry?.();
|
|
673
694
|
};
|
|
674
695
|
start();
|
|
@@ -698,48 +719,48 @@ function createRichUpdateStream(store, subscriptionRegistry, subscription, keyFi
|
|
|
698
719
|
};
|
|
699
720
|
}
|
|
700
721
|
|
|
701
|
-
function createTypedStateView(viewDef,
|
|
722
|
+
function createTypedStateView(viewDef, storage, subscriptionRegistry) {
|
|
702
723
|
return {
|
|
703
724
|
watch(key) {
|
|
704
|
-
return createUpdateStream(
|
|
725
|
+
return createUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, key }, key);
|
|
705
726
|
},
|
|
706
727
|
watchRich(key) {
|
|
707
|
-
return createRichUpdateStream(
|
|
728
|
+
return createRichUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, key }, key);
|
|
708
729
|
},
|
|
709
730
|
async get(key) {
|
|
710
|
-
return
|
|
731
|
+
return storage.get(viewDef.view, key);
|
|
711
732
|
},
|
|
712
733
|
getSync(key) {
|
|
713
|
-
return
|
|
734
|
+
return storage.getSync(viewDef.view, key);
|
|
714
735
|
},
|
|
715
736
|
};
|
|
716
737
|
}
|
|
717
|
-
function createTypedListView(viewDef,
|
|
738
|
+
function createTypedListView(viewDef, storage, subscriptionRegistry) {
|
|
718
739
|
return {
|
|
719
740
|
watch() {
|
|
720
|
-
return createUpdateStream(
|
|
741
|
+
return createUpdateStream(storage, subscriptionRegistry, { view: viewDef.view });
|
|
721
742
|
},
|
|
722
743
|
watchRich() {
|
|
723
|
-
return createRichUpdateStream(
|
|
744
|
+
return createRichUpdateStream(storage, subscriptionRegistry, { view: viewDef.view });
|
|
724
745
|
},
|
|
725
746
|
async get() {
|
|
726
|
-
return
|
|
747
|
+
return storage.getAll(viewDef.view);
|
|
727
748
|
},
|
|
728
749
|
getSync() {
|
|
729
|
-
return
|
|
750
|
+
return storage.getAllSync(viewDef.view);
|
|
730
751
|
},
|
|
731
752
|
};
|
|
732
753
|
}
|
|
733
|
-
function createTypedViews(stack,
|
|
754
|
+
function createTypedViews(stack, storage, subscriptionRegistry) {
|
|
734
755
|
const views = {};
|
|
735
756
|
for (const [viewName, viewGroup] of Object.entries(stack.views)) {
|
|
736
757
|
const group = viewGroup;
|
|
737
758
|
const typedGroup = {};
|
|
738
759
|
if (group.state) {
|
|
739
|
-
typedGroup.state = createTypedStateView(group.state,
|
|
760
|
+
typedGroup.state = createTypedStateView(group.state, storage, subscriptionRegistry);
|
|
740
761
|
}
|
|
741
762
|
if (group.list) {
|
|
742
|
-
typedGroup.list = createTypedListView(group.list,
|
|
763
|
+
typedGroup.list = createTypedListView(group.list, storage, subscriptionRegistry);
|
|
743
764
|
}
|
|
744
765
|
views[viewName] = typedGroup;
|
|
745
766
|
}
|
|
@@ -749,7 +770,10 @@ function createTypedViews(stack, store, subscriptionRegistry) {
|
|
|
749
770
|
class HyperStack {
|
|
750
771
|
constructor(url, options) {
|
|
751
772
|
this.stack = options.stack;
|
|
752
|
-
this.
|
|
773
|
+
this.storage = options.storage ?? new MemoryAdapter();
|
|
774
|
+
this.processor = new FrameProcessor(this.storage, {
|
|
775
|
+
maxEntriesPerView: options.maxEntriesPerView,
|
|
776
|
+
});
|
|
753
777
|
this.connection = new ConnectionManager({
|
|
754
778
|
websocketUrl: url,
|
|
755
779
|
reconnectIntervals: options.reconnectIntervals,
|
|
@@ -757,9 +781,9 @@ class HyperStack {
|
|
|
757
781
|
});
|
|
758
782
|
this.subscriptionRegistry = new SubscriptionRegistry(this.connection);
|
|
759
783
|
this.connection.onFrame((frame) => {
|
|
760
|
-
this.
|
|
784
|
+
this.processor.handleFrame(frame);
|
|
761
785
|
});
|
|
762
|
-
this._views = createTypedViews(this.stack, this.
|
|
786
|
+
this._views = createTypedViews(this.stack, this.storage, this.subscriptionRegistry);
|
|
763
787
|
}
|
|
764
788
|
static async connect(url, options) {
|
|
765
789
|
if (!url) {
|
|
@@ -783,6 +807,9 @@ class HyperStack {
|
|
|
783
807
|
get stackName() {
|
|
784
808
|
return this.stack.name;
|
|
785
809
|
}
|
|
810
|
+
get store() {
|
|
811
|
+
return this.storage;
|
|
812
|
+
}
|
|
786
813
|
onConnectionStateChange(callback) {
|
|
787
814
|
return this.connection.onStateChange(callback);
|
|
788
815
|
}
|
|
@@ -800,10 +827,10 @@ class HyperStack {
|
|
|
800
827
|
return this.connection.isConnected();
|
|
801
828
|
}
|
|
802
829
|
clearStore() {
|
|
803
|
-
this.
|
|
830
|
+
this.storage.clear();
|
|
804
831
|
}
|
|
805
832
|
getStore() {
|
|
806
|
-
return this.
|
|
833
|
+
return this.storage;
|
|
807
834
|
}
|
|
808
835
|
getConnection() {
|
|
809
836
|
return this.connection;
|
|
@@ -813,5 +840,5 @@ class HyperStack {
|
|
|
813
840
|
}
|
|
814
841
|
}
|
|
815
842
|
|
|
816
|
-
export { ConnectionManager, DEFAULT_CONFIG,
|
|
843
|
+
export { ConnectionManager, DEFAULT_CONFIG, DEFAULT_MAX_ENTRIES_PER_VIEW, FrameProcessor, HyperStack, HyperStackError, MemoryAdapter, SubscriptionRegistry, createRichUpdateStream, createTypedListView, createTypedStateView, createTypedViews, createUpdateStream, isSnapshotFrame, isValidFrame, parseFrame, parseFrameFromBlob };
|
|
817
844
|
//# sourceMappingURL=index.esm.js.map
|