@dxos/echo-pipeline 0.1.36-next.ef27157 → 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 (48) hide show
  1. package/dist/lib/browser/{chunk-LIPDNX3G.mjs → chunk-4YAT2XJW.mjs} +159 -125
  2. package/dist/lib/browser/chunk-4YAT2XJW.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +3 -3
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +5 -5
  6. package/dist/lib/browser/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/index.cjs +158 -124
  8. package/dist/lib/node/index.cjs.map +4 -4
  9. package/dist/lib/node/meta.json +1 -1
  10. package/dist/lib/node/testing/index.cjs +158 -124
  11. package/dist/lib/node/testing/index.cjs.map +4 -4
  12. package/dist/types/src/dbhost/data-service-host.d.ts.map +1 -1
  13. package/dist/types/src/dbhost/{database-backend.d.ts → database-host.d.ts} +2 -2
  14. package/dist/types/src/dbhost/database-host.d.ts.map +1 -0
  15. package/dist/types/src/dbhost/index.d.ts +1 -1
  16. package/dist/types/src/dbhost/index.d.ts.map +1 -1
  17. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  18. package/dist/types/src/pipeline/pipeline.d.ts +1 -0
  19. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  20. package/dist/types/src/pipeline/timeframe-clock.d.ts +11 -1
  21. package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
  22. package/dist/types/src/space/data-pipeline.d.ts +8 -9
  23. package/dist/types/src/space/data-pipeline.d.ts.map +1 -1
  24. package/dist/types/src/space/data-pipeline.test.d.ts +1 -0
  25. package/dist/types/src/space/data-pipeline.test.d.ts.map +1 -0
  26. package/dist/types/src/space/space-manager.d.ts +1 -0
  27. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  28. package/dist/types/src/testing/database-test-rig.d.ts +4 -4
  29. package/dist/types/src/testing/database-test-rig.d.ts.map +1 -1
  30. package/dist/types/src/testing/util.d.ts +4 -4
  31. package/dist/types/src/testing/util.d.ts.map +1 -1
  32. package/package.json +31 -29
  33. package/src/common/feeds.ts +1 -1
  34. package/src/dbhost/data-service-host.ts +16 -9
  35. package/src/dbhost/{database-backend.ts → database-host.ts} +1 -1
  36. package/src/dbhost/index.ts +1 -1
  37. package/src/metadata/metadata-store.ts +24 -20
  38. package/src/pipeline/pipeline.ts +6 -1
  39. package/src/pipeline/timeframe-clock.ts +22 -3
  40. package/src/space/data-pipeline.test.ts +3 -0
  41. package/src/space/data-pipeline.ts +63 -64
  42. package/src/space/space-manager.ts +2 -1
  43. package/src/testing/database-test-rig.ts +6 -6
  44. package/src/testing/util.ts +4 -4
  45. package/src/tests/database-unit.test.ts +13 -0
  46. package/src/tests/database.test.ts +39 -1
  47. package/dist/lib/browser/chunk-LIPDNX3G.mjs.map +0 -7
  48. package/dist/types/src/dbhost/database-backend.d.ts.map +0 -1
