@dxos/echo-pipeline 0.1.41 → 0.1.45-next.45667d4

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.
Files changed (74) hide show
  1. package/dist/lib/browser/{chunk-4YAT2XJW.mjs → chunk-2NGLSBL4.mjs} +1128 -1017
  2. package/dist/lib/browser/chunk-2NGLSBL4.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -3
  4. package/dist/lib/browser/index.mjs.map +1 -1
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +72 -48
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/index.cjs +1048 -938
  9. package/dist/lib/node/index.cjs.map +4 -4
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/testing/index.cjs +735 -540
  12. package/dist/lib/node/testing/index.cjs.map +4 -4
  13. package/dist/types/src/dbhost/database-host.d.ts +2 -4
  14. package/dist/types/src/dbhost/database-host.d.ts.map +1 -1
  15. package/dist/types/src/dbhost/snapshot-store.d.ts +2 -0
  16. package/dist/types/src/dbhost/snapshot-store.d.ts.map +1 -1
  17. package/dist/types/src/metadata/metadata-store.d.ts +3 -2
  18. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  19. package/dist/types/src/pipeline/pipeline.d.ts +27 -11
  20. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  21. package/dist/types/src/pipeline/timeframe-clock.d.ts +1 -0
  22. package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
  23. package/dist/types/src/space/auth.d.ts +4 -4
  24. package/dist/types/src/space/auth.d.ts.map +1 -1
  25. package/dist/types/src/space/control-pipeline.d.ts +2 -4
  26. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  27. package/dist/types/src/space/data-pipeline.d.ts +19 -10
  28. package/dist/types/src/space/data-pipeline.d.ts.map +1 -1
  29. package/dist/types/src/space/index.d.ts +0 -1
  30. package/dist/types/src/space/index.d.ts.map +1 -1
  31. package/dist/types/src/space/space-manager.d.ts +14 -14
  32. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  33. package/dist/types/src/space/space-protocol.d.ts +2 -2
  34. package/dist/types/src/space/space-protocol.d.ts.map +1 -1
  35. package/dist/types/src/space/space.d.ts +20 -7
  36. package/dist/types/src/space/space.d.ts.map +1 -1
  37. package/dist/types/src/testing/database-test-rig.d.ts.map +1 -1
  38. package/dist/types/src/testing/test-agent-builder.d.ts +15 -5
  39. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  40. package/package.json +30 -30
  41. package/src/common/feeds.ts +2 -2
  42. package/src/dbhost/data-service-host.ts +10 -10
  43. package/src/dbhost/data-service.ts +1 -1
  44. package/src/dbhost/database-host.ts +1 -9
  45. package/src/dbhost/snapshot-store.test.ts +2 -2
  46. package/src/dbhost/snapshot-store.ts +16 -1
  47. package/src/metadata/metadata-store.ts +14 -16
  48. package/src/pipeline/message-selector.ts +1 -1
  49. package/src/pipeline/pipeline.test.ts +68 -44
  50. package/src/pipeline/pipeline.ts +118 -35
  51. package/src/pipeline/timeframe-clock.ts +8 -2
  52. package/src/space/auth.ts +6 -6
  53. package/src/space/control-pipeline.test.ts +19 -20
  54. package/src/space/control-pipeline.ts +3 -5
  55. package/src/space/data-pipeline.ts +131 -69
  56. package/src/space/index.ts +0 -1
  57. package/src/space/replication.browser.test.ts +8 -8
  58. package/src/space/space-manager.browser.test.ts +3 -3
  59. package/src/space/space-manager.ts +25 -20
  60. package/src/space/space-protocol.browser.test.ts +1 -1
  61. package/src/space/space-protocol.test.ts +6 -6
  62. package/src/space/space-protocol.ts +7 -7
  63. package/src/space/space.test.ts +137 -48
  64. package/src/space/space.ts +82 -40
  65. package/src/testing/database-test-rig.ts +25 -24
  66. package/src/testing/test-agent-builder.ts +88 -49
  67. package/src/testing/test-feed-builder.ts +1 -1
  68. package/src/testing/util.ts +15 -15
  69. package/src/tests/database-unit.test.ts +4 -4
  70. package/src/tests/database.test.ts +1 -1
  71. package/dist/lib/browser/chunk-4YAT2XJW.mjs.map +0 -7
  72. package/dist/types/src/space/genesis.d.ts +0 -5
  73. package/dist/types/src/space/genesis.d.ts.map +0 -1
  74. package/src/space/genesis.ts +0 -69
