@dxos/echo-pipeline 0.1.57-main.c28f37d → 0.1.57-next.9496927

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/lib/browser/{chunk-GELWTWOW.mjs → chunk-VYZEP2BZ.mjs} +358 -132
  2. package/dist/lib/browser/chunk-VYZEP2BZ.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -1
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +5 -4
  6. package/dist/lib/browser/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/index.cjs +372 -146
  8. package/dist/lib/node/index.cjs.map +3 -3
  9. package/dist/lib/node/meta.json +1 -1
  10. package/dist/lib/node/testing/index.cjs +384 -157
  11. package/dist/lib/node/testing/index.cjs.map +3 -3
  12. package/dist/types/src/db-host/data-service-host.d.ts +3 -1
  13. package/dist/types/src/db-host/data-service-host.d.ts.map +1 -1
  14. package/dist/types/src/db-host/data-service.d.ts +2 -1
  15. package/dist/types/src/db-host/data-service.d.ts.map +1 -1
  16. package/dist/types/src/db-host/database-host.d.ts +4 -2
  17. package/dist/types/src/db-host/database-host.d.ts.map +1 -1
  18. package/dist/types/src/metadata/metadata-store.d.ts +12 -1
  19. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  20. package/dist/types/src/pipeline/pipeline.d.ts +1 -0
  21. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  22. package/dist/types/src/space/auth.d.ts +1 -0
  23. package/dist/types/src/space/auth.d.ts.map +1 -1
  24. package/dist/types/src/space/control-pipeline.d.ts +4 -0
  25. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  26. package/dist/types/src/space/data-pipeline.d.ts +1 -0
  27. package/dist/types/src/space/data-pipeline.d.ts.map +1 -1
  28. package/dist/types/src/space/space-protocol.d.ts +3 -2
  29. package/dist/types/src/space/space-protocol.d.ts.map +1 -1
  30. package/dist/types/src/space/space.d.ts.map +1 -1
  31. package/dist/types/src/testing/database-test-rig.d.ts.map +1 -1
  32. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  33. package/dist/types/src/testing/util.d.ts.map +1 -1
  34. package/package.json +32 -32
  35. package/src/db-host/data-service-host.ts +5 -0
  36. package/src/db-host/data-service.ts +8 -0
  37. package/src/db-host/database-host.ts +7 -3
  38. package/src/metadata/metadata-store.ts +125 -28
  39. package/src/pipeline/pipeline.ts +11 -0
  40. package/src/space/auth.ts +5 -0
  41. package/src/space/control-pipeline.ts +63 -10
  42. package/src/space/data-pipeline.ts +29 -4
  43. package/src/space/space-protocol.ts +7 -2
  44. package/src/space/space.ts +4 -2
  45. package/src/testing/database-test-rig.ts +26 -21
  46. package/src/testing/test-agent-builder.ts +2 -2
  47. package/src/testing/util.ts +3 -1
  48. package/src/tests/database.test.ts +3 -1
  49. package/dist/lib/browser/chunk-GELWTWOW.mjs.map +0 -7
@@ -43,9 +43,10 @@ import { EchoEvent } from "@dxos/protocols/proto/dxos/echo/service";
43
43
  import { ComplexMap } from "@dxos/util";
