@dxos/echo-pipeline 0.1.31-next.ea8f0bc → 0.1.32-next.77d513e

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 (49) hide show
  1. package/dist/lib/browser/{chunk-L44NG4N6.mjs → chunk-EM5HSJ7J.mjs} +192 -122
  2. package/dist/lib/browser/chunk-EM5HSJ7J.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +3 -5
  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 +34 -17
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/index.cjs +189 -120
  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 +175 -119
  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 +2 -2
  15. package/dist/types/src/dbhost/database-backend.d.ts.map +1 -1
  16. package/dist/types/src/metadata/metadata-store.d.ts +1 -2
  17. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  18. package/dist/types/src/pipeline/pipeline.d.ts +10 -1
  19. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  20. package/dist/types/src/space/{data-pipeline-controller.d.ts → data-pipeline.d.ts} +10 -18
  21. package/dist/types/src/space/data-pipeline.d.ts.map +1 -0
  22. package/dist/types/src/space/genesis.d.ts.map +1 -1
  23. package/dist/types/src/space/index.d.ts +1 -1
  24. package/dist/types/src/space/index.d.ts.map +1 -1
  25. package/dist/types/src/space/space.d.ts +6 -4
  26. package/dist/types/src/space/space.d.ts.map +1 -1
  27. package/dist/types/src/testing/test-agent-builder.d.ts +6 -5
  28. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  29. package/dist/types/src/testing/util.d.ts +2 -2
  30. package/dist/types/src/testing/util.d.ts.map +1 -1
  31. package/package.json +29 -29
  32. package/src/dbhost/data-service-host.ts +19 -25
  33. package/src/dbhost/database-backend.ts +1 -1
  34. package/src/metadata/metadata-store.ts +1 -2
  35. package/src/pipeline/pipeline.test.ts +12 -4
  36. package/src/pipeline/pipeline.ts +18 -3
  37. package/src/space/{data-pipeline-controller.ts → data-pipeline.ts} +62 -39
  38. package/src/space/genesis.ts +47 -7
  39. package/src/space/index.ts +1 -1
  40. package/src/space/space-protocol.browser.test.ts +8 -6
  41. package/src/space/space-protocol.test.ts +8 -6
  42. package/src/space/space.ts +22 -23
  43. package/src/testing/database-test-rig.ts +1 -1
  44. package/src/testing/test-agent-builder.ts +23 -11
  45. package/src/testing/util.ts +13 -12
  46. package/src/tests/database-unit.test.ts +25 -0
  47. package/src/tests/database.test.ts +5 -5
  48. package/dist/lib/browser/chunk-L44NG4N6.mjs.map +0 -7
  49. package/dist/types/src/space/data-pipeline-controller.d.ts.map +0 -1
@@ -48,7 +48,7 @@ var import_messaging = require("@dxos/messaging");
48
48
  var import_model_factory = require("@dxos/model-factory");
49
49
  var import_network_manager2 = require("@dxos/network-manager");
50
50
  var import_random_access_storage = require("@dxos/random-access-storage");
51
- var import_teleport_extension_presence = require("@dxos/teleport-extension-presence");
51
+ var import_teleport_extension_gossip = require("@dxos/teleport-extension-gossip");
52
52
  var import_util7 = require("@dxos/util");
53
53
 
54
54
  // packages/core/echo/echo-pipeline/src/dbhost/data-service-host.ts
@@ -75,56 +75,53 @@ var DataServiceHost = class {
75
75
  objects
76
76
  }
77
77
  });
