@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
@@ -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,
@@ -61,6 +61,7 @@ __export(src_exports, {
61
61
  mapFeedIndexesToTimeframe: () => mapFeedIndexesToTimeframe,
62
62
  mapTimeframeToFeedIndexes: () => mapTimeframeToFeedIndexes,
63
63
  spaceGenesis: () => spaceGenesis,
64
+ startAfter: () => startAfter,
64
65
  valueEncoding: () => valueEncoding
65
66
  });
66
67
  module.exports = __toCommonJS(src_exports);
@@ -115,8 +116,10 @@ var UnknownModelError = class extends DBError {
115
116
  };
116
117
 
117
118
  // packages/core/echo/echo-pipeline/src/metadata/metadata-store.ts
119
+ var import_crc_32 = __toESM(require("crc-32"));
118
120
  var import_node_assert = __toESM(require("node:assert"));
119
121
  var import_async = require("@dxos/async");
122
+ var import_errors = require("@dxos/errors");
120
123
  var import_log = require("@dxos/log");
121
124
  var import_protocols = require("@dxos/protocols");
122
125
  var __decorate = function(decorators, target, key, desc) {
@@ -161,31 +164,35 @@ var MetadataStore = class {
161
164
  const file = this._directory.getOrCreateFile("EchoMetadata");
162
165
  try {
163
166
  const { size: fileLength } = await file.stat();
164
- if (fileLength < 4) {
167
+ if (fileLength < 8) {
165
168
  return;
166
169
  }
167
170
  const dataSize = fromBytesInt32(await file.read(0, 4));
171
+ const checksum = fromBytesInt32(await file.read(4, 4));
168
172
  (0, import_log.log)("loaded", {
169
- size: dataSize
173
+ size: dataSize,
174
+ checksum
170
175
  }, {
171
176
  file: "metadata-store.ts",
172
- line: 67,
177
+ line: 70,
173
178
  scope: this,
174
179
  callSite: (f, a) => f(...a)
175
180
  });
176
- {
177
- if (fileLength < dataSize + 4) {
178
- throw new Error("Metadata storage is corrupted");
179
- }
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.");
180
188
  }
181
- const data = await file.read(4, dataSize);
182
189
  this._metadata = import_protocols.schema.getCodecForType("dxos.echo.metadata.EchoMetadata").decode(data);
183
190
  } catch (err) {
184
191
  import_log.log.error("failed to load metadata", {
185
192
  err
186
193
  }, {
187
194
  file: "metadata-store.ts",
188
- line: 79,
195
+ line: 85,
189
196
  scope: this,
190
197
  callSite: (f, a) => f(...a)
191
198
  });
@@ -205,16 +212,21 @@ var MetadataStore = class {
205
212
  const file = this._directory.getOrCreateFile("EchoMetadata");
206
213
  try {
207
214
  const encoded = Buffer.from(import_protocols.schema.getCodecForType("dxos.echo.metadata.EchoMetadata").encode(data));
208
- 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);
209
221
  (0, import_log.log)("saved", {
210
- size: encoded.length
222
+ size: encoded.length,
223
+ checksum
211
224
  }, {
212
225
  file: "metadata-store.ts",
213
- line: 102,
226
+ line: 116,
214
227
  scope: this,
215
228
  callSite: (f, a) => f(...a)
216
229
  });
217
- await file.write(4, encoded);
218
230
  } finally {
219
231
  await file.close();
220
232
  }
@@ -225,7 +237,7 @@ var MetadataStore = class {
225
237
  async clear() {
226
238
  (0, import_log.log)("clearing all metadata", {}, {
227
239
  file: "metadata-store.ts",
228
- line: 115,
240
+ line: 126,
229
241
  scope: this,
230
242
  callSite: (f, a) => f(...a)
231
243
  });
@@ -271,11 +283,6 @@ __decorate([
271
283
  __decorate([
272
284
  import_async.synchronized
273
285
  ], MetadataStore.prototype, "_save", null);
274
- var toBytesInt32 = (num) => {
275
- const buf = Buffer.alloc(4);
276
- buf.writeInt32LE(num, 0);
277
- return buf;
278
- };
279
286
  var fromBytesInt32 = (buf) => buf.readInt32LE(0);
280
287
 
281
288
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
@@ -299,7 +306,7 @@ var createMappedFeedWriter = (mapper, writer) => {
299
306
  (0, import_node_assert2.default)(mapper);
300
307
  (0, import_node_assert2.default)(writer);
301
308
  return {
302
- write: async (data) => await writer.write(await mapper(data))
309
+ write: async (data, options) => await writer.write(await mapper(data), options)
303
310
  };
304
311
  };
305
312
 
@@ -343,22 +350,40 @@ var mapFeedIndexesToTimeframe = (indexes) => new import_timeframe.Timeframe(inde
343
350
  feedKey,
344
351
  index
345
352
  ]));
353
+ var startAfter = (timeframe) => timeframe.frames().map(([feedKey, index]) => ({
354
+ feedKey,
355
+ index: index + 1
356
+ }));
346
357
  var TimeframeClock = class {
347
358
  // prettier-ignore
348
359
  constructor(_timeframe = new import_timeframe.Timeframe()) {
349
360
  this._timeframe = _timeframe;
350
361
  this.update = new import_async2.Event();
362
+ this._pendingTimeframe = _timeframe;
351
363
  }
364
+ /**
365
+ * Timeframe that was processed by ECHO.
366
+ */
352
367
  get timeframe() {
353
368
  return this._timeframe;
354
369
  }
355
- updateTimeframe(key, seq) {
356
- 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([
357
379
  [
358
380
  key,
359
381
  seq
360
382
  ]
361
383
  ]));
384
+ }
385
+ updateTimeframe() {
386
+ this._timeframe = this._pendingTimeframe;
362
387
  this.update.emit(this._timeframe);
363
388
  }
364
389
  hasGaps(timeframe) {
@@ -366,12 +391,12 @@ var TimeframeClock = class {
366
391
  return !gaps.isEmpty();
367
392
  }
368
393
  async waitUntilReached(target) {
369
- import_log2.log.debug("waitUntilReached", {
394
+ import_log2.log.info("waitUntilReached", {
370
395
  target,
371
396
  current: this._timeframe
372
397
  }, {
373
398
  file: "timeframe-clock.ts",
374
- line: 45,
399
+ line: 67,
375
400
  scope: this,
376
401
  callSite: (f, a) => f(...a)
377
402
  });
@@ -382,7 +407,7 @@ var TimeframeClock = class {
382
407
  deps: import_timeframe.Timeframe.dependencies(target, this._timeframe)
383
408
  }, {
384
409
  file: "timeframe-clock.ts",
385
- line: 47,
410
+ line: 69,
386
411
  scope: this,
387
412
  callSite: (f, a) => f(...a)
388
413
  });
@@ -395,6 +420,16 @@ __decorate2([
395
420
  ], TimeframeClock.prototype, "waitUntilReached", null);
396
421
 
397
422
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
423
+ var __decorate3 = function(decorators, target, key, desc) {
424
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
425
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
426
+ r = Reflect.decorate(decorators, target, key, desc);
427
+ else
428
+ for (var i = decorators.length - 1; i >= 0; i--)
429
+ if (d = decorators[i])
430
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
431
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
432
+ };
398
433
  var PipelineState = class {
399
434
  // prettier-ignore
400
435
  constructor(_iterator, _timeframeClock) {
@@ -406,18 +441,25 @@ var PipelineState = class {
406
441
  * Latest theoretical timeframe based on the last mutation in each feed.
407
442
  * NOTE: This might never be reached if the mutation dependencies
408
443
  */
444
+ // TODO(dmaretskyi): Rename `totalTimeframe`? or `lastTimeframe`.
409
445
  get endTimeframe() {
410
- return mapFeedIndexesToTimeframe(this._iterator.feeds.filter((feed) => feed.properties.length > 0).map((feed) => ({
446
+ return mapFeedIndexesToTimeframe(this._iterator.feeds.filter((feed) => feed.length > 0).map((feed) => ({
411
447
  feedKey: feed.key,
412
- index: feed.properties.length - 1
448
+ index: feed.length - 1
413
449
  })));
414
450
  }
415
451
  get timeframe() {
416
452
  return this._timeframeClock.timeframe;
417
453
  }
454
+ get pendingTimeframe() {
455
+ return this._timeframeClock.pendingTimeframe;
456
+ }
418
457
  get targetTimeframe() {
419
458
  return this._targetTimeframe ? this._targetTimeframe : new import_timeframe2.Timeframe();
420
459
  }
460
+ get feeds() {
461
+ return this._iterator.feeds;
462
+ }
421
463
  async waitUntilTimeframe(target) {
422
464
  await this._timeframeClock.waitUntilReached(target);
423
465
  }
@@ -439,7 +481,7 @@ var PipelineState = class {
439
481
  target: this.targetTimeframe
440
482
  }, {
441
483
  file: "pipeline.ts",
442
- line: 96,
484
+ line: 105,
443
485
  scope: this,
444
486
  callSite: (f, a) => f(...a)
445
487
  });
@@ -469,7 +511,7 @@ var PipelineState = class {
469
511
  dependencies: import_timeframe2.Timeframe.dependencies(this.targetTimeframe, this.timeframe)
470
512
  }, {
471
513
  file: "pipeline.ts",
472
- line: 122,
514
+ line: 131,
473
515
  scope: this,
474
516
  callSite: (f, a) => f(...a)
475
517
  });
@@ -486,7 +528,7 @@ var Pipeline = class {
486
528
  this._initialTimeframe = _initialTimeframe;
487
529
  this._timeframeClock = new TimeframeClock(this._initialTimeframe);
488
530
  this._feedSetIterator = new import_feed_store.FeedSetIterator(createMessageSelector(this._timeframeClock), {
489
- start: mapTimeframeToFeedIndexes(this._initialTimeframe),
531
+ start: startAfter(this._initialTimeframe),
490
532
  stallTimeout: 1e3
491
533
  });
492
534
  this._state = new PipelineState(this._feedSetIterator, this._timeframeClock);
@@ -495,7 +537,7 @@ var Pipeline = class {
495
537
  this._feedSetIterator.stalled.on((iterator) => {
496
538
  import_log3.log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
497
539
  file: "pipeline.ts",
498
- line: 198,
540
+ line: 207,
499
541
  scope: this,
500
542
  callSite: (f, a) => f(...a)
501
543
  });
@@ -511,6 +553,8 @@ var Pipeline = class {
511
553
  getFeeds() {
512
554
  return this._feedSetIterator.feeds;
513
555
  }
556
+ // NOTE: This cannot be synchronized with `stop` because stop waits for the mutation processing to complete,
557
+ // which might be opening feeds during the mutation processing, which w
514
558
  async addFeed(feed) {
515
559
  await this._feedSetIterator.addFeed(feed);
516
560
  }
@@ -528,14 +572,14 @@ var Pipeline = class {
528
572
  async start() {
529
573
  (0, import_log3.log)("starting...", {}, {
530
574
  file: "pipeline.ts",
531
- line: 237,
575
+ line: 249,
532
576
  scope: this,
533
577
  callSite: (f, a) => f(...a)
534
578
  });
535
579
  await this._feedSetIterator.open();
536
580
  (0, import_log3.log)("started", {}, {
537
581
  file: "pipeline.ts",
538
- line: 239,
582
+ line: 251,
539
583
  scope: this,
540
584
  callSite: (f, a) => f(...a)
541
585
  });
@@ -543,7 +587,7 @@ var Pipeline = class {
543
587
  async stop() {
544
588
  (0, import_log3.log)("stopping...", {}, {
545
589
  file: "pipeline.ts",
546
- line: 243,
590
+ line: 256,
547
591
  scope: this,
548
592
  callSite: (f, a) => f(...a)
549
593
  });
@@ -551,7 +595,7 @@ var Pipeline = class {
551
595
  await this._processingTrigger.wait();
552
596
  (0, import_log3.log)("stopped", {}, {
553
597
  file: "pipeline.ts",
554
- line: 246,
598
+ line: 259,
555
599
  scope: this,
556
600
  callSite: (f, a) => f(...a)
557
601
  });
@@ -565,13 +609,20 @@ var Pipeline = class {
565
609
  this._isOpen = true;
566
610
  for await (const block of this._feedSetIterator) {
567
611
  this._processingTrigger.reset();
612
+ this._timeframeClock.updatePendingTimeframe(import_keys.PublicKey.from(block.feedKey), block.seq);
568
613
  yield block;
569
614
  this._processingTrigger.wake();
570
- this._timeframeClock.updateTimeframe(import_keys.PublicKey.from(block.feedKey), block.seq);
615
+ this._timeframeClock.updateTimeframe();
571
616
  }
572
617
  this._isOpen = false;
573
618
  }
574
619
  };
620
+ __decorate3([
621
+ import_async3.synchronized
622
+ ], Pipeline.prototype, "start", null);
623
+ __decorate3([
624
+ import_async3.synchronized
625
+ ], Pipeline.prototype, "stop", null);
575
626
 
576
627
  // packages/core/echo/echo-pipeline/src/space/auth.ts
577
628
  var import_node_assert5 = __toESM(require("node:assert"));
@@ -783,7 +834,7 @@ var ControlPipeline = class {
783
834
  };
784
835
 
785
836
  // packages/core/echo/echo-pipeline/src/space/space.ts
786
- var __decorate3 = function(decorators, target, key, desc) {
837
+ var __decorate4 = function(decorators, target, key, desc) {
787
838
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
788
839
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
789
840
  r = Reflect.decorate(decorators, target, key, desc);
@@ -949,16 +1000,16 @@ var Space = class Space2 {
949
1000
  return pipeline;
950
1001
  }
951
1002
  };
952
- __decorate3([
1003
+ __decorate4([
953
1004
  import_log6.logInfo
954
1005
  ], Space.prototype, "key", null);
955
- __decorate3([
1006
+ __decorate4([
956
1007
  import_async5.synchronized
957
1008
  ], Space.prototype, "open", null);
958
- __decorate3([
1009
+ __decorate4([
959
1010
  import_async5.synchronized
960
1011
  ], Space.prototype, "close", null);
961
- Space = __decorate3([
1012
+ Space = __decorate4([
962
1013
  (0, import_async5.trackLeaks)("open", "close")
963
1014
  ], Space);
964
1015
 
@@ -978,7 +1029,7 @@ var import_network_manager = require("@dxos/network-manager");
978
1029
  var import_teleport2 = require("@dxos/teleport");
979
1030
  var import_teleport_extension_replicator = require("@dxos/teleport-extension-replicator");
980
1031
  var import_util3 = require("@dxos/util");
981
- var __decorate4 = function(decorators, target, key, desc) {
1032
+ var __decorate5 = function(decorators, target, key, desc) {
982
1033
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
983
1034
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
984
1035
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1085,10 +1136,10 @@ var SpaceProtocol = class {
1085
1136
  };
1086
1137
  }
1087
1138
  };
1088
- __decorate4([
1139
+ __decorate5([
1089
1140
  import_log7.logInfo
1090
1141
  ], SpaceProtocol.prototype, "_topic", void 0);
1091
- __decorate4([
1142
+ __decorate5([
1092
1143
  import_log7.logInfo
1093
1144
  ], SpaceProtocol.prototype, "_ownPeerKey", null);
1094
1145
  var AuthStatus;
@@ -1148,15 +1199,15 @@ var SpaceProtocolSession = class {
1148
1199
  await this._teleport.close();
1149
1200
  }
1150
1201
  };
1151
- __decorate4([
1202
+ __decorate5([
1152
1203
  import_log7.logInfo
1153
1204
  ], SpaceProtocolSession.prototype, "_wireParams", void 0);
1154
- __decorate4([
1205
+ __decorate5([
1155
1206
  import_log7.logInfo
1156
1207
  ], SpaceProtocolSession.prototype, "authStatus", null);
1157
1208
 
1158
1209
  // packages/core/echo/echo-pipeline/src/space/space-manager.ts
1159
- var __decorate5 = function(decorators, target, key, desc) {
1210
+ var __decorate6 = function(decorators, target, key, desc) {
1160
1211
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1161
1212
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1162
1213
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1179,10 +1230,11 @@ var SpaceManager = class SpaceManager2 {
1179
1230
  }
1180
1231
  async open() {
1181
1232
  import_log8.log.trace("dxos.echo.space-manager", import_protocols4.trace.begin({
1182
- id: this._instanceId
1233
+ id: this._instanceId,
1234
+ parentId: this._traceParent
1183
1235
  }), {
1184
1236
  file: "space-manager.ts",
1185
- line: 65,
1237
+ line: 66,
1186
1238
  scope: this,
1187
1239
  callSite: (f, a) => f(...a)
1188
1240
  });
@@ -1195,7 +1247,7 @@ var SpaceManager = class SpaceManager2 {
1195
1247
  id: this._instanceId
1196
1248
  }), {
1197
1249
  file: "space-manager.ts",
1198
- line: 71,
1250
+ line: 72,
1199
1251
  scope: this,
1200
1252
  callSite: (f, a) => f(...a)
1201
1253
  });
@@ -1206,7 +1258,7 @@ var SpaceManager = class SpaceManager2 {
1206
1258
  spaceKey: metadata.genesisFeedKey
1207
1259
  }, {
1208
1260
  file: "space-manager.ts",
1209
- line: 75,
1261
+ line: 76,
1210
1262
  scope: this,
1211
1263
  callSite: (f, a) => f(...a)
1212
1264
  });
@@ -1228,13 +1280,13 @@ var SpaceManager = class SpaceManager2 {
1228
1280
  return space;
1229
1281
  }
1230
1282
  };
1231
- __decorate5([
1283
+ __decorate6([
1232
1284
  import_async6.synchronized
1233
1285
  ], SpaceManager.prototype, "open", null);
1234
- __decorate5([
1286
+ __decorate6([
1235
1287
  import_async6.synchronized
1236
1288
  ], SpaceManager.prototype, "close", null);
1237
- SpaceManager = __decorate5([
1289
+ SpaceManager = __decorate6([
1238
1290
  (0, import_async6.trackLeaks)("open", "close")
1239
1291
  ], SpaceManager);
1240
1292
 
@@ -1333,12 +1385,12 @@ var DataServiceHost = class {
1333
1385
  this._itemDemuxer.mutation.on(ctx, (message) => {
1334
1386
  var _a;
1335
1387
  const { batch, meta } = message;
1336
- (0, import_log9.log)("Object update", {
1388
+ (0, import_log9.log)("message", {
1337
1389
  batch,
1338
1390
  meta
1339
1391
  }, {
1340
1392
  file: "data-service-host.ts",
1341
- line: 50,
1393
+ line: 49,
1342
1394
  scope: this,
1343
1395
  callSite: (f, a) => f(...a)
1344
1396
  });
@@ -1362,36 +1414,59 @@ var DataServiceHost = class {
1362
1414
  });
1363
1415
  }
1364
1416
  async write(request) {
1365
- var _a;
1417
+ var _a, _b, _c;
1366
1418
  (0, import_node_assert7.default)(this._writeStream, "Cannot write mutations in readonly mode");
1367
- 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 = {
1368
1429
  batch: {
1369
- objects: (_a = request.batch.objects) == null ? void 0 : _a.map((object) => {
1430
+ objects: (_c = request.batch.objects) == null ? void 0 : _c.map((object) => {
1370
1431
  var _a2;
1371
1432
  return {
1372
1433
  ...object,
1373
- mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((m) => ({
1374
- ...m,
1434
+ mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((mutation) => ({
1435
+ ...mutation,
1375
1436
  meta: void 0
1376
1437
  })),
1377
1438
  meta: void 0
1378
1439
  };
1379
1440
  })
1380
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
+ }
1381
1462
  });
1382
- if (request.clientTag) {
1383
- this._clientTagMap.set([
1384
- receipt.feedKey,
1385
- receipt.seq
1386
- ], request.clientTag);
1387
- }
1388
1463
  return receipt;
1389
1464
  }
1390
1465
  };
1391
1466
 
1392
- // packages/core/echo/echo-pipeline/src/dbhost/database-backend.ts
1467
+ // packages/core/echo/echo-pipeline/src/dbhost/database-host.ts
1393
1468
  var import_echo_db2 = require("@dxos/echo-db");
1394
- var DatabaseBackendHost = class {
1469
+ var DatabaseHost = class {
1395
1470
  constructor(_outboundStream, _snapshot) {
1396
1471
  this._outboundStream = _outboundStream;
1397
1472
  this._snapshot = _snapshot;
@@ -1429,7 +1504,7 @@ var DatabaseBackendHost = class {
1429
1504
  var import_async7 = require("@dxos/async");
1430
1505
  var import_protocols5 = require("@dxos/protocols");
1431
1506
  var import_teleport_extension_object_sync = require("@dxos/teleport-extension-object-sync");
1432
- var __decorate6 = function(decorators, target, key, desc) {
1507
+ var __decorate7 = function(decorators, target, key, desc) {
1433
1508
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1434
1509
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1435
1510
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1482,7 +1557,7 @@ var SnapshotManager = class SnapshotManager2 {
1482
1557
  return id;
1483
1558
  }
1484
1559
  };
1485
- SnapshotManager = __decorate6([
1560
+ SnapshotManager = __decorate7([
1486
1561
  (0, import_async7.trackLeaks)("open", "close")
1487
1562
  ], SnapshotManager);
1488
1563
 
@@ -1580,7 +1655,7 @@ var DataServiceImpl = class {
1580
1655
  };
1581
1656
 
1582
1657
  // packages/core/echo/echo-pipeline/src/space/data-pipeline.ts
1583
- var __decorate7 = function(decorators, target, key, desc) {
1658
+ var __decorate8 = function(decorators, target, key, desc) {
1584
1659
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1585
1660
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1586
1661
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1593,14 +1668,15 @@ var __decorate7 = function(decorators, target, key, desc) {
1593
1668
  var MESSAGES_PER_SNAPSHOT = 10;
1594
1669
  var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1595
1670
  var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
1596
- var DISABLE_SNAPSHOT_CACHE = false;
1671
+ var DISABLE_SNAPSHOT_CACHE = true;
1597
1672
  var DataPipeline = class DataPipeline2 {
1598
1673
  constructor(_params) {
1599
1674
  this._params = _params;
1600
1675
  this._ctx = new import_context3.Context();
1601
1676
  this._lastAutomaticSnapshotTimeframe = new import_timeframe3.Timeframe();
1602
1677
  this._isOpen = false;
1603
- this.onTimeframeReached = new import_async8.Event();
1678
+ this._lastTimeframeSaveTime = 0;
1679
+ this._lastSnapshotSaveTime = 0;
1604
1680
  }
1605
1681
  get isOpen() {
1606
1682
  return this._isOpen;
@@ -1628,7 +1704,7 @@ var DataPipeline = class DataPipeline2 {
1628
1704
  return;
1629
1705
  }
1630
1706
  this._spaceContext = spaceContext;
1631
- if (this._params.snapshotId) {
1707
+ if (this._params.snapshotId && !DISABLE_SNAPSHOT_CACHE) {
1632
1708
  this._snapshot = await this._params.snapshotManager.load(this._params.snapshotId);
1633
1709
  this._lastAutomaticSnapshotTimeframe = (_b = (_a = this._snapshot) == null ? void 0 : _a.timeframe) != null ? _b : new import_timeframe3.Timeframe();
1634
1710
  }
@@ -1639,64 +1715,14 @@ var DataPipeline = class DataPipeline2 {
1639
1715
  const feedWriter = createMappedFeedWriter((data) => ({
1640
1716
  data
1641
1717
  }), (_c = this._pipeline.writer) != null ? _c : (0, import_debug6.failUndefined)());
1642
- 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);
1643
1719
  this._itemManager = new import_echo_db3.ItemManager(this._params.modelFactory);
1644
1720
  await this.databaseBackend.open(this._itemManager, this._params.modelFactory);
1645
1721
  (0, import_async8.scheduleTask)(this._ctx, async () => {
1646
1722
  await this._consumePipeline();
1647
1723
  });
1648
- this._createPeriodicSnapshots();
1649
1724
  this._isOpen = true;
1650
1725
  }
1651
- _createPeriodicSnapshots() {
1652
- this.onTimeframeReached.debounce(TIMEFRAME_SAVE_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1653
- await this._saveLatestTimeframe();
1654
- });
1655
- if (!DISABLE_SNAPSHOT_CACHE) {
1656
- this.onTimeframeReached.debounce(AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1657
- var _a, _b;
1658
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1659
- if (!latestTimeframe) {
1660
- return;
1661
- }
1662
- if (latestTimeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1663
- const snapshot = await this._saveSnapshot();
1664
- this._lastAutomaticSnapshotTimeframe = (_b = snapshot.timeframe) != null ? _b : (0, import_debug6.failUndefined)();
1665
- (0, import_log11.log)("save", {
1666
- snapshot
1667
- }, {
1668
- file: "data-pipeline.ts",
1669
- line: 161,
1670
- scope: this,
1671
- callSite: (f, a) => f(...a)
1672
- });
1673
- }
1674
- });
1675
- }
1676
- }
1677
- async _saveSnapshot() {
1678
- const snapshot = await this.createSnapshot();
1679
- const snapshotKey = await this._params.snapshotManager.store(snapshot);
1680
- await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1681
- return snapshot;
1682
- }
1683
- async _saveLatestTimeframe() {
1684
- var _a, _b;
1685
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1686
- (0, import_log11.log)("save latest timeframe", {
1687
- latestTimeframe,
1688
- spaceKey: this._params.spaceKey
1689
- }, {
1690
- file: "data-pipeline.ts",
1691
- line: 176,
1692
- scope: this,
1693
- callSite: (f, a) => f(...a)
1694
- });
1695
- if (latestTimeframe) {
1696
- const newTimeframe = import_timeframe3.Timeframe.merge((_b = this._targetTimeframe) != null ? _b : new import_timeframe3.Timeframe(), latestTimeframe);
1697
- await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1698
- }
1699
- }
1700
1726
  async close() {
1701
1727
  var _a, _b, _c;
1702
1728
  if (!this._isOpen) {
@@ -1704,37 +1730,32 @@ var DataPipeline = class DataPipeline2 {
1704
1730
  }
1705
1731
  (0, import_log11.log)("close", {}, {
1706
1732
  file: "data-pipeline.ts",
1707
- line: 188,
1733
+ line: 145,
1708
1734
  scope: this,
1709
1735
  callSite: (f, a) => f(...a)
1710
1736
  });
1711
1737
  this._isOpen = false;
1738
+ await this._ctx.dispose();
1739
+ await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1712
1740
  try {
1713
- await this._saveLatestTimeframe();
1714
- 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
+ }
1715
1747
  } catch (err) {
1716
1748
  import_log11.log.catch(err, {}, {
1717
1749
  file: "data-pipeline.ts",
1718
- line: 195,
1750
+ line: 160,
1719
1751
  scope: this,
1720
1752
  callSite: (f, a) => f(...a)
1721
1753
  });
1722
1754
  }
1723
- await this._ctx.dispose();
1724
- await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1725
1755
  await ((_b = this.databaseBackend) == null ? void 0 : _b.close());
1726
1756
  await ((_c = this._itemManager) == null ? void 0 : _c.destroy());
1727
1757
  await this._params.snapshotManager.close();
1728
1758
  }
1729
- createSnapshot() {
1730
- var _a, _b;
1731
- (0, import_node_assert9.default)(this.databaseBackend, "Database backend is not initialized.");
1732
- return {
1733
- spaceKey: this._params.spaceKey.asUint8Array(),
1734
- timeframe: (_b = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe) != null ? _b : new import_timeframe3.Timeframe(),
1735
- database: this.databaseBackend.createSnapshot()
1736
- };
1737
- }
1738
1759
  async _consumePipeline() {
1739
1760
  (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1740
1761
  for await (const msg of this._pipeline.consume()) {
@@ -1743,7 +1764,7 @@ var DataPipeline = class DataPipeline2 {
1743
1764
  msg
1744
1765
  }, {
1745
1766
  file: "data-pipeline.ts",
1746
- line: 217,
1767
+ line: 172,
1747
1768
  scope: this,
1748
1769
  callSite: (f, a) => f(...a)
1749
1770
  });
@@ -1755,7 +1776,7 @@ var DataPipeline = class DataPipeline2 {
1755
1776
  feedKey
1756
1777
  }, {
1757
1778
  file: "data-pipeline.ts",
1758
- line: 223,
1779
+ line: 178,
1759
1780
  scope: this,
1760
1781
  callSite: (f, a) => f(...a)
1761
1782
  });
@@ -1770,30 +1791,70 @@ var DataPipeline = class DataPipeline2 {
1770
1791
  memberKey: feedInfo.assertion.identityKey
1771
1792
  }
1772
1793
  });
1773
- this.onTimeframeReached.emit(data.timeframe);
1794
+ await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1774
1795
  }
1775
1796
  } catch (err) {
1776
1797
  import_log11.log.catch(err, {}, {
1777
1798
  file: "data-pipeline.ts",
1778
- line: 239,
1799
+ line: 196,
1779
1800
  scope: this,
1780
1801
  callSite: (f, a) => f(...a)
1781
1802
  });
1782
1803
  }
1783
1804
  }
1784
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
+ }
1785
1846
  async waitUntilTimeframe(timeframe) {
1786
1847
  (0, import_node_assert9.default)(this._pipeline, "Pipeline is not initialized.");
1787
1848
  await this._pipeline.state.waitUntilTimeframe(timeframe);
1788
1849
  }
1789
1850
  };
1790
- __decorate7([
1851
+ __decorate8([
1791
1852
  import_async8.synchronized
1792
1853
  ], DataPipeline.prototype, "open", null);
1793
- __decorate7([
1854
+ __decorate8([
1794
1855
  import_async8.synchronized
1795
1856
  ], DataPipeline.prototype, "close", null);
1796
- DataPipeline = __decorate7([
1857
+ DataPipeline = __decorate8([
1797
1858
  (0, import_async8.trackLeaks)("open", "close")
1798
1859
  ], DataPipeline);
1799
1860
  var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
@@ -1811,7 +1872,7 @@ var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
1811
1872
  DataServiceHost,
1812
1873
  DataServiceImpl,
1813
1874
  DataServiceSubscriptions,
1814
- DatabaseBackendHost,
1875
+ DatabaseHost,
1815
1876
  EntityNotFoundError,
1816
1877
  IdentityNotInitializedError,
1817
1878
  InvalidInvitationError,
@@ -1835,6 +1896,7 @@ var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
1835
1896
  mapFeedIndexesToTimeframe,
1836
1897
  mapTimeframeToFeedIndexes,
1837
1898
  spaceGenesis,
1899
+ startAfter,
1838
1900
  valueEncoding
1839
1901
  });
1840
1902
  //# sourceMappingURL=index.cjs.map