@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
@@ -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
 
@@ -203,22 +209,40 @@ var mapFeedIndexesToTimeframe = (indexes) => new Timeframe(indexes.map(({ feedKe
203
209
  feedKey,
204
210
  index
205
211
  ]));
212
+ var startAfter = (timeframe) => timeframe.frames().map(([feedKey, index]) => ({
213
+ feedKey,
214
+ index: index + 1
215
+ }));
206
216
  var TimeframeClock = class {
207
217
  // prettier-ignore
208
218
  constructor(_timeframe = new Timeframe()) {
209
219
  this._timeframe = _timeframe;
210
220
  this.update = new Event();
221
+ this._pendingTimeframe = _timeframe;
211
222
  }
223
+ /**
224
+ * Timeframe that was processed by ECHO.
225
+ */
212
226
  get timeframe() {
213
227
  return this._timeframe;
214
228
  }
215
- updateTimeframe(key, seq) {
216
- 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([
217
238
  [
218
239
  key,
219
240
  seq
220
241
  ]
221
242
  ]));
243
+ }
244
+ updateTimeframe() {
245
+ this._timeframe = this._pendingTimeframe;
222
246
  this.update.emit(this._timeframe);
223
247
  }
224
248
  hasGaps(timeframe) {
@@ -226,12 +250,12 @@ var TimeframeClock = class {
226
250
  return !gaps.isEmpty();
227
251
  }
228
252
  async waitUntilReached(target) {
229
- log2.debug("waitUntilReached", {
253
+ log2.info("waitUntilReached", {
230
254
  target,
231
255
  current: this._timeframe
232
256
  }, {
233
257
  file: "timeframe-clock.ts",
234
- line: 45,
258
+ line: 67,
235
259
  scope: this,
236
260
  callSite: (f, a) => f(...a)
237
261
  });
@@ -242,7 +266,7 @@ var TimeframeClock = class {
242
266
  deps: Timeframe.dependencies(target, this._timeframe)
243
267
  }, {
244
268
  file: "timeframe-clock.ts",
245
- line: 47,
269
+ line: 69,
246
270
  scope: this,
247
271
  callSite: (f, a) => f(...a)
248
272
  });
@@ -256,7 +280,7 @@ __decorate2([
256
280
 
257
281
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
258
282
  import assert4 from "@dxos/node-std/assert";
259
- import { sleep, Trigger } from "@dxos/async";
283
+ import { sleep, synchronized as synchronized2, Trigger } from "@dxos/async";
260
284
  import { Context, rejectOnDispose } from "@dxos/context";
261
285
  import { FeedSetIterator } from "@dxos/feed-store";
262
286
  import { PublicKey } from "@dxos/keys";
@@ -281,6 +305,16 @@ var createMessageSelector = (timeframeClock) => {
281
305
  };
282
306
 
283
307
  // packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
308
+ var __decorate3 = function(decorators, target, key, desc) {
309
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
310
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
311
+ r = Reflect.decorate(decorators, target, key, desc);
312
+ else
313
+ for (var i = decorators.length - 1; i >= 0; i--)
314
+ if (d = decorators[i])
315
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
316
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
317
+ };
284
318
  var PipelineState = class {
285
319
  // prettier-ignore
286
320
  constructor(_iterator, _timeframeClock) {
@@ -292,18 +326,25 @@ var PipelineState = class {
292
326
  * Latest theoretical timeframe based on the last mutation in each feed.
293
327
  * NOTE: This might never be reached if the mutation dependencies
294
328
  */
329
+ // TODO(dmaretskyi): Rename `totalTimeframe`? or `lastTimeframe`.
295
330
  get endTimeframe() {
296
- return mapFeedIndexesToTimeframe(this._iterator.feeds.filter((feed) => feed.properties.length > 0).map((feed) => ({
331
+ return mapFeedIndexesToTimeframe(this._iterator.feeds.filter((feed) => feed.length > 0).map((feed) => ({
297
332
  feedKey: feed.key,
298
- index: feed.properties.length - 1
333
+ index: feed.length - 1
299
334
  })));
300
335
  }
301
336
  get timeframe() {
302
337
  return this._timeframeClock.timeframe;
303
338
  }
339
+ get pendingTimeframe() {
340
+ return this._timeframeClock.pendingTimeframe;
341
+ }
304
342
  get targetTimeframe() {
305
343
  return this._targetTimeframe ? this._targetTimeframe : new Timeframe2();
306
344
  }
345
+ get feeds() {
346
+ return this._iterator.feeds;
347
+ }
307
348
  async waitUntilTimeframe(target) {
308
349
  await this._timeframeClock.waitUntilReached(target);
309
350
  }
@@ -325,7 +366,7 @@ var PipelineState = class {
325
366
  target: this.targetTimeframe
326
367
  }, {
327
368
  file: "pipeline.ts",
328
- line: 96,
369
+ line: 105,
329
370
  scope: this,
330
371
  callSite: (f, a) => f(...a)
331
372
  });
@@ -355,7 +396,7 @@ var PipelineState = class {
355
396
  dependencies: Timeframe2.dependencies(this.targetTimeframe, this.timeframe)
356
397
  }, {
357
398
  file: "pipeline.ts",
358
- line: 122,
399
+ line: 131,
359
400
  scope: this,
360
401
  callSite: (f, a) => f(...a)
361
402
  });
@@ -372,7 +413,7 @@ var Pipeline = class {
372
413
  this._initialTimeframe = _initialTimeframe;
373
414
  this._timeframeClock = new TimeframeClock(this._initialTimeframe);
374
415
  this._feedSetIterator = new FeedSetIterator(createMessageSelector(this._timeframeClock), {
375
- start: mapTimeframeToFeedIndexes(this._initialTimeframe),
416
+ start: startAfter(this._initialTimeframe),
376
417
  stallTimeout: 1e3
377
418
  });
378
419
  this._state = new PipelineState(this._feedSetIterator, this._timeframeClock);
@@ -381,7 +422,7 @@ var Pipeline = class {
381
422
  this._feedSetIterator.stalled.on((iterator) => {
382
423
  log4.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, {}, {
383
424
  file: "pipeline.ts",
384
- line: 198,
425
+ line: 207,
385
426
  scope: this,
386
427
  callSite: (f, a) => f(...a)
387
428
  });
@@ -397,6 +438,8 @@ var Pipeline = class {
397
438
  getFeeds() {
398
439
  return this._feedSetIterator.feeds;
399
440
  }
441
+ // NOTE: This cannot be synchronized with `stop` because stop waits for the mutation processing to complete,
442
+ // which might be opening feeds during the mutation processing, which w
400
443
  async addFeed(feed) {
401
444
  await this._feedSetIterator.addFeed(feed);
402
445
  }
@@ -414,14 +457,14 @@ var Pipeline = class {
414
457
  async start() {
415
458
  log4("starting...", {}, {
416
459
  file: "pipeline.ts",
417
- line: 237,
460
+ line: 249,
418
461
  scope: this,
419
462
  callSite: (f, a) => f(...a)
420
463
  });
421
464
  await this._feedSetIterator.open();
422
465
  log4("started", {}, {
423
466
  file: "pipeline.ts",
424
- line: 239,
467
+ line: 251,
425
468
  scope: this,
426
469
  callSite: (f, a) => f(...a)
427
470
  });
@@ -429,7 +472,7 @@ var Pipeline = class {
429
472
  async stop() {
430
473
  log4("stopping...", {}, {
431
474
  file: "pipeline.ts",
432
- line: 243,
475
+ line: 256,
433
476
  scope: this,
434
477
  callSite: (f, a) => f(...a)
435
478
  });
@@ -437,7 +480,7 @@ var Pipeline = class {
437
480
  await this._processingTrigger.wait();
438
481
  log4("stopped", {}, {
439
482
  file: "pipeline.ts",
440
- line: 246,
483
+ line: 259,
441
484
  scope: this,
442
485
  callSite: (f, a) => f(...a)
443
486
  });
@@ -451,13 +494,20 @@ var Pipeline = class {
451
494
  this._isOpen = true;
452
495
  for await (const block of this._feedSetIterator) {
453
496
  this._processingTrigger.reset();
497
+ this._timeframeClock.updatePendingTimeframe(PublicKey.from(block.feedKey), block.seq);
454
498
  yield block;
455
499
  this._processingTrigger.wake();
456
- this._timeframeClock.updateTimeframe(PublicKey.from(block.feedKey), block.seq);
500
+ this._timeframeClock.updateTimeframe();
457
501
  }
458
502
  this._isOpen = false;
459
503
  }
460
504
  };
505
+ __decorate3([
506
+ synchronized2
507
+ ], Pipeline.prototype, "start", null);
508
+ __decorate3([
509
+ synchronized2
510
+ ], Pipeline.prototype, "stop", null);
461
511
 
462
512
  // packages/core/echo/echo-pipeline/src/space/auth.ts
463
513
  import assert5 from "@dxos/node-std/assert";
@@ -548,7 +598,7 @@ var AuthExtension = class extends RpcExtension {
548
598
 
549
599
  // packages/core/echo/echo-pipeline/src/space/space.ts
550
600
  import assert6 from "@dxos/node-std/assert";
551
- import { Event as Event2, synchronized as synchronized2, trackLeaks, Lock } from "@dxos/async";
601
+ import { Event as Event2, synchronized as synchronized3, trackLeaks, Lock } from "@dxos/async";
552
602
  import { log as log7, logInfo } from "@dxos/log";
553
603
  import { AdmittedFeed as AdmittedFeed2 } from "@dxos/protocols/proto/dxos/halo/credentials";
554
604
  import { Callback as Callback2 } from "@dxos/util";
@@ -669,7 +719,7 @@ var ControlPipeline = class {
669
719
  };
670
720
 
671
721
  // packages/core/echo/echo-pipeline/src/space/space.ts
672
- var __decorate3 = function(decorators, target, key, desc) {
722
+ var __decorate4 = function(decorators, target, key, desc) {
673
723
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
674
724
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
675
725
  r = Reflect.decorate(decorators, target, key, desc);
@@ -835,16 +885,16 @@ var Space = class Space2 {
835
885
  return pipeline;
836
886
  }
837
887
  };
838
- __decorate3([
888
+ __decorate4([
839
889
  logInfo
840
890
  ], Space.prototype, "key", null);
841
- __decorate3([
842
- synchronized2
891
+ __decorate4([
892
+ synchronized3
843
893
  ], Space.prototype, "open", null);
844
- __decorate3([
845
- synchronized2
894
+ __decorate4([
895
+ synchronized3
846
896
  ], Space.prototype, "close", null);
847
- Space = __decorate3([
897
+ Space = __decorate4([
848
898
  trackLeaks("open", "close")
849
899
  ], Space);
850
900
 
@@ -856,7 +906,7 @@ import { MMSTTopology } from "@dxos/network-manager";
856
906
  import { Teleport } from "@dxos/teleport";
857
907
  import { ReplicatorExtension } from "@dxos/teleport-extension-replicator";
858
908
  import { ComplexMap } from "@dxos/util";
859
- var __decorate4 = function(decorators, target, key, desc) {
909
+ var __decorate5 = function(decorators, target, key, desc) {
860
910
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
861
911
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
862
912
  r = Reflect.decorate(decorators, target, key, desc);
@@ -963,10 +1013,10 @@ var SpaceProtocol = class {
963
1013
  };
964
1014
  }
965
1015
  };
966
- __decorate4([
1016
+ __decorate5([
967
1017
  logInfo2
968
1018
  ], SpaceProtocol.prototype, "_topic", void 0);
969
- __decorate4([
1019
+ __decorate5([
970
1020
  logInfo2
971
1021
  ], SpaceProtocol.prototype, "_ownPeerKey", null);
972
1022
  var AuthStatus;
@@ -1026,21 +1076,21 @@ var SpaceProtocolSession = class {
1026
1076
  await this._teleport.close();
1027
1077
  }
1028
1078
  };
1029
- __decorate4([
1079
+ __decorate5([
1030
1080
  logInfo2
1031
1081
  ], SpaceProtocolSession.prototype, "_wireParams", void 0);
1032
- __decorate4([
1082
+ __decorate5([
1033
1083
  logInfo2
1034
1084
  ], SpaceProtocolSession.prototype, "authStatus", null);
1035
1085
 
1036
1086
  // packages/core/echo/echo-pipeline/src/space/space-manager.ts
1037
- import { synchronized as synchronized3, trackLeaks as trackLeaks2 } from "@dxos/async";
1087
+ import { synchronized as synchronized4, trackLeaks as trackLeaks2 } from "@dxos/async";
1038
1088
  import { failUndefined } from "@dxos/debug";
1039
1089
  import { PublicKey as PublicKey4 } from "@dxos/keys";
1040
1090
  import { log as log9 } from "@dxos/log";
1041
1091
  import { trace } from "@dxos/protocols";
1042
1092
  import { ComplexMap as ComplexMap2 } from "@dxos/util";
1043
- var __decorate5 = function(decorators, target, key, desc) {
1093
+ var __decorate6 = function(decorators, target, key, desc) {
1044
1094
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1045
1095
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1046
1096
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1063,10 +1113,11 @@ var SpaceManager = class SpaceManager2 {
1063
1113
  }
1064
1114
  async open() {
1065
1115
  log9.trace("dxos.echo.space-manager", trace.begin({
1066
- id: this._instanceId
1116
+ id: this._instanceId,
1117
+ parentId: this._traceParent
1067
1118
  }), {
1068
1119
  file: "space-manager.ts",
1069
- line: 65,
1120
+ line: 66,
1070
1121
  scope: this,
1071
1122
  callSite: (f, a) => f(...a)
1072
1123
  });
@@ -1079,7 +1130,7 @@ var SpaceManager = class SpaceManager2 {
1079
1130
  id: this._instanceId
1080
1131
  }), {
1081
1132
  file: "space-manager.ts",
1082
- line: 71,
1133
+ line: 72,
1083
1134
  scope: this,
1084
1135
  callSite: (f, a) => f(...a)
1085
1136
  });
@@ -1090,7 +1141,7 @@ var SpaceManager = class SpaceManager2 {
1090
1141
  spaceKey: metadata.genesisFeedKey
1091
1142
  }, {
1092
1143
  file: "space-manager.ts",
1093
- line: 75,
1144
+ line: 76,
1094
1145
  scope: this,
1095
1146
  callSite: (f, a) => f(...a)
1096
1147
  });
@@ -1112,13 +1163,13 @@ var SpaceManager = class SpaceManager2 {
1112
1163
  return space;
1113
1164
  }
1114
1165
  };
1115
- __decorate5([
1116
- synchronized3
1166
+ __decorate6([
1167
+ synchronized4
1117
1168
  ], SpaceManager.prototype, "open", null);
1118
- __decorate5([
1119
- synchronized3
1169
+ __decorate6([
1170
+ synchronized4
1120
1171
  ], SpaceManager.prototype, "close", null);
1121
- SpaceManager = __decorate5([
1172
+ SpaceManager = __decorate6([
1122
1173
  trackLeaks2("open", "close")
1123
1174
  ], SpaceManager);
1124
1175
 
@@ -1208,12 +1259,12 @@ var DataServiceHost = class {
1208
1259
  this._itemDemuxer.mutation.on(ctx, (message) => {
1209
1260
  var _a;
1210
1261
  const { batch, meta } = message;
1211
- log10("Object update", {
1262
+ log10("message", {
1212
1263
  batch,
1213
1264
  meta
1214
1265
  }, {
1215
1266
  file: "data-service-host.ts",
1216
- line: 50,
1267
+ line: 49,
1217
1268
  scope: this,
1218
1269
  callSite: (f, a) => f(...a)
1219
1270
  });
@@ -1237,36 +1288,59 @@ var DataServiceHost = class {
1237
1288
  });
1238
1289
  }
1239
1290
  async write(request) {
1240
- var _a;
1291
+ var _a, _b, _c;
1241
1292
  assert7(this._writeStream, "Cannot write mutations in readonly mode");
1242
- 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 = {
1243
1303
  batch: {
1244
- objects: (_a = request.batch.objects) == null ? void 0 : _a.map((object) => {
1304
+ objects: (_c = request.batch.objects) == null ? void 0 : _c.map((object) => {
1245
1305
  var _a2;
1246
1306
  return {
1247
1307
  ...object,
1248
- mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((m) => ({
1249
- ...m,
1308
+ mutations: (_a2 = object.mutations) == null ? void 0 : _a2.map((mutation) => ({
1309
+ ...mutation,
1250
1310
  meta: void 0
1251
1311
  })),
1252
1312
  meta: void 0
1253
1313
  };
1254
1314
  })
1255
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
+ }
1256
1336
  });
1257
- if (request.clientTag) {
1258
- this._clientTagMap.set([
1259
- receipt.feedKey,
1260
- receipt.seq
1261
- ], request.clientTag);
1262
- }
1263
1337
  return receipt;
1264
1338
  }
1265
1339
  };
1266
1340
 
1267
- // packages/core/echo/echo-pipeline/src/dbhost/database-backend.ts
1341
+ // packages/core/echo/echo-pipeline/src/dbhost/database-host.ts
1268
1342
  import { ItemDemuxer } from "@dxos/echo-db";
1269
- var DatabaseBackendHost = class {
1343
+ var DatabaseHost = class {
1270
1344
  constructor(_outboundStream, _snapshot) {
1271
1345
  this._outboundStream = _outboundStream;
1272
1346
  this._snapshot = _snapshot;
@@ -1304,7 +1378,7 @@ var DatabaseBackendHost = class {
1304
1378
  import { trackLeaks as trackLeaks3 } from "@dxos/async";
1305
1379
  import { schema as schema4 } from "@dxos/protocols";
1306
1380
  import { ObjectSync } from "@dxos/teleport-extension-object-sync";
1307
- var __decorate6 = function(decorators, target, key, desc) {
1381
+ var __decorate7 = function(decorators, target, key, desc) {
1308
1382
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1309
1383
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1310
1384
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1357,7 +1431,7 @@ var SnapshotManager = class SnapshotManager2 {
1357
1431
  return id;
1358
1432
  }
1359
1433
  };
1360
- SnapshotManager = __decorate6([
1434
+ SnapshotManager = __decorate7([
1361
1435
  trackLeaks3("open", "close")
1362
1436
  ], SnapshotManager);
1363
1437
 
@@ -1456,13 +1530,13 @@ var DataServiceImpl = class {
1456
1530
 
1457
1531
  // packages/core/echo/echo-pipeline/src/space/data-pipeline.ts
1458
1532
  import assert9 from "@dxos/node-std/assert";
1459
- import { Event as Event3, scheduleTask as scheduleTask2, synchronized as synchronized4, trackLeaks as trackLeaks4 } from "@dxos/async";
1533
+ import { scheduleTask as scheduleTask2, synchronized as synchronized5, trackLeaks as trackLeaks4 } from "@dxos/async";
1460
1534
  import { Context as Context3 } from "@dxos/context";
1461
1535
  import { failUndefined as failUndefined3 } from "@dxos/debug";
1462
1536
  import { ItemManager } from "@dxos/echo-db";
1463
1537
  import { log as log12 } from "@dxos/log";
1464
1538
  import { Timeframe as Timeframe3 } from "@dxos/timeframe";
1465
- var __decorate7 = function(decorators, target, key, desc) {
1539
+ var __decorate8 = function(decorators, target, key, desc) {
1466
1540
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1467
1541
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
1468
1542
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1475,14 +1549,15 @@ var __decorate7 = function(decorators, target, key, desc) {
1475
1549
  var MESSAGES_PER_SNAPSHOT = 10;
1476
1550
  var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1477
1551
  var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
1478
- var DISABLE_SNAPSHOT_CACHE = false;
1552
+ var DISABLE_SNAPSHOT_CACHE = true;
1479
1553
  var DataPipeline = class DataPipeline2 {
1480
1554
  constructor(_params) {
1481
1555
  this._params = _params;
1482
1556
  this._ctx = new Context3();
1483
1557
  this._lastAutomaticSnapshotTimeframe = new Timeframe3();
1484
1558
  this._isOpen = false;
1485
- this.onTimeframeReached = new Event3();
1559
+ this._lastTimeframeSaveTime = 0;
1560
+ this._lastSnapshotSaveTime = 0;
1486
1561
  }
1487
1562
  get isOpen() {
1488
1563
  return this._isOpen;
@@ -1510,7 +1585,7 @@ var DataPipeline = class DataPipeline2 {
1510
1585
  return;
1511
1586
  }
1512
1587
  this._spaceContext = spaceContext;
1513
- if (this._params.snapshotId) {
1588
+ if (this._params.snapshotId && !DISABLE_SNAPSHOT_CACHE) {
1514
1589
  this._snapshot = await this._params.snapshotManager.load(this._params.snapshotId);
1515
1590
  this._lastAutomaticSnapshotTimeframe = (_b = (_a = this._snapshot) == null ? void 0 : _a.timeframe) != null ? _b : new Timeframe3();
1516
1591
  }
@@ -1521,64 +1596,14 @@ var DataPipeline = class DataPipeline2 {
1521
1596
  const feedWriter = createMappedFeedWriter((data) => ({
1522
1597
  data
1523
1598
  }), (_c = this._pipeline.writer) != null ? _c : failUndefined3());
1524
- 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);
1525
1600
  this._itemManager = new ItemManager(this._params.modelFactory);
1526
1601
  await this.databaseBackend.open(this._itemManager, this._params.modelFactory);
1527
1602
  scheduleTask2(this._ctx, async () => {
1528
1603
  await this._consumePipeline();
1529
1604
  });
1530
- this._createPeriodicSnapshots();
1531
1605
  this._isOpen = true;
1532
1606
  }
1533
- _createPeriodicSnapshots() {
1534
- this.onTimeframeReached.debounce(TIMEFRAME_SAVE_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1535
- await this._saveLatestTimeframe();
1536
- });
1537
- if (!DISABLE_SNAPSHOT_CACHE) {
1538
- this.onTimeframeReached.debounce(AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL).on(this._ctx, async () => {
1539
- var _a, _b;
1540
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1541
- if (!latestTimeframe) {
1542
- return;
1543
- }
1544
- if (latestTimeframe.totalMessages() - this._lastAutomaticSnapshotTimeframe.totalMessages() > MESSAGES_PER_SNAPSHOT) {
1545
- const snapshot = await this._saveSnapshot();
1546
- this._lastAutomaticSnapshotTimeframe = (_b = snapshot.timeframe) != null ? _b : failUndefined3();
1547
- log12("save", {
1548
- snapshot
1549
- }, {
1550
- file: "data-pipeline.ts",
1551
- line: 161,
1552
- scope: this,
1553
- callSite: (f, a) => f(...a)
1554
- });
1555
- }
1556
- });
1557
- }
1558
- }
1559
- async _saveSnapshot() {
1560
- const snapshot = await this.createSnapshot();
1561
- const snapshotKey = await this._params.snapshotManager.store(snapshot);
1562
- await this._params.metadataStore.setSpaceSnapshot(this._params.spaceKey, snapshotKey);
1563
- return snapshot;
1564
- }
1565
- async _saveLatestTimeframe() {
1566
- var _a, _b;
1567
- const latestTimeframe = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe;
1568
- log12("save latest timeframe", {
1569
- latestTimeframe,
1570
- spaceKey: this._params.spaceKey
1571
- }, {
1572
- file: "data-pipeline.ts",
1573
- line: 176,
1574
- scope: this,
1575
- callSite: (f, a) => f(...a)
1576
- });
1577
- if (latestTimeframe) {
1578
- const newTimeframe = Timeframe3.merge((_b = this._targetTimeframe) != null ? _b : new Timeframe3(), latestTimeframe);
1579
- await this._params.metadataStore.setSpaceLatestTimeframe(this._params.spaceKey, newTimeframe);
1580
- }
1581
- }
1582
1607
  async close() {
1583
1608
  var _a, _b, _c;
1584
1609
  if (!this._isOpen) {
@@ -1586,37 +1611,32 @@ var DataPipeline = class DataPipeline2 {
1586
1611
  }
1587
1612
  log12("close", {}, {
1588
1613
  file: "data-pipeline.ts",
1589
- line: 188,
1614
+ line: 145,
1590
1615
  scope: this,
1591
1616
  callSite: (f, a) => f(...a)
1592
1617
  });
1593
1618
  this._isOpen = false;
1619
+ await this._ctx.dispose();
1620
+ await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1594
1621
  try {
1595
- await this._saveLatestTimeframe();
1596
- 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
+ }
1597
1628
  } catch (err) {
1598
1629
  log12.catch(err, {}, {
1599
1630
  file: "data-pipeline.ts",
1600
- line: 195,
1631
+ line: 160,
1601
1632
  scope: this,
1602
1633
  callSite: (f, a) => f(...a)
1603
1634
  });
1604
1635
  }
1605
- await this._ctx.dispose();
1606
- await ((_a = this._pipeline) == null ? void 0 : _a.stop());
1607
1636
  await ((_b = this.databaseBackend) == null ? void 0 : _b.close());
1608
1637
  await ((_c = this._itemManager) == null ? void 0 : _c.destroy());
1609
1638
  await this._params.snapshotManager.close();
1610
1639
  }
1611
- createSnapshot() {
1612
- var _a, _b;
1613
- assert9(this.databaseBackend, "Database backend is not initialized.");
1614
- return {
1615
- spaceKey: this._params.spaceKey.asUint8Array(),
1616
- timeframe: (_b = (_a = this._pipeline) == null ? void 0 : _a.state.timeframe) != null ? _b : new Timeframe3(),
1617
- database: this.databaseBackend.createSnapshot()
1618
- };
1619
- }
1620
1640
  async _consumePipeline() {
1621
1641
  assert9(this._pipeline, "Pipeline is not initialized.");
1622
1642
  for await (const msg of this._pipeline.consume()) {
@@ -1625,7 +1645,7 @@ var DataPipeline = class DataPipeline2 {
1625
1645
  msg
1626
1646
  }, {
1627
1647
  file: "data-pipeline.ts",
1628
- line: 217,
1648
+ line: 172,
1629
1649
  scope: this,
1630
1650
  callSite: (f, a) => f(...a)
1631
1651
  });
@@ -1637,7 +1657,7 @@ var DataPipeline = class DataPipeline2 {
1637
1657
  feedKey
1638
1658
  }, {
1639
1659
  file: "data-pipeline.ts",
1640
- line: 223,
1660
+ line: 178,
1641
1661
  scope: this,
1642
1662
  callSite: (f, a) => f(...a)
1643
1663
  });
@@ -1652,30 +1672,70 @@ var DataPipeline = class DataPipeline2 {
1652
1672
  memberKey: feedInfo.assertion.identityKey
1653
1673
  }
1654
1674
  });
1655
- this.onTimeframeReached.emit(data.timeframe);
1675
+ await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1656
1676
  }
1657
1677
  } catch (err) {
1658
1678
  log12.catch(err, {}, {
1659
1679
  file: "data-pipeline.ts",
1660
- line: 239,
1680
+ line: 196,
1661
1681
  scope: this,
1662
1682
  callSite: (f, a) => f(...a)
1663
1683
  });
1664
1684
  }
1665
1685
  }
1666
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
+ }
1667
1727
  async waitUntilTimeframe(timeframe) {
1668
1728
  assert9(this._pipeline, "Pipeline is not initialized.");
1669
1729
  await this._pipeline.state.waitUntilTimeframe(timeframe);
1670
1730
  }
1671
1731
  };
1672
- __decorate7([
1673
- synchronized4
1732
+ __decorate8([
1733
+ synchronized5
1674
1734
  ], DataPipeline.prototype, "open", null);
1675
- __decorate7([
1676
- synchronized4
1735
+ __decorate8([
1736
+ synchronized5
1677
1737
  ], DataPipeline.prototype, "close", null);
1678
- DataPipeline = __decorate7([
1738
+ DataPipeline = __decorate8([
1679
1739
  trackLeaks4("open", "close")
1680
1740
  ], DataPipeline);
1681
1741
  var snapshotTimeframeToStartingTimeframe = (snapshotTimeframe) => {
@@ -1693,6 +1753,7 @@ export {
1693
1753
  createMappedFeedWriter,
1694
1754
  mapTimeframeToFeedIndexes,
1695
1755
  mapFeedIndexesToTimeframe,
1756
+ startAfter,
1696
1757
  TimeframeClock,
1697
1758
  Pipeline,
1698
1759
  AuthExtension,
@@ -1705,11 +1766,11 @@ export {
1705
1766
  SpaceManager,
1706
1767
  spaceGenesis,
1707
1768
  DataServiceHost,
1708
- DatabaseBackendHost,
1769
+ DatabaseHost,
1709
1770
  SnapshotManager,
1710
1771
  SnapshotStore,
1711
1772
  DataServiceSubscriptions,
1712
1773
  DataServiceImpl,
1713
1774
  DataPipeline
1714
1775
  };
1715
- //# sourceMappingURL=chunk-6CRSMR4G.mjs.map
1776
+ //# sourceMappingURL=chunk-4YAT2XJW.mjs.map