@@ -42,14 +42,16 @@ __export(testing_exports, {
42
42
  module.exports = __toCommonJS(testing_exports);
43
43
 
44
44
  // packages/core/echo/echo-pipeline/src/testing/test-agent-builder.ts
45
+ var import_credentials5 = require("@dxos/credentials");
45
46
  var import_document_model = require("@dxos/document-model");
46
47
  var import_keys6 = require("@dxos/keys");
47
48
  var import_messaging = require("@dxos/messaging");
48
49
  var import_model_factory = require("@dxos/model-factory");
49
50
  var import_network_manager2 = require("@dxos/network-manager");
51
+ var import_credentials6 = require("@dxos/protocols/proto/dxos/halo/credentials");
50
52
  var import_random_access_storage = require("@dxos/random-access-storage");
51
53
  var import_teleport_extension_gossip = require("@dxos/teleport-extension-gossip");
52
- var import_util7 = require("@dxos/util");
54
+ var import_util8 = require("@dxos/util");
53
55
 
54
56
  // packages/core/echo/echo-pipeline/src/dbhost/data-service-host.ts
55
57
  var import_node_assert = __toESM(require("node:assert"));
@@ -160,9 +162,8 @@ var DataServiceHost = class {
160
162
  // packages/core/echo/echo-pipeline/src/dbhost/database-host.ts
161
163
  var import_echo_db2 = require("@dxos/echo-db");
162
164
  var DatabaseHost = class {
163
- constructor(_outboundStream, _snapshot) {
165
+ constructor(_outboundStream) {
164
166
  this._outboundStream = _outboundStream;
165
- this._snapshot = _snapshot;
166
167
  }
167
168
  get isReadOnly() {
168
169
  return !!this._outboundStream;
@@ -175,9 +176,6 @@ var DatabaseHost = class {
175
176
  this._itemManager._debugLabel = "host";
176
177
  this._itemDemuxer = new import_echo_db2.ItemDemuxer(itemManager, modelFactory);
177
178
  this._echoProcessor = this._itemDemuxer.open();
178
- if (this._snapshot) {
179
- this._itemDemuxer.restoreFromSnapshot(this._snapshot);
180
- }
181
179
  }
182
180
  async close() {
183
181
  }
@@ -287,6 +285,16 @@ var SnapshotStore = class {
287
285
  await file.close();
288
286
  }
289
287
  }
288
+ async listSnapshots() {
289
+ const entries = await this._directory.list();
290
+ return await Promise.all(entries.map(async (key) => {
291
+ const { size } = await this._directory.getOrCreateFile(key).stat();
292
+ return {
293
+ key,
294
+ size
295
+ };
296
+ }));
297
+ }
290
298
  };
291
299
 
292
300
  // packages/core/echo/echo-pipeline/src/dbhost/data-service.ts
@@ -463,13 +471,18 @@ var MetadataStore = class {
463
471
  await file.close();
464
472
  }
465
473
  }
474
+ _getSpace(spaceKey) {
475
+ const space = this.spaces.find((space2) => space2.key === spaceKey);
476
+ (0, import_node_assert3.default)(space, "Space not found");
477
+ return space;
478
+ }
466
479
  /**
467
480
  * Clears storage - doesn't work for now.
468
481
  */
469
482
  async clear() {
470
483
  (0, import_log3.log)("clearing all metadata", {}, {
471
484
  file: "metadata-store.ts",
472
- line: 126,
485
+ line: 132,
473
486
  scope: this,
474
487
  callSite: (f, a) => f(...a)
475
488
  });
@@ -490,20 +503,15 @@ var MetadataStore = class {
490
503
  await this._save();
491
504
  }
492
505
  async setSpaceLatestTimeframe(spaceKey, timeframe) {
493
- const space = this.spaces.find((space2) => space2.key === spaceKey);
494
- (0, import_node_assert3.default)(space, "Space not found");
495
- space.dataTimeframe = timeframe;
506
+ this._getSpace(spaceKey).dataTimeframe = timeframe;
496
507
  await this._save();
497
508
  }
498
- async setSpaceSnapshot(spaceKey, snapshot) {
499
- const space = this.spaces.find((space2) => space2.key === spaceKey);
500
- (0, import_node_assert3.default)(space, "Space not found");
501
- space.snapshot = snapshot;
509
+ async setCache(spaceKey, cache) {
510
+ this._getSpace(spaceKey).cache = cache;
502
511
  await this._save();
503
512
  }
504
513
  async setWritableFeedKeys(spaceKey, controlFeedKey, dataFeedKey) {
505
- const space = this.spaces.find((space2) => space2.key === spaceKey);
506
- (0, import_node_assert3.default)(space, "Space not found");
514
+ const space = this._getSpace(spaceKey);
507
515
  space.controlFeedKey = controlFeedKey;
508
516
  space.dataFeedKey = dataFeedKey;
509
517
  await this._save();
@@ -535,7 +543,6 @@ var AuthExtension = class extends import_teleport.RpcExtension {
535
543
  AuthService: import_protocols4.schema.getService("dxos.mesh.teleport.auth.AuthService")
536
544
  },
537
545
  timeout: 60 * 1e3
538
- // Long timeout because auth can wait for sync in certain cases.
539
546
  });
540
547
  this._authParams = _authParams;
541
548
  this._ctx = new import_context.Context({
@@ -605,20 +612,29 @@ var AuthExtension = class extends import_teleport.RpcExtension {
605
612
  };
606
613
 
607
614
  // packages/core/echo/echo-pipeline/src/space/space.ts
608
- var import_node_assert8 = __toESM(require("node:assert"));
609
- var import_async6 = require("@dxos/async");
610
- var import_log8 = require("@dxos/log");
611
- var import_credentials3 = require("@dxos/protocols/proto/dxos/halo/credentials");
615
+ var import_node_assert9 = __toESM(require("node:assert"));
616
+ var import_async7 = require("@dxos/async");
617
+ var import_log9 = require("@dxos/log");
618
+ var import_credentials4 = require("@dxos/protocols/proto/dxos/halo/credentials");
619
+ var import_util5 = require("@dxos/util");
620
+
621
+ // packages/core/echo/echo-pipeline/src/space/control-pipeline.ts
622
+ var import_credentials = require("@dxos/credentials");
623
+ var import_keys3 = require("@dxos/keys");
624
+ var import_log7 = require("@dxos/log");
625
+ var import_credentials2 = require("@dxos/protocols/proto/dxos/halo/credentials");
612
626
  var import_util4 = require("@dxos/util");
613
627
 
614
628
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
615
629
  var import_node_assert7 = __toESM(require("node:assert"));
616
630
  var import_async5 = require("@dxos/async");
617
631
  var import_context2 = require("@dxos/context");
632
+ var import_debug4 = require("@dxos/debug");
618
633
  var import_feed_store = require("@dxos/feed-store");
619
634
  var import_keys2 = require("@dxos/keys");
620
635
  var import_log6 = require("@dxos/log");
621
636
  var import_timeframe2 = require("@dxos/timeframe");
637
+ var import_util3 = require("@dxos/util");
622
638
 
623
639
  // packages/core/echo/echo-pipeline/src/common/codec.ts
624
640
  var import_hypercore = require("@dxos/hypercore");
@@ -696,6 +712,11 @@ var TimeframeClock = class {
696
712
  get pendingTimeframe() {
697
713
  return this._pendingTimeframe;
698
714
  }
715
+ setTimeframe(timeframe) {
716
+ this._timeframe = timeframe;
717
+ this._pendingTimeframe = timeframe;
718
+ this.update.emit(this._timeframe);
719
+ }
699
720
  updatePendingTimeframe(key, seq) {
700
721
  this._pendingTimeframe = import_timeframe.Timeframe.merge(this._pendingTimeframe, new import_timeframe.Timeframe([
701
722
  [
@@ -713,12 +734,12 @@ var TimeframeClock = class {
713
734
  return !gaps.isEmpty();
714
735
  }
715
736
  async waitUntilReached(target) {
716
- import_log5.log.info("waitUntilReached", {
737
+ (0, import_log5.log)("waitUntilReached", {
717
738
  target,
718
739
  current: this._timeframe
719
740
  }, {
720
741
  file: "timeframe-clock.ts",
721
- line: 67,
742
+ line: 73,
722
743
  scope: this,
723
744
  callSite: (f, a) => f(...a)
724
745
  });
@@ -729,7 +750,7 @@ var TimeframeClock = class {
729
750
  deps: import_timeframe.Timeframe.dependencies(target, this._timeframe)
730
751
  }, {
731
752
  file: "timeframe-clock.ts",
732
- line: 69,
753
+ line: 75,
733
754
  scope: this,
734
755
  callSite: (f, a) => f(...a)
735
756
  });
@@ -754,10 +775,11 @@ var __decorate4 = function(decorators, target, key, desc) {
754
775
  };
755
776
  var PipelineState = class {
756
777
  // prettier-ignore
757
- constructor(_iterator, _timeframeClock) {
758
- this._iterator = _iterator;
778
+ constructor(_feeds, _timeframeClock) {
779
+ this._feeds = _feeds;
759
780
  this._timeframeClock = _timeframeClock;
760
781
  this.timeframeUpdate = this._timeframeClock.update;
782
+ this.stalled = new import_async5.Event();
761
783
  }
762
784
  /**
763
785
  * Latest theoretical timeframe based on the last mutation in each feed.
@@ -765,7 +787,7 @@ var PipelineState = class {
765
787
  */
766
788
  // TODO(dmaretskyi): Rename `totalTimeframe`? or `lastTimeframe`.
767
789
  get endTimeframe() {
768
- return mapFeedIndexesToTimeframe(this._iterator.feeds.filter((feed) => feed.length > 0).map((feed) => ({
790
+ return mapFeedIndexesToTimeframe(Array.from(this._feeds.values()).filter((feed) => feed.length > 0).map((feed) => ({
769
791
  feedKey: feed.key,
770
792
  index: feed.length - 1
771
793
  })));
@@ -780,7 +802,7 @@ var PipelineState = class {
780
802
  return this._targetTimeframe ? this._targetTimeframe : new import_timeframe2.Timeframe();
781
803
  }
782
804
  get feeds() {
783
- return this._iterator.feeds;
805
+ return Array.from(this._feeds.values());
784
806
  }
785
807
  async waitUntilTimeframe(target) {
786
808
  await this._timeframeClock.waitUntilReached(target);
@@ -803,7 +825,7 @@ var PipelineState = class {
803
825
  target: this.targetTimeframe
804
826
  }, {
805
827
  file: "pipeline.ts",
806
- line: 105,
828
+ line: 109,
807
829
  scope: this,
808
830
  callSite: (f, a) => f(...a)
809
831
  });
@@ -812,7 +834,7 @@ var PipelineState = class {
812
834
  return import_timeframe2.Timeframe.dependencies(this.targetTimeframe, this.timeframe).isEmpty();
813
835
  }),
814
836
  ...breakOnStall ? [
815
- this._iterator.stalled.discardParameter().waitForCount(1)
837
+ this.stalled.discardParameter().waitForCount(1)
816
838
  ] : []
817
839
  ]);
818
840
  let done = false;
@@ -833,7 +855,7 @@ var PipelineState = class {
833
855
  dependencies: import_timeframe2.Timeframe.dependencies(this.targetTimeframe, this.timeframe)
834
856
  }, {
835
857
  file: "pipeline.ts",
836
- line: 131,
858
+ line: 135,
837
859
  scope: this,
838
860
  callSite: (f, a) => f(...a)
839
861
  });
@@ -845,25 +867,18 @@ var PipelineState = class {
845
867
  }
846
868
  };
847
869
  var Pipeline = class {
848
- // prettier-ignore
849
- constructor(_initialTimeframe = new import_timeframe2.Timeframe()) {
850
- this._initialTimeframe = _initialTimeframe;
851
- this._timeframeClock = new TimeframeClock(this._initialTimeframe);
852
- this._feedSetIterator = new import_feed_store.FeedSetIterator(createMessageSelector(this._timeframeClock), {
853
- start: startAfter(this._initialTimeframe),
854
- stallTimeout: 1e3
855
- });
856
- this._state = new PipelineState(this._feedSetIterator, this._timeframeClock);
870
+ constructor() {
871
+ this._timeframeClock = new TimeframeClock(new import_timeframe2.Timeframe());
872
+ this._feeds = new import_util3.ComplexMap(import_keys2.PublicKey.hash);
873
+ // External state accessor.
874
+ this._state = new PipelineState(this._feeds, this._timeframeClock);
875
+ // Waits for the message consumer to process the message and yield control back to the pipeline.
857
876
  this._processingTrigger = new import_async5.Trigger().wake();
877
+ this._pauseTrigger = new import_async5.Trigger().wake();
878
+ this._isStopping = false;
879
+ this._isStarted = false;
858
880
  this._isOpen = false;
859
- this._feedSetIterator.stalled.on((iterator) => {
860
- import_log6.log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
861
- file: "pipeline.ts",
862
- line: 207,
863
- scope: this,
864
- callSite: (f, a) => f(...a)
865
- });
866
- });
881
+ this._isPaused = false;
867
882
  }
868
883
  get state() {
869
884
  return this._state;
@@ -878,10 +893,13 @@ var Pipeline = class {
878
893
  // NOTE: This cannot be synchronized with `stop` because stop waits for the mutation processing to complete,
879
894
  // which might be opening feeds during the mutation processing, which w
880
895
  async addFeed(feed) {
881
- await this._feedSetIterator.addFeed(feed);
896
+ this._feeds.set(feed.key, feed);
897
+ if (this._feedSetIterator) {
898
+ await this._feedSetIterator.addFeed(feed);
899
+ }
882
900
  }
883
901
  hasFeed(feedKey) {
884
- return this._feedSetIterator.hasFeed(feedKey);
902
+ return this._feeds.has(feedKey);
885
903
  }
886
904
  setWriteFeed(feed) {
887
905
  (0, import_node_assert7.default)(!this._writer, "Writer already set.");
@@ -894,33 +912,68 @@ var Pipeline = class {
894
912
  async start() {
895
913
  (0, import_log6.log)("starting...", {}, {
896
914
  file: "pipeline.ts",
897
- line: 249,
915
+ line: 254,
898
916
  scope: this,
899
917
  callSite: (f, a) => f(...a)
900
918
  });
919
+ await this._initIterator();
901
920
  await this._feedSetIterator.open();
902
921
  (0, import_log6.log)("started", {}, {
903
922
  file: "pipeline.ts",
904
- line: 251,
923
+ line: 257,
905
924
  scope: this,
906
925
  callSite: (f, a) => f(...a)
907
926
  });
927
+ this._isStarted = true;
908
928
  }
909
929
  async stop() {
930
+ var _a;
910
931
  (0, import_log6.log)("stopping...", {}, {
911
932
  file: "pipeline.ts",
912
- line: 256,
933
+ line: 263,
913
934
  scope: this,
914
935
  callSite: (f, a) => f(...a)
915
936
  });
916
- await this._feedSetIterator.close();
937
+ this._isStopping = true;
938
+ await ((_a = this._feedSetIterator) == null ? void 0 : _a.close());
917
939
  await this._processingTrigger.wait();
918
940
  (0, import_log6.log)("stopped", {}, {
919
941
  file: "pipeline.ts",
920
- line: 259,
942
+ line: 267,
921
943
  scope: this,
922
944
  callSite: (f, a) => f(...a)
923
945
  });
946
+ this._isStarted = false;
947
+ }
948
+ /**
949
+ * @param timeframe Timeframe of already processed messages. The pipeline will start processing messages AFTER this timeframe.
950
+ */
951
+ async setCursor(timeframe) {
952
+ (0, import_node_assert7.default)(!this._isStarted || this._isPaused, "Invalid state.");
953
+ this._timeframeClock.setTimeframe(timeframe);
954
+ if (this._feedSetIterator) {
955
+ await this._feedSetIterator.close();
956
+ await this._initIterator();
957
+ await this._feedSetIterator.open();
958
+ }
959
+ }
960
+ /**
961
+ * Calling pause while processing will cause a deadlock.
962
+ */
963
+ async pause() {
964
+ (0, import_node_assert7.default)(this._isStarted, "Pipeline is not open.");
965
+ if (this._isPaused) {
966
+ return;
967
+ }
968
+ this._pauseTrigger.reset();
969
+ await this._processingTrigger.wait();
970
+ this._isPaused = true;
971
+ }
972
+ async unpause() {
973
+ (0, import_node_assert7.default)(this._isStarted, "Pipeline is not open.");
974
+ (0, import_node_assert7.default)(this._isPaused, "Pipeline is not paused.");
975
+ this._pauseTrigger.wake();
976
+ this._isPaused = false;
924
977
  }
925
978
  /**
926
979
  * Starts to iterate over the ordered messages from the added feeds.
@@ -929,7 +982,21 @@ var Pipeline = class {
929
982
  async *consume() {
930
983
  (0, import_node_assert7.default)(!this._isOpen, "Pipeline is already being consumed.");
931
984
  this._isOpen = true;
932
- for await (const block of this._feedSetIterator) {
985
+ (0, import_node_assert7.default)(this._feedSetIterator, "Iterator not initialized.");
986
+ let lastFeedSetIterator = this._feedSetIterator;
987
+ let iterable = lastFeedSetIterator[Symbol.asyncIterator]();
988
+ while (!this._isStopping) {
989
+ await this._pauseTrigger.wait();
990
+ if (lastFeedSetIterator !== this._feedSetIterator) {
991
+ (0, import_node_assert7.default)(this._feedSetIterator, "Iterator not initialized.");
992
+ lastFeedSetIterator = this._feedSetIterator;
993
+ iterable = lastFeedSetIterator[Symbol.asyncIterator]();
994
+ }
995
+ const { done, value } = await iterable.next();
996
+ if (done) {
997
+ continue;
998
+ }
999
+ const block = value != null ? value : (0, import_debug4.failUndefined)();
933
1000
  this._processingTrigger.reset();
934
1001
  this._timeframeClock.updatePendingTimeframe(import_keys2.PublicKey.from(block.feedKey), block.seq);
935
1002
  yield block;
@@ -938,6 +1005,24 @@ var Pipeline = class {
938
1005
  }
939
1006
  this._isOpen = false;
940
1007
  }
1008
+ async _initIterator() {
1009
+ this._feedSetIterator = new import_feed_store.FeedSetIterator(createMessageSelector(this._timeframeClock), {
1010
+ start: startAfter(this._timeframeClock.timeframe),
1011
+ stallTimeout: 1e3
1012
+ });
1013
+ this._feedSetIterator.stalled.on((iterator) => {
1014
+ import_log6.log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
1015
+ file: "pipeline.ts",
1016
+ line: 357,
1017
+ scope: this,
1018
+ callSite: (f, a) => f(...a)
1019
+ });
1020
+ this._state.stalled.emit();
1021
+ });
1022
+ for (const feed of this._feeds.values()) {
1023
+ await this._feedSetIterator.addFeed(feed);
1024
+ }
1025
+ }
941
1026
  };
942
1027
  __decorate4([
943
1028
  import_async5.synchronized
@@ -945,17 +1030,21 @@ __decorate4([
945
1030
  __decorate4([
946
1031
  import_async5.synchronized
947
1032
  ], Pipeline.prototype, "stop", null);
1033
+ __decorate4([
1034
+ import_async5.synchronized
1035
+ ], Pipeline.prototype, "setCursor", null);
1036
+ __decorate4([
1037
+ import_async5.synchronized
1038
+ ], Pipeline.prototype, "pause", null);
1039
+ __decorate4([
1040
+ import_async5.synchronized
1041
+ ], Pipeline.prototype, "unpause", null);
948
1042
 
949
1043
  // packages/core/echo/echo-pipeline/src/space/control-pipeline.ts
950
- var import_credentials = require("@dxos/credentials");
951
- var import_keys3 = require("@dxos/keys");
952
- var import_log7 = require("@dxos/log");
953
- var import_credentials2 = require("@dxos/protocols/proto/dxos/halo/credentials");
954
- var import_util3 = require("@dxos/util");
955
1044
  var ControlPipeline = class {
956
- constructor({ spaceKey, genesisFeed, feedProvider, initialTimeframe }) {
957
- this.onFeedAdmitted = new import_util3.Callback();
958
- this._pipeline = new Pipeline(initialTimeframe);
1045
+ constructor({ spaceKey, genesisFeed, feedProvider }) {
1046
+ this.onFeedAdmitted = new import_util4.Callback();
1047
+ this._pipeline = new Pipeline();
959
1048
  void this._pipeline.addFeed(genesisFeed);
960
1049
  this._spaceStateMachine = new import_credentials.SpaceStateMachine(spaceKey);
961
1050
  this._spaceStateMachine.onFeedAdmitted.set(async (info) => {
@@ -963,7 +1052,7 @@ var ControlPipeline = class {
963
1052
  key: info.key
964
1053
  }, {
965
1054
  file: "control-pipeline.ts",
966
- line: 41,
1055
+ line: 39,
967
1056
  scope: this,
968
1057
  callSite: (f, a) => f(...a)
969
1058
  });
@@ -974,7 +1063,7 @@ var ControlPipeline = class {
974
1063
  } catch (err) {
975
1064
  import_log7.log.catch(err, {}, {
976
1065
  file: "control-pipeline.ts",
977
- line: 49,
1066
+ line: 47,
978
1067
  scope: this,
979
1068
  callSite: (f, a) => f(...a)
980
1069
  });
@@ -997,7 +1086,7 @@ var ControlPipeline = class {
997
1086
  async start() {
998
1087
  (0, import_log7.log)("starting...", {}, {
999
1088
  file: "control-pipeline.ts",
1000
- line: 73,
1089
+ line: 71,
1001
1090
  scope: this,
1002
1091
  callSite: (f, a) => f(...a)
1003
1092
  });
@@ -1009,7 +1098,7 @@ var ControlPipeline = class {
1009
1098
  seq: msg.seq
1010
1099
  }, {
1011
1100
  file: "control-pipeline.ts",
1012
- line: 78,
1101
+ line: 76,
1013
1102
  scope: this,
1014
1103
  callSite: (f, a) => f(...a)
1015
1104
  });
@@ -1020,7 +1109,7 @@ var ControlPipeline = class {
1020
1109
  msg
1021
1110
  }, {
1022
1111
  file: "control-pipeline.ts",
1023
- line: 85,
1112
+ line: 83,
1024
1113
  scope: this,
1025
1114
  callSite: (f, a) => f(...a)
1026
1115
  });
@@ -1029,7 +1118,7 @@ var ControlPipeline = class {
1029
1118
  } catch (err) {
1030
1119
  import_log7.log.catch(err, {}, {
1031
1120
  file: "control-pipeline.ts",
1032
- line: 89,
1121
+ line: 87,
1033
1122
  scope: this,
1034
1123
  callSite: (f, a) => f(...a)
1035
1124
  });
@@ -1039,7 +1128,7 @@ var ControlPipeline = class {
1039
1128
  await this._pipeline.start();
1040
1129
  (0, import_log7.log)("started", {}, {
1041
1130
  file: "control-pipeline.ts",
1042
- line: 95,
1131
+ line: 93,
1043
1132
  scope: this,
1044
1133
  callSite: (f, a) => f(...a)
1045
1134
  });
@@ -1047,21 +1136,28 @@ var ControlPipeline = class {
1047
1136
  async stop() {
1048
1137
  (0, import_log7.log)("stopping...", {}, {
1049
1138
  file: "control-pipeline.ts",
1050
- line: 99,
1139
+ line: 97,
1051
1140
  scope: this,
1052
1141
  callSite: (f, a) => f(...a)
1053
1142
  });
1054
1143
  await this._pipeline.stop();
1055
1144
  (0, import_log7.log)("stopped", {}, {
1056
1145
  file: "control-pipeline.ts",
1057
- line: 101,
1146
+ line: 99,
1058
1147
  scope: this,
1059
1148
  callSite: (f, a) => f(...a)
1060
1149
  });
1061
1150
  }
1062
1151
  };
1063
1152
 
1064
- // packages/core/echo/echo-pipeline/src/space/space.ts
1153
+ // packages/core/echo/echo-pipeline/src/space/data-pipeline.ts
1154
+ var import_node_assert8 = __toESM(require("node:assert"));
1155
+ var import_async6 = require("@dxos/async");
1156
+ var import_context3 = require("@dxos/context");
1157
+ var import_credentials3 = require("@dxos/credentials");
1158
+ var import_echo_db3 = require("@dxos/echo-db");
1159
+ var import_log8 = require("@dxos/log");
1160
+ var import_timeframe3 = require("@dxos/timeframe");
1065
1161
  var __decorate5 = function(decorators, target, key, desc) {
1066
1162
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1067
1163
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -1072,191 +1168,257 @@ var __decorate5 = function(decorators, target, key, desc) {
1072
1168
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1073
1169
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1074
1170
  };
1075
- var Space = class Space2 {
1076
- constructor({ spaceKey, protocol, genesisFeed, feedProvider }) {
1077
- this._addFeedLock = new import_async6.Lock();
1078
- this.onCredentialProcessed = new import_util4.Callback();
1079
- this.stateUpdate = new import_async6.Event();
1171
+ var MESSAGES_PER_SNAPSHOT = 10;
1172
+ var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1173
+ var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
1174
+ var DataPipeline = class DataPipeline2 {
1175
+ constructor(_params) {
1176
+ this._params = _params;
1177
+ this._ctx = new import_context3.Context();
1178
+ this._lastAutomaticSnapshotTimeframe = new import_timeframe3.Timeframe();
1080
1179
  this._isOpen = false;
1081
- (0, import_node_assert8.default)(spaceKey && feedProvider);
1082
- this._key = spaceKey;
1083
- this._genesisFeedKey = genesisFeed.key;
1084
- this._feedProvider = feedProvider;
1085
- this._controlPipeline = new ControlPipeline({
1086
- spaceKey,
1087
- genesisFeed,
1088
- feedProvider
1089
- });
1090
- this._controlPipeline.onFeedAdmitted.set(async (info) => {
1091
- if (info.assertion.designation === import_credentials3.AdmittedFeed.Designation.DATA) {
1092
- await this._addFeedLock.executeSynchronized(async () => {
1093
- if (this._dataPipeline) {
1094
- if (!this._dataPipeline.hasFeed(info.key)) {
1095
- return this._dataPipeline.addFeed(await this._feedProvider(info.key));
1096
- }
1097
- }
1098
- });
1099
- }
1100
- if (!info.key.equals(genesisFeed.key)) {
1101
- this.protocol.addFeed(await feedProvider(info.key));
1102
- }
1103
- });
1104
- this._controlPipeline.onCredentialProcessed.set(async (credential) => {
1105
- await this.onCredentialProcessed.callIfSet(credential);
1106
- (0, import_log8.log)("onCredentialProcessed", {
1107
- credential
1108
- }, {
1109
- file: "space.ts",
1110
- line: 87,
1111
- scope: this,
1112
- callSite: (f, a) => f(...a)
1113
- });
1114
- this.stateUpdate.emit();
1115
- });
1116
- this.protocol = protocol;
1117
- this.protocol.addFeed(genesisFeed);
1118
- }
1119
- get key() {
1120
- return this._key;
1180
+ this._lastTimeframeSaveTime = 0;
1181
+ this._lastSnapshotSaveTime = 0;
1182
+ this.onNewEpoch = new import_async6.Event();
1121
1183
  }
1122
1184
  get isOpen() {
1123
1185
  return this._isOpen;
1124
1186
  }
1125
- get genesisFeedKey() {
1126
- return this._genesisFeedKey;
1127
- }
1128
- get controlFeedKey() {
1129
- var _a;
1130
- return (_a = this._controlFeed) == null ? void 0 : _a.key;
1187
+ get pipeline() {
1188
+ return this._pipeline;
1131
1189
  }
1132
- get dataFeedKey() {
1190
+ get pipelineState() {
1133
1191
  var _a;
1134
- return (_a = this._dataFeed) == null ? void 0 : _a.key;
1135
- }
1136
- get spaceState() {
1137
- return this._controlPipeline.spaceState;
1138
- }
1139
- /**
1140
- * @test-only
1141
- */
1142
- get controlPipeline() {
1143
- return this._controlPipeline.pipeline;
1144
- }
1145
- setControlFeed(feed) {
1146
- (0, import_node_assert8.default)(!this._controlFeed, "Control feed already set.");
1147
- this._controlFeed = feed;
1148
- this._controlPipeline.setWriteFeed(feed);
1149
- return this;
1192
+ return (_a = this._pipeline) == null ? void 0 : _a.state;
1150
1193
  }
1151
- setDataFeed(feed) {
1194
+ setTargetTimeframe(timeframe) {
1152
1195
  var _a;
1153
- (0, import_node_assert8.default)(!this._dataFeed, "Data feed already set.");
1154
- this._dataFeed = feed;
1155
- (_a = this._dataPipeline) == null ? void 0 : _a.setWriteFeed(feed);
1156
- return this;
1196
+ this._targetTimeframe = timeframe;
1197
+ (_a = this._pipeline) == null ? void 0 : _a.state.setTargetTimeframe(timeframe);
1157
1198
  }
1158
- /**
1159
- * Use for diagnostics.
1160
- */
1161
- getControlFeeds() {
1162
- return Array.from(this._controlPipeline.spaceState.feeds.values());
1199
+ createCredentialProcessor() {
1200
+ return {
1201
+ process: async (credential) => {
1202
+ const assertion = (0, import_credentials3.getCredentialAssertion)(credential);
1203
+ if (assertion["@type"] !== "dxos.halo.credentials.Epoch") {
1204
+ return;
1205
+ }
1206
+ (0, import_log8.log)("new epoch", {
1207
+ credential
1208
+ }, {
1209
+ file: "data-pipeline.ts",
1210
+ line: 110,
1211
+ scope: this,
1212
+ callSite: (f, a) => f(...a)
1213
+ });
1214
+ await this._processEpoch(assertion);
1215
+ this.currentEpoch = credential;
1216
+ this.onNewEpoch.emit(credential);
1217
+ }
1218
+ };
1163
1219
  }
1164
- /**
1165
- * Use for diagnostics.
1166
- */
1167
- // getDataFeeds(): FeedInfo[] {
1168
- // return this._dataPipeline?.getFeeds();
1169
- // }
1170
1220
  async open() {
1171
- (0, import_log8.log)("opening...", {}, {
1172
- file: "space.ts",
1173
- line: 157,
1174
- scope: this,
1175
- callSite: (f, a) => f(...a)
1176
- });
1177
1221
  if (this._isOpen) {
1178
1222
  return;
1179
1223
  }
1180
- await this._controlPipeline.start();
1181
- await this.protocol.start();
1182
- this._isOpen = true;
1183
- (0, import_log8.log)("opened", {}, {
1184
- file: "space.ts",
1185
- line: 167,
1186
- scope: this,
1187
- callSite: (f, a) => f(...a)
1224
+ this._pipeline = new Pipeline();
1225
+ await this._params.onPipelineCreated(this._pipeline);
1226
+ await this._pipeline.start();
1227
+ await this._pipeline.pause();
1228
+ if (this._targetTimeframe) {
1229
+ this._pipeline.state.setTargetTimeframe(this._targetTimeframe);
1230
+ }
1231
+ const feedWriter = {
1232
+ write: (data, options) => {
1233
+ (0, import_node_assert8.default)(this._pipeline, "Pipeline is not initialized.");
1234
+ (0, import_node_assert8.default)(this.currentEpoch, "Epoch is not initialized.");
1235
+ return this._pipeline.writer.write({
1236
+ data
1237
+ }, options);
1238
+ }
1239
+ };
1240
+ this.databaseHost = new DatabaseHost(feedWriter);
1241
+ this.itemManager = new import_echo_db3.ItemManager(this._params.modelFactory);
1242
+ await this.databaseHost.open(this.itemManager, this._params.modelFactory);
1243
+ (0, import_async6.scheduleTask)(this._ctx, async () => {
1244
+ await this._consumePipeline();
1188
1245
  });
1246
+ this._isOpen = true;
1189
1247
  }
1190
1248
  async close() {
1191
- (0, import_log8.log)("closing...", {
1192
- key: this._key
1193
- }, {
1194
- file: "space.ts",
1195
- line: 172,
1196
- scope: this,
1197
- callSite: (f, a) => f(...a)
1198
- });
1249
+ var _a, _b, _c;
1199
1250
  if (!this._isOpen) {
1200
1251
  return;
1201
1252
  }
1202
- await this.protocol.stop();
1203
- await this._controlPipeline.stop();
1204
- this._isOpen = false;
1205
- (0, import_log8.log)("closed", {}, {
1206
- file: "space.ts",
1207
- line: 182,
1253
+ (0, import_log8.log)("close", {}, {
1254
+ file: "data-pipeline.ts",
1255
+ line: 162,
1208
1256
  scope: this,
1209
1257
  callSite: (f, a) => f(...a)
1210
1258
  });
1211
- }
1212
- // TODO(dmaretskyi): Make reusable.
1213
- async createDataPipeline({ start }) {
1214
- (0, import_node_assert8.default)(this._isOpen, "Space must be open to initialize data pipeline.");
1215
- (0, import_node_assert8.default)(!this._dataPipeline, "Data pipeline already initialized.");
1216
- const pipeline = new Pipeline(start);
1217
- if (this._dataFeed) {
1218
- pipeline.setWriteFeed(this._dataFeed);
1219
- }
1220
- this._dataPipeline = pipeline;
1221
- await this._addFeedLock.executeSynchronized(async () => {
1222
- for (const feed of this._controlPipeline.spaceState.feeds.values()) {
1223
- if (feed.assertion.designation === import_credentials3.AdmittedFeed.Designation.DATA && !pipeline.hasFeed(feed.key)) {
1224
- await pipeline.addFeed(await this._feedProvider(feed.key));
1225
- }
1259
+ this._isOpen = false;
1260
+ await this._ctx.dispose();
1261
+ await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1262
+ try {
1263
+ await this._saveCache();
1264
+ if (this._pipeline) {
1265
+ await this._saveTargetTimeframe(this._pipeline.state.timeframe);
1226
1266
  }
1227
- });
1228
- return pipeline;
1267
+ } catch (err) {
1268
+ import_log8.log.catch(err, {}, {
1269
+ file: "data-pipeline.ts",
1270
+ line: 175,
1271
+ scope: this,
1272
+ callSite: (f, a) => f(...a)
1273
+ });
1274
+ }
1275
+ await ((_b = this.databaseHost) == null ? void 0 : _b.close());
1276
+ await ((_c = this.itemManager) == null ? void 0 : _c.destroy());
1277
+ await this._params.snapshotManager.close();
1229
1278
  }
1230
- };
1231
- __decorate5([
1232
- import_log8.logInfo
1233
- ], Space.prototype, "key", null);
1234
- __decorate5([
1235
- import_async6.synchronized
1236
- ], Space.prototype, "open", null);
1237
- __decorate5([
1238
- import_async6.synchronized
1239
- ], Space.prototype, "close", null);
1240
- Space = __decorate5([
1241
- (0, import_async6.trackLeaks)("open", "close")
1242
- ], Space);
1243
-
1244
- // packages/core/echo/echo-pipeline/src/space/space-manager.ts
1245
- var import_async7 = require("@dxos/async");
1246
- var import_debug4 = require("@dxos/debug");
1247
- var import_keys5 = require("@dxos/keys");
1248
- var import_log10 = require("@dxos/log");
1249
- var import_protocols6 = require("@dxos/protocols");
1250
- var import_util6 = require("@dxos/util");
1251
-
1252
- // packages/core/echo/echo-pipeline/src/space/space-protocol.ts
1253
- var import_crypto3 = require("@dxos/crypto");
1254
- var import_keys4 = require("@dxos/keys");
1255
- var import_log9 = require("@dxos/log");
1256
- var import_network_manager = require("@dxos/network-manager");
1257
- var import_teleport2 = require("@dxos/teleport");
1258
- var import_teleport_extension_replicator = require("@dxos/teleport-extension-replicator");
1259
- var import_util5 = require("@dxos/util");
1279
+ async _consumePipeline() {
1280
+ (0, import_node_assert8.default)(this._pipeline, "Pipeline is not initialized.");
1281
+ for await (const msg of this._pipeline.consume()) {
1282
+ const { feedKey, seq, data } = msg;
1283
+ (0, import_log8.log)("processing message", {
1284
+ feedKey,
1285
+ seq
1286
+ }, {
1287
+ file: "data-pipeline.ts",
1288
+ line: 187,
1289
+ scope: this,
1290
+ callSite: (f, a) => f(...a)
1291
+ });
1292
+ try {
1293
+ if (data.payload.data) {
1294
+ const feedInfo = this._params.feedInfoProvider(feedKey);
1295
+ if (!feedInfo) {
1296
+ import_log8.log.error("Could not find feed.", {
1297
+ feedKey
1298
+ }, {
1299
+ file: "data-pipeline.ts",
1300
+ line: 193,
1301
+ scope: this,
1302
+ callSite: (f, a) => f(...a)
1303
+ });
1304
+ continue;
1305
+ }
1306
+ await this.databaseHost.echoProcessor({
1307
+ batch: data.payload.data.batch,
1308
+ meta: {
1309
+ feedKey,
1310
+ seq,
1311
+ timeframe: data.timeframe,
1312
+ memberKey: feedInfo.assertion.identityKey
1313
+ }
1314
+ });
1315
+ await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1316
+ }
1317
+ } catch (err) {
1318
+ import_log8.log.catch(err, {}, {
1319
+ file: "data-pipeline.ts",
1320
+ line: 211,
1321
+ scope: this,
1322
+ callSite: (f, a) => f(...a)
1323
+ });
1324
+ }
1325
+ }
1326
+ }
1327
+ _createSnapshot() {
1328
+ (0, import_node_assert8.default)(this.databaseHost, "Database backend is not initialized.");
1329
+ return {
1330
+ spaceKey: this._params.spaceKey.asUint8Array(),
1331
+ timeframe: this._pipeline.state.timeframe,
1332
+ database: this.databaseHost.createSnapshot()
1333
+ };
1334
+ }
1335
+ async _saveTargetTimeframe(timeframe) {
1336
+ var _a;
1337
+ const newTimeframe = import_timeframe3.Timeframe.merge((_a = this._targetTimeframe) != null ? _a : new import_timeframe3.Timeframe(), timeframe);
1338
+ await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1339
+ this._targetTimeframe = newTimeframe;
1340
+ }
1341
+ async _saveCache() {
1342
+ var _a;
1343
+ const cache = {};
1344
+ try {
1345
+ const propertiesItem = this.itemManager.items.find((item) => {
1346
+ var _a2, _b;
1347
+ return ((_a2 = item.modelMeta) == null ? void 0 : _a2.type) === "dxos:model/document" && ((_b = (0, import_echo_db3.getStateMachineFromItem)(item)) == null ? void 0 : _b.snapshot().type) === "dxos.sdk.client.Properties";
1348
+ });
1349
+ if (propertiesItem) {
1350
+ cache.properties = (_a = (0, import_echo_db3.getStateMachineFromItem)(propertiesItem)) == null ? void 0 : _a.snapshot();
1351
+ }
1352
+ } catch (err) {
1353
+ import_log8.log.warn("Failed to cache properties", err, {
1354
+ file: "data-pipeline.ts",
1355
+ line: 245,
1356
+ scope: this,
1357
+ callSite: (f, a) => f(...a)
1358
+ });
1359
+ }
1360
+ await this._params.metadataStore.setCache(this._params.spaceKey, cache);
1361
+ }
1362
+ async _noteTargetStateIfNeeded(timeframe) {
1363
+ if (Date.now() - this._lastTimeframeSaveTime > TIMEFRAME_SAVE_DEBOUNCE_INTERVAL) {
1364
+ this._lastTimeframeSaveTime = Date.now();
1365
+ await this._saveTargetTimeframe(timeframe);
1366
+ }
1367
+ if (Date.now() - this._lastSnapshotSaveTime > AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL && timeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1368
+ await this._saveCache();
1369
+ }
1370
+ }
1371
+ async _processEpoch(epoch) {
1372
+ (0, import_node_assert8.default)(this._isOpen);
1373
+ (0, import_node_assert8.default)(this._pipeline);
1374
+ if (epoch.snapshotCid) {
1375
+ const snapshot = await this._params.snapshotManager.load(epoch.snapshotCid);
1376
+ this.databaseHost._itemDemuxer.restoreFromSnapshot(snapshot.database);
1377
+ }
1378
+ await this._pipeline.pause();
1379
+ await this._pipeline.setCursor(epoch.timeframe);
1380
+ await this._pipeline.unpause();
1381
+ }
1382
+ async waitUntilTimeframe(timeframe) {
1383
+ (0, import_node_assert8.default)(this._pipeline, "Pipeline is not initialized.");
1384
+ await this._pipeline.state.waitUntilTimeframe(timeframe);
1385
+ }
1386
+ async createEpoch() {
1387
+ (0, import_node_assert8.default)(this._pipeline);
1388
+ (0, import_node_assert8.default)(this.currentEpoch);
1389
+ await this._pipeline.pause();
1390
+ const snapshot = await this._createSnapshot();
1391
+ const snapshotCid = await this._params.snapshotManager.store(snapshot);
1392
+ const epoch = {
1393
+ previousId: this.currentEpoch.id,
1394
+ timeframe: this._pipeline.state.timeframe,
1395
+ number: this.currentEpoch.subject.assertion.number + 1,
1396
+ snapshotCid
1397
+ };
1398
+ await this._pipeline.unpause();
1399
+ return epoch;
1400
+ }
1401
+ async ensureEpochInitialized() {
1402
+ await this.onNewEpoch.waitForCondition(() => !!this.currentEpoch);
1403
+ }
1404
+ };
1405
+ __decorate5([
1406
+ import_async6.synchronized
1407
+ ], DataPipeline.prototype, "open", null);
1408
+ __decorate5([
1409
+ import_async6.synchronized
1410
+ ], DataPipeline.prototype, "close", null);
1411
+ __decorate5([
1412
+ import_async6.synchronized
1413
+ ], DataPipeline.prototype, "_processEpoch", null);
1414
+ __decorate5([
1415
+ import_async6.synchronized
1416
+ ], DataPipeline.prototype, "createEpoch", null);
1417
+ DataPipeline = __decorate5([
1418
+ (0, import_async6.trackLeaks)("open", "close")
1419
+ ], DataPipeline);
1420
+
1421
+ // packages/core/echo/echo-pipeline/src/space/space.ts
1260
1422
  var __decorate6 = function(decorators, target, key, desc) {
1261
1423
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1262
1424
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -1267,12 +1429,235 @@ var __decorate6 = function(decorators, target, key, desc) {
1267
1429
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1268
1430
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1269
1431
  };
1432
+ var Space = class Space2 {
1433
+ constructor(params) {
1434
+ this._addFeedLock = new import_async7.Lock();
1435
+ this.onCredentialProcessed = new import_util5.Callback();
1436
+ this.stateUpdate = new import_async7.Event();
1437
+ // Processes epoch credentials.
1438
+ this._dataPipelineCredentialConsumer = void 0;
1439
+ this._isOpen = false;
1440
+ (0, import_node_assert9.default)(params.spaceKey && params.feedProvider);
1441
+ this._key = params.spaceKey;
1442
+ this._genesisFeedKey = params.genesisFeed.key;
1443
+ this._feedProvider = params.feedProvider;
1444
+ this._snapshotManager = params.snapshotManager;
1445
+ this._controlPipeline = new ControlPipeline({
1446
+ spaceKey: params.spaceKey,
1447
+ genesisFeed: params.genesisFeed,
1448
+ feedProvider: params.feedProvider
1449
+ });
1450
+ this._controlPipeline.onFeedAdmitted.set(async (info) => {
1451
+ if (info.assertion.designation === import_credentials4.AdmittedFeed.Designation.DATA) {
1452
+ await this._addFeedLock.executeSynchronized(async () => {
1453
+ if (this._dataPipeline.pipeline) {
1454
+ if (!this._dataPipeline.pipeline.hasFeed(info.key)) {
1455
+ return this._dataPipeline.pipeline.addFeed(await this._feedProvider(info.key));
1456
+ }
1457
+ }
1458
+ });
1459
+ }
1460
+ if (!info.key.equals(params.genesisFeed.key)) {
1461
+ this.protocol.addFeed(await params.feedProvider(info.key));
1462
+ }
1463
+ });
1464
+ this._controlPipeline.onCredentialProcessed.set(async (credential) => {
1465
+ await this.onCredentialProcessed.callIfSet(credential);
1466
+ (0, import_log9.log)("onCredentialProcessed", {
1467
+ credential
1468
+ }, {
1469
+ file: "space.ts",
1470
+ line: 106,
1471
+ scope: this,
1472
+ callSite: (f, a) => f(...a)
1473
+ });
1474
+ this.stateUpdate.emit();
1475
+ });
1476
+ this.protocol = params.protocol;
1477
+ this.protocol.addFeed(params.genesisFeed);
1478
+ this._dataPipeline = new DataPipeline({
1479
+ modelFactory: params.modelFactory,
1480
+ metadataStore: params.metadataStore,
1481
+ snapshotManager: params.snapshotManager,
1482
+ memberKey: params.memberKey,
1483
+ spaceKey: this._key,
1484
+ feedInfoProvider: (feedKey) => this._controlPipeline.spaceState.feeds.get(feedKey),
1485
+ snapshotId: params.snapshotId,
1486
+ onPipelineCreated: async (pipeline) => {
1487
+ if (this._dataFeed) {
1488
+ pipeline.setWriteFeed(this._dataFeed);
1489
+ }
1490
+ await this._addFeedLock.executeSynchronized(async () => {
1491
+ for (const feed of this._controlPipeline.spaceState.feeds.values()) {
1492
+ if (feed.assertion.designation === import_credentials4.AdmittedFeed.Designation.DATA && !pipeline.hasFeed(feed.key)) {
1493
+ await pipeline.addFeed(await this._feedProvider(feed.key));
1494
+ }
1495
+ }
1496
+ });
1497
+ }
1498
+ });
1499
+ }
1500
+ get key() {
1501
+ return this._key;
1502
+ }
1503
+ get isOpen() {
1504
+ return this._isOpen;
1505
+ }
1506
+ get genesisFeedKey() {
1507
+ return this._genesisFeedKey;
1508
+ }
1509
+ get controlFeedKey() {
1510
+ var _a;
1511
+ return (_a = this._controlFeed) == null ? void 0 : _a.key;
1512
+ }
1513
+ get dataFeedKey() {
1514
+ var _a;
1515
+ return (_a = this._dataFeed) == null ? void 0 : _a.key;
1516
+ }
1517
+ get spaceState() {
1518
+ return this._controlPipeline.spaceState;
1519
+ }
1520
+ /**
1521
+ * @test-only
1522
+ */
1523
+ get controlPipeline() {
1524
+ return this._controlPipeline.pipeline;
1525
+ }
1526
+ get dataPipeline() {
1527
+ return this._dataPipeline;
1528
+ }
1529
+ get snapshotManager() {
1530
+ return this._snapshotManager;
1531
+ }
1532
+ setControlFeed(feed) {
1533
+ (0, import_node_assert9.default)(!this._controlFeed, "Control feed already set.");
1534
+ this._controlFeed = feed;
1535
+ this._controlPipeline.setWriteFeed(feed);
1536
+ return this;
1537
+ }
1538
+ setDataFeed(feed) {
1539
+ var _a;
1540
+ (0, import_node_assert9.default)(!this._dataFeed, "Data feed already set.");
1541
+ this._dataFeed = feed;
1542
+ (_a = this._dataPipeline.pipeline) == null ? void 0 : _a.setWriteFeed(feed);
1543
+ return this;
1544
+ }
1545
+ /**
1546
+ * Use for diagnostics.
1547
+ */
1548
+ getControlFeeds() {
1549
+ return Array.from(this._controlPipeline.spaceState.feeds.values());
1550
+ }
1551
+ /**
1552
+ * Use for diagnostics.
1553
+ */
1554
+ // getDataFeeds(): FeedInfo[] {
1555
+ // return this._dataPipeline?.getFeeds();
1556
+ // }
1557
+ async open() {
1558
+ (0, import_log9.log)("opening...", {}, {
1559
+ file: "space.ts",
1560
+ line: 208,
1561
+ scope: this,
1562
+ callSite: (f, a) => f(...a)
1563
+ });
1564
+ if (this._isOpen) {
1565
+ return;
1566
+ }
1567
+ await this._controlPipeline.start();
1568
+ await this.protocol.start();
1569
+ this._dataPipelineCredentialConsumer = this._controlPipeline.spaceState.registerProcessor(this._dataPipeline.createCredentialProcessor());
1570
+ this._isOpen = true;
1571
+ (0, import_log9.log)("opened", {}, {
1572
+ file: "space.ts",
1573
+ line: 222,
1574
+ scope: this,
1575
+ callSite: (f, a) => f(...a)
1576
+ });
1577
+ }
1578
+ async close() {
1579
+ var _a;
1580
+ (0, import_log9.log)("closing...", {
1581
+ key: this._key
1582
+ }, {
1583
+ file: "space.ts",
1584
+ line: 227,
1585
+ scope: this,
1586
+ callSite: (f, a) => f(...a)
1587
+ });
1588
+ if (!this._isOpen) {
1589
+ return;
1590
+ }
1591
+ await ((_a = this._dataPipelineCredentialConsumer) == null ? void 0 : _a.close());
1592
+ this._dataPipelineCredentialConsumer = void 0;
1593
+ await this._dataPipeline.close();
1594
+ await this.protocol.stop();
1595
+ await this._controlPipeline.stop();
1596
+ this._isOpen = false;
1597
+ (0, import_log9.log)("closed", {}, {
1598
+ file: "space.ts",
1599
+ line: 241,
1600
+ scope: this,
1601
+ callSite: (f, a) => f(...a)
1602
+ });
1603
+ }
1604
+ async initializeDataPipeline() {
1605
+ import_log9.log.info("initializeDataPipeline", {}, {
1606
+ file: "space.ts",
1607
+ line: 245,
1608
+ scope: this,
1609
+ callSite: (f, a) => f(...a)
1610
+ });
1611
+ (0, import_node_assert9.default)(this._isOpen, "Space must be open to initialize data pipeline.");
1612
+ await this._dataPipeline.open();
1613
+ await this._dataPipelineCredentialConsumer.open();
1614
+ }
1615
+ };
1616
+ __decorate6([
1617
+ import_log9.logInfo
1618
+ ], Space.prototype, "key", null);
1619
+ __decorate6([
1620
+ import_async7.synchronized
1621
+ ], Space.prototype, "open", null);
1622
+ __decorate6([
1623
+ import_async7.synchronized
1624
+ ], Space.prototype, "close", null);
1625
+ Space = __decorate6([
1626
+ (0, import_async7.trackLeaks)("open", "close")
1627
+ ], Space);
1628
+
1629
+ // packages/core/echo/echo-pipeline/src/space/space-manager.ts
1630
+ var import_async8 = require("@dxos/async");
1631
+ var import_debug5 = require("@dxos/debug");
1632
+ var import_keys5 = require("@dxos/keys");
1633
+ var import_log11 = require("@dxos/log");
1634
+ var import_protocols6 = require("@dxos/protocols");
1635
+ var import_util7 = require("@dxos/util");
1636
+
1637
+ // packages/core/echo/echo-pipeline/src/space/space-protocol.ts
1638
+ var import_crypto3 = require("@dxos/crypto");
1639
+ var import_keys4 = require("@dxos/keys");
1640
+ var import_log10 = require("@dxos/log");
1641
+ var import_network_manager = require("@dxos/network-manager");
1642
+ var import_teleport2 = require("@dxos/teleport");
1643
+ var import_teleport_extension_replicator = require("@dxos/teleport-extension-replicator");
1644
+ var import_util6 = require("@dxos/util");
1645
+ var __decorate7 = function(decorators, target, key, desc) {
1646
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1647
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1648
+ r = Reflect.decorate(decorators, target, key, desc);
1649
+ else
1650
+ for (var i = decorators.length - 1; i >= 0; i--)
1651
+ if (d = decorators[i])
1652
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1653
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1654
+ };
1270
1655
  var MOCK_AUTH_PROVIDER = async (nonce) => Buffer.from("mock");
1271
1656
  var MOCK_AUTH_VERIFIER = async (nonce, credential) => true;
1272
1657
  var SpaceProtocol = class {
1273
1658
  constructor({ topic, swarmIdentity, networkManager, onSessionAuth }) {
1274
1659
  this._feeds = /* @__PURE__ */ new Set();
1275
- this._sessions = new import_util5.ComplexMap(import_keys4.PublicKey.hash);
1660
+ this._sessions = new import_util6.ComplexMap(import_keys4.PublicKey.hash);
1276
1661
  this._networkManager = networkManager;
1277
1662
  this._swarmIdentity = swarmIdentity;
1278
1663
  this._onSessionAuth = onSessionAuth;
@@ -1289,7 +1674,7 @@ var SpaceProtocol = class {
1289
1674
  }
1290
1675
  // TODO(burdon): Create abstraction for Space (e.g., add keys and have provider).
1291
1676
  addFeed(feed) {
1292
- (0, import_log9.log)("addFeed", {
1677
+ (0, import_log10.log)("addFeed", {
1293
1678
  key: feed.key
1294
1679
  }, {
1295
1680
  file: "space-protocol.ts",
@@ -1312,7 +1697,7 @@ var SpaceProtocol = class {
1312
1697
  maxPeers: 10,
1313
1698
  sampleSize: 20
1314
1699
  };
1315
- (0, import_log9.log)("starting...", {}, {
1700
+ (0, import_log10.log)("starting...", {}, {
1316
1701
  file: "space-protocol.ts",
1317
1702
  line: 107,
1318
1703
  scope: this,
@@ -1325,7 +1710,7 @@ var SpaceProtocol = class {
1325
1710
  topology: new import_network_manager.MMSTTopology(topologyConfig),
1326
1711
  label: `Protocol swarm: ${this._topic}`
1327
1712
  });
1328
- (0, import_log9.log)("started", {}, {
1713
+ (0, import_log10.log)("started", {}, {
1329
1714
  file: "space-protocol.ts",
1330
1715
  line: 116,
1331
1716
  scope: this,
@@ -1334,14 +1719,14 @@ var SpaceProtocol = class {
1334
1719
  }
1335
1720
  async stop() {
1336
1721
  if (this._connection) {
1337
- (0, import_log9.log)("stopping...", {}, {
1722
+ (0, import_log10.log)("stopping...", {}, {
1338
1723
  file: "space-protocol.ts",
1339
1724
  line: 121,
1340
1725
  scope: this,
1341
1726
  callSite: (f, a) => f(...a)
1342
1727
  });
1343
1728
  await this._connection.close();
1344
- (0, import_log9.log)("stopped", {}, {
1729
+ (0, import_log10.log)("stopped", {}, {
1345
1730
  file: "space-protocol.ts",
1346
1731
  line: 123,
1347
1732
  scope: this,
@@ -1364,11 +1749,11 @@ var SpaceProtocol = class {
1364
1749
  };
1365
1750
  }
1366
1751
  };
1367
- __decorate6([
1368
- import_log9.logInfo
1752
+ __decorate7([
1753
+ import_log10.logInfo
1369
1754
  ], SpaceProtocol.prototype, "_topic", void 0);
1370
- __decorate6([
1371
- import_log9.logInfo
1755
+ __decorate7([
1756
+ import_log10.logInfo
1372
1757
  ], SpaceProtocol.prototype, "_ownPeerKey", null);
1373
1758
  var AuthStatus;
1374
1759
  (function(AuthStatus2) {
@@ -1403,7 +1788,7 @@ var SpaceProtocolSession = class {
1403
1788
  onAuthSuccess: () => {
1404
1789
  var _a;
1405
1790
  this._authStatus = AuthStatus.SUCCESS;
1406
- (0, import_log9.log)("Peer authenticated", {}, {
1791
+ (0, import_log10.log)("Peer authenticated", {}, {
1407
1792
  file: "space-protocol.ts",
1408
1793
  line: 206,
1409
1794
  scope: this,
@@ -1412,7 +1797,7 @@ var SpaceProtocolSession = class {
1412
1797
  (_a = this._onSessionAuth) == null ? void 0 : _a.call(this, this._teleport);
1413
1798
  },
1414
1799
  onAuthFailure: () => {
1415
- import_log9.log.warn("Auth failed", {}, {
1800
+ import_log10.log.warn("Auth failed", {}, {
1416
1801
  file: "space-protocol.ts",
1417
1802
  line: 211,
1418
1803
  scope: this,
@@ -1427,15 +1812,15 @@ var SpaceProtocolSession = class {
1427
1812
  await this._teleport.close();
1428
1813
  }
1429
1814
  };
1430
- __decorate6([
1431
- import_log9.logInfo
1815
+ __decorate7([
1816
+ import_log10.logInfo
1432
1817
  ], SpaceProtocolSession.prototype, "_wireParams", void 0);
1433
- __decorate6([
1434
- import_log9.logInfo
1818
+ __decorate7([
1819
+ import_log10.logInfo
1435
1820
  ], SpaceProtocolSession.prototype, "authStatus", null);
1436
1821
 
1437
1822
  // packages/core/echo/echo-pipeline/src/space/space-manager.ts
1438
- var __decorate7 = function(decorators, target, key, desc) {
1823
+ var __decorate8 = function(decorators, target, key, desc) {
1439
1824
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1440
1825
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1441
1826
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1446,51 +1831,45 @@ var __decorate7 = function(decorators, target, key, desc) {
1446
1831
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1447
1832
  };
1448
1833
  var SpaceManager = class SpaceManager2 {
1449
- constructor({ feedStore, networkManager }) {
1450
- this._spaces = new import_util6.ComplexMap(import_keys5.PublicKey.hash);
1834
+ constructor({ feedStore, networkManager, modelFactory, metadataStore, snapshotStore }) {
1835
+ this._spaces = new import_util7.ComplexMap(import_keys5.PublicKey.hash);
1451
1836
  this._instanceId = import_keys5.PublicKey.random().toHex();
1452
1837
  this._feedStore = feedStore;
1453
1838
  this._networkManager = networkManager;
1839
+ this._modelFactory = modelFactory;
1840
+ this._metadataStore = metadataStore;
1841
+ this._snapshotStore = snapshotStore;
1454
1842
  }
1455
1843
  // TODO(burdon): Remove.
1456
1844
  get spaces() {
1457
1845
  return this._spaces;
1458
1846
  }
1459
1847
  async open() {
1460
- import_log10.log.trace("dxos.echo.space-manager", import_protocols6.trace.begin({
1461
- id: this._instanceId,
1462
- parentId: this._traceParent
1463
- }), {
1464
- file: "space-manager.ts",
1465
- line: 66,
1466
- scope: this,
1467
- callSite: (f, a) => f(...a)
1468
- });
1469
1848
  }
1470
1849
  async close() {
1471
1850
  await Promise.all([
1472
1851
  ...this._spaces.values()
1473
1852
  ].map((space) => space.close()));
1474
- import_log10.log.trace("dxos.echo.space-manager", import_protocols6.trace.end({
1853
+ }
1854
+ async constructSpace({ metadata, swarmIdentity, onNetworkConnection, memberKey }) {
1855
+ var _a;
1856
+ import_log11.log.trace("dxos.echo.space-manager.construct-space", import_protocols6.trace.begin({
1475
1857
  id: this._instanceId
1476
1858
  }), {
1477
1859
  file: "space-manager.ts",
1478
- line: 72,
1860
+ line: 74,
1479
1861
  scope: this,
1480
1862
  callSite: (f, a) => f(...a)
1481
1863
  });
1482
- }
1483
- async constructSpace({ metadata, swarmIdentity, onNetworkConnection }) {
1484
- var _a;
1485
- (0, import_log10.log)("constructing space...", {
1864
+ (0, import_log11.log)("constructing space...", {
1486
1865
  spaceKey: metadata.genesisFeedKey
1487
1866
  }, {
1488
1867
  file: "space-manager.ts",
1489
- line: 76,
1868
+ line: 75,
1490
1869
  scope: this,
1491
1870
  callSite: (f, a) => f(...a)
1492
1871
  });
1493
- const genesisFeed = await this._feedStore.openFeed((_a = metadata.genesisFeedKey) != null ? _a : (0, import_debug4.failUndefined)());
1872
+ const genesisFeed = await this._feedStore.openFeed((_a = metadata.genesisFeedKey) != null ? _a : (0, import_debug5.failUndefined)());
1494
1873
  const spaceKey = metadata.key;
1495
1874
  const protocol = new SpaceProtocol({
1496
1875
  topic: spaceKey,
@@ -1498,247 +1877,38 @@ var SpaceManager = class SpaceManager2 {
1498
1877
  networkManager: this._networkManager,
1499
1878
  onSessionAuth: onNetworkConnection
1500
1879
  });
1880
+ const snapshotManager = new SnapshotManager(this._snapshotStore);
1501
1881
  const space = new Space({
1502
1882
  spaceKey,
1503
1883
  protocol,
1504
1884
  genesisFeed,
1505
- feedProvider: (feedKey) => this._feedStore.openFeed(feedKey)
1885
+ feedProvider: (feedKey) => this._feedStore.openFeed(feedKey),
1886
+ modelFactory: this._modelFactory,
1887
+ metadataStore: this._metadataStore,
1888
+ snapshotManager,
1889
+ memberKey
1506
1890
  });
1507
1891
  this._spaces.set(space.key, space);
1508
- return space;
1509
- }
1510
- };
1511
- __decorate7([
1512
- import_async7.synchronized
1513
- ], SpaceManager.prototype, "open", null);
1514
- __decorate7([
1515
- import_async7.synchronized
1516
- ], SpaceManager.prototype, "close", null);
1517
- SpaceManager = __decorate7([
1518
- (0, import_async7.trackLeaks)("open", "close")
1519
- ], SpaceManager);
1520
-
1521
- // packages/core/echo/echo-pipeline/src/space/genesis.ts
1522
- var import_credentials4 = require("@dxos/credentials");
1523
- var import_debug5 = require("@dxos/debug");
1524
- var import_credentials5 = require("@dxos/protocols/proto/dxos/halo/credentials");
1525
-
1526
- // packages/core/echo/echo-pipeline/src/space/data-pipeline.ts
1527
- var import_node_assert9 = __toESM(require("node:assert"));
1528
- var import_async8 = require("@dxos/async");
1529
- var import_context3 = require("@dxos/context");
1530
- var import_debug6 = require("@dxos/debug");
1531
- var import_echo_db3 = require("@dxos/echo-db");
1532
- var import_log11 = require("@dxos/log");
1533
- var import_timeframe3 = require("@dxos/timeframe");
1534
- var __decorate8 = function(decorators, target, key, desc) {
1535
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1536
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1537
- r = Reflect.decorate(decorators, target, key, desc);
1538
- else
1539
- for (var i = decorators.length - 1; i >= 0; i--)
1540
- if (d = decorators[i])
1541
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1542
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1543
- };
1544
- var MESSAGES_PER_SNAPSHOT = 10;
1545
- var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1546
- var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
1547
- var DISABLE_SNAPSHOT_CACHE = true;
1548
- var DataPipeline = class DataPipeline2 {
1549
- constructor(_params) {
1550
- this._params = _params;
1551
- this._ctx = new import_context3.Context();
1552
- this._lastAutomaticSnapshotTimeframe = new import_timeframe3.Timeframe();
1553
- this._isOpen = false;
1554
- this._lastTimeframeSaveTime = 0;
1555
- this._lastSnapshotSaveTime = 0;
1556
- }
1557
- get isOpen() {
1558
- return this._isOpen;
1559
- }
1560
- get pipelineState() {
1561
- var _a;
1562
- return (_a = this._pipeline) == null ? void 0 : _a.state;
1563
- }
1564
- get snapshotTimeframe() {
1565
- var _a;
1566
- return (_a = this._snapshot) == null ? void 0 : _a.timeframe;
1567
- }
1568
- getStartTimeframe() {
1569
- var _a;
1570
- return snapshotTimeframeToStartingTimeframe((_a = this.snapshotTimeframe) != null ? _a : new import_timeframe3.Timeframe());
1571
- }
1572
- setTargetTimeframe(timeframe) {
1573
- var _a;
1574
- this._targetTimeframe = timeframe;
1575
- (_a = this._pipeline) == null ? void 0 : _a.state.setTargetTimeframe(timeframe);
1576
- }
1577
- async open(spaceContext) {
1578
- var _a, _b, _c, _d;
1579
- if (this._isOpen) {
1580
- return;
1581
- }
1582
- this._spaceContext = spaceContext;
1583
- if (this._params.snapshotId && !DISABLE_SNAPSHOT_CACHE) {
1584
- this._snapshot = await this._params.snapshotManager.load(this._params.snapshotId);
1585
- this._lastAutomaticSnapshotTimeframe = (_b = (_a = this._snapshot) == null ? void 0 : _a.timeframe) != null ? _b : new import_timeframe3.Timeframe();
1586
- }
1587
- this._pipeline = await this._spaceContext.openPipeline(this.getStartTimeframe());
1588
- if (this._targetTimeframe) {
1589
- this._pipeline.state.setTargetTimeframe(this._targetTimeframe);
1590
- }
1591
- const feedWriter = createMappedFeedWriter((data) => ({
1592
- data
1593
- }), (_c = this._pipeline.writer) != null ? _c : (0, import_debug6.failUndefined)());
1594
- this.databaseBackend = new DatabaseHost(feedWriter, (_d = this._snapshot) == null ? void 0 : _d.database);
1595
- this._itemManager = new import_echo_db3.ItemManager(this._params.modelFactory);
1596
- await this.databaseBackend.open(this._itemManager, this._params.modelFactory);
1597
- (0, import_async8.scheduleTask)(this._ctx, async () => {
1598
- await this._consumePipeline();
1599
- });
1600
- this._isOpen = true;
1601
- }
1602
- async close() {
1603
- var _a, _b, _c;
1604
- if (!this._isOpen) {
1605
- return;
1606
- }
1607
- (0, import_log11.log)("close", {}, {
1608
- file: "data-pipeline.ts",
1609
- line: 145,
1892
+ import_log11.log.trace("dxos.echo.space-manager.construct-space", import_protocols6.trace.end({
1893
+ id: this._instanceId
1894
+ }), {
1895
+ file: "space-manager.ts",
1896
+ line: 100,
1610
1897
  scope: this,
1611
1898
  callSite: (f, a) => f(...a)
1612
1899
  });
1613
- this._isOpen = false;
1614
- await this._ctx.dispose();
1615
- await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1616
- try {
1617
- if (this._pipeline) {
1618
- await this._saveTargetTimeframe(this._pipeline.state.timeframe);
1619
- if (!DISABLE_SNAPSHOT_CACHE) {
1620
- await this._saveSnapshot(this._pipeline.state.timeframe);
1621
- }
1622
- }
1623
- } catch (err) {
1624
- import_log11.log.catch(err, {}, {
1625
- file: "data-pipeline.ts",
1626
- line: 160,
1627
- scope: this,
1628
- callSite: (f, a) => f(...a)
1629
- });
1630
- }
1631
- await ((_b = this.databaseBackend) == null ? void 0 : _b.close());
1632
- await ((_c = this._itemManager) == null ? void 0 : _c.destroy());
1633
- await this._params.snapshotManager.close();
1634
- }
1635
- async _consumePipeline() {
1636
- (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1637
- for await (const msg of this._pipeline.consume()) {
1638
- const { feedKey, seq, data } = msg;
1639
- (0, import_log11.log)("processing message", {
1640
- msg
1641
- }, {
1642
- file: "data-pipeline.ts",
1643
- line: 172,
1644
- scope: this,
1645
- callSite: (f, a) => f(...a)
1646
- });
1647
- try {
1648
- if (data.payload.data) {
1649
- const feedInfo = this._params.feedInfoProvider(feedKey);
1650
- if (!feedInfo) {
1651
- import_log11.log.error("Could not find feed.", {
1652
- feedKey
1653
- }, {
1654
- file: "data-pipeline.ts",
1655
- line: 178,
1656
- scope: this,
1657
- callSite: (f, a) => f(...a)
1658
- });
1659
- continue;
1660
- }
1661
- await this.databaseBackend.echoProcessor({
1662
- batch: data.payload.data.batch,
1663
- meta: {
1664
- feedKey,
1665
- seq,
1666
- timeframe: data.timeframe,
1667
- memberKey: feedInfo.assertion.identityKey
1668
- }
1669
- });
1670
- await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1671
- }
1672
- } catch (err) {
1673
- import_log11.log.catch(err, {}, {
1674
- file: "data-pipeline.ts",
1675
- line: 196,
1676
- scope: this,
1677
- callSite: (f, a) => f(...a)
1678
- });
1679
- }
1680
- }
1681
- }
1682
- _createSnapshot(timeframe) {
1683
- (0, import_node_assert9.default)(this.databaseBackend, "Database backend is not initialized.");
1684
- return {
1685
- spaceKey: this._params.spaceKey.asUint8Array(),
1686
- timeframe,
1687
- database: this.databaseBackend.createSnapshot()
1688
- };
1689
- }
1690
- async _saveSnapshot(timeframe) {
1691
- const snapshot = await this._createSnapshot(timeframe);
1692
- const snapshotKey = await this._params.snapshotManager.store(snapshot);
1693
- await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1694
- return snapshot;
1695
- }
1696
- async _saveTargetTimeframe(timeframe) {
1697
- var _a;
1698
- const newTimeframe = import_timeframe3.Timeframe.merge((_a = this._targetTimeframe) != null ? _a : new import_timeframe3.Timeframe(), timeframe);
1699
- await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1700
- this._targetTimeframe = newTimeframe;
1701
- }
1702
- async _noteTargetStateIfNeeded(timeframe) {
1703
- var _a;
1704
- if (Date.now() - this._lastTimeframeSaveTime > TIMEFRAME_SAVE_DEBOUNCE_INTERVAL) {
1705
- this._lastTimeframeSaveTime = Date.now();
1706
- await this._saveTargetTimeframe(timeframe);
1707
- }
1708
- if (!DISABLE_SNAPSHOT_CACHE && Date.now() - this._lastSnapshotSaveTime > AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL && timeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1709
- this._lastSnapshotSaveTime = Date.now();
1710
- const snapshot = await this._saveSnapshot(timeframe);
1711
- this._lastAutomaticSnapshotTimeframe = (_a = snapshot.timeframe) != null ? _a : (0, import_debug6.failUndefined)();
1712
- (0, import_log11.log)("save", {
1713
- snapshot
1714
- }, {
1715
- file: "data-pipeline.ts",
1716
- line: 239,
1717
- scope: this,
1718
- callSite: (f, a) => f(...a)
1719
- });
1720
- }
1721
- }
1722
- async waitUntilTimeframe(timeframe) {
1723
- (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1724
- await this._pipeline.state.waitUntilTimeframe(timeframe);
1900
+ return space;
1725
1901
  }
1726
1902
  };
1727
1903
  __decorate8([
1728
1904
  import_async8.synchronized
1729
- ], DataPipeline.prototype, "open", null);
1905
+ ], SpaceManager.prototype, "open", null);
1730
1906
  __decorate8([
1731
1907
  import_async8.synchronized
1732
- ], DataPipeline.prototype, "close", null);
1733
- DataPipeline = __decorate8([
1908
+ ], SpaceManager.prototype, "close", null);
1909
+ SpaceManager = __decorate8([
1734
1910
  (0, import_async8.trackLeaks)("open", "close")
1735
- ], DataPipeline);
1736
- var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
1737
- return snapshotTimeframe.map(([key, seq]) => [
1738
- key,
1739
- seq + 1
1740
- ]);
1741
- };
1911
+ ], SpaceManager);
1742
1912
 
1743
1913
  // packages/core/echo/echo-pipeline/src/testing/test-feed-builder.ts
1744
1914
  var import_testing = require("@dxos/feed-store/testing");
@@ -1765,7 +1935,7 @@ var WebsocketNetworkManagerProvider = (signalUrl) => () => new import_network_ma
1765
1935
  });
1766
1936
  var TestAgentBuilder = class {
1767
1937
  constructor({ storage, networkManagerProvider } = {}) {
1768
- this._agents = new import_util7.ComplexMap(import_keys6.PublicKey.hash);
1938
+ this._agents = new import_util8.ComplexMap(import_keys6.PublicKey.hash);
1769
1939
  this._storage = storage != null ? storage : (0, import_random_access_storage.createStorage)({
1770
1940
  type: import_random_access_storage.StorageType.RAM
1771
1941
  });
@@ -1790,12 +1960,22 @@ var TestAgentBuilder = class {
1790
1960
  }
1791
1961
  };
1792
1962
  var TestAgent = class {
1963
+ get metadataStore() {
1964
+ var _a;
1965
+ return (_a = this._metadataStore) != null ? _a : this._metadataStore = new MetadataStore(this.storage.createDirectory("metadata"));
1966
+ }
1967
+ get snapshotStore() {
1968
+ var _a;
1969
+ return (_a = this._snapshotStore) != null ? _a : this._snapshotStore = new SnapshotStore(this.storage.createDirectory("snapshots"));
1970
+ }
1793
1971
  constructor(_networkManagerProvider, _feedBuilder, identityKey, deviceKey) {
1794
1972
  this._networkManagerProvider = _networkManagerProvider;
1795
1973
  this._feedBuilder = _feedBuilder;
1796
1974
  this.identityKey = identityKey;
1797
1975
  this.deviceKey = deviceKey;
1798
- this._spaces = new import_util7.ComplexMap(import_keys6.PublicKey.hash);
1976
+ this._spaces = new import_util8.ComplexMap(import_keys6.PublicKey.hash);
1977
+ this.modelFactory = new import_model_factory.ModelFactory().registerModel(import_document_model.DocumentModel);
1978
+ this.storage = this._feedBuilder.storage;
1799
1979
  this.keyring = this._feedBuilder.keyring;
1800
1980
  this.feedStore = this._feedBuilder.createFeedStore();
1801
1981
  }
@@ -1810,60 +1990,60 @@ var TestAgent = class {
1810
1990
  getSpace(spaceKey) {
1811
1991
  return this._spaces.get(spaceKey);
1812
1992
  }
1813
- createSpaceManager() {
1814
- return new SpaceManager({
1815
- feedStore: this._feedBuilder.createFeedStore(),
1816
- networkManager: this._networkManagerProvider()
1993
+ get spaceManager() {
1994
+ var _a;
1995
+ return (_a = this._spaceManager) != null ? _a : this._spaceManager = new SpaceManager({
1996
+ feedStore: this.feedStore,
1997
+ networkManager: this._networkManagerProvider(),
1998
+ modelFactory: this.modelFactory,
1999
+ metadataStore: this.metadataStore,
2000
+ snapshotStore: this.snapshotStore
1817
2001
  });
1818
2002
  }
1819
- async createSpace(identityKey = this.identityKey, spaceKey, genesisKey) {
2003
+ async createSpace(identityKey = this.identityKey, spaceKey, genesisKey, dataKey) {
2004
+ let saveMetadata = false;
1820
2005
  if (!spaceKey) {
2006
+ saveMetadata = true;
1821
2007
  spaceKey = await this.keyring.createKey();
1822
2008
  }
1823
- const dataFeedKey = await this.keyring.createKey();
1824
- const dataFeed = await this.feedStore.openFeed(dataFeedKey, {
2009
+ if (!genesisKey) {
2010
+ genesisKey = await this.keyring.createKey();
2011
+ }
2012
+ const controlFeed = await this.feedStore.openFeed(genesisKey, {
1825
2013
  writable: true
1826
2014
  });
1827
- const controlFeedKey = await this.keyring.createKey();
1828
- const controlFeed = await this.feedStore.openFeed(controlFeedKey, {
2015
+ const dataFeed = await this.feedStore.openFeed(dataKey != null ? dataKey : await this.keyring.createKey(), {
1829
2016
  writable: true
1830
2017
  });
1831
- const genesisFeed = genesisKey ? await this.feedStore.openFeed(genesisKey) : controlFeed;
1832
- const snapshotManager = new SnapshotManager(new SnapshotStore((0, import_random_access_storage.createStorage)().createDirectory("snapshots")));
1833
- const metadataStore = new MetadataStore((0, import_random_access_storage.createStorage)().createDirectory("metadata"));
1834
- await metadataStore.addSpace({
1835
- key: spaceKey
1836
- });
1837
- const dataPipelineController = new DataPipeline({
1838
- modelFactory: new import_model_factory.ModelFactory().registerModel(import_document_model.DocumentModel),
1839
- metadataStore,
1840
- snapshotManager,
2018
+ const metadata = {
2019
+ key: spaceKey,
2020
+ genesisFeedKey: genesisKey,
2021
+ controlFeedKey: controlFeed.key,
2022
+ dataFeedKey: dataFeed.key
2023
+ };
2024
+ if (saveMetadata) {
2025
+ await this.metadataStore.addSpace(metadata);
2026
+ }
2027
+ await this.spaceManager.open();
2028
+ const space = await this.spaceManager.constructSpace({
2029
+ metadata,
2030
+ swarmIdentity: {
2031
+ peerKey: this.deviceKey,
2032
+ credentialProvider: MOCK_AUTH_PROVIDER,
2033
+ credentialAuthenticator: MOCK_AUTH_VERIFIER
2034
+ },
1841
2035
  memberKey: identityKey,
1842
- spaceKey,
1843
- feedInfoProvider: (feedKey) => space.spaceState.feeds.get(feedKey),
1844
- snapshotId: void 0
1845
- });
1846
- const space = new Space({
1847
- spaceKey,
1848
- protocol: this.createSpaceProtocol(spaceKey),
1849
- genesisFeed,
1850
- feedProvider: (feedKey) => this.feedStore.openFeed(feedKey)
1851
- }).setControlFeed(controlFeed).setDataFeed(dataFeed);
1852
- await space.open();
1853
- await dataPipelineController.open({
1854
- openPipeline: async (start) => {
1855
- const pipeline = await space.createDataPipeline({
1856
- start
1857
- });
1858
- await pipeline.start();
1859
- return pipeline;
2036
+ onNetworkConnection: (session) => {
2037
+ session.addExtension("dxos.mesh.teleport.gossip", this.createGossip().createExtension({
2038
+ remotePeerId: session.remotePeerId
2039
+ }));
1860
2040
  }
1861
2041
  });
2042
+ space.setControlFeed(controlFeed);
2043
+ space.setDataFeed(dataFeed);
2044
+ await space.open();
1862
2045
  this._spaces.set(spaceKey, space);
1863
- return [
1864
- space,
1865
- dataPipelineController
1866
- ];
2046
+ return space;
1867
2047
  }
1868
2048
  createSpaceProtocol(topic, gossip) {
1869
2049
  return new SpaceProtocol({
@@ -1894,6 +2074,21 @@ var TestAgent = class {
1894
2074
  gossip: gossip != null ? gossip : this.createGossip()
1895
2075
  });
1896
2076
  }
2077
+ async spaceGenesis(space) {
2078
+ const generator = new import_credentials5.CredentialGenerator(this.keyring, this.identityKey, this.deviceKey);
2079
+ const credentials = [
2080
+ ...await generator.createSpaceGenesis(space.key, space.controlFeedKey),
2081
+ await generator.createFeedAdmission(space.key, space.dataFeedKey, import_credentials6.AdmittedFeed.Designation.DATA),
2082
+ await generator.createEpochCredential(space.key)
2083
+ ];
2084
+ for (const credential of credentials) {
2085
+ await space.controlPipeline.writer.write({
2086
+ credential: {
2087
+ credential
2088
+ }
2089
+ });
2090
+ }
2091
+ }
1897
2092
  };
1898
2093
 
1899
2094
  // packages/core/echo/echo-pipeline/src/testing/util.ts
@@ -1906,7 +2101,7 @@ var import_model_factory2 = require("@dxos/model-factory");
1906
2101
  var import_timeframe4 = require("@dxos/timeframe");
1907
2102
  var createMemoryDatabase = async (modelFactory) => {
1908
2103
  const feed = new import_testing2.MockFeedWriter();
1909
- const backend = new DatabaseHost(feed, void 0);
2104
+ const backend = new DatabaseHost(feed);
1910
2105
  feed.written.on(([data, meta]) => backend.echoProcessor({
1911
2106
  batch: data.batch,
1912
2107
  meta: {
@@ -1943,7 +2138,7 @@ var createRemoteDatabaseFromDataServiceHost = async (modelFactory, dataServiceHo
1943
2138
  var testLocalDatabase = async (create, check = create) => {
1944
2139
  var _a;
1945
2140
  const objectId = import_keys7.PublicKey.random().toHex();
1946
- await ((_a = create.databaseBackend.getWriteStream()) == null ? void 0 : _a.write({
2141
+ await ((_a = create.databaseHost.getWriteStream()) == null ? void 0 : _a.write({
1947
2142
  batch: {
1948
2143
  objects: [
1949
2144
  {
@@ -1955,7 +2150,7 @@ var testLocalDatabase = async (create, check = create) => {
1955
2150
  ]
1956
2151
  }
1957
2152
  }));
1958
- await (0, import_async9.asyncTimeout)(check.databaseBackend._itemDemuxer.mutation.waitForCondition(() => check._itemManager.entities.has(objectId)), 500);
2153
+ await (0, import_async9.asyncTimeout)(check.databaseHost._itemDemuxer.mutation.waitForCondition(() => check.itemManager.entities.has(objectId)), 500);
1959
2154
  };
1960
2155
  // Annotate the CommonJS export names for ESM import in node:
1961
2156
  0 && (module.exports = {