@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
@@ -1,8 +1,10 @@
1
1
  import "@dxos/node-std/globals"
2
2
 
3
3
  // packages/core/echo/echo-pipeline/src/metadata/metadata-store.ts
4
+ import CRC32 from "crc-32";
4
5
  import assert from "@dxos/node-std/assert";
5
6
  import { synchronized } from "@dxos/async";
7
+ import { DataCorruptionError } from "@dxos/errors";
6
8
  import { log } from "@dxos/log";
7
9
  import { schema } from "@dxos/protocols";
8
10
  var __decorate = function(decorators, target, key, desc) {
@@ -47,31 +49,35 @@ var MetadataStore = class {
47
49
  const file = this._directory.getOrCreateFile("EchoMetadata");
48
50
  try {
49
51
  const { size: fileLength } = await file.stat();
50
- if (fileLength < 4) {
52
+ if (fileLength < 8) {
51
53
  return;
52
54
  }
53
55
  const dataSize = fromBytesInt32(await file.read(0, 4));
56
+ const checksum = fromBytesInt32(await file.read(4, 4));
54
57
  log("loaded", {
55
- size: dataSize
58
+ size: dataSize,
59
+ checksum
56
60
  }, {
57
61
  file: "metadata-store.ts",
58
- line: 67,
62
+ line: 70,
59
63
  scope: this,
60
64
  callSite: (f, a) => f(...a)
61
65
  });
62
- {
63
- if (fileLength < dataSize + 4) {
64
- throw new Error("Metadata storage is corrupted");
65
- }
66
+ if (fileLength < dataSize + 8) {
67
+ throw new DataCorruptionError("Metadata size is smaller than expected.");
68
+ }
69
+ const data = await file.read(8, dataSize);
70
+ const calculatedChecksum = CRC32.buf(data);
71
+ if (calculatedChecksum !== checksum) {
72
+ throw new DataCorruptionError("Metadata checksum is invalid.");
66
73
  }
67
- const data = await file.read(4, dataSize);
68
74
  this._metadata = schema.getCodecForType("dxos.echo.metadata.EchoMetadata").decode(data);
69
75
  } catch (err) {
70
76
  log.error("failed to load metadata", {
71
77
  err
72
78
  }, {
73
79
  file: "metadata-store.ts",
74
- line: 79,
80
+ line: 85,
75
81
  scope: this,
76
82
  callSite: (f, a) => f(...a)
77
83
  });
@@ -91,16 +97,21 @@ var MetadataStore = class {
91
97
  const file = this._directory.getOrCreateFile("EchoMetadata");
92
98
  try {
93
99
  const encoded = Buffer.from(schema.getCodecForType("dxos.echo.metadata.EchoMetadata").encode(data));
94
- await file.write(0, toBytesInt32(encoded.length));
100
+ const checksum = CRC32.buf(encoded);
101
+ const result = Buffer.alloc(8 + encoded.length);
102
+ result.writeInt32LE(encoded.length, 0);
103
+ result.writeInt32LE(checksum, 4);
104
+ encoded.copy(result, 8);
105
+ await file.write(0, result);
95
106
  log("saved", {
96
- size: encoded.length
107
+ size: encoded.length,
108
+ checksum
97
109
  }, {
98
110
  file: "metadata-store.ts",
99
- line: 102,
111
+ line: 116,
100
112
  scope: this,
101
113
  callSite: (f, a) => f(...a)
102
114
  });
103
- await file.write(4, encoded);
104
115
  } finally {
105
116
  await file.close();
106
117
  }
@@ -111,7 +122,7 @@ var MetadataStore = class {
111
122
  async clear() {
112
123
  log("clearing all metadata", {}, {
113
124
  file: "metadata-store.ts",
114
- line: 115,
125
+ line: 126,
115
126
  scope: this,
116
127
  callSite: (f, a) => f(...a)
117
128
  });
@@ -157,11 +168,6 @@ __decorate([
157
168
  __decorate([
158
169
  synchronized
159
170
  ], MetadataStore.prototype, "_save", null);
160
- var toBytesInt32 = (num) => {
161
- const buf = Buffer.alloc(4);
162
- buf.writeInt32LE(num, 0);
163
- return buf;
164
- };
165
171
  var fromBytesInt32 = (buf) => buf.readInt32LE(0);
166
172
 
167
173
  // packages/core/echo/echo-pipeline/src/common/codec.ts
@@ -176,7 +182,7 @@ var createMappedFeedWriter = (mapper, writer) => {
176
182
  assert2(mapper);
177
183
  assert2(writer);
178
184
  return {
179
- write: async (data) => await writer.write(await mapper(data))
185
+ write: async (data, options) => await writer.write(await mapper(data), options)
180
186
  };
181
187
  };
182
188
 
@@ -212,17 +218,31 @@ var TimeframeClock = class {
212
218
  constructor(_timeframe = new Timeframe()) {
213
219
  this._timeframe = _timeframe;
214
220
  this.update = new Event();
221
+ this._pendingTimeframe = _timeframe;
215
222
  }
223
+ /**
224
+ * Timeframe that was processed by ECHO.
225
+ */
216
226
  get timeframe() {
217
227
  return this._timeframe;
218
228
  }
219
- updateTimeframe(key, seq) {
220
- this._timeframe = Timeframe.merge(this._timeframe, new Timeframe([
229
+ /**
230
+ * Timeframe that is currently being processed by ECHO.
231
+ * Will be equal to `timeframe` after the processing is complete.
232
+ */
233
+ get pendingTimeframe() {
234
+ return this._pendingTimeframe;
235
+ }
236
+ updatePendingTimeframe(key, seq) {
237
+ this._pendingTimeframe = Timeframe.merge(this._pendingTimeframe, new Timeframe([
221
238
  [
222
239
  key,
223
240
  seq
224
241
  ]
225
242
  ]));
243
+ }
244
+ updateTimeframe() {
245
+ this._timeframe = this._pendingTimeframe;
226
246
  this.update.emit(this._timeframe);
227
247
  }
228
248
  hasGaps(timeframe) {
@@ -235,7 +255,7 @@ var TimeframeClock = class {
235
255
  current: this._timeframe
236
256
  }, {
237
257
  file: "timeframe-clock.ts",
238
- line: 48,
258
+ line: 67,
239
259
  scope: this,
240
260
  callSite: (f, a) => f(...a)
241
261
  });
@@ -246,7 +266,7 @@ var TimeframeClock = class {
246
266
  deps: Timeframe.dependencies(target, this._timeframe)
247
267
  }, {
248
268
  file: "timeframe-clock.ts",
249
- line: 50,
269
+ line: 69,
250
270
  scope: this,
251
271
  callSite: (f, a) => f(...a)
252
272
  });
@@ -316,6 +336,9 @@ var PipelineState = class {
316
336
  get timeframe() {
317
337
  return this._timeframeClock.timeframe;
318
338
  }
339
+ get pendingTimeframe() {
340
+ return this._timeframeClock.pendingTimeframe;
341
+ }
319
342
  get targetTimeframe() {
320
343
  return this._targetTimeframe ? this._targetTimeframe : new Timeframe2();
321
344
  }
@@ -343,7 +366,7 @@ var PipelineState = class {
343
366
  target: this.targetTimeframe
344
367
  }, {
345
368
  file: "pipeline.ts",
346
- line: 101,
369
+ line: 105,
347
370
  scope: this,
348
371
  callSite: (f, a) => f(...a)
349
372
  });
@@ -373,7 +396,7 @@ var PipelineState = class {
373
396
  dependencies: Timeframe2.dependencies(this.targetTimeframe, this.timeframe)
374
397
  }, {
375
398
  file: "pipeline.ts",
376
- line: 127,
399
+ line: 131,
377
400
  scope: this,
378
401
  callSite: (f, a) => f(...a)
379
402
  });
@@ -399,7 +422,7 @@ var Pipeline = class {
399
422
  this._feedSetIterator.stalled.on((iterator) => {
400
423
  log4.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
401
424
  file: "pipeline.ts",
402
- line: 203,
425
+ line: 207,
403
426
  scope: this,
404
427
  callSite: (f, a) => f(...a)
405
428
  });
@@ -434,14 +457,14 @@ var Pipeline = class {
434
457
  async start() {
435
458
  log4("starting...", {}, {
436
459
  file: "pipeline.ts",
437
- line: 245,
460
+ line: 249,
438
461
  scope: this,
439
462
  callSite: (f, a) => f(...a)
440
463
  });
441
464
  await this._feedSetIterator.open();
442
465
  log4("started", {}, {
443
466
  file: "pipeline.ts",
444
- line: 247,
467
+ line: 251,
445
468
  scope: this,
446
469
  callSite: (f, a) => f(...a)
447
470
  });
@@ -449,7 +472,7 @@ var Pipeline = class {
449
472
  async stop() {
450
473
  log4("stopping...", {}, {
451
474
  file: "pipeline.ts",
452
- line: 252,
475
+ line: 256,
453
476
  scope: this,
454
477
  callSite: (f, a) => f(...a)
455
478
  });
@@ -457,7 +480,7 @@ var Pipeline = class {
457
480
  await this._processingTrigger.wait();
458
481
  log4("stopped", {}, {
459
482
  file: "pipeline.ts",
460
- line: 255,
483
+ line: 259,
461
484
  scope: this,
462
485
  callSite: (f, a) => f(...a)
463
486
  });
@@ -471,9 +494,10 @@ var Pipeline = class {
471
494
  this._isOpen = true;
472
495
  for await (const block of this._feedSetIterator) {
473
496
  this._processingTrigger.reset();
497
+ this._timeframeClock.updatePendingTimeframe(PublicKey.from(block.feedKey), block.seq);
474
498
  yield block;
475
499
  this._processingTrigger.wake();
476
- this._timeframeClock.updateTimeframe(PublicKey.from(block.feedKey), block.seq);
500
+ this._timeframeClock.updateTimeframe();
477
501
  }
478
502
  this._isOpen = false;
479
503
  }
@@ -1089,10 +1113,11 @@ var SpaceManager = class SpaceManager2 {
1089
1113
  }
1090
1114
  async open() {
1091
1115
  log9.trace("dxos.echo.space-manager", trace.begin({
1092
- id: this._instanceId
1116
+ id: this._instanceId,
1117
+ parentId: this._traceParent
1093
1118
  }), {
1094
1119
  file: "space-manager.ts",
1095
- line: 65,
1120
+ line: 66,
1096
1121
  scope: this,
1097
1122
  callSite: (f, a) => f(...a)
1098
1123
  });
@@ -1105,7 +1130,7 @@ var SpaceManager = class SpaceManager2 {
1105
1130
  id: this._instanceId
1106
1131
  }), {
1107
1132
  file: "space-manager.ts",
1108
- line: 71,
1133
+ line: 72,
1109
1134
  scope: this,
1110
1135
  callSite: (f, a) => f(...a)
1111
1136
  });
@@ -1116,7 +1141,7 @@ var SpaceManager = class SpaceManager2 {
1116
1141
  spaceKey: metadata.genesisFeedKey
1117
1142
  }, {
1118
1143
  file: "space-manager.ts",
1119
- line: 75,
1144
+ line: 76,
1120
1145
  scope: this,
1121
1146
  callSite: (f, a) => f(...a)
1122
1147
  });
@@ -1234,12 +1259,12 @@ var DataServiceHost = class {
1234
1259
  this._itemDemuxer.mutation.on(ctx, (message) => {
1235
1260
  var _a;
1236
1261
  const { batch, meta } = message;
1237
- log10("Object update", {
1262
+ log10("message", {
1238
1263
  batch,
1239
1264
  meta
1240
1265
  }, {
1241
1266
  file: "data-service-host.ts",
1242
- line: 50,
1267
+ line: 49,
1243
1268
  scope: this,
1244
1269
  callSite: (f, a) => f(...a)
1245
1270
  });
@@ -1263,36 +1288,59 @@ var DataServiceHost = class {
1263
1288
  });
1264
1289
  }
1265
1290
  async write(request) {
1266
- var _a;
1291
+ var _a, _b, _c;
1267
1292
  assert7(this._writeStream, "Cannot write mutations in readonly mode");
1268
- const receipt = await this._writeStream.write({
1293
+ log10("write", {
1294
+ clientTag: request.clientTag,
1295
+ objectCount: (_b = (_a = request.batch.objects) == null ? void 0 : _a.length) != null ? _b : 0
1296
+ }, {
1297
+ file: "data-service-host.ts",
1298
+ line: 77,
1299
+ scope: this,
1300
+ callSite: (f, a) => f(...a)
1301
+ });
1302
+ const message = {
1269
1303
  batch: {
1270
- objects: (_a = request.batch.objects) == null ? void 0 : _a.map((object) => {
1304
+ objects: (_c = request.batch.objects) == null ? void 0 : _c.map((object) => {
1271
1305
  var _a2;
1272
1306
  return {
1273
1307
  ...object,
1274
- mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((m) => ({
1275
- ...m,
1308
+ mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((mutation) => ({
1309
+ ...mutation,
1276
1310
  meta: void 0
1277
1311
  })),
1278
1312
  meta: void 0
1279
1313
  };
1280
1314
  })
1281
1315
  }
1316
+ };
1317
+ const receipt = await this._writeStream.write(message, {
1318
+ afterWrite: async (receipt2) => {
1319
+ if (request.clientTag) {
1320
+ log10("tag", {
1321
+ clientTag: request.clientTag,
1322
+ feedKey: receipt2.feedKey,
1323
+ seq: receipt2.seq
1324
+ }, {
1325
+ file: "data-service-host.ts",
1326
+ line: 96,
1327
+ scope: this,
1328
+ callSite: (f, a) => f(...a)
1329
+ });
1330
+ this._clientTagMap.set([
1331
+ receipt2.feedKey,
1332
+ receipt2.seq
1333
+ ], request.clientTag);
1334
+ }
1335
+ }
1282
1336
  });
1283
- if (request.clientTag) {
1284
- this._clientTagMap.set([
1285
- receipt.feedKey,
1286
- receipt.seq
1287
- ], request.clientTag);
1288
- }
1289
1337
  return receipt;
1290
1338
  }
1291
1339
  };
1292
1340
 
1293
- // packages/core/echo/echo-pipeline/src/dbhost/database-backend.ts
1341
+ // packages/core/echo/echo-pipeline/src/dbhost/database-host.ts
1294
1342
  import { ItemDemuxer } from "@dxos/echo-db";
1295
- var DatabaseBackendHost = class {
1343
+ var DatabaseHost = class {
1296
1344
  constructor(_outboundStream, _snapshot) {
1297
1345
  this._outboundStream = _outboundStream;
1298
1346
  this._snapshot = _snapshot;
@@ -1482,7 +1530,7 @@ var DataServiceImpl = class {
1482
1530
 
1483
1531
  // packages/core/echo/echo-pipeline/src/space/data-pipeline.ts
1484
1532
  import assert9 from "@dxos/node-std/assert";
1485
- import { Event as Event3, scheduleTask as scheduleTask2, synchronized as synchronized5, trackLeaks as trackLeaks4 } from "@dxos/async";
1533
+ import { scheduleTask as scheduleTask2, synchronized as synchronized5, trackLeaks as trackLeaks4 } from "@dxos/async";
1486
1534
  import { Context as Context3 } from "@dxos/context";
1487
1535
  import { failUndefined as failUndefined3 } from "@dxos/debug";
1488
1536
  import { ItemManager } from "@dxos/echo-db";
@@ -1508,7 +1556,8 @@ var DataPipeline = class DataPipeline2 {
1508
1556
  this._ctx = new Context3();
1509
1557
  this._lastAutomaticSnapshotTimeframe = new Timeframe3();
1510
1558
  this._isOpen = false;
1511
- this.onTimeframeReached = new Event3();
1559
+ this._lastTimeframeSaveTime = 0;
1560
+ this._lastSnapshotSaveTime = 0;
1512
1561
  }
1513
1562
  get isOpen() {
1514
1563
  return this._isOpen;
@@ -1547,64 +1596,14 @@ var DataPipeline = class DataPipeline2 {
1547
1596
  const feedWriter = createMappedFeedWriter((data) => ({
1548
1597
  data
1549
1598
  }), (_c = this._pipeline.writer) != null ? _c : failUndefined3());
1550
- this.databaseBackend = new DatabaseBackendHost(feedWriter, (_d = this._snapshot) == null ? void 0 : _d.database);
1599
+ this.databaseBackend = new DatabaseHost(feedWriter, (_d = this._snapshot) == null ? void 0 : _d.database);
1551
1600
  this._itemManager = new ItemManager(this._params.modelFactory);
1552
1601
  await this.databaseBackend.open(this._itemManager, this._params.modelFactory);
1553
1602
  scheduleTask2(this._ctx, async () => {
1554
1603
  await this._consumePipeline();
1555
1604
  });
1556
- this._createPeriodicSnapshots();
1557
1605
  this._isOpen = true;
1558
1606
  }
1559
- _createPeriodicSnapshots() {
1560
- this.onTimeframeReached.debounce(TIMEFRAME_SAVE_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1561
- await this._saveLatestTimeframe();
1562
- });
1563
- if (!DISABLE_SNAPSHOT_CACHE) {
1564
- this.onTimeframeReached.debounce(AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1565
- var _a, _b;
1566
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1567
- if (!latestTimeframe) {
1568
- return;
1569
- }
1570
- if (latestTimeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1571
- const snapshot = await this._saveSnapshot();
1572
- this._lastAutomaticSnapshotTimeframe = (_b = snapshot.timeframe) != null ? _b : failUndefined3();
1573
- log12("save", {
1574
- snapshot
1575
- }, {
1576
- file: "data-pipeline.ts",
1577
- line: 161,
1578
- scope: this,
1579
- callSite: (f, a) => f(...a)
1580
- });
1581
- }
1582
- });
1583
- }
1584
- }
1585
- async _saveSnapshot() {
1586
- const snapshot = await this.createSnapshot();
1587
- const snapshotKey = await this._params.snapshotManager.store(snapshot);
1588
- await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1589
- return snapshot;
1590
- }
1591
- async _saveLatestTimeframe() {
1592
- var _a, _b;
1593
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1594
- log12("save latest timeframe", {
1595
- latestTimeframe,
1596
- spaceKey: this._params.spaceKey
1597
- }, {
1598
- file: "data-pipeline.ts",
1599
- line: 176,
1600
- scope: this,
1601
- callSite: (f, a) => f(...a)
1602
- });
1603
- if (latestTimeframe) {
1604
- const newTimeframe = Timeframe3.merge((_b = this._targetTimeframe) != null ? _b : new Timeframe3(), latestTimeframe);
1605
- await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1606
- }
1607
- }
1608
1607
  async close() {
1609
1608
  var _a, _b, _c;
1610
1609
  if (!this._isOpen) {
@@ -1612,37 +1611,32 @@ var DataPipeline = class DataPipeline2 {
1612
1611
  }
1613
1612
  log12("close", {}, {
1614
1613
  file: "data-pipeline.ts",
1615
- line: 188,
1614
+ line: 145,
1616
1615
  scope: this,
1617
1616
  callSite: (f, a) => f(...a)
1618
1617
  });
1619
1618
  this._isOpen = false;
1619
+ await this._ctx.dispose();
1620
+ await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1620
1621
  try {
1621
- await this._saveLatestTimeframe();
1622
- await this._saveSnapshot();
1622
+ if (this._pipeline) {
1623
+ await this._saveTargetTimeframe(this._pipeline.state.timeframe);
1624
+ if (!DISABLE_SNAPSHOT_CACHE) {
1625
+ await this._saveSnapshot(this._pipeline.state.timeframe);
1626
+ }
1627
+ }
1623
1628
  } catch (err) {
1624
1629
  log12.catch(err, {}, {
1625
1630
  file: "data-pipeline.ts",
1626
- line: 195,
1631
+ line: 160,
1627
1632
  scope: this,
1628
1633
  callSite: (f, a) => f(...a)
1629
1634
  });
1630
1635
  }
1631
- await this._ctx.dispose();
1632
- await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1633
1636
  await ((_b = this.databaseBackend) == null ? void 0 : _b.close());
1634
1637
  await ((_c = this._itemManager) == null ? void 0 : _c.destroy());
1635
1638
  await this._params.snapshotManager.close();
1636
1639
  }
1637
- createSnapshot() {
1638
- var _a, _b;
1639
- assert9(this.databaseBackend, "Database backend is not initialized.");
1640
- return {
1641
- spaceKey: this._params.spaceKey.asUint8Array(),
1642
- timeframe: (_b = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe) != null ? _b : new Timeframe3(),
1643
- database: this.databaseBackend.createSnapshot()
1644
- };
1645
- }
1646
1640
  async _consumePipeline() {
1647
1641
  assert9(this._pipeline, "Pipeline is not initialized.");
1648
1642
  for await (const msg of this._pipeline.consume()) {
@@ -1651,7 +1645,7 @@ var DataPipeline = class DataPipeline2 {
1651
1645
  msg
1652
1646
  }, {
1653
1647
  file: "data-pipeline.ts",
1654
- line: 217,
1648
+ line: 172,
1655
1649
  scope: this,
1656
1650
  callSite: (f, a) => f(...a)
1657
1651
  });
@@ -1663,7 +1657,7 @@ var DataPipeline = class DataPipeline2 {
1663
1657
  feedKey
1664
1658
  }, {
1665
1659
  file: "data-pipeline.ts",
1666
- line: 223,
1660
+ line: 178,
1667
1661
  scope: this,
1668
1662
  callSite: (f, a) => f(...a)
1669
1663
  });
@@ -1678,18 +1672,58 @@ var DataPipeline = class DataPipeline2 {
1678
1672
  memberKey: feedInfo.assertion.identityKey
1679
1673
  }
1680
1674
  });
1681
- this.onTimeframeReached.emit(data.timeframe);
1675
+ await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1682
1676
  }
1683
1677
  } catch (err) {
1684
1678
  log12.catch(err, {}, {
1685
1679
  file: "data-pipeline.ts",
1686
- line: 239,
1680
+ line: 196,
1687
1681
  scope: this,
1688
1682
  callSite: (f, a) => f(...a)
1689
1683
  });
1690
1684
  }
1691
1685
  }
1692
1686
  }
1687
+ _createSnapshot(timeframe) {
1688
+ assert9(this.databaseBackend, "Database backend is not initialized.");
1689
+ return {
1690
+ spaceKey: this._params.spaceKey.asUint8Array(),
1691
+ timeframe,
1692
+ database: this.databaseBackend.createSnapshot()
1693
+ };
1694
+ }
1695
+ async _saveSnapshot(timeframe) {
1696
+ const snapshot = await this._createSnapshot(timeframe);
1697
+ const snapshotKey = await this._params.snapshotManager.store(snapshot);
1698
+ await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1699
+ return snapshot;
1700
+ }
1701
+ async _saveTargetTimeframe(timeframe) {
1702
+ var _a;
1703
+ const newTimeframe = Timeframe3.merge((_a = this._targetTimeframe) != null ? _a : new Timeframe3(), timeframe);
1704
+ await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1705
+ this._targetTimeframe = newTimeframe;
1706
+ }
1707
+ async _noteTargetStateIfNeeded(timeframe) {
1708
+ var _a;
1709
+ if (Date.now() - this._lastTimeframeSaveTime > TIMEFRAME_SAVE_DEBOUNCE_INTERVAL) {
1710
+ this._lastTimeframeSaveTime = Date.now();
1711
+ await this._saveTargetTimeframe(timeframe);
1712
+ }
1713
+ if (!DISABLE_SNAPSHOT_CACHE && Date.now() - this._lastSnapshotSaveTime > AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL && timeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1714
+ this._lastSnapshotSaveTime = Date.now();
1715
+ const snapshot = await this._saveSnapshot(timeframe);
1716
+ this._lastAutomaticSnapshotTimeframe = (_a = snapshot.timeframe) != null ? _a : failUndefined3();
1717
+ log12("save", {
1718
+ snapshot
1719
+ }, {
1720
+ file: "data-pipeline.ts",
1721
+ line: 239,
1722
+ scope: this,
1723
+ callSite: (f, a) => f(...a)
1724
+ });
1725
+ }
1726
+ }
1693
1727
  async waitUntilTimeframe(timeframe) {
1694
1728
  assert9(this._pipeline, "Pipeline is not initialized.");
1695
1729
  await this._pipeline.state.waitUntilTimeframe(timeframe);
@@ -1732,11 +1766,11 @@ export {
1732
1766
  SpaceManager,
1733
1767
  spaceGenesis,
1734
1768
  DataServiceHost,
1735
- DatabaseBackendHost,
1769
+ DatabaseHost,
1736
1770
  SnapshotManager,
1737
1771
  SnapshotStore,
1738
1772
  DataServiceSubscriptions,
1739
1773
  DataServiceImpl,
1740
1774
  DataPipeline
1741
1775
  };
1742
- //# sourceMappingURL=chunk-LIPDNX3G.mjs.map
1776
+ //# sourceMappingURL=chunk-4YAT2XJW.mjs.map