@@ -37,7 +37,7 @@ __export(src_exports, {
37
37
  DataServiceHost: () => DataServiceHost,
38
38
  DataServiceImpl: () => DataServiceImpl,
39
39
  DataServiceSubscriptions: () => DataServiceSubscriptions,
40
- DatabaseBackendHost: () => DatabaseBackendHost,
40
+ DatabaseHost: () => DatabaseHost,
41
41
  EntityNotFoundError: () => EntityNotFoundError,
42
42
  IdentityNotInitializedError: () => IdentityNotInitializedError,
43
43
  InvalidInvitationError: () => InvalidInvitationError,
@@ -116,8 +116,10 @@ var UnknownModelError = class extends DBError {
116
116
  };
117
117
 
118
118
  // packages/core/echo/echo-pipeline/src/metadata/metadata-store.ts
119
+ var import_crc_32 = __toESM(require("crc-32"));
119
120
  var import_node_assert = __toESM(require("node:assert"));
120
121
  var import_async = require("@dxos/async");
122
+ var import_errors = require("@dxos/errors");
121
123
  var import_log = require("@dxos/log");
122
124
  var import_protocols = require("@dxos/protocols");
123
125
  var __decorate = function(decorators, target, key, desc) {
@@ -162,31 +164,35 @@ var MetadataStore = class {
162
164
  const file = this._directory.getOrCreateFile("EchoMetadata");
163
165
  try {
164
166
  const { size: fileLength } = await file.stat();
165
- if (fileLength < 4) {
167
+ if (fileLength < 8) {
166
168
  return;
167
169
  }
168
170
  const dataSize = fromBytesInt32(await file.read(0, 4));
171
+ const checksum = fromBytesInt32(await file.read(4, 4));
169
172
  (0, import_log.log)("loaded", {
170
- size: dataSize
173
+ size: dataSize,
174
+ checksum
171
175
  }, {
172
176
  file: "metadata-store.ts",
173
- line: 67,
177
+ line: 70,
174
178
  scope: this,
175
179
  callSite: (f, a) => f(...a)
176
180
  });
177
- {
178
- if (fileLength < dataSize + 4) {
179
- throw new Error("Metadata storage is corrupted");
180
- }
181
+ if (fileLength < dataSize + 8) {
182
+ throw new import_errors.DataCorruptionError("Metadata size is smaller than expected.");
183
+ }
184
+ const data = await file.read(8, dataSize);
185
+ const calculatedChecksum = import_crc_32.default.buf(data);
186
+ if (calculatedChecksum !== checksum) {
187
+ throw new import_errors.DataCorruptionError("Metadata checksum is invalid.");
181
188
  }
182
- const data = await file.read(4, dataSize);
183
189
  this._metadata = import_protocols.schema.getCodecForType("dxos.echo.metadata.EchoMetadata").decode(data);
184
190
  } catch (err) {
185
191
  import_log.log.error("failed to load metadata", {
186
192
  err
187
193
  }, {
188
194
  file: "metadata-store.ts",
189
- line: 79,
195
+ line: 85,
190
196
  scope: this,
191
197
  callSite: (f, a) => f(...a)
192
198
  });
@@ -206,16 +212,21 @@ var MetadataStore = class {
206
212
  const file = this._directory.getOrCreateFile("EchoMetadata");
207
213
  try {
208
214
  const encoded = Buffer.from(import_protocols.schema.getCodecForType("dxos.echo.metadata.EchoMetadata").encode(data));
209
- await file.write(0, toBytesInt32(encoded.length));
215
+ const checksum = import_crc_32.default.buf(encoded);
216
+ const result = Buffer.alloc(8 + encoded.length);
217
+ result.writeInt32LE(encoded.length, 0);
218
+ result.writeInt32LE(checksum, 4);
219
+ encoded.copy(result, 8);
220
+ await file.write(0, result);
210
221
  (0, import_log.log)("saved", {
211
- size: encoded.length
222
+ size: encoded.length,
223
+ checksum
212
224
  }, {
213
225
  file: "metadata-store.ts",
214
- line: 102,
226
+ line: 116,
215
227
  scope: this,
216
228
  callSite: (f, a) => f(...a)
217
229
  });
218
- await file.write(4, encoded);
219
230
  } finally {
220
231
  await file.close();
221
232
  }
@@ -226,7 +237,7 @@ var MetadataStore = class {
226
237
  async clear() {
227
238
  (0, import_log.log)("clearing all metadata", {}, {
228
239
  file: "metadata-store.ts",
229
- line: 115,
240
+ line: 126,
230
241
  scope: this,
231
242
  callSite: (f, a) => f(...a)
232
243
  });
@@ -272,11 +283,6 @@ __decorate([
272
283
  __decorate([
273
284
  import_async.synchronized
274
285
  ], MetadataStore.prototype, "_save", null);
275
- var toBytesInt32 = (num) => {
276
- const buf = Buffer.alloc(4);
277
- buf.writeInt32LE(num, 0);
278
- return buf;
279
- };
280
286
  var fromBytesInt32 = (buf) => buf.readInt32LE(0);
281
287
 
282
288
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
@@ -300,7 +306,7 @@ var createMappedFeedWriter = (mapper, writer) => {
300
306
  (0, import_node_assert2.default)(mapper);
301
307
  (0, import_node_assert2.default)(writer);
302
308
  return {
303
- write: async (data) => await writer.write(await mapper(data))
309
+ write: async (data, options) => await writer.write(await mapper(data), options)
304
310
  };
305
311
  };
306
312
 
@@ -353,17 +359,31 @@ var TimeframeClock = class {
353
359
  constructor(_timeframe = new import_timeframe.Timeframe()) {
354
360
  this._timeframe = _timeframe;
355
361
  this.update = new import_async2.Event();
362
+ this._pendingTimeframe = _timeframe;
356
363
  }
364
+ /**
365
+ * Timeframe that was processed by ECHO.
366
+ */
357
367
  get timeframe() {
358
368
  return this._timeframe;
359
369
  }
360
- updateTimeframe(key, seq) {
361
- this._timeframe = import_timeframe.Timeframe.merge(this._timeframe, new import_timeframe.Timeframe([
370
+ /**
371
+ * Timeframe that is currently being processed by ECHO.
372
+ * Will be equal to `timeframe` after the processing is complete.
373
+ */
374
+ get pendingTimeframe() {
375
+ return this._pendingTimeframe;
376
+ }
377
+ updatePendingTimeframe(key, seq) {
378
+ this._pendingTimeframe = import_timeframe.Timeframe.merge(this._pendingTimeframe, new import_timeframe.Timeframe([
362
379
  [
363
380
  key,
364
381
  seq
365
382
  ]
366
383
  ]));
384
+ }
385
+ updateTimeframe() {
386
+ this._timeframe = this._pendingTimeframe;
367
387
  this.update.emit(this._timeframe);
368
388
  }
369
389
  hasGaps(timeframe) {
@@ -376,7 +396,7 @@ var TimeframeClock = class {
376
396
  current: this._timeframe
377
397
  }, {
378
398
  file: "timeframe-clock.ts",
379
- line: 48,
399
+ line: 67,
380
400
  scope: this,
381
401
  callSite: (f, a) => f(...a)
382
402
  });
@@ -387,7 +407,7 @@ var TimeframeClock = class {
387
407
  deps: import_timeframe.Timeframe.dependencies(target, this._timeframe)
388
408
  }, {
389
409
  file: "timeframe-clock.ts",
390
- line: 50,
410
+ line: 69,
391
411
  scope: this,
392
412
  callSite: (f, a) => f(...a)
393
413
  });
@@ -431,6 +451,9 @@ var PipelineState = class {
431
451
  get timeframe() {
432
452
  return this._timeframeClock.timeframe;
433
453
  }
454
+ get pendingTimeframe() {
455
+ return this._timeframeClock.pendingTimeframe;
456
+ }
434
457
  get targetTimeframe() {
435
458
  return this._targetTimeframe ? this._targetTimeframe : new import_timeframe2.Timeframe();
436
459
  }
@@ -458,7 +481,7 @@ var PipelineState = class {
458
481
  target: this.targetTimeframe
459
482
  }, {
460
483
  file: "pipeline.ts",
461
- line: 101,
484
+ line: 105,
462
485
  scope: this,
463
486
  callSite: (f, a) => f(...a)
464
487
  });
@@ -488,7 +511,7 @@ var PipelineState = class {
488
511
  dependencies: import_timeframe2.Timeframe.dependencies(this.targetTimeframe, this.timeframe)
489
512
  }, {
490
513
  file: "pipeline.ts",
491
- line: 127,
514
+ line: 131,
492
515
  scope: this,
493
516
  callSite: (f, a) => f(...a)
494
517
  });
@@ -514,7 +537,7 @@ var Pipeline = class {
514
537
  this._feedSetIterator.stalled.on((iterator) => {
515
538
  import_log3.log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
516
539
  file: "pipeline.ts",
517
- line: 203,
540
+ line: 207,
518
541
  scope: this,
519
542
  callSite: (f, a) => f(...a)
520
543
  });
@@ -549,14 +572,14 @@ var Pipeline = class {
549
572
  async start() {
550
573
  (0, import_log3.log)("starting...", {}, {
551
574
  file: "pipeline.ts",
552
- line: 245,
575
+ line: 249,
553
576
  scope: this,
554
577
  callSite: (f, a) => f(...a)
555
578
  });
556
579
  await this._feedSetIterator.open();
557
580
  (0, import_log3.log)("started", {}, {
558
581
  file: "pipeline.ts",
559
- line: 247,
582
+ line: 251,
560
583
  scope: this,
561
584
  callSite: (f, a) => f(...a)
562
585
  });
@@ -564,7 +587,7 @@ var Pipeline = class {
564
587
  async stop() {
565
588
  (0, import_log3.log)("stopping...", {}, {
566
589
  file: "pipeline.ts",
567
- line: 252,
590
+ line: 256,
568
591
  scope: this,
569
592
  callSite: (f, a) => f(...a)
570
593
  });
@@ -572,7 +595,7 @@ var Pipeline = class {
572
595
  await this._processingTrigger.wait();
573
596
  (0, import_log3.log)("stopped", {}, {
574
597
  file: "pipeline.ts",
575
- line: 255,
598
+ line: 259,
576
599
  scope: this,
577
600
  callSite: (f, a) => f(...a)
578
601
  });
@@ -586,9 +609,10 @@ var Pipeline = class {
586
609
  this._isOpen = true;
587
610
  for await (const block of this._feedSetIterator) {
588
611
  this._processingTrigger.reset();
612
+ this._timeframeClock.updatePendingTimeframe(import_keys.PublicKey.from(block.feedKey), block.seq);
589
613
  yield block;
590
614
  this._processingTrigger.wake();
591
- this._timeframeClock.updateTimeframe(import_keys.PublicKey.from(block.feedKey), block.seq);
615
+ this._timeframeClock.updateTimeframe();
592
616
  }
593
617
  this._isOpen = false;
594
618
  }
@@ -1206,10 +1230,11 @@ var SpaceManager = class SpaceManager2 {
1206
1230
  }
1207
1231
  async open() {
1208
1232
  import_log8.log.trace("dxos.echo.space-manager", import_protocols4.trace.begin({
1209
- id: this._instanceId
1233
+ id: this._instanceId,
1234
+ parentId: this._traceParent
1210
1235
  }), {
1211
1236
  file: "space-manager.ts",
1212
- line: 65,
1237
+ line: 66,
1213
1238
  scope: this,
1214
1239
  callSite: (f, a) => f(...a)
1215
1240
  });
@@ -1222,7 +1247,7 @@ var SpaceManager = class SpaceManager2 {
1222
1247
  id: this._instanceId
1223
1248
  }), {
1224
1249
  file: "space-manager.ts",
1225
- line: 71,
1250
+ line: 72,
1226
1251
  scope: this,
1227
1252
  callSite: (f, a) => f(...a)
1228
1253
  });
@@ -1233,7 +1258,7 @@ var SpaceManager = class SpaceManager2 {
1233
1258
  spaceKey: metadata.genesisFeedKey
1234
1259
  }, {
1235
1260
  file: "space-manager.ts",
1236
- line: 75,
1261
+ line: 76,
1237
1262
  scope: this,
1238
1263
  callSite: (f, a) => f(...a)
1239
1264
  });
@@ -1360,12 +1385,12 @@ var DataServiceHost = class {
1360
1385
  this._itemDemuxer.mutation.on(ctx, (message) => {
1361
1386
  var _a;
1362
1387
  const { batch, meta } = message;
1363
- (0, import_log9.log)("Object update", {
1388
+ (0, import_log9.log)("message", {
1364
1389
  batch,
1365
1390
  meta
1366
1391
  }, {
1367
1392
  file: "data-service-host.ts",
1368
- line: 50,
1393
+ line: 49,
1369
1394
  scope: this,
1370
1395
  callSite: (f, a) => f(...a)
1371
1396
  });
@@ -1389,36 +1414,59 @@ var DataServiceHost = class {
1389
1414
  });
1390
1415
  }
1391
1416
  async write(request) {
1392
- var _a;
1417
+ var _a, _b, _c;
1393
1418
  (0, import_node_assert7.default)(this._writeStream, "Cannot write mutations in readonly mode");
1394
- const receipt = await this._writeStream.write({
1419
+ (0, import_log9.log)("write", {
1420
+ clientTag: request.clientTag,
1421
+ objectCount: (_b = (_a = request.batch.objects) == null ? void 0 : _a.length) != null ? _b : 0
1422
+ }, {
1423
+ file: "data-service-host.ts",
1424
+ line: 77,
1425
+ scope: this,
1426
+ callSite: (f, a) => f(...a)
1427
+ });
1428
+ const message = {
1395
1429
  batch: {
1396
- objects: (_a = request.batch.objects) == null ? void 0 : _a.map((object) => {
1430
+ objects: (_c = request.batch.objects) == null ? void 0 : _c.map((object) => {
1397
1431
  var _a2;
1398
1432
  return {
1399
1433
  ...object,
1400
- mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((m) => ({
1401
- ...m,
1434
+ mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((mutation) => ({
1435
+ ...mutation,
1402
1436
  meta: void 0
1403
1437
  })),
1404
1438
  meta: void 0
1405
1439
  };
1406
1440
  })
1407
1441
  }
1442
+ };
1443
+ const receipt = await this._writeStream.write(message, {
1444
+ afterWrite: async (receipt2) => {
1445
+ if (request.clientTag) {
1446
+ (0, import_log9.log)("tag", {
1447
+ clientTag: request.clientTag,
1448
+ feedKey: receipt2.feedKey,
1449
+ seq: receipt2.seq
1450
+ }, {
1451
+ file: "data-service-host.ts",
1452
+ line: 96,
1453
+ scope: this,
1454
+ callSite: (f, a) => f(...a)
1455
+ });
1456
+ this._clientTagMap.set([
1457
+ receipt2.feedKey,
1458
+ receipt2.seq
1459
+ ], request.clientTag);
1460
+ }
1461
+ }
1408
1462
  });
1409
- if (request.clientTag) {
1410
- this._clientTagMap.set([
1411
- receipt.feedKey,
1412
- receipt.seq
1413
- ], request.clientTag);
1414
- }
1415
1463
  return receipt;
1416
1464
  }
1417
1465
  };
1418
1466
 
1419
- // packages/core/echo/echo-pipeline/src/dbhost/database-backend.ts
1467
+ // packages/core/echo/echo-pipeline/src/dbhost/database-host.ts
1420
1468
  var import_echo_db2 = require("@dxos/echo-db");
1421
- var DatabaseBackendHost = class {
1469
+ var DatabaseHost = class {
1422
1470
  constructor(_outboundStream, _snapshot) {
1423
1471
  this._outboundStream = _outboundStream;
1424
1472
  this._snapshot = _snapshot;
@@ -1627,7 +1675,8 @@ var DataPipeline = class DataPipeline2 {
1627
1675
  this._ctx = new import_context3.Context();
1628
1676
  this._lastAutomaticSnapshotTimeframe = new import_timeframe3.Timeframe();
1629
1677
  this._isOpen = false;
1630
- this.onTimeframeReached = new import_async8.Event();
1678
+ this._lastTimeframeSaveTime = 0;
1679
+ this._lastSnapshotSaveTime = 0;
1631
1680
  }
1632
1681
  get isOpen() {
1633
1682
  return this._isOpen;
@@ -1666,64 +1715,14 @@ var DataPipeline = class DataPipeline2 {
1666
1715
  const feedWriter = createMappedFeedWriter((data) => ({
1667
1716
  data
1668
1717
  }), (_c = this._pipeline.writer) != null ? _c : (0, import_debug6.failUndefined)());
1669
- this.databaseBackend = new DatabaseBackendHost(feedWriter, (_d = this._snapshot) == null ? void 0 : _d.database);
1718
+ this.databaseBackend = new DatabaseHost(feedWriter, (_d = this._snapshot) == null ? void 0 : _d.database);
1670
1719
  this._itemManager = new import_echo_db3.ItemManager(this._params.modelFactory);
1671
1720
  await this.databaseBackend.open(this._itemManager, this._params.modelFactory);
1672
1721
  (0, import_async8.scheduleTask)(this._ctx, async () => {
1673
1722
  await this._consumePipeline();
1674
1723
  });
1675
- this._createPeriodicSnapshots();
1676
1724
  this._isOpen = true;
1677
1725
  }
1678
- _createPeriodicSnapshots() {
1679
- this.onTimeframeReached.debounce(TIMEFRAME_SAVE_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1680
- await this._saveLatestTimeframe();
1681
- });
1682
- if (!DISABLE_SNAPSHOT_CACHE) {
1683
- this.onTimeframeReached.debounce(AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1684
- var _a, _b;
1685
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1686
- if (!latestTimeframe) {
1687
- return;
1688
- }
1689
- if (latestTimeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1690
- const snapshot = await this._saveSnapshot();
1691
- this._lastAutomaticSnapshotTimeframe = (_b = snapshot.timeframe) != null ? _b : (0, import_debug6.failUndefined)();
1692
- (0, import_log11.log)("save", {
1693
- snapshot
1694
- }, {
1695
- file: "data-pipeline.ts",
1696
- line: 161,
1697
- scope: this,
1698
- callSite: (f, a) => f(...a)
1699
- });
1700
- }
1701
- });
1702
- }
1703
- }
1704
- async _saveSnapshot() {
1705
- const snapshot = await this.createSnapshot();
1706
- const snapshotKey = await this._params.snapshotManager.store(snapshot);
1707
- await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1708
- return snapshot;
1709
- }
1710
- async _saveLatestTimeframe() {
1711
- var _a, _b;
1712
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1713
- (0, import_log11.log)("save latest timeframe", {
1714
- latestTimeframe,
1715
- spaceKey: this._params.spaceKey
1716
- }, {
1717
- file: "data-pipeline.ts",
1718
- line: 176,
1719
- scope: this,
1720
- callSite: (f, a) => f(...a)
1721
- });
1722
- if (latestTimeframe) {
1723
- const newTimeframe = import_timeframe3.Timeframe.merge((_b = this._targetTimeframe) != null ? _b : new import_timeframe3.Timeframe(), latestTimeframe);
1724
- await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1725
- }
1726
- }
1727
1726
  async close() {
1728
1727
  var _a, _b, _c;
1729
1728
  if (!this._isOpen) {
@@ -1731,37 +1730,32 @@ var DataPipeline = class DataPipeline2 {
1731
1730
  }
1732
1731
  (0, import_log11.log)("close", {}, {
1733
1732
  file: "data-pipeline.ts",
1734
- line: 188,
1733
+ line: 145,
1735
1734
  scope: this,
1736
1735
  callSite: (f, a) => f(...a)
1737
1736
  });
1738
1737
  this._isOpen = false;
1738
+ await this._ctx.dispose();
1739
+ await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1739
1740
  try {
1740
- await this._saveLatestTimeframe();
1741
- await this._saveSnapshot();
1741
+ if (this._pipeline) {
1742
+ await this._saveTargetTimeframe(this._pipeline.state.timeframe);
1743
+ if (!DISABLE_SNAPSHOT_CACHE) {
1744
+ await this._saveSnapshot(this._pipeline.state.timeframe);
1745
+ }
1746
+ }
1742
1747
  } catch (err) {
1743
1748
  import_log11.log.catch(err, {}, {
1744
1749
  file: "data-pipeline.ts",
1745
- line: 195,
1750
+ line: 160,
1746
1751
  scope: this,
1747
1752
  callSite: (f, a) => f(...a)
1748
1753
  });
1749
1754
  }
1750
- await this._ctx.dispose();
1751
- await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1752
1755
  await ((_b = this.databaseBackend) == null ? void 0 : _b.close());
1753
1756
  await ((_c = this._itemManager) == null ? void 0 : _c.destroy());
1754
1757
  await this._params.snapshotManager.close();
1755
1758
  }
1756
- createSnapshot() {
1757
- var _a, _b;
1758
- (0, import_node_assert9.default)(this.databaseBackend, "Database backend is not initialized.");
1759
- return {
1760
- spaceKey: this._params.spaceKey.asUint8Array(),
1761
- timeframe: (_b = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe) != null ? _b : new import_timeframe3.Timeframe(),
1762
- database: this.databaseBackend.createSnapshot()
1763
- };
1764
- }
1765
1759
  async _consumePipeline() {
1766
1760
  (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1767
1761
  for await (const msg of this._pipeline.consume()) {
@@ -1770,7 +1764,7 @@ var DataPipeline = class DataPipeline2 {
1770
1764
  msg
1771
1765
  }, {
1772
1766
  file: "data-pipeline.ts",
1773
- line: 217,
1767
+ line: 172,
1774
1768
  scope: this,
1775
1769
  callSite: (f, a) => f(...a)
1776
1770
  });
@@ -1782,7 +1776,7 @@ var DataPipeline = class DataPipeline2 {
1782
1776
  feedKey
1783
1777
  }, {
1784
1778
  file: "data-pipeline.ts",
1785
- line: 223,
1779
+ line: 178,
1786
1780
  scope: this,
1787
1781
  callSite: (f, a) => f(...a)
1788
1782
  });
@@ -1797,18 +1791,58 @@ var DataPipeline = class DataPipeline2 {
1797
1791
  memberKey: feedInfo.assertion.identityKey
1798
1792
  }
1799
1793
  });
1800
- this.onTimeframeReached.emit(data.timeframe);
1794
+ await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1801
1795
  }
1802
1796
  } catch (err) {
1803
1797
  import_log11.log.catch(err, {}, {
1804
1798
  file: "data-pipeline.ts",
1805
- line: 239,
1799
+ line: 196,
1806
1800
  scope: this,
1807
1801
  callSite: (f, a) => f(...a)
1808
1802
  });
1809
1803
  }
1810
1804
  }
1811
1805
  }
1806
+ _createSnapshot(timeframe) {
1807
+ (0, import_node_assert9.default)(this.databaseBackend, "Database backend is not initialized.");
1808
+ return {
1809
+ spaceKey: this._params.spaceKey.asUint8Array(),
1810
+ timeframe,
1811
+ database: this.databaseBackend.createSnapshot()
1812
+ };
1813
+ }
1814
+ async _saveSnapshot(timeframe) {
1815
+ const snapshot = await this._createSnapshot(timeframe);
1816
+ const snapshotKey = await this._params.snapshotManager.store(snapshot);
1817
+ await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1818
+ return snapshot;
1819
+ }
1820
+ async _saveTargetTimeframe(timeframe) {
1821
+ var _a;
1822
+ const newTimeframe = import_timeframe3.Timeframe.merge((_a = this._targetTimeframe) != null ? _a : new import_timeframe3.Timeframe(), timeframe);
1823
+ await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1824
+ this._targetTimeframe = newTimeframe;
1825
+ }
1826
+ async _noteTargetStateIfNeeded(timeframe) {
1827
+ var _a;
1828
+ if (Date.now() - this._lastTimeframeSaveTime > TIMEFRAME_SAVE_DEBOUNCE_INTERVAL) {
1829
+ this._lastTimeframeSaveTime = Date.now();
1830
+ await this._saveTargetTimeframe(timeframe);
1831
+ }
1832
+ if (!DISABLE_SNAPSHOT_CACHE && Date.now() - this._lastSnapshotSaveTime > AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL && timeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1833
+ this._lastSnapshotSaveTime = Date.now();
1834
+ const snapshot = await this._saveSnapshot(timeframe);
1835
+ this._lastAutomaticSnapshotTimeframe = (_a = snapshot.timeframe) != null ? _a : (0, import_debug6.failUndefined)();
1836
+ (0, import_log11.log)("save", {
1837
+ snapshot
1838
+ }, {
1839
+ file: "data-pipeline.ts",
1840
+ line: 239,
1841
+ scope: this,
1842
+ callSite: (f, a) => f(...a)
1843
+ });
1844
+ }
1845
+ }
1812
1846
  async waitUntilTimeframe(timeframe) {
1813
1847
  (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1814
1848
  await this._pipeline.state.waitUntilTimeframe(timeframe);
@@ -1838,7 +1872,7 @@ var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
1838
1872
  DataServiceHost,
1839
1873
  DataServiceImpl,
1840
1874
  DataServiceSubscriptions,
1841
- DatabaseBackendHost,
1875
+ DatabaseHost,
1842
1876
  EntityNotFoundError,
1843
1877
  IdentityNotInitializedError,
1844
1878
  InvalidInvitationError,