@dxos/echo-pipeline 0.1.35 → 0.1.36

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 (50) hide show
  1. package/dist/lib/browser/{chunk-6CRSMR4G.mjs → chunk-4YAT2XJW.mjs} +221 -160
  2. package/dist/lib/browser/chunk-4YAT2XJW.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +5 -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 +5 -5
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/index.cjs +212 -150
  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 +208 -152
  12. package/dist/lib/node/testing/index.cjs.map +4 -4
  13. package/dist/types/src/dbhost/data-service-host.d.ts.map +1 -1
  14. package/dist/types/src/dbhost/{database-backend.d.ts → database-host.d.ts} +2 -2
  15. package/dist/types/src/dbhost/database-host.d.ts.map +1 -0
  16. package/dist/types/src/dbhost/index.d.ts +1 -1
  17. package/dist/types/src/dbhost/index.d.ts.map +1 -1
  18. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  19. package/dist/types/src/pipeline/pipeline.d.ts +2 -0
  20. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  21. package/dist/types/src/pipeline/timeframe-clock.d.ts +12 -1
  22. package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
  23. package/dist/types/src/space/data-pipeline.d.ts +8 -9
  24. package/dist/types/src/space/data-pipeline.d.ts.map +1 -1
  25. package/dist/types/src/space/data-pipeline.test.d.ts +1 -0
  26. package/dist/types/src/space/data-pipeline.test.d.ts.map +1 -0
  27. package/dist/types/src/space/space-manager.d.ts +1 -0
  28. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  29. package/dist/types/src/testing/database-test-rig.d.ts +4 -4
  30. package/dist/types/src/testing/database-test-rig.d.ts.map +1 -1
  31. package/dist/types/src/testing/util.d.ts +4 -4
  32. package/dist/types/src/testing/util.d.ts.map +1 -1
  33. package/package.json +32 -29
  34. package/src/common/feeds.ts +1 -1
  35. package/src/dbhost/data-service-host.ts +16 -9
  36. package/src/dbhost/{database-backend.ts → database-host.ts} +1 -1
  37. package/src/dbhost/index.ts +1 -1
  38. package/src/metadata/metadata-store.ts +24 -20
  39. package/src/pipeline/pipeline.test.ts +214 -0
  40. package/src/pipeline/pipeline.ts +20 -6
  41. package/src/pipeline/timeframe-clock.ts +26 -4
  42. package/src/space/data-pipeline.test.ts +3 -0
  43. package/src/space/data-pipeline.ts +65 -66
  44. package/src/space/space-manager.ts +2 -1
  45. package/src/testing/database-test-rig.ts +6 -6
  46. package/src/testing/util.ts +4 -4
  47. package/src/tests/database-unit.test.ts +13 -0
  48. package/src/tests/database.test.ts +39 -1
  49. package/dist/lib/browser/chunk-6CRSMR4G.mjs.map +0 -7
  50. package/dist/types/src/dbhost/database-backend.d.ts.map +0 -1