78
- this._itemDemuxer.mutation.on(ctx, (mutation) => {
78
+ this._itemDemuxer.mutation.on(ctx, (message) => {
79
79
  var _a;
80
+ const { batch, meta } = message;
80
81
  (0, import_log.log)("Object update", {
81
- mutation
82
+ batch,
83
+ meta
82
84
  }, {
83
85
  file: "data-service-host.ts",
84
- line: 49,
86
+ line: 50,
85
87
  scope: this,
86
88
  callSite: (f, a) => f(...a)
87
89
  });
88
90
  const clientTag = this._clientTagMap.get([
89
- mutation.meta.feedKey,
90
- mutation.meta.seq
91
+ message.meta.feedKey,
92
+ message.meta.seq
91
93
  ]);
92
- const batch = {
93
- objects: [
94
- {
95
- ...mutation.data,
96
- mutations: (_a = mutation.data.mutations) == null ? void 0 : _a.map((m, mutationIdx) => ({
97
- ...m,
98
- meta: mutation.meta
99
- })),
100
- meta: mutation.meta
101
- }
102
- ]
103
- };
94
+ (_a = batch.objects) == null ? void 0 : _a.forEach((object) => {
95
+ (0, import_echo_db.setMetadataOnObject)(object, meta);
96
+ });
104
97
  if (clientTag) {
105
98
  (0, import_echo_db.tagMutationsInBatch)(batch, clientTag);
106
99
  }
107
100
  next({
108
101
  clientTag,
109
- feedKey: mutation.meta.feedKey,
110
- seq: mutation.meta.seq,
102
+ feedKey: message.meta.feedKey,
103
+ seq: message.meta.seq,
111
104
  batch
112
105
  });
113
106
  });
114
107
  });
115
108
  }
116
109
  async write(request) {
117
- var _a, _b;
110
+ var _a;
118
111
  (0, import_node_assert.default)(this._writeStream, "Cannot write mutations in readonly mode");
119
- (0, import_node_assert.default)(((_a = request.batch.objects) == null ? void 0 : _a.length) === 1, "Only single object mutations are supported");
120
112
  const receipt = await this._writeStream.write({
121
- object: {
122
- ...request.batch.objects[0],
123
- mutations: (_b = request.batch.objects[0].mutations) == null ? void 0 : _b.map((m) => ({
124
- ...m,
125
- meta: void 0
126
- })),
127
- meta: void 0
113
+ batch: {
114
+ objects: (_a = request.batch.objects) == null ? void 0 : _a.map((object) => {
115
+ var _a2;
116
+ return {
117
+ ...object,
118
+ mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((m) => ({
119
+ ...m,
120
+ meta: void 0
121
+ })),
122
+ meta: void 0
123
+ };
124
+ })
128
125
  }
129
126
  });
130
127
  if (request.clientTag) {
@@ -382,7 +379,7 @@ var MetadataStore = class {
382
379
  size: dataSize
383
380
  }, {
384
381
  file: "metadata-store.ts",
385
- line: 68,
382
+ line: 67,
386
383
  scope: this,
387
384
  callSite: (f, a) => f(...a)
388
385
  });
@@ -398,7 +395,7 @@ var MetadataStore = class {
398
395
  err
399
396
  }, {
400
397
  file: "metadata-store.ts",
401
- line: 80,
398
+ line: 79,
402
399
  scope: this,
403
400
  callSite: (f, a) => f(...a)
404
401
  });
@@ -423,7 +420,7 @@ var MetadataStore = class {
423
420
  size: encoded.length
424
421
  }, {
425
422
  file: "metadata-store.ts",
426
- line: 103,
423
+ line: 102,
427
424
  scope: this,
428
425
  callSite: (f, a) => f(...a)
429
426
  });