44
44
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/data-service-host.ts";
45
45
  var DataServiceHost = class {
46
- constructor(_itemManager, _itemDemuxer, _writeStream) {
46
+ constructor(_itemManager, _itemDemuxer, _flush, _writeStream) {
47
47
  this._itemManager = _itemManager;
48
48
  this._itemDemuxer = _itemDemuxer;
49
+ this._flush = _flush;
49
50
  this._writeStream = _writeStream;
50
51
  this._ctx = new Context();
51
52
  this._clientTagMap = new ComplexMap(([feedKey, seq]) => `${feedKey.toHex()}:${seq}`);
@@ -79,7 +80,7 @@ var DataServiceHost = class {
79
80
  const { batch, meta } = message;
80
81
  invariant2(!meta.clientTag, "Unexpected client tag in mutation message", {
81
82
  F: __dxlog_file2,
82
- L: 68,
83
+ L: 69,
83
84
  S: this,
84
85
  A: [
85
86
  "!(meta as any).clientTag",
@@ -91,7 +92,7 @@ var DataServiceHost = class {
91
92
  meta
92
93
  }, {
93
94
  F: __dxlog_file2,
94
- L: 69,
95
+ L: 70,
95
96
  S: this,
96
97
  C: (f, a) => f(...a)
97
98
  });
@@ -119,7 +120,7 @@ var DataServiceHost = class {
119
120
  async write(request) {
120
121
  invariant2(!this._ctx.disposed, "Cannot write to closed DataServiceHost", {
121
122
  F: __dxlog_file2,
122
- L: 95,
123
+ L: 96,
123
124
  S: this,
124
125
  A: [
125
126
  "!this._ctx.disposed",
@@ -128,7 +129,7 @@ var DataServiceHost = class {
128
129
  });
129
130
  invariant2(this._writeStream, "Cannot write mutations in readonly mode", {
130
131
  F: __dxlog_file2,
131
- L: 96,
132
+ L: 97,
132
133
  S: this,
133
134
  A: [
134
135
  "this._writeStream",
@@ -140,7 +141,7 @@ var DataServiceHost = class {
140
141
  objectCount: request.batch.objects?.length ?? 0
141
142
  }, {
142
143
  F: __dxlog_file2,
143
- L: 98,
144
+ L: 99,
144
145
  S: this,
145
146
  C: (f, a) => f(...a)
146
147
  });
@@ -154,7 +155,7 @@ var DataServiceHost = class {
154
155
  seq: receipt2.seq
155
156
  }, {
156
157
  F: __dxlog_file2,
157
- L: 107,
158
+ L: 108,
158
159
  S: this,
159
160
  C: (f, a) => f(...a)
160
161
  });
@@ -167,6 +168,9 @@ var DataServiceHost = class {
167
168
  });
168
169
  return receipt;
169
170
  }
171
+ async flush() {
172
+ await this._flush();
173
+ }
170
174
  };
171
175
  var createDataMessage = (batch) => ({
172
176
  batch: {
@@ -184,8 +188,9 @@ var createDataMessage = (batch) => ({
184
188
  // packages/core/echo/echo-pipeline/src/db-host/database-host.ts
185
189
  import { ItemDemuxer } from "@dxos/echo-db";
186
190
  var DatabaseHost = class {
187
- constructor(_outboundStream) {
191
+ constructor(_outboundStream, _flush) {
188
192
  this._outboundStream = _outboundStream;
193
+ this._flush = _flush;
189
194
  }
190
195
  get isReadOnly() {
191
196
  return !!this._outboundStream;
@@ -208,7 +213,7 @@ var DatabaseHost = class {
208
213
  return this._itemDemuxer.createSnapshot();
209
214
  }
210
215
  createDataServiceHost() {
211
- return new DataServiceHost(this._itemManager, this._itemDemuxer, this._outboundStream ?? void 0);
216
+ return new DataServiceHost(this._itemManager, this._itemDemuxer, this._flush, this._outboundStream ?? void 0);
212
217
  }
213
218
  };
214
219
 
@@ -328,13 +333,13 @@ var DataServiceSubscriptions = class {
328
333
  spaceKey
329
334
  }, {
330
335
  F: __dxlog_file3,
331
- L: 30,
336
+ L: 31,
332
337
  S: this,
333
338
  C: (f, a) => f(...a)
334
339
  });
335
340
  invariant3(!this._spaces.has(spaceKey), void 0, {
336
341
  F: __dxlog_file3,
337
- L: 31,
342
+ L: 32,
338
343
  S: this,
339
344
  A: [
340
345
  "!this._spaces.has(spaceKey)",
@@ -349,7 +354,7 @@ var DataServiceSubscriptions = class {
349
354
  spaceKey
350
355
  }, {
351
356
  F: __dxlog_file3,
352
- L: 37,
357
+ L: 38,
353
358
  S: this,
354
359
  C: (f, a) => f(...a)
355
360
  });
@@ -368,7 +373,7 @@ var DataServiceImpl = class {
368
373
  subscribe(request) {
369
374
  invariant3(request.spaceKey, void 0, {
370
375
  F: __dxlog_file3,
371
- L: 56,
376
+ L: 57,
372
377
  S: this,
373
378
  A: [
374
379
  "request.spaceKey",
@@ -381,7 +386,7 @@ var DataServiceImpl = class {
381
386
  write(request) {
382
387
  invariant3(request.spaceKey, void 0, {
383
388
  F: __dxlog_file3,
384
- L: 63,
389
+ L: 64,
385
390
  S: this,
386
391
  A: [
387
392
  "request.spaceKey",
@@ -390,7 +395,7 @@ var DataServiceImpl = class {
390
395
  });
391
396
  invariant3(request.batch, void 0, {
392
397
  F: __dxlog_file3,
393
- L: 64,
398
+ L: 65,
394
399
  S: this,
395
400
  A: [
396
401
  "request.batch",
@@ -400,6 +405,19 @@ var DataServiceImpl = class {
400
405
  const host = this._subscriptions.getDataService(request.spaceKey) ?? raise(new Error(`space not found: ${request.spaceKey}`));
401
406
  return host.write(request);
402
407
  }
408
+ flush(request) {
409
+ invariant3(request.spaceKey, void 0, {
410
+ F: __dxlog_file3,
411
+ L: 72,
412
+ S: this,
413
+ A: [
414
+ "request.spaceKey",
415
+ ""
416
+ ]
417
+ });
418
+ const host = this._subscriptions.getDataService(request.spaceKey) ?? raise(new Error(`space not found: ${request.spaceKey}`));
419
+ return host.flush();
420
+ }
403
421
  };
404
422
 
405
423
  // packages/core/echo/echo-pipeline/src/metadata/metadata-store.ts
@@ -407,10 +425,11 @@ import CRC32 from "crc-32";
407
425
  import { synchronized, Event } from "@dxos/async";
408
426
  import { DataCorruptionError } from "@dxos/errors";
409
427
  import { invariant as invariant4 } from "@dxos/invariant";
428
+ import { PublicKey as PublicKey3 } from "@dxos/keys";
410
429
  import { log as log3 } from "@dxos/log";
411
430
  import { STORAGE_VERSION, schema as schema4 } from "@dxos/protocols";
412
431
  import { SpaceState } from "@dxos/protocols/proto/dxos/client/services";
413
- import { arrayToBuffer } from "@dxos/util";
432
+ import { ComplexMap as ComplexMap3, arrayToBuffer, forEachAsync, isNotNullOrUndefined } from "@dxos/util";
414
433
  function _ts_decorate2(decorators, target, key, desc) {
415
434
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
416
435
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -428,12 +447,16 @@ var emptyEchoMetadata = () => ({
428
447
  created: /* @__PURE__ */ new Date(),
429
448
  updated: /* @__PURE__ */ new Date()
430
449
  });
450
+ var emptyLargeSpaceMetadata = () => ({});
431
451
  var EchoMetadata = schema4.getCodecForType("dxos.echo.metadata.EchoMetadata");
452
+ var LargeSpaceMetadata = schema4.getCodecForType("dxos.echo.metadata.LargeSpaceMetadata");
432
453
  var MetadataStore = class {
433
454
  // prettier-ignore
434
455
  constructor(_directory) {
435
456
  this._directory = _directory;
436
457
  this._metadata = emptyEchoMetadata();
458
+ this._spaceLargeMetadata = new ComplexMap3(PublicKey3.hash);
459
+ this._metadataFile = void 0;
437
460
  this.update = new Event();
438
461
  }
439
462
  get metadata() {
@@ -449,11 +472,7 @@ var MetadataStore = class {
449
472
  get spaces() {
450
473
  return this._metadata.spaces ?? [];
451
474
  }
452
- /**
453
- * Loads metadata from persistent storage.
454
- */
455
- async load() {
456
- const file = this._directory.getOrCreateFile("EchoMetadata");
475
+ async _readFile(file, codec2) {
457
476
  try {
458
477
  const { size: fileLength } = await file.stat();
459
478
  if (fileLength < 8) {
@@ -463,10 +482,11 @@ var MetadataStore = class {
463
482
  const checksum = fromBytesInt32(await file.read(4, 4));
464
483
  log3("loaded", {
465
484
  size: dataSize,
466
- checksum
485
+ checksum,
486
+ name: file.filename
467
487
  }, {
468
488
  F: __dxlog_file4,
469
- L: 72,
489
+ L: 82,
470
490
  S: this,
471
491
  C: (f, a) => f(...a)
472
492
  });
@@ -481,7 +501,48 @@ var MetadataStore = class {
481
501
  if (calculatedChecksum !== checksum) {
482
502
  throw new DataCorruptionError("Metadata checksum is invalid.");
483
503
  }
484
- this._metadata = EchoMetadata.decode(data);
504
+ return codec2.decode(data);
505
+ } finally {
506
+ await file.close();
507
+ }
508
+ }
509
+ async _writeFile(file, codec2, data) {
510
+ const encoded = arrayToBuffer(codec2.encode(data));
511
+ const checksum = CRC32.buf(encoded);
512
+ const result = Buffer.alloc(8 + encoded.length);
513
+ result.writeInt32LE(encoded.length, 0);
514
+ result.writeInt32LE(checksum, 4);
515
+ encoded.copy(result, 8);
516
+ await file.write(0, result);
517
+ log3("saved", {
518
+ size: encoded.length,
519
+ checksum
520
+ }, {
521
+ F: __dxlog_file4,
522
+ L: 114,
523
+ S: this,
524
+ C: (f, a) => f(...a)
525
+ });
526
+ }
527
+ async close() {
528
+ await this.flush();
529
+ await this._metadataFile?.close();
530
+ this._metadataFile = void 0;
531
+ this._metadata = emptyEchoMetadata();
532
+ this._spaceLargeMetadata.clear();
533
+ }
534
+ /**
535
+ * Loads metadata from persistent storage.
536
+ */
537
+ async load() {
538
+ if (!this._metadataFile || this._metadataFile.closed) {
539
+ this._metadataFile = this._directory.getOrCreateFile("EchoMetadata");
540
+ }
541
+ try {
542
+ const metadata = await this._readFile(this._metadataFile, EchoMetadata);
543
+ if (metadata) {
544
+ this._metadata = metadata;
545
+ }
485
546
  this._metadata.spaces?.forEach((space) => {
486
547
  space.state ??= SpaceState.ACTIVE;
487
548
  });
@@ -490,14 +551,29 @@ var MetadataStore = class {
490
551
  err
491
552
  }, {
492
553
  F: __dxlog_file4,
493
- L: 92,
554
+ L: 145,
494
555
  S: this,
495
556
  C: (f, a) => f(...a)
496
557
  });
497
558
  this._metadata = emptyEchoMetadata();
498
- } finally {
499
- await file.close();
500
559
  }
560
+ await forEachAsync([
561
+ this._metadata.identity?.haloSpace.key,
562
+ ...this._metadata.spaces?.map((space) => space.key) ?? []
563
+ ].filter(isNotNullOrUndefined), async (key) => {
564
+ try {
565
+ await this._loadSpaceLargeMetadata(key);
566
+ } catch (err) {
567
+ log3.error("failed to load space large metadata", {
568
+ err
569
+ }, {
570
+ F: __dxlog_file4,
571
+ L: 157,
572
+ S: this,
573
+ C: (f, a) => f(...a)
574
+ });
575
+ }
576
+ });
501
577
  }
502
578
  async _save() {
503
579
  const data = {
@@ -508,27 +584,34 @@ var MetadataStore = class {
508
584
  };
509
585
  this.update.emit(data);
510
586
  const file = this._directory.getOrCreateFile("EchoMetadata");
587
+ await this._writeFile(file, EchoMetadata, data);
588
+ }
589
+ async _loadSpaceLargeMetadata(key) {
590
+ const file = this._directory.getOrCreateFile(`space_${key.toHex()}_large`);
511
591
  try {
512
- const encoded = arrayToBuffer(EchoMetadata.encode(data));
513
- const checksum = CRC32.buf(encoded);
514
- const result = Buffer.alloc(8 + encoded.length);
515
- result.writeInt32LE(encoded.length, 0);
516
- result.writeInt32LE(checksum, 4);
517
- encoded.copy(result, 8);
518
- await file.write(0, result);
519
- log3("saved", {
520
- size: encoded.length,
521
- checksum
592
+ const metadata = await this._readFile(file, LargeSpaceMetadata);
593
+ if (metadata) {
594
+ this._spaceLargeMetadata.set(key, metadata);
595
+ }
596
+ } catch (err) {
597
+ log3.error("failed to load space large metadata", {
598
+ err
522
599
  }, {
523
600
  F: __dxlog_file4,
524
- L: 124,
601
+ L: 186,
525
602
  S: this,
526
603
  C: (f, a) => f(...a)
527
604
  });
528
- } finally {
529
- await file.close();
530
605
  }
531
606
  }
607
+ async _saveSpaceLargeMetadata(key) {
608
+ const data = this._getLargeSpaceMetadata(key);
609
+ const file = this._directory.getOrCreateFile(`space_${key.toHex()}_large`);
610
+ await this._writeFile(file, LargeSpaceMetadata, data);
611
+ }
612
+ async flush() {
613
+ await this._directory.flush();
614
+ }
532
615
  _getSpace(spaceKey) {
533
616
  if (this._metadata.identity?.haloSpace.key.equals(spaceKey)) {
534
617
  return this._metadata.identity.haloSpace;
@@ -536,7 +619,7 @@ var MetadataStore = class {
536
619
  const space = this.spaces.find((space2) => space2.key === spaceKey);
537
620
  invariant4(space, "Space not found", {
538
621
  F: __dxlog_file4,
539
- L: 137,
622
+ L: 208,
540
623
  S: this,
541
624
  A: [
542
625
  "space",
@@ -545,13 +628,22 @@ var MetadataStore = class {
545
628
  });
546
629
  return space;
547
630
  }
631
+ _getLargeSpaceMetadata(key) {
632
+ let entry = this._spaceLargeMetadata.get(key);
633
+ if (entry) {
634
+ return entry;
635
+ }
636
+ entry = emptyLargeSpaceMetadata();
637
+ this._spaceLargeMetadata.set(key, entry);
638
+ return entry;
639
+ }
548
640
  /**
549
641
  * Clears storage - doesn't work for now.
550
642
  */
551
643
  async clear() {
552
644
  log3("clearing all metadata", void 0, {
553
645
  F: __dxlog_file4,
554
- L: 145,
646
+ L: 227,
555
647
  S: this,
556
648
  C: (f, a) => f(...a)
557
649
  });
@@ -564,7 +656,7 @@ var MetadataStore = class {
564
656
  async setIdentityRecord(record) {
565
657
  invariant4(!this._metadata.identity, "Cannot overwrite existing identity in metadata", {
566
658
  F: __dxlog_file4,
567
- L: 155,
659
+ L: 237,
568
660
  S: this,
569
661
  A: [
570
662
  "!this._metadata.identity",
@@ -573,11 +665,12 @@ var MetadataStore = class {
573
665
  });
574
666
  this._metadata.identity = record;
575
667
  await this._save();
668
+ await this.flush();
576
669
  }
577
670
  async addSpace(record) {
578
671
  invariant4(!(this._metadata.spaces ?? []).find((space) => space.key === record.key), "Cannot overwrite existing space in metadata", {
579
672
  F: __dxlog_file4,
580
- L: 162,
673
+ L: 245,
581
674
  S: this,
582
675
  A: [
583
676
  "!(this._metadata.spaces ?? []).find((space) => space.key === record.key)",
@@ -586,6 +679,7 @@ var MetadataStore = class {
586
679
  });
587
680
  (this._metadata.spaces ??= []).push(record);
588
681
  await this._save();
682
+ await this.flush();
589
683
  }
590
684
  async setSpaceDataLatestTimeframe(spaceKey, timeframe) {
591
685
  this._getSpace(spaceKey).dataTimeframe = timeframe;
@@ -594,6 +688,7 @@ var MetadataStore = class {
594
688
  async setSpaceControlLatestTimeframe(spaceKey, timeframe) {
595
689
  this._getSpace(spaceKey).controlTimeframe = timeframe;
596
690
  await this._save();
691
+ await this.flush();
597
692
  }
598
693
  async setCache(spaceKey, cache) {
599
694
  this._getSpace(spaceKey).cache = cache;
@@ -604,10 +699,20 @@ var MetadataStore = class {
604
699
  space.controlFeedKey = controlFeedKey;
605
700
  space.dataFeedKey = dataFeedKey;
606
701
  await this._save();
702
+ await this.flush();
607
703
  }
608
704
  async setSpaceState(spaceKey, state) {
609
705
  this._getSpace(spaceKey).state = state;
610
706
  await this._save();
707
+ await this.flush();
708
+ }
709
+ getSpaceControlPipelineSnapshot(spaceKey) {
710
+ return this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot;
711
+ }
712
+ async setSpaceControlPipelineSnapshot(spaceKey, snapshot) {
713
+ this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot = snapshot;
714
+ await this._saveSpaceLargeMetadata(spaceKey);
715
+ await this.flush();
611
716
  }
612
717
  };
613
718
  _ts_decorate2([
@@ -616,6 +721,9 @@ _ts_decorate2([
616
721
  _ts_decorate2([
617
722
  synchronized
618
723
  ], MetadataStore.prototype, "_save", null);
724
+ _ts_decorate2([
725
+ synchronized
726
+ ], MetadataStore.prototype, "_saveSpaceLargeMetadata", null);
619
727
  var fromBytesInt32 = (buf) => buf.readInt32LE(0);
620
728
 
621
729
  // packages/core/echo/echo-pipeline/src/pipeline/timeframe-clock.ts
@@ -722,10 +830,10 @@ import { Context as Context2, rejectOnDispose } from "@dxos/context";
722
830
  import { failUndefined } from "@dxos/debug";
723
831
  import { FeedSetIterator } from "@dxos/feed-store";
724
832
  import { invariant as invariant6 } from "@dxos/invariant";
725
- import { PublicKey as PublicKey3 } from "@dxos/keys";
833
+ import { PublicKey as PublicKey4 } from "@dxos/keys";
726
834
  import { log as log6 } from "@dxos/log";
727
835
  import { Timeframe as Timeframe2 } from "@dxos/timeframe";
728
- import { ComplexMap as ComplexMap3 } from "@dxos/util";
836
+ import { ComplexMap as ComplexMap4 } from "@dxos/util";
729
837
 
730
838
  // packages/core/echo/echo-pipeline/src/pipeline/message-selector.ts
731
839
  import { invariant as invariant5 } from "@dxos/invariant";
@@ -778,6 +886,7 @@ var PipelineState = class {
778
886
  this.timeframeUpdate = this._timeframeClock.update;
779
887
  this.stalled = new Event3();
780
888
  this._startTimeframe = new Timeframe2();
889
+ this._reachedTarget = false;
781
890
  }
782
891
  /**
783
892
  * Latest theoretical timeframe based on the last mutation in each feed.
@@ -802,6 +911,9 @@ var PipelineState = class {
802
911
  get targetTimeframe() {
803
912
  return this._targetTimeframe ? this._targetTimeframe : new Timeframe2();
804
913
  }
914
+ get reachedTarget() {
915
+ return this._reachedTarget;
916
+ }
805
917
  get feeds() {
806
918
  return Array.from(this._feeds.values());
807
919
  }
@@ -825,7 +937,7 @@ var PipelineState = class {
825
937
  target: this.targetTimeframe
826
938
  }, {
827
939
  F: __dxlog_file7,
828
- L: 125,
940
+ L: 134,
829
941
  S: this,
830
942
  C: (f, a) => f(...a)
831
943
  });
@@ -844,6 +956,7 @@ var PipelineState = class {
844
956
  rejectOnDispose(this._ctx),
845
957
  this._reachedTargetPromise.then(() => {
846
958
  done = true;
959
+ this._reachedTarget = true;
847
960
  }),
848
961
  sleep(timeout).then(() => {
849
962
  if (done) {
@@ -856,7 +969,7 @@ var PipelineState = class {
856
969
  dependencies: Timeframe2.dependencies(this.targetTimeframe, this.timeframe)
857
970
  }, {
858
971
  F: __dxlog_file7,
859
- L: 152,
972
+ L: 162,
860
973
  S: this,
861
974
  C: (f, a) => f(...a)
862
975
  });
@@ -870,14 +983,14 @@ var PipelineState = class {
870
983
  var Pipeline = class {
871
984
  constructor() {
872
985
  this._timeframeClock = new TimeframeClock(new Timeframe2());
873
- this._feeds = new ComplexMap3(PublicKey3.hash);
986
+ this._feeds = new ComplexMap4(PublicKey4.hash);
874
987
  // External state accessor.
875
988
  this._state = new PipelineState(this._feeds, this._timeframeClock);
876
989
  // Waits for the message consumer to process the message and yield control back to the pipeline.
877
990
  this._processingTrigger = new Trigger().wake();
878
991
  this._pauseTrigger = new Trigger().wake();
879
992
  // Pending downloads.
880
- this._downloads = new ComplexMap3((value) => PublicKey3.hash(value.key));
993
+ this._downloads = new ComplexMap4((value) => PublicKey4.hash(value.key));
881
994
  this._isStopping = false;
882
995
  this._isStarted = false;
883
996
  this._isBeingConsumed = false;
@@ -889,7 +1002,7 @@ var Pipeline = class {
889
1002
  get writer() {
890
1003
  invariant6(this._writer, "Writer not set.", {
891
1004
  F: __dxlog_file7,
892
- L: 233,
1005
+ L: 243,
893
1006
  S: this,
894
1007
  A: [
895
1008
  "this._writer",
@@ -918,7 +1031,7 @@ var Pipeline = class {
918
1031
  setWriteFeed(feed) {
919
1032
  invariant6(!this._writer, "Writer already set.", {
920
1033
  F: __dxlog_file7,
921
- L: 260,
1034
+ L: 270,
922
1035
  S: this,
923
1036
  A: [
924
1037
  "!this._writer",
@@ -927,7 +1040,7 @@ var Pipeline = class {
927
1040
  });
928
1041
  invariant6(feed.properties.writable, "Feed must be writable.", {
929
1042
  F: __dxlog_file7,
930
- L: 261,
1043
+ L: 271,
931
1044
  S: this,
932
1045
  A: [
933
1046
  "feed.properties.writable",
@@ -942,7 +1055,7 @@ var Pipeline = class {
942
1055
  async start() {
943
1056
  invariant6(!this._isStarted, "Pipeline is already started.", {
944
1057
  F: __dxlog_file7,
945
- L: 274,
1058
+ L: 284,
946
1059
  S: this,
947
1060
  A: [
948
1061
  "!this._isStarted",
@@ -951,7 +1064,7 @@ var Pipeline = class {
951
1064
  });
952
1065
  log6("starting...", void 0, {
953
1066
  F: __dxlog_file7,
954
- L: 275,
1067
+ L: 285,
955
1068
  S: this,
956
1069
  C: (f, a) => f(...a)
957
1070
  });
@@ -960,7 +1073,7 @@ var Pipeline = class {
960
1073
  this._isStarted = true;
961
1074
  log6("started", void 0, {
962
1075
  F: __dxlog_file7,
963
- L: 279,
1076
+ L: 289,
964
1077
  S: this,
965
1078
  C: (f, a) => f(...a)
966
1079
  });
@@ -973,7 +1086,7 @@ var Pipeline = class {
973
1086
  async stop() {
974
1087
  log6("stopping...", void 0, {
975
1088
  F: __dxlog_file7,
976
- L: 290,
1089
+ L: 300,
977
1090
  S: this,
978
1091
  C: (f, a) => f(...a)
979
1092
  });
@@ -987,10 +1100,11 @@ var Pipeline = class {
987
1100
  await this._state._ctx.dispose();
988
1101
  this._state._ctx = new Context2();
989
1102
  this._state._reachedTargetPromise = void 0;
1103
+ this._state._reachedTarget = false;
990
1104
  this._isStarted = false;
991
1105
  log6("stopped", void 0, {
992
1106
  F: __dxlog_file7,
993
- L: 302,
1107
+ L: 313,
994
1108
  S: this,
995
1109
  C: (f, a) => f(...a)
996
1110
  });
@@ -1002,7 +1116,7 @@ var Pipeline = class {
1002
1116
  async setCursor(timeframe) {
1003
1117
  invariant6(!this._isStarted || this._isPaused, "Invalid state.", {
1004
1118
  F: __dxlog_file7,
1005
- L: 311,
1119
+ L: 322,
1006
1120
  S: this,
1007
1121
  A: [
1008
1122
  "!this._isStarted || this._isPaused",
@@ -1031,7 +1145,7 @@ var Pipeline = class {
1031
1145
  async unpause() {
1032
1146
  invariant6(this._isPaused, "Pipeline is not paused.", {
1033
1147
  F: __dxlog_file7,
1034
- L: 340,
1148
+ L: 351,
1035
1149
  S: this,
1036
1150
  A: [
1037
1151
  "this._isPaused",
@@ -1051,7 +1165,7 @@ var Pipeline = class {
1051
1165
  async *consume() {
1052
1166
  invariant6(!this._isBeingConsumed, "Pipeline is already being consumed.", {
1053
1167
  F: __dxlog_file7,
1054
- L: 355,
1168
+ L: 366,
1055
1169
  S: this,
1056
1170
  A: [
1057
1171
  "!this._isBeingConsumed",
@@ -1061,7 +1175,7 @@ var Pipeline = class {
1061
1175
  this._isBeingConsumed = true;
1062
1176
  invariant6(this._feedSetIterator, "Iterator not initialized.", {
1063
1177
  F: __dxlog_file7,
1064
- L: 358,
1178
+ L: 369,
1065
1179
  S: this,
1066
1180
  A: [
1067
1181
  "this._feedSetIterator",
@@ -1075,7 +1189,7 @@ var Pipeline = class {
1075
1189
  if (lastFeedSetIterator !== this._feedSetIterator) {
1076
1190
  invariant6(this._feedSetIterator, "Iterator not initialized.", {
1077
1191
  F: __dxlog_file7,
1078
- L: 367,
1192
+ L: 378,
1079
1193
  S: this,
1080
1194
  A: [
1081
1195
  "this._feedSetIterator",
@@ -1089,7 +1203,7 @@ var Pipeline = class {
1089
1203
  if (!done) {
1090
1204
  const block = value ?? failUndefined();
1091
1205
  this._processingTrigger.reset();
1092
- this._timeframeClock.updatePendingTimeframe(PublicKey3.from(block.feedKey), block.seq);
1206
+ this._timeframeClock.updatePendingTimeframe(PublicKey4.from(block.feedKey), block.seq);
1093
1207
  yield block;
1094
1208
  this._processingTrigger.wake();
1095
1209
  this._timeframeClock.updateTimeframe();
@@ -1110,7 +1224,7 @@ var Pipeline = class {
1110
1224
  length: feed.length
1111
1225
  }, {
1112
1226
  F: __dxlog_file7,
1113
- L: 396,
1227
+ L: 407,
1114
1228
  S: this,
1115
1229
  C: (f, a) => f(...a)
1116
1230
  });
@@ -1124,7 +1238,7 @@ var Pipeline = class {
1124
1238
  data
1125
1239
  }, {
1126
1240
  F: __dxlog_file7,
1127
- L: 401,
1241
+ L: 412,
1128
1242
  S: this,
1129
1243
  C: (f, a) => f(...a)
1130
1244
  });
@@ -1140,7 +1254,7 @@ var Pipeline = class {
1140
1254
  this._feedSetIterator.stalled.on((iterator) => {
1141
1255
  log6.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, void 0, {
1142
1256
  F: __dxlog_file7,
1143
- L: 415,
1257
+ L: 426,
1144
1258
  S: this,
1145
1259
  C: (f, a) => f(...a)
1146
1260
  });
@@ -1268,10 +1382,14 @@ var AuthExtension = class extends RpcExtension {
1268
1382
  await this._ctx.dispose();
1269
1383
  await super.onClose();
1270
1384
  }
1385
+ async onAbort() {
1386
+ await this._ctx.dispose();
1387
+ await super.onAbort();
1388
+ }
1271
1389
  };
1272
1390
 
1273
1391
  // packages/core/echo/echo-pipeline/src/space/data-pipeline.ts
1274
- import { Event as Event4, scheduleTask as scheduleTask2, synchronized as synchronized3, trackLeaks as trackLeaks2 } from "@dxos/async";
1392
+ import { Event as Event4, scheduleTask as scheduleTask2, sleep as sleep2, synchronized as synchronized3, trackLeaks as trackLeaks2 } from "@dxos/async";
1275
1393
  import { Context as Context4 } from "@dxos/context";
1276
1394
  import { checkCredentialType } from "@dxos/credentials";
1277
1395
  import { getStateMachineFromItem, ItemManager, TYPE_PROPERTIES } from "@dxos/echo-db";
@@ -1294,7 +1412,7 @@ function _ts_decorate5(decorators, target, key, desc) {
1294
1412
  var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/data-pipeline.ts";
1295
1413
  var MESSAGES_PER_SNAPSHOT = 10;
1296
1414
  var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1297
- var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
1415
+ var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 5e3;
1298
1416
  var DataPipeline = class DataPipeline2 {
1299
1417
  constructor(_params) {
1300
1418
  this._params = _params;
@@ -1370,7 +1488,7 @@ var DataPipeline = class DataPipeline2 {
1370
1488
  }, options);
1371
1489
  }
1372
1490
  };
1373
- this.databaseHost = new DatabaseHost(feedWriter);
1491
+ this.databaseHost = new DatabaseHost(feedWriter, () => this._flush());
1374
1492
  this.itemManager = new ItemManager(this._params.modelFactory);
1375
1493
  await this.databaseHost.open(this.itemManager, this._params.modelFactory);
1376
1494
  scheduleTask2(this._ctx, async () => {
@@ -1421,9 +1539,10 @@ var DataPipeline = class DataPipeline2 {
1421
1539
  await this._processEpochInSeparateTask(this.currentEpoch);
1422
1540
  await waitForOneEpoch;
1423
1541
  }
1542
+ let messageCounter = 0;
1424
1543
  invariant8(this._pipeline, "Pipeline is not initialized.", {
1425
1544
  F: __dxlog_file9,
1426
- L: 215,
1545
+ L: 217,
1427
1546
  S: this,
1428
1547
  A: [
1429
1548
  "this._pipeline",
@@ -1439,7 +1558,7 @@ var DataPipeline = class DataPipeline2 {
1439
1558
  seq
1440
1559
  }, {
1441
1560
  F: __dxlog_file9,
1442
- L: 221,
1561
+ L: 223,
1443
1562
  S: this,
1444
1563
  C: (f, a) => f(...a)
1445
1564
  });
@@ -1451,7 +1570,7 @@ var DataPipeline = class DataPipeline2 {
1451
1570
  feedKey
1452
1571
  }, {
1453
1572
  F: __dxlog_file9,
1454
- L: 227,
1573
+ L: 229,
1455
1574
  S: this,
1456
1575
  C: (f, a) => f(...a)
1457
1576
  });
@@ -1474,7 +1593,7 @@ var DataPipeline = class DataPipeline2 {
1474
1593
  spaceKey: this._params.spaceKey.toHex()
1475
1594
  }, {
1476
1595
  F: __dxlog_file9,
1477
- L: 244,
1596
+ L: 246,
1478
1597
  S: this,
1479
1598
  C: (f, a) => f(...a)
1480
1599
  });
@@ -1483,18 +1602,22 @@ var DataPipeline = class DataPipeline2 {
1483
1602
  } catch (err) {
1484
1603
  log8.catch(err, void 0, {
1485
1604
  F: __dxlog_file9,
1486
- L: 254,
1605
+ L: 256,
1487
1606
  S: this,
1488
1607
  C: (f, a) => f(...a)
1489
1608
  });
1490
1609
  }
1491
1610
  span.end();
1611
+ if (++messageCounter > 1e3) {
1612
+ messageCounter = 0;
1613
+ await sleep2(1);
1614
+ }
1492
1615
  }
1493
1616
  }
1494
1617
  _createSnapshot() {
1495
1618
  invariant8(this.databaseHost, "Database backend is not initialized.", {
1496
1619
  F: __dxlog_file9,
1497
- L: 262,
1620
+ L: 270,
1498
1621
  S: this,
1499
1622
  A: [
1500
1623
  "this.databaseHost",
@@ -1523,7 +1646,7 @@ var DataPipeline = class DataPipeline2 {
1523
1646
  } catch (err) {
1524
1647
  log8.warn("Failed to cache properties", err, {
1525
1648
  F: __dxlog_file9,
1526
- L: 291,
1649
+ L: 299,
1527
1650
  S: this,
1528
1651
  C: (f, a) => f(...a)
1529
1652
  });
@@ -1531,6 +1654,9 @@ var DataPipeline = class DataPipeline2 {
1531
1654
  await this._params.metadataStore.setCache(this._params.spaceKey, cache);
1532
1655
  }
1533
1656
  async _noteTargetStateIfNeeded(timeframe) {
1657
+ if (!this._pipeline?.state.reachedTarget) {
1658
+ return;
1659
+ }
1534
1660
  if (Date.now() - this._lastTimeframeSaveTime > TIMEFRAME_SAVE_DEBOUNCE_INTERVAL) {
1535
1661
  this._lastTimeframeSaveTime = Date.now();
1536
1662
  await this._saveTargetTimeframe(timeframe);
@@ -1549,14 +1675,14 @@ var DataPipeline = class DataPipeline2 {
1549
1675
  if (err instanceof CancelledError) {
1550
1676
  log8("Epoch processing cancelled.", void 0, {
1551
1677
  F: __dxlog_file9,
1552
- L: 323,
1678
+ L: 335,
1553
1679
  S: this,
1554
1680
  C: (f, a) => f(...a)
1555
1681
  });
1556
1682
  } else {
1557
1683
  log8.catch(err, void 0, {
1558
1684
  F: __dxlog_file9,
1559
- L: 325,
1685
+ L: 337,
1560
1686
  S: this,
1561
1687
  C: (f, a) => f(...a)
1562
1688
  });
@@ -1576,7 +1702,7 @@ var DataPipeline = class DataPipeline2 {
1576
1702
  async _processEpoch(ctx, epoch) {
1577
1703
  invariant8(this._isOpen, "Space is closed.", {
1578
1704
  F: __dxlog_file9,
1579
- L: 344,
1705
+ L: 356,
1580
1706
  S: this,
1581
1707
  A: [
1582
1708
  "this._isOpen",
@@ -1585,7 +1711,7 @@ var DataPipeline = class DataPipeline2 {
1585
1711
  });
1586
1712
  invariant8(this._pipeline, void 0, {
1587
1713
  F: __dxlog_file9,
1588
- L: 345,
1714
+ L: 357,
1589
1715
  S: this,
1590
1716
  A: [
1591
1717
  "this._pipeline",
@@ -1597,7 +1723,7 @@ var DataPipeline = class DataPipeline2 {
1597
1723
  epoch: omit(epoch, "proof")
1598
1724
  }, {
1599
1725
  F: __dxlog_file9,
1600
- L: 348,
1726
+ L: 360,
1601
1727
  S: this,
1602
1728
  C: (f, a) => f(...a)
1603
1729
  });
@@ -1607,7 +1733,7 @@ var DataPipeline = class DataPipeline2 {
1607
1733
  }
1608
1734
  log8("restarting pipeline from epoch", void 0, {
1609
1735
  F: __dxlog_file9,
1610
- L: 354,
1736
+ L: 366,
1611
1737
  S: this,
1612
1738
  C: (f, a) => f(...a)
1613
1739
  });
@@ -1618,7 +1744,7 @@ var DataPipeline = class DataPipeline2 {
1618
1744
  async waitUntilTimeframe(timeframe) {
1619
1745
  invariant8(this._pipeline, "Pipeline is not initialized.", {
1620
1746
  F: __dxlog_file9,
1621
- L: 361,
1747
+ L: 373,
1622
1748
  S: this,
1623
1749
  A: [
1624
1750
  "this._pipeline",
@@ -1630,7 +1756,7 @@ var DataPipeline = class DataPipeline2 {
1630
1756
  async createEpoch() {
1631
1757
  invariant8(this._pipeline, void 0, {
1632
1758
  F: __dxlog_file9,
1633
- L: 367,
1759
+ L: 379,
1634
1760
  S: this,
1635
1761
  A: [
1636
1762
  "this._pipeline",
@@ -1639,7 +1765,7 @@ var DataPipeline = class DataPipeline2 {
1639
1765
  });
1640
1766
  invariant8(this.currentEpoch, void 0, {
1641
1767
  F: __dxlog_file9,
1642
- L: 368,
1768
+ L: 380,
1643
1769
  S: this,
1644
1770
  A: [
1645
1771
  "this.currentEpoch",
@@ -1661,6 +1787,22 @@ var DataPipeline = class DataPipeline2 {
1661
1787
  async ensureEpochInitialized() {
1662
1788
  await this.onNewEpoch.waitForCondition(() => !!this.currentEpoch);
1663
1789
  }
1790
+ async _flush() {
1791
+ try {
1792
+ await this._saveCache();
1793
+ if (this._pipeline) {
1794
+ await this._saveTargetTimeframe(this._pipeline.state.timeframe);
1795
+ }
1796
+ } catch (err) {
1797
+ log8.catch(err, void 0, {
1798
+ F: __dxlog_file9,
1799
+ L: 410,
1800
+ S: this,
1801
+ C: (f, a) => f(...a)
1802
+ });
1803
+ }
1804
+ await this._params.metadataStore.flush();
1805
+ }
1664
1806
  };
1665
1807
  _ts_decorate5([
1666
1808
  trace.metricsCounter()
@@ -1694,9 +1836,10 @@ import { trace as trace3 } from "@dxos/tracing";
1694
1836
  import { Callback as Callback2 } from "@dxos/util";
1695
1837
 
1696
1838
  // packages/core/echo/echo-pipeline/src/space/control-pipeline.ts
1839
+ import { DeferredTask, sleep as sleep3 } from "@dxos/async";
1697
1840
  import { Context as Context5 } from "@dxos/context";
1698
1841
  import { SpaceStateMachine } from "@dxos/credentials";
1699
- import { PublicKey as PublicKey4 } from "@dxos/keys";
1842
+ import { PublicKey as PublicKey5 } from "@dxos/keys";
1700
1843
  import { log as log9 } from "@dxos/log";
1701
1844
  import { AdmittedFeed } from "@dxos/protocols/proto/dxos/halo/credentials";
1702
1845
  import { Timeframe as Timeframe4 } from "@dxos/timeframe";
@@ -1714,12 +1857,19 @@ function _ts_decorate6(decorators, target, key, desc) {
1714
1857
  }
1715
1858
  var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/control-pipeline.ts";
1716
1859
  var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL2 = 500;
1860
+ var CONTROL_PIPELINE_SNAPSHOT_DELAY = 1e4;
1861
+ var USE_SNAPSHOTS = true;
1717
1862
  var ControlPipeline = class ControlPipeline2 {
1718
1863
  constructor({ spaceKey, genesisFeed, feedProvider, metadataStore }) {
1864
+ this._ctx = new Context5();
1719
1865
  this._lastTimeframeSaveTime = Date.now();
1720
1866
  this.onFeedAdmitted = new Callback();
1721
1867
  this._usage = new TimeUsageCounter2();
1722
1868
  this._mutations = new TimeSeriesCounter2();
1869
+ this._snapshotTask = new DeferredTask(this._ctx, async () => {
1870
+ await sleep3(CONTROL_PIPELINE_SNAPSHOT_DELAY);
1871
+ await this._saveSnapshot();
1872
+ });
1723
1873
  this._spaceKey = spaceKey;
1724
1874
  this._metadata = metadataStore;
1725
1875
  this._pipeline = new Pipeline();
@@ -1730,22 +1880,24 @@ var ControlPipeline = class ControlPipeline2 {
1730
1880
  key: info.key
1731
1881
  }, {
1732
1882
  F: __dxlog_file10,
1733
- L: 61,
1883
+ L: 73,
1734
1884
  S: this,
1735
1885
  C: (f, a) => f(...a)
1736
1886
  });
1737
1887
  if (info.assertion.designation === AdmittedFeed.Designation.CONTROL && !info.key.equals(genesisFeed.key)) {
1738
- try {
1739
- const feed = await feedProvider(info.key);
1740
- await this._pipeline.addFeed(feed);
1741
- } catch (err) {
1742
- log9.catch(err, void 0, {
1743
- F: __dxlog_file10,
1744
- L: 69,
1745
- S: this,
1746
- C: (f, a) => f(...a)
1747
- });
1748
- }
1888
+ queueMicrotask(async () => {
1889
+ try {
1890
+ const feed = await feedProvider(info.key);
1891
+ await this._pipeline.addFeed(feed);
1892
+ } catch (err) {
1893
+ log9.catch(err, void 0, {
1894
+ F: __dxlog_file10,
1895
+ L: 82,
1896
+ S: this,
1897
+ C: (f, a) => f(...a)
1898
+ });
1899
+ }
1900
+ });
1749
1901
  }
1750
1902
  await this.onFeedAdmitted.callIfSet(info);
1751
1903
  });
@@ -1762,9 +1914,23 @@ var ControlPipeline = class ControlPipeline2 {
1762
1914
  this._pipeline.setWriteFeed(feed);
1763
1915
  }
1764
1916
  async start() {
1917
+ const snapshot = this._metadata.getSpaceControlPipelineSnapshot(this._spaceKey);
1918
+ log9("load snapshot", {
1919
+ key: this._spaceKey,
1920
+ present: !!snapshot,
1921
+ tf: snapshot?.timeframe
1922
+ }, {
1923
+ F: __dxlog_file10,
1924
+ L: 109,
1925
+ S: this,
1926
+ C: (f, a) => f(...a)
1927
+ });
1928
+ if (USE_SNAPSHOTS && snapshot) {
1929
+ await this._processSnapshot(snapshot);
1930
+ }
1765
1931
  log9("starting...", void 0, {
1766
1932
  F: __dxlog_file10,
1767
- L: 93,
1933
+ L: 114,
1768
1934
  S: this,
1769
1935
  C: (f, a) => f(...a)
1770
1936
  });
@@ -1774,10 +1940,50 @@ var ControlPipeline = class ControlPipeline2 {
1774
1940
  await this._pipeline.start();
1775
1941
  log9("started", void 0, {
1776
1942
  F: __dxlog_file10,
1777
- L: 99,
1943
+ L: 120,
1944
+ S: this,
1945
+ C: (f, a) => f(...a)
1946
+ });
1947
+ }
1948
+ async _processSnapshot(snapshot) {
1949
+ await this._pipeline.setCursor(snapshot.timeframe);
1950
+ for (const message of snapshot.messages ?? []) {
1951
+ const result = await this._spaceStateMachine.process(message.credential, {
1952
+ sourceFeed: message.feedKey,
1953
+ skipVerification: true
1954
+ });
1955
+ if (!result) {
1956
+ log9.warn("credential processing failed from snapshot", {
1957
+ message
1958
+ }, {
1959
+ F: __dxlog_file10,
1960
+ L: 133,
1961
+ S: this,
1962
+ C: (f, a) => f(...a)
1963
+ });
1964
+ }
1965
+ }
1966
+ }
1967
+ async _saveSnapshot() {
1968
+ await this._pipeline.pause();
1969
+ const snapshot = {
1970
+ timeframe: this._pipeline.state.timeframe,
1971
+ messages: this._spaceStateMachine.credentialEntries.map((entry) => ({
1972
+ feedKey: entry.sourceFeed,
1973
+ credential: entry.credential
1974
+ }))
1975
+ };
1976
+ await this._pipeline.unpause();
1977
+ log9("save snapshot", {
1978
+ key: this._spaceKey,
1979
+ snapshot
1980
+ }, {
1981
+ F: __dxlog_file10,
1982
+ L: 149,
1778
1983
  S: this,
1779
1984
  C: (f, a) => f(...a)
1780
1985
  });
1986
+ await this._metadata.setSpaceControlPipelineSnapshot(this._spaceKey, snapshot);
1781
1987
  }
1782
1988
  async _consumePipeline(ctx) {
1783
1989
  for await (const msg of this._pipeline.consume()) {
@@ -1788,7 +1994,7 @@ var ControlPipeline = class ControlPipeline2 {
1788
1994
  } catch (err) {
1789
1995
  log9.catch(err, void 0, {
1790
1996
  F: __dxlog_file10,
1791
- L: 111,
1997
+ L: 162,
1792
1998
  S: this,
1793
1999
  C: (f, a) => f(...a)
1794
2000
  });
@@ -1802,26 +2008,29 @@ var ControlPipeline = class ControlPipeline2 {
1802
2008
  seq: msg.seq
1803
2009
  }, {
1804
2010
  F: __dxlog_file10,
1805
- L: 121,
2011
+ L: 172,
1806
2012
  S: this,
1807
2013
  C: (f, a) => f(...a)
1808
2014
  });
1809
2015
  if (msg.data.payload.credential) {
1810
2016
  const timer = tracer2.mark("dxos.echo.pipeline.control");
1811
- const result = await this._spaceStateMachine.process(msg.data.payload.credential.credential, PublicKey4.from(msg.feedKey));
2017
+ const result = await this._spaceStateMachine.process(msg.data.payload.credential.credential, {
2018
+ sourceFeed: PublicKey5.from(msg.feedKey)
2019
+ });
1812
2020
  timer.end();
1813
2021
  if (!result) {
1814
2022
  log9.warn("processing failed", {
1815
2023
  msg
1816
2024
  }, {
1817
2025
  F: __dxlog_file10,
1818
- L: 131,
2026
+ L: 181,
1819
2027
  S: this,
1820
2028
  C: (f, a) => f(...a)
1821
2029
  });
1822
2030
  } else {
1823
2031
  await this._noteTargetStateIfNeeded(this._pipeline.state.pendingTimeframe);
1824
2032
  }
2033
+ this._snapshotTask.schedule();
1825
2034
  }
1826
2035
  }
1827
2036
  async _noteTargetStateIfNeeded(timeframe) {
@@ -1833,15 +2042,16 @@ var ControlPipeline = class ControlPipeline2 {
1833
2042
  async stop() {
1834
2043
  log9("stopping...", void 0, {
1835
2044
  F: __dxlog_file10,
1836
- L: 149,
2045
+ L: 201,
1837
2046
  S: this,
1838
2047
  C: (f, a) => f(...a)
1839
2048
  });
2049
+ await this._ctx.dispose();
1840
2050
  await this._pipeline.stop();
1841
2051
  await this._saveTargetTimeframe(this._pipeline.state.timeframe);
1842
2052
  log9("stopped", void 0, {
1843
2053
  F: __dxlog_file10,
1844
- L: 152,
2054
+ L: 205,
1845
2055
  S: this,
1846
2056
  C: (f, a) => f(...a)
1847
2057
  });
@@ -1854,7 +2064,7 @@ var ControlPipeline = class ControlPipeline2 {
1854
2064
  } catch (err) {
1855
2065
  log9(err, void 0, {
1856
2066
  F: __dxlog_file10,
1857
- L: 161,
2067
+ L: 214,
1858
2068
  S: this,
1859
2069
  C: (f, a) => f(...a)
1860
2070
  });
@@ -1867,6 +2077,11 @@ _ts_decorate6([
1867
2077
  _ts_decorate6([
1868
2078
  trace2.metricsCounter()
1869
2079
  ], ControlPipeline.prototype, "_mutations", void 0);
2080
+ _ts_decorate6([
2081
+ trace2.span({
2082
+ showInBrowserTimeline: true
2083
+ })
2084
+ ], ControlPipeline.prototype, "start", null);
1870
2085
  _ts_decorate6([
1871
2086
  trace2.span()
1872
2087
  ], ControlPipeline.prototype, "_consumePipeline", null);
@@ -1917,7 +2132,7 @@ var Space = class Space2 {
1917
2132
  this._controlPipeline.onFeedAdmitted.set(async (info) => {
1918
2133
  const sparse = info.assertion.designation === AdmittedFeed2.Designation.DATA;
1919
2134
  if (info.assertion.designation === AdmittedFeed2.Designation.DATA) {
1920
- await this._addFeedLock.executeSynchronized(async () => {
2135
+ queueMicrotask(async () => {
1921
2136
  if (this._dataPipeline.pipeline) {
1922
2137
  if (!this._dataPipeline.pipeline.hasFeed(info.key)) {
1923
2138
  return this._dataPipeline.pipeline.addFeed(await this._feedProvider(info.key, {
@@ -1928,9 +2143,11 @@ var Space = class Space2 {
1928
2143
  });
1929
2144
  }
1930
2145
  if (!info.key.equals(params.genesisFeed.key)) {
1931
- this.protocol.addFeed(await params.feedProvider(info.key, {
1932
- sparse
1933
- }));
2146
+ queueMicrotask(async () => {
2147
+ this.protocol.addFeed(await params.feedProvider(info.key, {
2148
+ sparse
2149
+ }));
2150
+ });
1934
2151
  }
1935
2152
  });
1936
2153
  this._controlPipeline.onCredentialProcessed.set(async (credential) => {
@@ -1939,7 +2156,7 @@ var Space = class Space2 {
1939
2156
  credential
1940
2157
  }, {
1941
2158
  F: __dxlog_file11,
1942
- L: 109,
2159
+ L: 111,
1943
2160
  S: this,
1944
2161
  C: (f, a) => f(...a)
1945
2162
  });
@@ -2004,7 +2221,7 @@ var Space = class Space2 {
2004
2221
  setControlFeed(feed) {
2005
2222
  invariant9(!this._controlFeed, "Control feed already set.", {
2006
2223
  F: __dxlog_file11,
2007
- L: 184,
2224
+ L: 186,
2008
2225
  S: this,
2009
2226
  A: [
2010
2227
  "!this._controlFeed",
@@ -2018,7 +2235,7 @@ var Space = class Space2 {
2018
2235
  setDataFeed(feed) {
2019
2236
  invariant9(!this._dataFeed, "Data feed already set.", {
2020
2237
  F: __dxlog_file11,
2021
- L: 191,
2238
+ L: 193,
2022
2239
  S: this,
2023
2240
  A: [
2024
2241
  "!this._dataFeed",
@@ -2044,7 +2261,7 @@ var Space = class Space2 {
2044
2261
  async open(ctx) {
2045
2262
  log10("opening...", void 0, {
2046
2263
  F: __dxlog_file11,
2047
- L: 213,
2264
+ L: 215,
2048
2265
  S: this,
2049
2266
  C: (f, a) => f(...a)
2050
2267
  });
@@ -2057,7 +2274,7 @@ var Space = class Space2 {
2057
2274
  this._isOpen = true;
2058
2275
  log10("opened", void 0, {
2059
2276
  F: __dxlog_file11,
2060
- L: 224,
2277
+ L: 226,
2061
2278
  S: this,
2062
2279
  C: (f, a) => f(...a)
2063
2280
  });
@@ -2067,7 +2284,7 @@ var Space = class Space2 {
2067
2284
  key: this._key
2068
2285
  }, {
2069
2286
  F: __dxlog_file11,
2070
- L: 229,
2287
+ L: 231,
2071
2288
  S: this,
2072
2289
  C: (f, a) => f(...a)
2073
2290
  });
@@ -2081,7 +2298,7 @@ var Space = class Space2 {
2081
2298
  this._isOpen = false;
2082
2299
  log10("closed", void 0, {
2083
2300
  F: __dxlog_file11,
2084
- L: 242,
2301
+ L: 244,
2085
2302
  S: this,
2086
2303
  C: (f, a) => f(...a)
2087
2304
  });
@@ -2089,13 +2306,13 @@ var Space = class Space2 {
2089
2306
  async initializeDataPipeline() {
2090
2307
  log10("initializeDataPipeline", void 0, {
2091
2308
  F: __dxlog_file11,
2092
- L: 247,
2309
+ L: 249,
2093
2310
  S: this,
2094
2311
  C: (f, a) => f(...a)
2095
2312
  });
2096
2313
  invariant9(this._isOpen, "Space must be open to initialize data pipeline.", {
2097
2314
  F: __dxlog_file11,
2098
- L: 248,
2315
+ L: 250,
2099
2316
  S: this,
2100
2317
  A: [
2101
2318
  "this._isOpen",
@@ -2126,13 +2343,13 @@ Space = _ts_decorate7([
2126
2343
 
2127
2344
  // packages/core/echo/echo-pipeline/src/space/space-protocol.ts
2128
2345
  import { discoveryKey, subtleCrypto as subtleCrypto2 } from "@dxos/crypto";
2129
- import { PublicKey as PublicKey5 } from "@dxos/keys";
2346
+ import { PublicKey as PublicKey6 } from "@dxos/keys";
2130
2347
  import { log as log11, logInfo as logInfo2 } from "@dxos/log";
2131
2348
  import { MMSTTopology } from "@dxos/network-manager";
2132
2349
  import { Teleport } from "@dxos/teleport";
2133
2350
  import { BlobSync } from "@dxos/teleport-extension-object-sync";
2134
2351
  import { ReplicatorExtension } from "@dxos/teleport-extension-replicator";
2135
- import { ComplexMap as ComplexMap4 } from "@dxos/util";
2352
+ import { ComplexMap as ComplexMap5 } from "@dxos/util";
2136
2353
  function _ts_decorate8(decorators, target, key, desc) {
2137
2354
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2138
2355
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -2149,7 +2366,7 @@ var MOCK_AUTH_VERIFIER = async (nonce, credential) => true;
2149
2366
  var SpaceProtocol = class {
2150
2367
  constructor({ topic, swarmIdentity, networkManager, onSessionAuth, onAuthFailure, blobStore }) {
2151
2368
  this._feeds = /* @__PURE__ */ new Set();
2152
- this._sessions = new ComplexMap4(PublicKey5.hash);
2369
+ this._sessions = new ComplexMap5(PublicKey6.hash);
2153
2370
  this._networkManager = networkManager;
2154
2371
  this._swarmIdentity = swarmIdentity;
2155
2372
  this._onSessionAuth = onSessionAuth;
@@ -2157,7 +2374,7 @@ var SpaceProtocol = class {
2157
2374
  this.blobSync = new BlobSync({
2158
2375
  blobStore
2159
2376
  });
2160
- this._topic = subtleCrypto2.digest("SHA-256", topic.asBuffer()).then(discoveryKey).then(PublicKey5.from);
2377
+ this._topic = subtleCrypto2.digest("SHA-256", topic.asBuffer()).then(discoveryKey).then(PublicKey6.from);
2161
2378
  }
2162
2379
  get sessions() {
2163
2380
  return this._sessions;
@@ -2287,7 +2504,7 @@ var SpaceProtocolSession = class {
2287
2504
  get stream() {
2288
2505
  return this._teleport.stream;
2289
2506
  }
2290
- async initialize() {
2507
+ async open() {
2291
2508
  await this._teleport.open();
2292
2509
  this._teleport.addExtension("dxos.mesh.teleport.auth", new AuthExtension({
2293
2510
  provider: this._swarmIdentity.credentialProvider,
@@ -2310,9 +2527,18 @@ var SpaceProtocolSession = class {
2310
2527
  this._teleport.addExtension("dxos.mesh.teleport.replicator", this.replicator);
2311
2528
  this._teleport.addExtension("dxos.mesh.teleport.blobsync", this._blobSync.createExtension());
2312
2529
  }
2313
- async destroy() {
2530
+ async close() {
2531
+ log11.info("close", void 0, {
2532
+ F: __dxlog_file12,
2533
+ L: 254,
2534
+ S: this,
2535
+ C: (f, a) => f(...a)
2536
+ });
2314
2537
  await this._teleport.close();
2315
2538
  }
2539
+ async abort() {
2540
+ await this._teleport.abort();
2541
+ }
2316
2542
  };
2317
2543
  _ts_decorate8([
2318
2544
  logInfo2
@@ -2324,10 +2550,10 @@ _ts_decorate8([
2324
2550
  // packages/core/echo/echo-pipeline/src/space/space-manager.ts
2325
2551
  import { synchronized as synchronized5, trackLeaks as trackLeaks4 } from "@dxos/async";
2326
2552
  import { failUndefined as failUndefined2 } from "@dxos/debug";
2327
- import { PublicKey as PublicKey6 } from "@dxos/keys";
2553
+ import { PublicKey as PublicKey7 } from "@dxos/keys";
2328
2554
  import { log as log12 } from "@dxos/log";
2329
2555
  import { trace as trace4 } from "@dxos/protocols";
2330
- import { ComplexMap as ComplexMap5 } from "@dxos/util";
2556
+ import { ComplexMap as ComplexMap6 } from "@dxos/util";
2331
2557
  function _ts_decorate9(decorators, target, key, desc) {
2332
2558
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2333
2559
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -2341,8 +2567,8 @@ function _ts_decorate9(decorators, target, key, desc) {
2341
2567
  var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/space-manager.ts";
2342
2568
  var SpaceManager = class SpaceManager2 {
2343
2569
  constructor({ feedStore, networkManager, modelFactory, metadataStore, snapshotStore, blobStore }) {
2344
- this._spaces = new ComplexMap5(PublicKey6.hash);
2345
- this._instanceId = PublicKey6.random().toHex();
2570
+ this._spaces = new ComplexMap6(PublicKey7.hash);
2571
+ this._instanceId = PublicKey7.random().toHex();
2346
2572
  this._feedStore = feedStore;
2347
2573
  this._networkManager = networkManager;
2348
2574
  this._modelFactory = modelFactory;
@@ -2447,4 +2673,4 @@ export {
2447
2673
  SpaceProtocolSession,
2448
2674
  SpaceManager
2449
2675
  };
2450
- //# sourceMappingURL=chunk-GELWTWOW.mjs.map
2676
+ //# sourceMappingURL=chunk-VYZEP2BZ.mjs.map