@@ -78,12 +78,12 @@ var DataServiceHost = class {
78
78
  this._itemDemuxer.mutation.on(ctx, (message) => {
79
79
  var _a;
80
80
  const { batch, meta } = message;
81
- (0, import_log.log)("Object update", {
81
+ (0, import_log.log)("message", {
82
82
  batch,
83
83
  meta
84
84
  }, {
85
85
  file: "data-service-host.ts",
86
- line: 50,
86
+ line: 49,
87
87
  scope: this,
88
88
  callSite: (f, a) => f(...a)
89
89
  });
@@ -107,36 +107,59 @@ var DataServiceHost = class {
107
107
  });
108
108
  }
109
109
  async write(request) {
110
- var _a;
110
+ var _a, _b, _c;
111
111
  (0, import_node_assert.default)(this._writeStream, "Cannot write mutations in readonly mode");
112
- const receipt = await this._writeStream.write({
112
+ (0, import_log.log)("write", {
113
+ clientTag: request.clientTag,
114
+ objectCount: (_b = (_a = request.batch.objects) == null ? void 0 : _a.length) != null ? _b : 0
115
+ }, {
116
+ file: "data-service-host.ts",
117
+ line: 77,
118
+ scope: this,
119
+ callSite: (f, a) => f(...a)
120
+ });
121
+ const message = {
113
122
  batch: {
114
- objects: (_a = request.batch.objects) == null ? void 0 : _a.map((object) => {
123
+ objects: (_c = request.batch.objects) == null ? void 0 : _c.map((object) => {
115
124
  var _a2;
116
125
  return {
117
126
  ...object,
118
- mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((m) => ({
119
- ...m,
127
+ mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((mutation) => ({
128
+ ...mutation,
120
129
  meta: void 0
121
130
  })),
122
131
  meta: void 0
123
132
  };
124
133
  })
125
134
  }
135
+ };
136
+ const receipt = await this._writeStream.write(message, {
137
+ afterWrite: async (receipt2) => {
138
+ if (request.clientTag) {
139
+ (0, import_log.log)("tag", {
140
+ clientTag: request.clientTag,
141
+ feedKey: receipt2.feedKey,
142
+ seq: receipt2.seq
143
+ }, {
144
+ file: "data-service-host.ts",
145
+ line: 96,
146
+ scope: this,
147
+ callSite: (f, a) => f(...a)
148
+ });
149
+ this._clientTagMap.set([
150
+ receipt2.feedKey,
151
+ receipt2.seq
152
+ ], request.clientTag);
153
+ }
154
+ }
126
155
  });
127
- if (request.clientTag) {
128
- this._clientTagMap.set([
129
- receipt.feedKey,
130
- receipt.seq
131
- ], request.clientTag);
132
- }
133
156
  return receipt;
134
157
  }
135
158
  };
136
159
 
137
- // packages/core/echo/echo-pipeline/src/dbhost/database-backend.ts
160
+ // packages/core/echo/echo-pipeline/src/dbhost/database-host.ts
138
161
  var import_echo_db2 = require("@dxos/echo-db");
139
- var DatabaseBackendHost = class {
162
+ var DatabaseHost = class {
140
163
  constructor(_outboundStream, _snapshot) {
141
164
  this._outboundStream = _outboundStream;
142
165
  this._snapshot = _snapshot;
@@ -325,8 +348,10 @@ var DataServiceImpl = class {
325
348
  };
326
349
 
327
350
  // packages/core/echo/echo-pipeline/src/metadata/metadata-store.ts
351
+ var import_crc_32 = __toESM(require("crc-32"));
328
352
  var import_node_assert3 = __toESM(require("node:assert"));
329
353
  var import_async2 = require("@dxos/async");
354
+ var import_errors = require("@dxos/errors");
330
355
  var import_log3 = require("@dxos/log");
331
356
  var import_protocols3 = require("@dxos/protocols");
332
357
  var __decorate2 = function(decorators, target, key, desc) {
@@ -371,31 +396,35 @@ var MetadataStore = class {
371
396
  const file = this._directory.getOrCreateFile("EchoMetadata");
372
397
  try {
373
398
  const { size: fileLength } = await file.stat();
374
- if (fileLength < 4) {
399
+ if (fileLength < 8) {
375
400
  return;
376
401
  }
377
402
  const dataSize = fromBytesInt32(await file.read(0, 4));
403
+ const checksum = fromBytesInt32(await file.read(4, 4));
378
404
  (0, import_log3.log)("loaded", {
379
- size: dataSize
405
+ size: dataSize,
406
+ checksum
380
407
  }, {
381
408
  file: "metadata-store.ts",
382
- line: 67,
409
+ line: 70,
383
410
  scope: this,
384
411
  callSite: (f, a) => f(...a)
385
412
  });
386
- {
387
- if (fileLength < dataSize + 4) {
388
- throw new Error("Metadata storage is corrupted");
389
- }
413
+ if (fileLength < dataSize + 8) {
414
+ throw new import_errors.DataCorruptionError("Metadata size is smaller than expected.");
415
+ }
416
+ const data = await file.read(8, dataSize);
417
+ const calculatedChecksum = import_crc_32.default.buf(data);
418
+ if (calculatedChecksum !== checksum) {
419
+ throw new import_errors.DataCorruptionError("Metadata checksum is invalid.");
390
420
  }
391
- const data = await file.read(4, dataSize);
392
421
  this._metadata = import_protocols3.schema.getCodecForType("dxos.echo.metadata.EchoMetadata").decode(data);
393
422
  } catch (err) {
394
423
  import_log3.log.error("failed to load metadata", {
395
424
  err
396
425
  }, {
397
426
  file: "metadata-store.ts",
398
- line: 79,
427
+ line: 85,
399
428
  scope: this,
400
429
  callSite: (f, a) => f(...a)
401
430
  });
@@ -415,16 +444,21 @@ var MetadataStore = class {
415
444
  const file = this._directory.getOrCreateFile("EchoMetadata");
416
445
  try {
417
446
  const encoded = Buffer.from(import_protocols3.schema.getCodecForType("dxos.echo.metadata.EchoMetadata").encode(data));
418
- await file.write(0, toBytesInt32(encoded.length));
447
+ const checksum = import_crc_32.default.buf(encoded);
448
+ const result = Buffer.alloc(8 + encoded.length);
449
+ result.writeInt32LE(encoded.length, 0);
450
+ result.writeInt32LE(checksum, 4);
451
+ encoded.copy(result, 8);
452
+ await file.write(0, result);
419
453
  (0, import_log3.log)("saved", {
420
- size: encoded.length
454
+ size: encoded.length,
455
+ checksum
421
456
  }, {
422
457
  file: "metadata-store.ts",
423
- line: 102,
458
+ line: 116,
424
459
  scope: this,
425
460
  callSite: (f, a) => f(...a)
426
461
  });
427
- await file.write(4, encoded);
428
462
  } finally {
429
463
  await file.close();
430
464
  }
@@ -435,7 +469,7 @@ var MetadataStore = class {
435
469
  async clear() {
436
470
  (0, import_log3.log)("clearing all metadata", {}, {
437
471
  file: "metadata-store.ts",
438
- line: 115,
472
+ line: 126,
439
473
  scope: this,
440
474
  callSite: (f, a) => f(...a)
441
475
  });
@@ -481,11 +515,6 @@ __decorate2([
481
515
  __decorate2([
482
516
  import_async2.synchronized
483
517
  ], MetadataStore.prototype, "_save", null);
484
- var toBytesInt32 = (num) => {
485
- const buf = Buffer.alloc(4);
486
- buf.writeInt32LE(num, 0);
487
- return buf;
488
- };
489
518
  var fromBytesInt32 = (buf) => buf.readInt32LE(0);
490
519
 
491
520
  // packages/core/echo/echo-pipeline/src/space/auth.ts
@@ -603,7 +632,7 @@ var createMappedFeedWriter = (mapper, writer) => {
603
632
  (0, import_node_assert5.default)(mapper);
604
633
  (0, import_node_assert5.default)(writer);
605
634
  return {
606
- write: async (data) => await writer.write(await mapper(data))
635
+ write: async (data, options) => await writer.write(await mapper(data), options)
607
636
  };
608
637
  };
609
638
 
@@ -639,30 +668,44 @@ var __decorate3 = function(decorators, target, key, desc) {
639
668
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
640
669
  return c > 3 && r && Object.defineProperty(target, key, r), r;
641
670
  };
642
- var mapTimeframeToFeedIndexes = (timeframe) => timeframe.frames().map(([feedKey, index]) => ({
643
- feedKey,
644
- index
645
- }));
646
671
  var mapFeedIndexesToTimeframe = (indexes) => new import_timeframe.Timeframe(indexes.map(({ feedKey, index }) => [
647
672
  feedKey,
648
673
  index
649
674
  ]));
675
+ var startAfter = (timeframe) => timeframe.frames().map(([feedKey, index]) => ({
676
+ feedKey,
677
+ index: index + 1
678
+ }));
650
679
  var TimeframeClock = class {
651
680
  // prettier-ignore
652
681
  constructor(_timeframe = new import_timeframe.Timeframe()) {
653
682
  this._timeframe = _timeframe;
654
683
  this.update = new import_async4.Event();
684
+ this._pendingTimeframe = _timeframe;
655
685
  }
686
+ /**
687
+ * Timeframe that was processed by ECHO.
688
+ */
656
689
  get timeframe() {
657
690
  return this._timeframe;
658
691
  }
659
- updateTimeframe(key, seq) {
660
- this._timeframe = import_timeframe.Timeframe.merge(this._timeframe, new import_timeframe.Timeframe([
692
+ /**
693
+ * Timeframe that is currently being processed by ECHO.
694
+ * Will be equal to `timeframe` after the processing is complete.
695
+ */
696
+ get pendingTimeframe() {
697
+ return this._pendingTimeframe;
698
+ }
699
+ updatePendingTimeframe(key, seq) {
700
+ this._pendingTimeframe = import_timeframe.Timeframe.merge(this._pendingTimeframe, new import_timeframe.Timeframe([
661
701
  [
662
702
  key,
663
703
  seq
664
704
  ]
665
705
  ]));
706
+ }
707
+ updateTimeframe() {
708
+ this._timeframe = this._pendingTimeframe;
666
709
  this.update.emit(this._timeframe);
667
710
  }
668
711
  hasGaps(timeframe) {
@@ -670,12 +713,12 @@ var TimeframeClock = class {
670
713
  return !gaps.isEmpty();
671
714
  }
672
715
  async waitUntilReached(target) {
673
- import_log5.log.debug("waitUntilReached", {
716
+ import_log5.log.info("waitUntilReached", {
674
717
  target,
675
718
  current: this._timeframe
676
719
  }, {
677
720
  file: "timeframe-clock.ts",
678
- line: 45,
721
+ line: 67,
679
722
  scope: this,
680
723
  callSite: (f, a) => f(...a)
681
724
  });
@@ -686,7 +729,7 @@ var TimeframeClock = class {
686
729
  deps: import_timeframe.Timeframe.dependencies(target, this._timeframe)
687
730
  }, {
688
731
  file: "timeframe-clock.ts",
689
- line: 47,
732
+ line: 69,
690
733
  scope: this,
691
734
  callSite: (f, a) => f(...a)
692
735
  });
@@ -699,6 +742,16 @@ __decorate3([
699
742
  ], TimeframeClock.prototype, "waitUntilReached", null);
700
743
 
701
744
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
745
+ var __decorate4 = function(decorators, target, key, desc) {
746
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
747
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
748
+ r = Reflect.decorate(decorators, target, key, desc);
749
+ else
750
+ for (var i = decorators.length - 1; i >= 0; i--)
751
+ if (d = decorators[i])
752
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
753
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
754
+ };
702
755
  var PipelineState = class {
703
756
  // prettier-ignore
704
757
  constructor(_iterator, _timeframeClock) {
@@ -710,18 +763,25 @@ var PipelineState = class {
710
763
  * Latest theoretical timeframe based on the last mutation in each feed.
711
764
  * NOTE: This might never be reached if the mutation dependencies
712
765
  */
766
+ // TODO(dmaretskyi): Rename `totalTimeframe`? or `lastTimeframe`.
713
767
  get endTimeframe() {
714
- return mapFeedIndexesToTimeframe(this._iterator.feeds.filter((feed) => feed.properties.length > 0).map((feed) => ({
768
+ return mapFeedIndexesToTimeframe(this._iterator.feeds.filter((feed) => feed.length > 0).map((feed) => ({
715
769
  feedKey: feed.key,
716
- index: feed.properties.length - 1
770
+ index: feed.length - 1
717
771
  })));
718
772
  }
719
773
  get timeframe() {
720
774
  return this._timeframeClock.timeframe;
721
775
  }
776
+ get pendingTimeframe() {
777
+ return this._timeframeClock.pendingTimeframe;
778
+ }
722
779
  get targetTimeframe() {
723
780
  return this._targetTimeframe ? this._targetTimeframe : new import_timeframe2.Timeframe();
724
781
  }
782
+ get feeds() {
783
+ return this._iterator.feeds;
784
+ }
725
785
  async waitUntilTimeframe(target) {
726
786
  await this._timeframeClock.waitUntilReached(target);
727
787
  }
@@ -743,7 +803,7 @@ var PipelineState = class {
743
803
  target: this.targetTimeframe
744
804
  }, {
745
805
  file: "pipeline.ts",
746
- line: 96,
806
+ line: 105,
747
807
  scope: this,
748
808
  callSite: (f, a) => f(...a)
749
809
  });
@@ -773,7 +833,7 @@ var PipelineState = class {
773
833
  dependencies: import_timeframe2.Timeframe.dependencies(this.targetTimeframe, this.timeframe)
774
834
  }, {
775
835
  file: "pipeline.ts",
776
- line: 122,
836
+ line: 131,
777
837
  scope: this,
778
838
  callSite: (f, a) => f(...a)
779
839
  });
@@ -790,7 +850,7 @@ var Pipeline = class {
790
850
  this._initialTimeframe = _initialTimeframe;
791
851
  this._timeframeClock = new TimeframeClock(this._initialTimeframe);
792
852
  this._feedSetIterator = new import_feed_store.FeedSetIterator(createMessageSelector(this._timeframeClock), {
793
- start: mapTimeframeToFeedIndexes(this._initialTimeframe),
853
+ start: startAfter(this._initialTimeframe),
794
854
  stallTimeout: 1e3
795
855
  });
796
856
  this._state = new PipelineState(this._feedSetIterator, this._timeframeClock);
@@ -799,7 +859,7 @@ var Pipeline = class {
799
859
  this._feedSetIterator.stalled.on((iterator) => {
800
860
  import_log6.log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
801
861
  file: "pipeline.ts",
802
- line: 198,
862
+ line: 207,
803
863
  scope: this,
804
864
  callSite: (f, a) => f(...a)
805
865
  });
@@ -815,6 +875,8 @@ var Pipeline = class {
815
875
  getFeeds() {
816
876
  return this._feedSetIterator.feeds;
817
877
  }
878
+ // NOTE: This cannot be synchronized with `stop` because stop waits for the mutation processing to complete,
879
+ // which might be opening feeds during the mutation processing, which w
818
880
  async addFeed(feed) {
819
881
  await this._feedSetIterator.addFeed(feed);
820
882
  }
@@ -832,14 +894,14 @@ var Pipeline = class {
832
894
  async start() {
833
895
  (0, import_log6.log)("starting...", {}, {
834
896
  file: "pipeline.ts",
835
- line: 237,
897
+ line: 249,
836
898
  scope: this,
837
899
  callSite: (f, a) => f(...a)
838
900
  });
839
901
  await this._feedSetIterator.open();
840
902
  (0, import_log6.log)("started", {}, {
841
903
  file: "pipeline.ts",
842
- line: 239,
904
+ line: 251,
843
905
  scope: this,
844
906
  callSite: (f, a) => f(...a)
845
907
  });
@@ -847,7 +909,7 @@ var Pipeline = class {
847
909
  async stop() {
848
910
  (0, import_log6.log)("stopping...", {}, {
849
911
  file: "pipeline.ts",
850
- line: 243,
912
+ line: 256,
851
913
  scope: this,
852
914
  callSite: (f, a) => f(...a)
853
915
  });
@@ -855,7 +917,7 @@ var Pipeline = class {
855
917
  await this._processingTrigger.wait();
856
918
  (0, import_log6.log)("stopped", {}, {
857
919
  file: "pipeline.ts",
858
- line: 246,
920
+ line: 259,
859
921
  scope: this,
860
922
  callSite: (f, a) => f(...a)
861
923
  });
@@ -869,13 +931,20 @@ var Pipeline = class {
869
931
  this._isOpen = true;
870
932
  for await (const block of this._feedSetIterator) {
871
933
  this._processingTrigger.reset();
934
+ this._timeframeClock.updatePendingTimeframe(import_keys2.PublicKey.from(block.feedKey), block.seq);
872
935
  yield block;
873
936
  this._processingTrigger.wake();
874
- this._timeframeClock.updateTimeframe(import_keys2.PublicKey.from(block.feedKey), block.seq);
937
+ this._timeframeClock.updateTimeframe();
875
938
  }
876
939
  this._isOpen = false;
877
940
  }
878
941
  };
942
+ __decorate4([
943
+ import_async5.synchronized
944
+ ], Pipeline.prototype, "start", null);
945
+ __decorate4([
946
+ import_async5.synchronized
947
+ ], Pipeline.prototype, "stop", null);
879
948
 
880
949
  // packages/core/echo/echo-pipeline/src/space/control-pipeline.ts
881
950
  var import_credentials = require("@dxos/credentials");
@@ -993,7 +1062,7 @@ var ControlPipeline = class {
993
1062
  };
994
1063
 
995
1064
  // packages/core/echo/echo-pipeline/src/space/space.ts
996
- var __decorate4 = function(decorators, target, key, desc) {
1065
+ var __decorate5 = function(decorators, target, key, desc) {
997
1066
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
998
1067
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
999
1068
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1159,16 +1228,16 @@ var Space = class Space2 {
1159
1228
  return pipeline;
1160
1229
  }
1161
1230
  };
1162
- __decorate4([
1231
+ __decorate5([
1163
1232
  import_log8.logInfo
1164
1233
  ], Space.prototype, "key", null);
1165
- __decorate4([
1234
+ __decorate5([
1166
1235
  import_async6.synchronized
1167
1236
  ], Space.prototype, "open", null);
1168
- __decorate4([
1237
+ __decorate5([
1169
1238
  import_async6.synchronized
1170
1239
  ], Space.prototype, "close", null);
1171
- Space = __decorate4([
1240
+ Space = __decorate5([
1172
1241
  (0, import_async6.trackLeaks)("open", "close")
1173
1242
  ], Space);
1174
1243
 
@@ -1188,7 +1257,7 @@ var import_network_manager = require("@dxos/network-manager");
1188
1257
  var import_teleport2 = require("@dxos/teleport");
1189
1258
  var import_teleport_extension_replicator = require("@dxos/teleport-extension-replicator");
1190
1259
  var import_util5 = require("@dxos/util");
1191
- var __decorate5 = function(decorators, target, key, desc) {
1260
+ var __decorate6 = function(decorators, target, key, desc) {
1192
1261
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1193
1262
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1194
1263
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1295,10 +1364,10 @@ var SpaceProtocol = class {
1295
1364
  };
1296
1365
  }
1297
1366
  };
1298
- __decorate5([
1367
+ __decorate6([
1299
1368
  import_log9.logInfo
1300
1369
  ], SpaceProtocol.prototype, "_topic", void 0);
1301
- __decorate5([
1370
+ __decorate6([
1302
1371
  import_log9.logInfo
1303
1372
  ], SpaceProtocol.prototype, "_ownPeerKey", null);
1304
1373
  var AuthStatus;
@@ -1358,15 +1427,15 @@ var SpaceProtocolSession = class {
1358
1427
  await this._teleport.close();
1359
1428
  }
1360
1429
  };
1361
- __decorate5([
1430
+ __decorate6([
1362
1431
  import_log9.logInfo
1363
1432
  ], SpaceProtocolSession.prototype, "_wireParams", void 0);
1364
- __decorate5([
1433
+ __decorate6([
1365
1434
  import_log9.logInfo
1366
1435
  ], SpaceProtocolSession.prototype, "authStatus", null);
1367
1436
 
1368
1437
  // packages/core/echo/echo-pipeline/src/space/space-manager.ts
1369
- var __decorate6 = function(decorators, target, key, desc) {
1438
+ var __decorate7 = function(decorators, target, key, desc) {
1370
1439
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1371
1440
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1372
1441
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1389,10 +1458,11 @@ var SpaceManager = class SpaceManager2 {
1389
1458
  }
1390
1459
  async open() {
1391
1460
  import_log10.log.trace("dxos.echo.space-manager", import_protocols6.trace.begin({
1392
- id: this._instanceId
1461
+ id: this._instanceId,
1462
+ parentId: this._traceParent
1393
1463
  }), {
1394
1464
  file: "space-manager.ts",
1395
- line: 65,
1465
+ line: 66,
1396
1466
  scope: this,
1397
1467
  callSite: (f, a) => f(...a)
1398
1468
  });
@@ -1405,7 +1475,7 @@ var SpaceManager = class SpaceManager2 {
1405
1475
  id: this._instanceId
1406
1476
  }), {
1407
1477
  file: "space-manager.ts",
1408
- line: 71,
1478
+ line: 72,
1409
1479
  scope: this,
1410
1480
  callSite: (f, a) => f(...a)
1411
1481
  });
@@ -1416,7 +1486,7 @@ var SpaceManager = class SpaceManager2 {
1416
1486
  spaceKey: metadata.genesisFeedKey
1417
1487
  }, {
1418
1488
  file: "space-manager.ts",
1419
- line: 75,
1489
+ line: 76,
1420
1490
  scope: this,
1421
1491
  callSite: (f, a) => f(...a)
1422
1492
  });
@@ -1438,13 +1508,13 @@ var SpaceManager = class SpaceManager2 {
1438
1508
  return space;
1439
1509
  }
1440
1510
  };
1441
- __decorate6([
1511
+ __decorate7([
1442
1512
  import_async7.synchronized
1443
1513
  ], SpaceManager.prototype, "open", null);
1444
- __decorate6([
1514
+ __decorate7([
1445
1515
  import_async7.synchronized
1446
1516
  ], SpaceManager.prototype, "close", null);
1447
- SpaceManager = __decorate6([
1517
+ SpaceManager = __decorate7([
1448
1518
  (0, import_async7.trackLeaks)("open", "close")
1449
1519
  ], SpaceManager);
1450
1520
 
@@ -1461,7 +1531,7 @@ var import_debug6 = require("@dxos/debug");
1461
1531
  var import_echo_db3 = require("@dxos/echo-db");
1462
1532
  var import_log11 = require("@dxos/log");
1463
1533
  var import_timeframe3 = require("@dxos/timeframe");
1464
- var __decorate7 = function(decorators, target, key, desc) {
1534
+ var __decorate8 = function(decorators, target, key, desc) {
1465
1535
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1466
1536
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1467
1537
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1474,14 +1544,15 @@ var __decorate7 = function(decorators, target, key, desc) {
1474
1544
  var MESSAGES_PER_SNAPSHOT = 10;
1475
1545
  var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1476
1546
  var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
1477
- var DISABLE_SNAPSHOT_CACHE = false;
1547
+ var DISABLE_SNAPSHOT_CACHE = true;
1478
1548
  var DataPipeline = class DataPipeline2 {
1479
1549
  constructor(_params) {
1480
1550
  this._params = _params;
1481
1551
  this._ctx = new import_context3.Context();
1482
1552
  this._lastAutomaticSnapshotTimeframe = new import_timeframe3.Timeframe();
1483
1553
  this._isOpen = false;
1484
- this.onTimeframeReached = new import_async8.Event();
1554
+ this._lastTimeframeSaveTime = 0;
1555
+ this._lastSnapshotSaveTime = 0;
1485
1556
  }
1486
1557
  get isOpen() {
1487
1558
  return this._isOpen;
@@ -1509,7 +1580,7 @@ var DataPipeline = class DataPipeline2 {
1509
1580
  return;
1510
1581
  }
1511
1582
  this._spaceContext = spaceContext;
1512
- if (this._params.snapshotId) {
1583
+ if (this._params.snapshotId && !DISABLE_SNAPSHOT_CACHE) {
1513
1584
  this._snapshot = await this._params.snapshotManager.load(this._params.snapshotId);
1514
1585
  this._lastAutomaticSnapshotTimeframe = (_b = (_a = this._snapshot) == null ? void 0 : _a.timeframe) != null ? _b : new import_timeframe3.Timeframe();
1515
1586
  }
@@ -1520,64 +1591,14 @@ var DataPipeline = class DataPipeline2 {
1520
1591
  const feedWriter = createMappedFeedWriter((data) => ({
1521
1592
  data
1522
1593
  }), (_c = this._pipeline.writer) != null ? _c : (0, import_debug6.failUndefined)());
1523
- this.databaseBackend = new DatabaseBackendHost(feedWriter, (_d = this._snapshot) == null ? void 0 : _d.database);
1594
+ this.databaseBackend = new DatabaseHost(feedWriter, (_d = this._snapshot) == null ? void 0 : _d.database);
1524
1595
  this._itemManager = new import_echo_db3.ItemManager(this._params.modelFactory);
1525
1596
  await this.databaseBackend.open(this._itemManager, this._params.modelFactory);
1526
1597
  (0, import_async8.scheduleTask)(this._ctx, async () => {
1527
1598
  await this._consumePipeline();
1528
1599
  });
1529
- this._createPeriodicSnapshots();
1530
1600
  this._isOpen = true;
1531
1601
  }
1532
- _createPeriodicSnapshots() {
1533
- this.onTimeframeReached.debounce(TIMEFRAME_SAVE_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1534
- await this._saveLatestTimeframe();
1535
- });
1536
- if (!DISABLE_SNAPSHOT_CACHE) {
1537
- this.onTimeframeReached.debounce(AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1538
- var _a, _b;
1539
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1540
- if (!latestTimeframe) {
1541
- return;
1542
- }
1543
- if (latestTimeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1544
- const snapshot = await this._saveSnapshot();
1545
- this._lastAutomaticSnapshotTimeframe = (_b = snapshot.timeframe) != null ? _b : (0, import_debug6.failUndefined)();
1546
- (0, import_log11.log)("save", {
1547
- snapshot
1548
- }, {
1549
- file: "data-pipeline.ts",
1550
- line: 161,
1551
- scope: this,
1552
- callSite: (f, a) => f(...a)
1553
- });
1554
- }
1555
- });
1556
- }
1557
- }
1558
- async _saveSnapshot() {
1559
- const snapshot = await this.createSnapshot();
1560
- const snapshotKey = await this._params.snapshotManager.store(snapshot);
1561
- await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1562
- return snapshot;
1563
- }
1564
- async _saveLatestTimeframe() {
1565
- var _a, _b;
1566
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1567
- (0, import_log11.log)("save latest timeframe", {
1568
- latestTimeframe,
1569
- spaceKey: this._params.spaceKey
1570
- }, {
1571
- file: "data-pipeline.ts",
1572
- line: 176,
1573
- scope: this,
1574
- callSite: (f, a) => f(...a)
1575
- });
1576
- if (latestTimeframe) {
1577
- const newTimeframe = import_timeframe3.Timeframe.merge((_b = this._targetTimeframe) != null ? _b : new import_timeframe3.Timeframe(), latestTimeframe);
1578
- await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1579
- }
1580
- }
1581
1602
  async close() {
1582
1603
  var _a, _b, _c;
1583
1604
  if (!this._isOpen) {
@@ -1585,37 +1606,32 @@ var DataPipeline = class DataPipeline2 {
1585
1606
  }
1586
1607
  (0, import_log11.log)("close", {}, {
1587
1608
  file: "data-pipeline.ts",
1588
- line: 188,
1609
+ line: 145,
1589
1610
  scope: this,
1590
1611
  callSite: (f, a) => f(...a)
1591
1612
  });
1592
1613
  this._isOpen = false;
1614
+ await this._ctx.dispose();
1615
+ await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1593
1616
  try {
1594
- await this._saveLatestTimeframe();
1595
- await this._saveSnapshot();
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
+ }
1596
1623
  } catch (err) {
1597
1624
  import_log11.log.catch(err, {}, {
1598
1625
  file: "data-pipeline.ts",
1599
- line: 195,
1626
+ line: 160,
1600
1627
  scope: this,
1601
1628
  callSite: (f, a) => f(...a)
1602
1629
  });
1603
1630
  }
1604
- await this._ctx.dispose();
1605
- await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1606
1631
  await ((_b = this.databaseBackend) == null ? void 0 : _b.close());
1607
1632
  await ((_c = this._itemManager) == null ? void 0 : _c.destroy());
1608
1633
  await this._params.snapshotManager.close();
1609
1634
  }
1610
- createSnapshot() {
1611
- var _a, _b;
1612
- (0, import_node_assert9.default)(this.databaseBackend, "Database backend is not initialized.");
1613
- return {
1614
- spaceKey: this._params.spaceKey.asUint8Array(),
1615
- timeframe: (_b = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe) != null ? _b : new import_timeframe3.Timeframe(),
1616
- database: this.databaseBackend.createSnapshot()
1617
- };
1618
- }
1619
1635
  async _consumePipeline() {
1620
1636
  (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1621
1637
  for await (const msg of this._pipeline.consume()) {
@@ -1624,7 +1640,7 @@ var DataPipeline = class DataPipeline2 {
1624
1640
  msg
1625
1641
  }, {
1626
1642
  file: "data-pipeline.ts",
1627
- line: 217,
1643
+ line: 172,
1628
1644
  scope: this,
1629
1645
  callSite: (f, a) => f(...a)
1630
1646
  });
@@ -1636,7 +1652,7 @@ var DataPipeline = class DataPipeline2 {
1636
1652
  feedKey
1637
1653
  }, {
1638
1654
  file: "data-pipeline.ts",
1639
- line: 223,
1655
+ line: 178,
1640
1656
  scope: this,
1641
1657
  callSite: (f, a) => f(...a)
1642
1658
  });
@@ -1651,30 +1667,70 @@ var DataPipeline = class DataPipeline2 {
1651
1667
  memberKey: feedInfo.assertion.identityKey
1652
1668
  }
1653
1669
  });
1654
- this.onTimeframeReached.emit(data.timeframe);
1670
+ await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1655
1671
  }
1656
1672
  } catch (err) {
1657
1673
  import_log11.log.catch(err, {}, {
1658
1674
  file: "data-pipeline.ts",
1659
- line: 239,
1675
+ line: 196,
1660
1676
  scope: this,
1661
1677
  callSite: (f, a) => f(...a)
1662
1678
  });
1663
1679
  }
1664
1680
  }
1665
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
+ }
1666
1722
  async waitUntilTimeframe(timeframe) {
1667
1723
  (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1668
1724
  await this._pipeline.state.waitUntilTimeframe(timeframe);
1669
1725
  }
1670
1726
  };
1671
- __decorate7([
1727
+ __decorate8([
1672
1728
  import_async8.synchronized
1673
1729
  ], DataPipeline.prototype, "open", null);
1674
- __decorate7([
1730
+ __decorate8([
1675
1731
  import_async8.synchronized
1676
1732
  ], DataPipeline.prototype, "close", null);
1677
- DataPipeline = __decorate7([
1733
+ DataPipeline = __decorate8([
1678
1734
  (0, import_async8.trackLeaks)("open", "close")
1679
1735
  ], DataPipeline);
1680
1736
  var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
@@ -1848,7 +1904,7 @@ var import_model_factory2 = require("@dxos/model-factory");
1848
1904
  var import_timeframe4 = require("@dxos/timeframe");
1849
1905
  var createMemoryDatabase = async (modelFactory) => {
1850
1906
  const feed = new import_testing2.MockFeedWriter();
1851
- const backend = new DatabaseBackendHost(feed, void 0);
1907
+ const backend = new DatabaseHost(feed, void 0);
1852
1908
  feed.written.on(([data, meta]) => backend.echoProcessor({
1853
1909
  batch: data.batch,
1854
1910
  meta: {
@@ -1874,7 +1930,7 @@ var createRemoteDatabaseFromDataServiceHost = async (modelFactory, dataServiceHo
1874
1930
  const dataService = new DataServiceImpl(dataServiceSubscriptions);
1875
1931
  const spaceKey = import_keys7.PublicKey.random();
1876
1932
  dataServiceSubscriptions.registerSpace(spaceKey, dataServiceHost);
1877
- const backend = new import_echo_db4.DatabaseBackendProxy(dataService, spaceKey);
1933
+ const backend = new import_echo_db4.DatabaseProxy(dataService, spaceKey);
1878
1934
  const itemManager = new import_echo_db4.ItemManager(modelFactory);
1879
1935
  await backend.open(itemManager, new import_model_factory2.ModelFactory().registerModel(import_document_model2.DocumentModel));
1880
1936
  return {