hyperstack-typescript 0.2.5 → 0.3.1

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