@@ -438,7 +435,7 @@ var MetadataStore = class {
438
435
  async clear() {
439
436
  (0, import_log3.log)("clearing all metadata", {}, {
440
437
  file: "metadata-store.ts",
441
- line: 116,
438
+ line: 115,
442
439
  scope: this,
443
440
  callSite: (f, a) => f(...a)
444
441
  });
@@ -588,6 +585,7 @@ var import_util4 = require("@dxos/util");
588
585
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
589
586
  var import_node_assert7 = __toESM(require("node:assert"));
590
587
  var import_async5 = require("@dxos/async");
588
+ var import_context2 = require("@dxos/context");
591
589
  var import_feed_store = require("@dxos/feed-store");
592
590
  var import_keys2 = require("@dxos/keys");
593
591
  var import_log6 = require("@dxos/log");
@@ -722,7 +720,7 @@ var PipelineState = class {
722
720
  return this._timeframeClock.timeframe;
723
721
  }
724
722
  get targetTimeframe() {
725
- return this._targetTimeframe ? import_timeframe2.Timeframe.merge(this.endTimeframe, this._targetTimeframe) : this.endTimeframe;
723
+ return this._targetTimeframe ? this._targetTimeframe : new import_timeframe2.Timeframe();
726
724
  }
727
725
  async waitUntilTimeframe(target) {
728
726
  await this._timeframeClock.waitUntilReached(target);
@@ -737,7 +735,7 @@ var PipelineState = class {
737
735
  *
738
736
  * @param timeout Timeout in milliseconds to specify the maximum wait time.
739
737
  */
740
- async waitUntilReachedTargetTimeframe({ timeout } = {}) {
738
+ async waitUntilReachedTargetTimeframe({ ctx = new import_context2.Context(), timeout, breakOnStall = true } = {}) {
741
739
  var _a;
742
740
  (0, import_log6.log)("waitUntilReachedTargetTimeframe", {
743
741
  timeout,
@@ -745,7 +743,7 @@ var PipelineState = class {
745
743
  target: this.targetTimeframe
746
744
  }, {
747
745
  file: "pipeline.ts",
748
- line: 82,
746
+ line: 96,
749
747
  scope: this,
750
748
  callSite: (f, a) => f(...a)
751
749
  });
@@ -753,11 +751,14 @@ var PipelineState = class {
753
751
  this._timeframeClock.update.waitForCondition(() => {
754
752
  return import_timeframe2.Timeframe.dependencies(this.targetTimeframe, this.timeframe).isEmpty();
755
753
  }),
756
- this._iterator.stalled.discardParameter().waitForCount(1)
754
+ ...breakOnStall ? [
755
+ this._iterator.stalled.discardParameter().waitForCount(1)
756
+ ] : []
757
757
  ]);
758
758
  let done = false;
759
759
  if (timeout) {
760
760
  return Promise.race([
761
+ (0, import_context2.rejectOnDispose)(ctx),
761
762
  this._reachedTargetPromise.then(() => {
762
763
  done = true;
763
764
  }),
@@ -772,7 +773,7 @@ var PipelineState = class {
772
773
  dependencies: import_timeframe2.Timeframe.dependencies(this.targetTimeframe, this.timeframe)
773
774
  }, {
774
775
  file: "pipeline.ts",
775
- line: 107,
776
+ line: 122,
776
777
  scope: this,
777
778
  callSite: (f, a) => f(...a)
778
779
  });
@@ -798,7 +799,7 @@ var Pipeline = class {
798
799
  this._feedSetIterator.stalled.on((iterator) => {
799
800
  import_log6.log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
800
801
  file: "pipeline.ts",
801
- line: 183,
802
+ line: 198,
802
803
  scope: this,
803
804
  callSite: (f, a) => f(...a)
804
805
  });
@@ -828,14 +829,14 @@ var Pipeline = class {
828
829
  async start() {
829
830
  (0, import_log6.log)("starting...", {}, {
830
831
  file: "pipeline.ts",
831
- line: 218,
832
+ line: 233,
832
833
  scope: this,
833
834
  callSite: (f, a) => f(...a)
834
835
  });
835
836
  await this._feedSetIterator.open();
836
837
  (0, import_log6.log)("started", {}, {
837
838
  file: "pipeline.ts",
838
- line: 220,
839
+ line: 235,
839
840
  scope: this,
840
841
  callSite: (f, a) => f(...a)
841
842
  });
@@ -843,7 +844,7 @@ var Pipeline = class {
843
844
  async stop() {
844
845
  (0, import_log6.log)("stopping...", {}, {
845
846
  file: "pipeline.ts",
846
- line: 224,
847
+ line: 239,
847
848
  scope: this,
848
849
  callSite: (f, a) => f(...a)
849
850
  });
@@ -851,7 +852,7 @@ var Pipeline = class {
851
852
  await this._processingTrigger.wait();
852
853
  (0, import_log6.log)("stopped", {}, {
853
854
  file: "pipeline.ts",
854
- line: 227,
855
+ line: 242,
855
856
  scope: this,
856
857
  callSite: (f, a) => f(...a)
857
858
  });
@@ -1029,7 +1030,7 @@ var Space = class Space2 {
1029
1030
  credential
1030
1031
  }, {
1031
1032
  file: "space.ts",
1032
- line: 74,
1033
+ line: 79,
1033
1034
  scope: this,
1034
1035
  callSite: (f, a) => f(...a)
1035
1036
  });
@@ -1092,7 +1093,7 @@ var Space = class Space2 {
1092
1093
  async open() {
1093
1094
  (0, import_log8.log)("opening...", {}, {
1094
1095
  file: "space.ts",
1095
- line: 145,
1096
+ line: 149,
1096
1097
  scope: this,
1097
1098
  callSite: (f, a) => f(...a)
1098
1099
  });
@@ -1104,18 +1105,17 @@ var Space = class Space2 {
1104
1105
  this._isOpen = true;
1105
1106
  (0, import_log8.log)("opened", {}, {
1106
1107
  file: "space.ts",
1107
- line: 155,
1108
+ line: 159,
1108
1109
  scope: this,
1109
1110
  callSite: (f, a) => f(...a)
1110
1111
  });
1111
1112
  }
1112
1113
  async close() {
1113
- var _a;
1114
1114
  (0, import_log8.log)("closing...", {
1115
1115
  key: this._key
1116
1116
  }, {
1117
1117
  file: "space.ts",
1118
- line: 160,
1118
+ line: 164,
1119
1119
  scope: this,
1120
1120
  callSite: (f, a) => f(...a)
1121
1121
  });
@@ -1123,37 +1123,30 @@ var Space = class Space2 {
1123
1123
  return;
1124
1124
  }
1125
1125
  await this.protocol.stop();
1126
- await ((_a = this._dataPipelineController) == null ? void 0 : _a.close());
1127
1126
  await this._controlPipeline.stop();
1128
1127
  this._isOpen = false;
1129
1128
  (0, import_log8.log)("closed", {}, {
1130
1129
  file: "space.ts",
1131
- line: 171,
1130
+ line: 174,
1132
1131
  scope: this,
1133
1132
  callSite: (f, a) => f(...a)
1134
1133
  });
1135
1134
  }
1136
- async initDataPipeline(controller) {
1135
+ // TODO(dmaretskyi): Make reusable.
1136
+ async createDataPipeline({ start }) {
1137
1137
  (0, import_node_assert8.default)(this._isOpen, "Space must be open to initialize data pipeline.");
1138
- (0, import_node_assert8.default)(!this._dataPipelineController, "Data pipeline already initialized.");
1139
1138
  (0, import_node_assert8.default)(!this._dataPipeline, "Data pipeline already initialized.");
1140
- this._dataPipelineController = controller;
1141
- await this._dataPipelineController.open({
1142
- openPipeline: async (start) => {
1143
- (0, import_node_assert8.default)(!this._dataPipeline, "Data pipeline already initialized.");
1144
- this._dataPipeline = new Pipeline(start);
1145
- if (this._dataFeed) {
1146
- this._dataPipeline.setWriteFeed(this._dataFeed);
1147
- }
1148
- for (const feed of this._controlPipeline.spaceState.feeds.values()) {
1149
- if (feed.assertion.designation === import_credentials3.AdmittedFeed.Designation.DATA) {
1150
- await this._dataPipeline.addFeed(await this._feedProvider(feed.key));
1151
- }
1152
- }
1153
- await this._dataPipeline.start();
1154
- return this._dataPipeline;
1139
+ const pipeline = new Pipeline(start);
1140
+ if (this._dataFeed) {
1141
+ pipeline.setWriteFeed(this._dataFeed);
1142
+ }
1143
+ this._dataPipeline = pipeline;
1144
+ for (const feed of this._controlPipeline.spaceState.feeds.values()) {
1145
+ if (feed.assertion.designation === import_credentials3.AdmittedFeed.Designation.DATA) {
1146
+ await pipeline.addFeed(await this._feedProvider(feed.key));
1155
1147
  }
1156
- });
1148
+ }
1149
+ return pipeline;
1157
1150
  }
1158
1151
  };
1159
1152
  __decorate4([
@@ -1432,10 +1425,10 @@ var import_credentials4 = require("@dxos/credentials");
1432
1425
  var import_debug5 = require("@dxos/debug");
1433
1426
  var import_credentials5 = require("@dxos/protocols/proto/dxos/halo/credentials");
1434
1427
 
1435
- // packages/core/echo/echo-pipeline/src/space/data-pipeline-controller.ts
1428
+ // packages/core/echo/echo-pipeline/src/space/data-pipeline.ts
1436
1429
  var import_node_assert9 = __toESM(require("node:assert"));
1437
1430
  var import_async8 = require("@dxos/async");
1438
- var import_context2 = require("@dxos/context");
1431
+ var import_context3 = require("@dxos/context");
1439
1432
  var import_debug6 = require("@dxos/debug");
1440
1433
  var import_echo_db3 = require("@dxos/echo-db");
1441
1434
  var import_log11 = require("@dxos/log");
@@ -1453,13 +1446,18 @@ var __decorate7 = function(decorators, target, key, desc) {
1453
1446
  var MESSAGES_PER_SNAPSHOT = 10;
1454
1447
  var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1455
1448
  var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
1456
- var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1449
+ var DISABLE_SNAPSHOT_CACHE = false;
1450
+ var DataPipeline = class DataPipeline2 {
1457
1451
  constructor(_params) {
1458
1452
  this._params = _params;
1459
- this._ctx = new import_context2.Context();
1453
+ this._ctx = new import_context3.Context();
1460
1454
  this._lastAutomaticSnapshotTimeframe = new import_timeframe3.Timeframe();
1455
+ this._isOpen = false;
1461
1456
  this.onTimeframeReached = new import_async8.Event();
1462
1457
  }
1458
+ get isOpen() {
1459
+ return this._isOpen;
1460
+ }
1463
1461
  get pipelineState() {
1464
1462
  var _a;
1465
1463
  return (_a = this._pipeline) == null ? void 0 : _a.state;
@@ -1472,14 +1470,25 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1472
1470
  var _a;
1473
1471
  return snapshotTimeframeToStartingTimeframe((_a = this.snapshotTimeframe) != null ? _a : new import_timeframe3.Timeframe());
1474
1472
  }
1473
+ setTargetTimeframe(timeframe) {
1474
+ var _a;
1475
+ this._targetTimeframe = timeframe;
1476
+ (_a = this._pipeline) == null ? void 0 : _a.state.setTargetTimeframe(timeframe);
1477
+ }
1475
1478
  async open(spaceContext) {
1476
1479
  var _a, _b, _c, _d;
1480
+ if (this._isOpen) {
1481
+ return;
1482
+ }
1477
1483
  this._spaceContext = spaceContext;
1478
1484
  if (this._params.snapshotId) {
1479
1485
  this._snapshot = await this._params.snapshotManager.load(this._params.snapshotId);
1480
1486
  this._lastAutomaticSnapshotTimeframe = (_b = (_a = this._snapshot) == null ? void 0 : _a.timeframe) != null ? _b : new import_timeframe3.Timeframe();
1481
1487
  }
1482
1488
  this._pipeline = await this._spaceContext.openPipeline(this.getStartTimeframe());
1489
+ if (this._targetTimeframe) {
1490
+ this._pipeline.state.setTargetTimeframe(this._targetTimeframe);
1491
+ }
1483
1492
  const feedWriter = createMappedFeedWriter((data) => ({
1484
1493
  data
1485
1494
  }), (_c = this._pipeline.writer) != null ? _c : (0, import_debug6.failUndefined)());
@@ -1490,30 +1499,33 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1490
1499
  await this._consumePipeline();
1491
1500
  });
1492
1501
  this._createPeriodicSnapshots();
1502
+ this._isOpen = true;
1493
1503
  }
1494
1504
  _createPeriodicSnapshots() {
1495
1505
  this.onTimeframeReached.debounce(TIMEFRAME_SAVE_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1496
1506
  await this._saveLatestTimeframe();
1497
1507
  });
1498
- this.onTimeframeReached.debounce(AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1499
- var _a, _b;
1500
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1501
- if (!latestTimeframe) {
1502
- return;
1503
- }
1504
- if (latestTimeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1505
- const snapshot = await this._saveSnapshot();
1506
- this._lastAutomaticSnapshotTimeframe = (_b = snapshot.timeframe) != null ? _b : (0, import_debug6.failUndefined)();
1507
- (0, import_log11.log)("save", {
1508
- snapshot
1509
- }, {
1510
- file: "data-pipeline-controller.ts",
1511
- line: 149,
1512
- scope: this,
1513
- callSite: (f, a) => f(...a)
1514
- });
1515
- }
1516
- });
1508
+ if (!DISABLE_SNAPSHOT_CACHE) {
1509
+ this.onTimeframeReached.debounce(AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1510
+ var _a, _b;
1511
+ const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1512
+ if (!latestTimeframe) {
1513
+ return;
1514
+ }
1515
+ if (latestTimeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1516
+ const snapshot = await this._saveSnapshot();
1517
+ this._lastAutomaticSnapshotTimeframe = (_b = snapshot.timeframe) != null ? _b : (0, import_debug6.failUndefined)();
1518
+ (0, import_log11.log)("save", {
1519
+ snapshot
1520
+ }, {
1521
+ file: "data-pipeline.ts",
1522
+ line: 161,
1523
+ scope: this,
1524
+ callSite: (f, a) => f(...a)
1525
+ });
1526
+ }
1527
+ });
1528
+ }
1517
1529
  }
1518
1530
  async _saveSnapshot() {
1519
1531
  const snapshot = await this.createSnapshot();
@@ -1522,21 +1534,41 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1522
1534
  return snapshot;
1523
1535
  }
1524
1536
  async _saveLatestTimeframe() {
1525
- var _a;
1537
+ var _a, _b;
1526
1538
  const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1539
+ (0, import_log11.log)("save latest timeframe", {
1540
+ latestTimeframe,
1541
+ spaceKey: this._params.spaceKey
1542
+ }, {
1543
+ file: "data-pipeline.ts",
1544
+ line: 176,
1545
+ scope: this,
1546
+ callSite: (f, a) => f(...a)
1547
+ });
1527
1548
  if (latestTimeframe) {
1528
- await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, latestTimeframe);
1549
+ const newTimeframe = import_timeframe3.Timeframe.merge((_b = this._targetTimeframe) != null ? _b : new import_timeframe3.Timeframe(), latestTimeframe);
1550
+ await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1529
1551
  }
1530
1552
  }
1531
1553
  async close() {
1532
1554
  var _a, _b, _c;
1555
+ if (!this._isOpen) {
1556
+ return;
1557
+ }
1558
+ (0, import_log11.log)("close", {}, {
1559
+ file: "data-pipeline.ts",
1560
+ line: 188,
1561
+ scope: this,
1562
+ callSite: (f, a) => f(...a)
1563
+ });
1564
+ this._isOpen = false;
1533
1565
  try {
1534
1566
  await this._saveLatestTimeframe();
1535
1567
  await this._saveSnapshot();
1536
1568
  } catch (err) {
1537
1569
  import_log11.log.catch(err, {}, {
1538
- file: "data-pipeline-controller.ts",
1539
- line: 173,
1570
+ file: "data-pipeline.ts",
1571
+ line: 195,
1540
1572
  scope: this,
1541
1573
  callSite: (f, a) => f(...a)
1542
1574
  });
@@ -1549,6 +1581,7 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1549
1581
  }
1550
1582
  createSnapshot() {
1551
1583
  var _a, _b;
1584
+ (0, import_node_assert9.default)(this.databaseBackend, "Database backend is not initialized.");
1552
1585
  return {
1553
1586
  spaceKey: this._params.spaceKey.asUint8Array(),
1554
1587
  timeframe: (_b = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe) != null ? _b : new import_timeframe3.Timeframe(),
@@ -1562,8 +1595,8 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1562
1595
  (0, import_log11.log)("processing message", {
1563
1596
  msg
1564
1597
  }, {
1565
- file: "data-pipeline-controller.ts",
1566
- line: 194,
1598
+ file: "data-pipeline.ts",
1599
+ line: 217,
1567
1600
  scope: this,
1568
1601
  callSite: (f, a) => f(...a)
1569
1602
  });
@@ -1574,15 +1607,15 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1574
1607
  import_log11.log.error("Could not find feed.", {
1575
1608
  feedKey
1576
1609
  }, {
1577
- file: "data-pipeline-controller.ts",
1578
- line: 200,
1610
+ file: "data-pipeline.ts",
1611
+ line: 223,
1579
1612
  scope: this,
1580
1613
  callSite: (f, a) => f(...a)
1581
1614
  });
1582
1615
  continue;
1583
1616
  }
1584
1617
  await this.databaseBackend.echoProcessor({
1585
- data: data.payload.data.object,
1618
+ batch: data.payload.data.batch,
1586
1619
  meta: {
1587
1620
  feedKey,
1588
1621
  seq,
@@ -1594,8 +1627,8 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1594
1627
  }
1595
1628
  } catch (err) {
1596
1629
  import_log11.log.catch(err, {}, {
1597
- file: "data-pipeline-controller.ts",
1598
- line: 216,
1630
+ file: "data-pipeline.ts",
1631
+ line: 239,
1599
1632
  scope: this,
1600
1633
  callSite: (f, a) => f(...a)
1601
1634
  });
@@ -1607,9 +1640,15 @@ var DataPipelineControllerImpl = class DataPipelineControllerImpl2 {
1607
1640
  await this._pipeline.state.waitUntilTimeframe(timeframe);
1608
1641
  }
1609
1642
  };
1610
- DataPipelineControllerImpl = __decorate7([
1643
+ __decorate7([
1644
+ import_async8.synchronized
1645
+ ], DataPipeline.prototype, "open", null);
1646
+ __decorate7([
1647
+ import_async8.synchronized
1648
+ ], DataPipeline.prototype, "close", null);
1649
+ DataPipeline = __decorate7([
1611
1650
  (0, import_async8.trackLeaks)("open", "close")
1612
- ], DataPipelineControllerImpl);
1651
+ ], DataPipeline);
1613
1652
  var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
1614
1653
  return snapshotTimeframe.map(([key, seq]) => [
1615
1654
  key,
@@ -1709,7 +1748,7 @@ var TestAgent = class {
1709
1748
  await metadataStore.addSpace({
1710
1749
  key: spaceKey
1711
1750
  });
1712
- const dataPipelineController = new DataPipelineControllerImpl({
1751
+ const dataPipelineController = new DataPipeline({
1713
1752
  modelFactory: new import_model_factory.ModelFactory().registerModel(import_document_model.DocumentModel),
1714
1753
  metadataStore,
1715
1754
  snapshotManager,
@@ -1725,14 +1764,22 @@ var TestAgent = class {
1725
1764
  feedProvider: (feedKey) => this.feedStore.openFeed(feedKey)
1726
1765
  }).setControlFeed(controlFeed).setDataFeed(dataFeed);
1727
1766
  await space.open();
1728
- await space.initDataPipeline(dataPipelineController);
1767
+ await dataPipelineController.open({
1768
+ openPipeline: async (start) => {
1769
+ const pipeline = await space.createDataPipeline({
1770
+ start
1771
+ });
1772
+ await pipeline.start();
1773
+ return pipeline;
1774
+ }
1775
+ });
1729
1776
  this._spaces.set(spaceKey, space);
1730
1777
  return [
1731
1778
  space,
1732
1779
  dataPipelineController
1733
1780
  ];
1734
1781
  }
1735
- createSpaceProtocol(topic, presence) {
1782
+ createSpaceProtocol(topic, gossip) {
1736
1783
  return new SpaceProtocol({
1737
1784
  topic,
1738
1785
  swarmIdentity: {
@@ -1742,18 +1789,23 @@ var TestAgent = class {
1742
1789
  },
1743
1790
  networkManager: this._networkManagerProvider(),
1744
1791
  onSessionAuth: (session) => {
1745
- session.addExtension("dxos.mesh.teleport.presence", (presence != null ? presence : this.createPresence()).createExtension({
1792
+ session.addExtension("dxos.mesh.teleport.gossip", (gossip != null ? gossip : this.createGossip()).createExtension({
1746
1793
  remotePeerId: session.remotePeerId
1747
1794
  }));
1748
1795
  }
1749
1796
  });
1750
1797
  }
1751
- createPresence() {
1752
- return new import_teleport_extension_presence.Presence({
1753
- localPeerId: this.deviceKey,
1798
+ createGossip() {
1799
+ return new import_teleport_extension_gossip.Gossip({
1800
+ localPeerId: this.deviceKey
1801
+ });
1802
+ }
1803
+ createPresence(gossip) {
1804
+ return new import_teleport_extension_gossip.Presence({
1754
1805
  announceInterval: 30,
1755
1806
  offlineTimeout: 200,
1756
- identityKey: this.identityKey
1807
+ identityKey: this.identityKey,
1808
+ gossip: gossip != null ? gossip : this.createGossip()
1757
1809
  });
1758
1810
  }
1759
1811
  };
@@ -1770,7 +1822,7 @@ var createMemoryDatabase = async (modelFactory) => {
1770
1822
  const feed = new import_testing2.MockFeedWriter();
1771
1823
  const backend = new DatabaseBackendHost(feed, void 0);
1772
1824
  feed.written.on(([data, meta]) => backend.echoProcessor({
1773
- data: data.object,
1825
+ batch: data.batch,
1774
1826
  meta: {
1775
1827
  ...meta,
1776
1828
  memberKey: import_keys7.PublicKey.random(),
@@ -1806,14 +1858,18 @@ var testLocalDatabase = async (create, check = create) => {
1806
1858
  var _a;
1807
1859
  const objectId = import_keys7.PublicKey.random().toHex();
1808
1860
  await ((_a = create.databaseBackend.getWriteStream()) == null ? void 0 : _a.write({
1809
- object: {
1810
- objectId,
1811
- genesis: {
1812
- modelType: import_document_model2.DocumentModel.meta.type
1813
- }
1861
+ batch: {
1862
+ objects: [
1863
+ {
1864
+ objectId,
1865
+ genesis: {
1866
+ modelType: import_document_model2.DocumentModel.meta.type
1867
+ }
1868
+ }
1869
+ ]
1814
1870
  }
1815
1871
  }));
1816
- await (0, import_async9.asyncTimeout)(check._itemManager.update.waitForCondition(() => check._itemManager.entities.has(objectId)), 500);
1872
+ await (0, import_async9.asyncTimeout)(check.databaseBackend._itemDemuxer.mutation.waitForCondition(() => check._itemManager.entities.has(objectId)), 500);
1817
1873
  };
1818
1874
  // Annotate the CommonJS export names for ESM import in node:
1819
1875
  0 && (module.exports = {