@dxos/client-services 0.8.4-main.d05539e30a → 0.8.4-main.d9fc60f731

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 (43) hide show
  1. package/dist/lib/browser/{chunk-NGONP3EI.mjs → chunk-YJFGXOFW.mjs} +871 -527
  2. package/dist/lib/browser/chunk-YJFGXOFW.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +4 -1
  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 +1 -1
  7. package/dist/lib/node-esm/{chunk-OAECSUV2.mjs → chunk-DE3U3XQV.mjs} +871 -527
  8. package/dist/lib/node-esm/chunk-DE3U3XQV.mjs.map +7 -0
  9. package/dist/lib/node-esm/index.mjs +4 -1
  10. package/dist/lib/node-esm/index.mjs.map +1 -1
  11. package/dist/lib/node-esm/meta.json +1 -1
  12. package/dist/lib/node-esm/testing/index.mjs +1 -1
  13. package/dist/types/src/packlets/services/feed-syncer.d.ts +19 -3
  14. package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -1
  15. package/dist/types/src/packlets/services/index.d.ts +1 -0
  16. package/dist/types/src/packlets/services/index.d.ts.map +1 -1
  17. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  18. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +3 -3
  19. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -1
  20. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +3 -3
  21. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -1
  22. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +16 -0
  23. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  24. package/dist/types/src/packlets/spaces/data-space.d.ts +8 -0
  25. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  26. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  27. package/dist/types/src/version.d.ts +1 -1
  28. package/dist/types/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +44 -45
  30. package/src/packlets/services/feed-syncer.test.ts +45 -9
  31. package/src/packlets/services/feed-syncer.ts +219 -60
  32. package/src/packlets/services/index.ts +1 -0
  33. package/src/packlets/services/service-context.ts +35 -0
  34. package/src/packlets/space-export/serialized-space-reader.ts +28 -10
  35. package/src/packlets/space-export/serialized-space-writer.ts +25 -17
  36. package/src/packlets/space-export/space-archive.test.ts +41 -20
  37. package/src/packlets/spaces/data-space-manager.test.ts +89 -0
  38. package/src/packlets/spaces/data-space-manager.ts +77 -0
  39. package/src/packlets/spaces/data-space.ts +18 -0
  40. package/src/packlets/spaces/spaces-service.ts +6 -1
  41. package/src/version.ts +1 -1
  42. package/dist/lib/browser/chunk-NGONP3EI.mjs.map +0 -7
  43. package/dist/lib/node-esm/chunk-OAECSUV2.mjs.map +0 -7
@@ -395,7 +395,7 @@ import { SpaceMember } from "@dxos/protocols/proto/dxos/client/services";
395
395
  import { TRACE_PROCESSOR } from "@dxos/tracing";
396
396
 
397
397
  // src/version.ts
398
- var DXOS_VERSION = "0.8.4-main.d05539e30a";
398
+ var DXOS_VERSION = "0.8.4-main.d9fc60f731";
399
399
 
400
400
  // src/packlets/services/platform.ts
401
401
  import { Platform } from "@dxos/protocols/proto/dxos/client/services";
@@ -741,7 +741,7 @@ function _ts_dispose_resources(env) {
741
741
  var e = new Error(message);
742
742
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
743
743
  };
744
- return (_ts_dispose_resources = function _ts_dispose_resources5(env2) {
744
+ return (_ts_dispose_resources = function _ts_dispose_resources6(env2) {
745
745
  function fail(e) {
746
746
  env2.error = env2.hasError ? new _SuppressedError(e, env2.error, "An error was suppressed during disposal.") : e;
747
747
  env2.hasError = true;
@@ -1275,9 +1275,15 @@ var DataSpaceManager = class extends Resource2 {
1275
1275
  const spacesToActivate = [];
1276
1276
  await forEachAsync(this._metadataStore.spaces, async (spaceMetadata) => {
1277
1277
  try {
1278
+ if (spaceMetadata.state === SpaceState.SPACE_DELETED || this.isSpaceDeleted(spaceMetadata.key)) {
1279
+ log4("skipping deleted space", {
1280
+ spaceKey: spaceMetadata.key
1281
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 107, S: this });
1282
+ return;
1283
+ }
1278
1284
  log4("load space", {
1279
1285
  spaceMetadata
1280
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 105, S: this });
1286
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 112, S: this });
1281
1287
  const space = await this._constructSpace(ctx, spaceMetadata);
1282
1288
  if (this._runtimeProps?.autoActivateSpaces && spaceMetadata.state === SpaceState.SPACE_ACTIVE) {
1283
1289
  spacesToActivate.push(space);
@@ -1286,24 +1292,24 @@ var DataSpaceManager = class extends Resource2 {
1286
1292
  log4.error("Error loading space", {
1287
1293
  spaceMetadata,
1288
1294
  err
1289
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 114, S: this });
1295
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 121, S: this });
1290
1296
  }
1291
1297
  });
1292
1298
  for (const space of spacesToActivate) {
1293
1299
  log4("auto-activating space", {
1294
1300
  spaceKey: space.key
1295
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 122, S: this });
1301
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 129, S: this });
1296
1302
  space.activate(ctx).catch((err) => {
1297
1303
  log4.error("Error auto-activating space", {
1298
1304
  spaceKey: space.key,
1299
1305
  err
1300
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 126, S: this });
1306
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 133, S: this });
1301
1307
  });
1302
1308
  }
1303
1309
  this.updated.emit();
1304
1310
  }
1305
1311
  async _close(ctx) {
1306
- log4("close", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 135, S: this });
1312
+ log4("close", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 142, S: this });
1307
1313
  for (const space of this._spaces.values()) {
1308
1314
  await space.close(ctx);
1309
1315
  }
@@ -1331,14 +1337,14 @@ var DataSpaceManager = class extends Resource2 {
1331
1337
  log4("creating space...", {
1332
1338
  spaceId,
1333
1339
  spaceKey
1334
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 159, S: this });
1340
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 166, S: this });
1335
1341
  const documentIdMapping = {};
1336
1342
  if (options.documents) {
1337
- invariant3(Object.keys(options.documents).every((documentId) => /^[a-zA-Z0-9]+$/.test(documentId)), "Invalid document IDs", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 166, S: this, A: ["Object.keys(options.documents).every((documentId)=>/^[a-zA-Z0-9]+$/.test(documentId))", "'Invalid document IDs'"] });
1343
+ invariant3(Object.keys(options.documents).every((documentId) => /^[a-zA-Z0-9]+$/.test(documentId)), "Invalid document IDs", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 173, S: this, A: ["Object.keys(options.documents).every((documentId)=>/^[a-zA-Z0-9]+$/.test(documentId))", "'Invalid document IDs'"] });
1338
1344
  await Promise.all(Object.entries(options.documents).map(async ([documentId, data]) => {
1339
1345
  log4("creating document...", {
1340
1346
  documentId
1341
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 168, S: this });
1347
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 175, S: this });
1342
1348
  const newDoc = await this._echoHost.createDoc(data, {
1343
1349
  preserveHistory: true
1344
1350
  });
@@ -1352,12 +1358,12 @@ var DataSpaceManager = class extends Resource2 {
1352
1358
  }
1353
1359
  log4("opening space...", {
1354
1360
  spaceKey
1355
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 184, S: this });
1361
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 191, S: this });
1356
1362
  let root;
1357
1363
  if (options.rootUrl) {
1358
1364
  const newRootDocId = documentIdMapping[interpretAsDocumentId(options.rootUrl)] ?? failedInvariant();
1359
1365
  const rootDocHandle = await this._echoHost.loadDoc(ctx, newRootDocId);
1360
- invariant3(rootDocHandle, "Root document must be available after import.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 191, S: this, A: ["rootDocHandle", "'Root document must be available after import.'"] });
1366
+ invariant3(rootDocHandle, "Root document must be available after import.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 198, S: this, A: ["rootDocHandle", "'Root document must be available after import.'"] });
1361
1367
  DatabaseRoot.mapLinks(rootDocHandle, documentIdMapping);
1362
1368
  root = await this._echoHost.openSpaceRoot(ctx, spaceId, `automerge:${newRootDocId}`);
1363
1369
  } else {
@@ -1366,22 +1372,22 @@ var DataSpaceManager = class extends Resource2 {
1366
1372
  await this._echoHost.flush(ctx);
1367
1373
  log4("constructing space...", {
1368
1374
  spaceKey
1369
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 198, S: this });
1375
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 205, S: this });
1370
1376
  const space = await this._constructSpace(ctx, metadata);
1371
1377
  await space.open(ctx);
1372
1378
  log4("adding space...", {
1373
1379
  spaceKey
1374
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 203, S: this });
1380
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 210, S: this });
1375
1381
  const credentials = await spaceGenesis(this._keyring, this._signingContext, space.inner, root.url, tags, options.membershipPolicy);
1376
1382
  await this._metadataStore.addSpace(metadata);
1377
1383
  const memberCredential = credentials[1];
1378
- invariant3(getCredentialAssertion(memberCredential)["@type"] === "dxos.halo.credentials.SpaceMember", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 209, S: this, A: ["getCredentialAssertion(memberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember'", ""] });
1384
+ invariant3(getCredentialAssertion(memberCredential)["@type"] === "dxos.halo.credentials.SpaceMember", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 216, S: this, A: ["getCredentialAssertion(memberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember'", ""] });
1379
1385
  await this._signingContext.recordCredential(memberCredential);
1380
1386
  await space.initializeDataPipeline(ctx);
1381
1387
  log4("space ready.", {
1382
1388
  spaceId,
1383
1389
  spaceKey
1384
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 212, S: this });
1390
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 219, S: this });
1385
1391
  this.updated.emit();
1386
1392
  return space;
1387
1393
  }
@@ -1394,9 +1400,10 @@ var DataSpaceManager = class extends Resource2 {
1394
1400
  async acceptSpace(ctx, opts) {
1395
1401
  log4("accept space", {
1396
1402
  opts
1397
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 225, S: this });
1398
- invariant3(this._lifecycleState === LifecycleState.OPEN, "Not open.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 228, S: this, A: ["this._lifecycleState === LifecycleState.OPEN", "'Not open.'"] });
1399
- invariant3(!this._spaces.has(opts.spaceKey), "Space already exists.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 229, S: this, A: ["!this._spaces.has(opts.spaceKey)", "'Space already exists.'"] });
1403
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 232, S: this });
1404
+ invariant3(this._lifecycleState === LifecycleState.OPEN, "Not open.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 235, S: this, A: ["this._lifecycleState === LifecycleState.OPEN", "'Not open.'"] });
1405
+ invariant3(!this._spaces.has(opts.spaceKey), "Space already exists.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 236, S: this, A: ["!this._spaces.has(opts.spaceKey)", "'Space already exists.'"] });
1406
+ invariant3(!this.isSpaceDeleted(opts.spaceKey), "Cannot accept a deleted space.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 237, S: this, A: ["!this.isSpaceDeleted(opts.spaceKey)", "'Cannot accept a deleted space.'"] });
1400
1407
  const tags = opts.tags ? Array.from(opts.tags) : [];
1401
1408
  const metadata = {
1402
1409
  key: opts.spaceKey,
@@ -1412,16 +1419,68 @@ var DataSpaceManager = class extends Resource2 {
1412
1419
  this.updated.emit();
1413
1420
  return space;
1414
1421
  }
1422
+ /**
1423
+ * Whether the space has been tombstoned (soft-deleted). Deleted spaces are never opened or replicated.
1424
+ */
1425
+ isSpaceDeleted(spaceKey) {
1426
+ return this._metadataStore.deletedSpaces.some((key) => key.equals(spaceKey)) || this._metadataStore.spaces.some((spaceMetadata) => spaceMetadata.key.equals(spaceKey) && spaceMetadata.state === SpaceState.SPACE_DELETED);
1427
+ }
1428
+ /**
1429
+ * Tombstones (soft-deletes) a space initiated locally on this device.
1430
+ * Records a SpaceDeleted credential in the HALO so the deletion replicates to the user's other devices,
1431
+ * then unloads the space locally. Data is not removed until garbage collection (future work).
1432
+ */
1433
+ async markSpaceDeleted(ctx, spaceKey) {
1434
+ if (this.isSpaceDeleted(spaceKey)) {
1435
+ return;
1436
+ }
1437
+ const credential = await this._signingContext.credentialSigner.createCredential({
1438
+ subject: spaceKey,
1439
+ assertion: {
1440
+ "@type": "dxos.halo.credentials.SpaceDeleted",
1441
+ spaceKey,
1442
+ deletedAt: /* @__PURE__ */ new Date()
1443
+ }
1444
+ });
1445
+ await this._signingContext.recordCredential(credential);
1446
+ await this._tombstoneSpace(ctx, spaceKey);
1447
+ }
1448
+ /**
1449
+ * Tombstones a space in response to a SpaceDeleted credential replicated from another device.
1450
+ * Does not write a credential (one already exists in the HALO).
1451
+ */
1452
+ async handleRemoteSpaceDeleted(ctx, spaceKey) {
1453
+ if (this.isSpaceDeleted(spaceKey)) {
1454
+ return;
1455
+ }
1456
+ await this._tombstoneSpace(ctx, spaceKey);
1457
+ }
1458
+ /**
1459
+ * Persists the tombstone and unloads the space if it is currently loaded.
1460
+ * Must be called while holding the DataSpaceManager lock (see callers).
1461
+ */
1462
+ async _tombstoneSpace(ctx, spaceKey) {
1463
+ await this._metadataStore.addDeletedSpace(spaceKey);
1464
+ const space = this._spaces.get(spaceKey);
1465
+ if (space) {
1466
+ if (space.isOpen) {
1467
+ await space.close(ctx);
1468
+ }
1469
+ await space.delete();
1470
+ this._spaces.delete(spaceKey);
1471
+ }
1472
+ this.updated.emit();
1473
+ }
1415
1474
  async admitMember(options) {
1416
1475
  const space = this._spaceManager.spaces.get(options.spaceKey);
1417
- invariant3(space, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 251, S: this, A: ["space", ""] });
1476
+ invariant3(space, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 310, S: this, A: ["space", ""] });
1418
1477
  if (space.spaceState.getMemberRole(options.identityKey) !== SpaceMember3.Role.REMOVED) {
1419
1478
  throw new AlreadyJoinedError();
1420
1479
  }
1421
1480
  const credentials = await createAdmissionCredentials(this._signingContext.credentialSigner, options.identityKey, space.key, space.genesisFeedKey, options.role, space.spaceState.membershipChainHeads, options.profile, options.delegationCredentialId, space.spaceState.tags);
1422
- invariant3(credentials[0].credential, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 258, S: this, A: ["credentials[0].credential", ""] });
1481
+ invariant3(credentials[0].credential, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 317, S: this, A: ["credentials[0].credential", ""] });
1423
1482
  const spaceMemberCredential = credentials[0].credential.credential;
1424
- invariant3(getCredentialAssertion(spaceMemberCredential)["@type"] === "dxos.halo.credentials.SpaceMember", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 260, S: this, A: ["getCredentialAssertion(spaceMemberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember'", ""] });
1483
+ invariant3(getCredentialAssertion(spaceMemberCredential)["@type"] === "dxos.halo.credentials.SpaceMember", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 319, S: this, A: ["getCredentialAssertion(spaceMemberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember'", ""] });
1425
1484
  await writeMessages(space.controlPipeline.writer, credentials);
1426
1485
  return spaceMemberCredential;
1427
1486
  }
@@ -1451,7 +1510,7 @@ var DataSpaceManager = class extends Resource2 {
1451
1510
  }
1452
1511
  async setSpaceEdgeReplicationSetting(ctx, spaceKey, setting) {
1453
1512
  const space = this._spaces.get(spaceKey);
1454
- invariant3(space, "Space not found.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 289, S: this, A: ["space", "'Space not found.'"] });
1513
+ invariant3(space, "Space not found.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 348, S: this, A: ["space", "'Space not found.'"] });
1455
1514
  await this._metadataStore.setSpaceEdgeReplicationSetting(spaceKey, setting);
1456
1515
  if (space.isOpen) {
1457
1516
  switch (setting) {
@@ -1468,7 +1527,7 @@ var DataSpaceManager = class extends Resource2 {
1468
1527
  async _constructSpace(ctx, metadata) {
1469
1528
  log4("construct space", {
1470
1529
  metadata
1471
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 304, S: this });
1530
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 363, S: this });
1472
1531
  const gossip = new Gossip({
1473
1532
  localPeerId: this._signingContext.deviceKey
1474
1533
  });
@@ -1507,12 +1566,12 @@ var DataSpaceManager = class extends Resource2 {
1507
1566
  } catch (err) {
1508
1567
  log4.warn("error on authorized connection", {
1509
1568
  err
1510
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 343, S: this });
1569
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 402, S: this });
1511
1570
  await session.close(err);
1512
1571
  }
1513
1572
  }),
1514
1573
  onAuthFailure: () => {
1515
- log4.warn("auth failure", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 350, S: this });
1574
+ log4.warn("auth failure", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 409, S: this });
1516
1575
  },
1517
1576
  onMemberRolesChanged: async (members) => {
1518
1577
  if (dataSpace?.state === SpaceState.SPACE_READY) {
@@ -1540,13 +1599,13 @@ var DataSpaceManager = class extends Resource2 {
1540
1599
  beforeReady: async () => {
1541
1600
  log4("before space ready", {
1542
1601
  space: space.key
1543
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 376, S: this });
1602
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 435, S: this });
1544
1603
  },
1545
1604
  afterReady: async () => {
1546
1605
  log4("after space ready", {
1547
1606
  space: space.key,
1548
1607
  open: this._lifecycleState === LifecycleState.OPEN
1549
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 381, S: this });
1608
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 440, S: this });
1550
1609
  if (this._lifecycleState === LifecycleState.OPEN) {
1551
1610
  await this._createDelegatedInvitations(dataSpace, [
1552
1611
  ...space.spaceState.invitations.entries()
@@ -1560,7 +1619,7 @@ var DataSpaceManager = class extends Resource2 {
1560
1619
  beforeClose: async () => {
1561
1620
  log4("before space close", {
1562
1621
  space: space.key
1563
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 396, S: this });
1622
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 455, S: this });
1564
1623
  }
1565
1624
  },
1566
1625
  cache: metadata.cache,
@@ -1577,7 +1636,7 @@ var DataSpaceManager = class extends Resource2 {
1577
1636
  } else if (this._echoEdgeReplicator) {
1578
1637
  log4("not connecting edge replicator because of EdgeReplicationSetting", {
1579
1638
  spaceId: dataSpace.id
1580
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 414, S: this });
1639
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 473, S: this });
1581
1640
  }
1582
1641
  });
1583
1642
  dataSpace.preClose.append(async () => {
@@ -1602,7 +1661,7 @@ var DataSpaceManager = class extends Resource2 {
1602
1661
  if (!replicator) {
1603
1662
  log4.warn("p2p automerge replication disabled", {
1604
1663
  space: space.key
1605
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 439, S: this });
1664
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 498, S: this });
1606
1665
  return;
1607
1666
  }
1608
1667
  await replicator.authorizeDevice(space.key, session.remotePeerId);
@@ -1630,7 +1689,7 @@ var DataSpaceManager = class extends Resource2 {
1630
1689
  roleChangeCount: memberInfo.length,
1631
1690
  peersOnline: presence.getPeersOnline().length,
1632
1691
  closedSessions
1633
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 466, S: this });
1692
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 525, S: this });
1634
1693
  spaceProtocol.updateTopology();
1635
1694
  }
1636
1695
  _handleNewPeerConnected(space, peerState) {
@@ -1640,7 +1699,7 @@ var DataSpaceManager = class extends Resource2 {
1640
1699
  if (session != null) {
1641
1700
  log4("closing a session with a removed peer", {
1642
1701
  peerId: peerState.peerId
1643
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 479, S: this });
1702
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 538, S: this });
1644
1703
  void session.close().catch(log4.error);
1645
1704
  }
1646
1705
  }
@@ -1705,6 +1764,12 @@ _ts_decorate2([
1705
1764
  op: "lifecycle"
1706
1765
  })
1707
1766
  ], DataSpaceManager.prototype, "acceptSpace", null);
1767
+ _ts_decorate2([
1768
+ synchronized
1769
+ ], DataSpaceManager.prototype, "markSpaceDeleted", null);
1770
+ _ts_decorate2([
1771
+ synchronized
1772
+ ], DataSpaceManager.prototype, "handleRemoteSpaceDeleted", null);
1708
1773
  DataSpaceManager = _ts_decorate2([
1709
1774
  trackLeaks("open", "close"),
1710
1775
  trace.resource({
@@ -1762,13 +1827,16 @@ var detectSpaceArchiveFormat = (archive) => {
1762
1827
  };
1763
1828
 
1764
1829
  // src/packlets/space-export/serialized-space-reader.ts
1830
+ import { Type as Type2 } from "@dxos/echo";
1765
1831
  import { assertArgument as assertArgument2 } from "@dxos/invariant";
1832
+ import { URI } from "@dxos/keys";
1766
1833
  var ATTR_TYPE = "@type";
1767
1834
  var ATTR_META = "@meta";
1768
1835
  var ATTR_DELETED = "@deleted";
1769
1836
  var ATTR_PARENT = "@parent";
1770
1837
  var ATTR_RELATION_SOURCE = "@relationSource";
1771
1838
  var ATTR_RELATION_TARGET = "@relationTarget";
1839
+ var TYPE_KIND_SCHEMA_URI = Type2.getURI(Type2.Type).toString();
1772
1840
  var INTERNAL_KEYS = /* @__PURE__ */ new Set([
1773
1841
  "id",
1774
1842
  ATTR_TYPE,
@@ -1798,13 +1866,13 @@ var objJsonToObjectStructure = (obj) => {
1798
1866
  const type = obj[ATTR_TYPE];
1799
1867
  if (type) {
1800
1868
  system.type = {
1801
- "/": type
1869
+ "/": URI.make(type)
1802
1870
  };
1803
1871
  }
1804
1872
  const parent = obj[ATTR_PARENT];
1805
1873
  if (typeof parent === "string") {
1806
1874
  system.parent = {
1807
- "/": parent
1875
+ "/": URI.make(parent)
1808
1876
  };
1809
1877
  }
1810
1878
  const relationSource = obj[ATTR_RELATION_SOURCE];
@@ -1813,14 +1881,16 @@ var objJsonToObjectStructure = (obj) => {
1813
1881
  system.kind = "relation";
1814
1882
  if (typeof relationSource === "string") {
1815
1883
  system.source = {
1816
- "/": relationSource
1884
+ "/": URI.make(relationSource)
1817
1885
  };
1818
1886
  }
1819
1887
  if (typeof relationTarget === "string") {
1820
1888
  system.target = {
1821
- "/": relationTarget
1889
+ "/": URI.make(relationTarget)
1822
1890
  };
1823
1891
  }
1892
+ } else if (type === TYPE_KIND_SCHEMA_URI) {
1893
+ system.kind = "type";
1824
1894
  } else {
1825
1895
  system.kind = "object";
1826
1896
  }
@@ -1834,6 +1904,15 @@ var objJsonToObjectStructure = (obj) => {
1834
1904
  keys: meta?.keys ?? [],
1835
1905
  ...meta?.tags ? {
1836
1906
  tags: meta.tags
1907
+ } : {},
1908
+ // Preserve registry-provenance fields so persisted `Type.Type` entities
1909
+ // round-trip with their typename / semver (see the symmetric write in
1910
+ // `objectStructureToObjJson`).
1911
+ ...meta?.key !== void 0 ? {
1912
+ key: meta.key
1913
+ } : {},
1914
+ ...meta?.version !== void 0 ? {
1915
+ version: meta.version
1837
1916
  } : {}
1838
1917
  },
1839
1918
  data
@@ -1958,6 +2037,16 @@ var objectStructureToObjJson = (objectId, structure) => {
1958
2037
  keys: structure.meta.keys ?? [],
1959
2038
  ...structure.meta.tags ? {
1960
2039
  tags: structure.meta.tags
2040
+ } : {},
2041
+ // Preserve the registry-provenance fields (typename / semver) so persisted
2042
+ // `Type.Type` entities round-trip with their `meta.key` / `meta.version`
2043
+ // intact — `Type.getTypename` / `Type.getVersion` read these. Without them
2044
+ // a type loaded from an archive would fall back to its object id.
2045
+ ...structure.meta.key !== void 0 ? {
2046
+ key: structure.meta.key
2047
+ } : {},
2048
+ ...structure.meta.version !== void 0 ? {
2049
+ version: structure.meta.version
1961
2050
  } : {}
1962
2051
  };
1963
2052
  }
@@ -1983,18 +2072,14 @@ var exportFeedData = async (space, echoHost, objects) => {
1983
2072
  if (obj[ATTR_TYPE2] == null) {
1984
2073
  continue;
1985
2074
  }
1986
- const typeDXN = DXN.tryParse(obj[ATTR_TYPE2]);
1987
- if (typeDXN?.asTypeDXN()?.type !== FEED_TYPENAME) {
2075
+ const typeDxn = obj[ATTR_TYPE2];
2076
+ const typeDxnNsid = DXN.isDXN(typeDxn) ? DXN.getName(typeDxn) : void 0;
2077
+ if (typeDxnNsid !== FEED_TYPENAME) {
1988
2078
  continue;
1989
2079
  }
1990
2080
  const namespace = obj.namespace === "trace" ? "trace" : "data";
1991
- const queueDXN = new DXN(DXN.kind.QUEUE, [
1992
- namespace,
1993
- spaceId,
1994
- obj.id
1995
- ]);
1996
2081
  try {
1997
- const messages = await collectQueueMessages(echoHost, queueDXN);
2082
+ const messages = await collectQueueMessages(echoHost, spaceId, obj.id, namespace);
1998
2083
  if (messages.length > 0) {
1999
2084
  feeds.push({
2000
2085
  feedObjectId: obj.id,
@@ -2006,25 +2091,23 @@ var exportFeedData = async (space, echoHost, objects) => {
2006
2091
  log5.warn("failed to export feed data", {
2007
2092
  feedObjectId: obj.id,
2008
2093
  error: err
2009
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 179, S: void 0 });
2094
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 185, S: void 0 });
2010
2095
  }
2011
2096
  }
2012
2097
  return feeds;
2013
2098
  };
2014
- var collectQueueMessages = async (echoHost, queueDXN) => {
2015
- const parts = queueDXN.asQueueDXN();
2016
- invariant4(parts, "Expected a queue DXN", { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 189, S: void 0, A: ["parts", "'Expected a queue DXN'"] });
2017
- const namespace = parts.subspaceTag === "trace" ? FeedProtocol.WellKnownNamespaces.trace : FeedProtocol.WellKnownNamespaces.data;
2099
+ var collectQueueMessages = async (echoHost, spaceId, queueId, namespace) => {
2100
+ const queuesNamespace = namespace === "trace" ? FeedProtocol.WellKnownNamespaces.trace : FeedProtocol.WellKnownNamespaces.data;
2018
2101
  const messages = [];
2019
2102
  let cursor;
2020
2103
  while (true) {
2021
2104
  const result = await echoHost.queuesService.queryQueue({
2022
2105
  query: {
2023
- spaceId: parts.spaceId,
2106
+ spaceId,
2024
2107
  queueIds: [
2025
- parts.queueId
2108
+ queueId
2026
2109
  ],
2027
- queuesNamespace: namespace,
2110
+ queuesNamespace,
2028
2111
  after: cursor
2029
2112
  }
2030
2113
  });
@@ -2037,7 +2120,7 @@ var collectQueueMessages = async (echoHost, queueDXN) => {
2037
2120
  log5.verbose("queue object JSON parse failed; object ignored", {
2038
2121
  encoded,
2039
2122
  error: err
2040
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 210, S: void 0 });
2123
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 214, S: void 0 });
2041
2124
  return [];
2042
2125
  }
2043
2126
  });
@@ -2249,7 +2332,7 @@ function _ts_dispose_resources2(env) {
2249
2332
  var e = new Error(message);
2250
2333
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
2251
2334
  };
2252
- return (_ts_dispose_resources2 = function _ts_dispose_resources5(env2) {
2335
+ return (_ts_dispose_resources2 = function _ts_dispose_resources6(env2) {
2253
2336
  function fail(e) {
2254
2337
  env2.error = env2.hasError ? new _SuppressedError(e, env2.error, "An error was suppressed during disposal.") : e;
2255
2338
  env2.hasError = true;
@@ -2310,6 +2393,9 @@ var SpacesServiceImpl = class {
2310
2393
  case SpaceState2.SPACE_INACTIVE:
2311
2394
  await space.deactivate(ctx);
2312
2395
  break;
2396
+ case SpaceState2.SPACE_DELETED:
2397
+ await dataSpaceManager.markSpaceDeleted(ctx, spaceKey);
2398
+ return;
2313
2399
  default:
2314
2400
  throw new ApiError({
2315
2401
  message: "Invalid space state"
@@ -2336,9 +2422,9 @@ var SpacesServiceImpl = class {
2336
2422
  });
2337
2423
  }
2338
2424
  const credentials = await createAdmissionCredentials2(identity.getIdentityCredentialSigner(), request.memberKey, space.key, space.genesisFeedKey, request.newRole, space.spaceState.membershipChainHeads);
2339
- invariant6(credentials[0].credential, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 142, S: this, A: ["credentials[0].credential", ""] });
2425
+ invariant6(credentials[0].credential, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 146, S: this, A: ["credentials[0].credential", ""] });
2340
2426
  const spaceMemberCredential = credentials[0].credential.credential;
2341
- invariant6(getCredentialAssertion2(spaceMemberCredential)["@type"] === "dxos.halo.credentials.SpaceMember", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 144, S: this, A: ["getCredentialAssertion(spaceMemberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember'", ""] });
2427
+ invariant6(getCredentialAssertion2(spaceMemberCredential)["@type"] === "dxos.halo.credentials.SpaceMember", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 148, S: this, A: ["getCredentialAssertion(spaceMemberCredential)['@type'] === 'dxos.halo.credentials.SpaceMember'", ""] });
2342
2428
  await writeMessages2(space.controlPipeline.writer, credentials);
2343
2429
  }
2344
2430
  querySpaces() {
@@ -2348,7 +2434,7 @@ var SpacesServiceImpl = class {
2348
2434
  const spaces = await Promise.all(Array.from(dataSpaceManager.spaces.values()).map((space) => this._serializeSpace(space)));
2349
2435
  log7("update", () => ({
2350
2436
  ids: spaces.map((space) => space.id)
2351
- }), { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 152, S: this });
2437
+ }), { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 156, S: this });
2352
2438
  await this._updateMetrics();
2353
2439
  next({
2354
2440
  spaces
@@ -2435,10 +2521,10 @@ var SpacesServiceImpl = class {
2435
2521
  }
2436
2522
  });
2437
2523
  } else {
2438
- invariant6(!credential.id, "Id on unsigned credentials is not allowed", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 244, S: this, A: ["!credential.id", "'Id on unsigned credentials is not allowed'"] });
2439
- invariant6(this._identityManager.identity, "Identity is not available", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 245, S: this, A: ["this._identityManager.identity", "'Identity is not available'"] });
2524
+ invariant6(!credential.id, "Id on unsigned credentials is not allowed", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 248, S: this, A: ["!credential.id", "'Id on unsigned credentials is not allowed'"] });
2525
+ invariant6(this._identityManager.identity, "Identity is not available", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 249, S: this, A: ["this._identityManager.identity", "'Identity is not available'"] });
2440
2526
  const signer = this._identityManager.identity.getIdentityCredentialSigner();
2441
- invariant6(credential.issuer.equals(signer.getIssuer()), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 247, S: this, A: ["credential.issuer.equals(signer.getIssuer())", ""] });
2527
+ invariant6(credential.issuer.equals(signer.getIssuer()), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 251, S: this, A: ["credential.issuer.equals(signer.getIssuer())", ""] });
2442
2528
  const signedCredential = await signer.createCredential({
2443
2529
  subject: credential.subject.id,
2444
2530
  assertion: credential.subject.assertion
@@ -2472,7 +2558,7 @@ var SpacesServiceImpl = class {
2472
2558
  });
2473
2559
  }
2474
2560
  async joinBySpaceKey({ spaceKey }, options) {
2475
- const ctx = options?.ctx ?? Context5.default(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 281 });
2561
+ const ctx = options?.ctx ?? Context5.default(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 285 });
2476
2562
  const dataSpaceManager = await this._getDataSpaceManager();
2477
2563
  const credential = await dataSpaceManager.requestSpaceAdmissionCredential(ctx, spaceKey);
2478
2564
  return this._joinByAdmission(ctx, {
@@ -2535,7 +2621,7 @@ var SpacesServiceImpl = class {
2535
2621
  }
2536
2622
  }
2537
2623
  async importSpace(request, options) {
2538
- const ctx = options?.ctx ?? Context5.default(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 344 });
2624
+ const ctx = options?.ctx ?? Context5.default(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 348 });
2539
2625
  const dataSpaceManager = await this._getDataSpaceManager();
2540
2626
  const format = request.archive.format ?? detectSpaceArchiveFormat(request.archive);
2541
2627
  if (format === SpaceArchive4.Format.JSON) {
@@ -2550,7 +2636,7 @@ var SpacesServiceImpl = class {
2550
2636
  };
2551
2637
  }
2552
2638
  const extracted = await extractSpaceArchive(request.archive);
2553
- invariant6(extracted.metadata.echo?.currentRootUrl, "Space archive does not contain a root URL", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 359, S: this, A: ["extracted.metadata.echo?.currentRootUrl", "'Space archive does not contain a root URL'"] });
2639
+ invariant6(extracted.metadata.echo?.currentRootUrl, "Space archive does not contain a root URL", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 363, S: this, A: ["extracted.metadata.echo?.currentRootUrl", "'Space archive does not contain a root URL'"] });
2554
2640
  const space = await dataSpaceManager.createSpace(ctx, {
2555
2641
  documents: extracted.documents,
2556
2642
  rootUrl: extracted.metadata.echo?.currentRootUrl,
@@ -2565,7 +2651,7 @@ var SpacesServiceImpl = class {
2565
2651
  * Populate a freshly-created space with the objects and feed messages described in a {@link SerializedSpace}.
2566
2652
  *
2567
2653
  * Objects are written directly into the space's automerge root document as inline
2568
- * {@link ObjectStructure} entries; feed messages are appended to the appropriate queue
2654
+ * {@link EntityStructure} entries; feed messages are appended to the appropriate queue
2569
2655
  * via {@link EchoHost.queuesService}.
2570
2656
  */
2571
2657
  async _hydrateSpaceFromSerialized(space, serialized) {
@@ -2595,15 +2681,15 @@ var SpacesServiceImpl = class {
2595
2681
  log7.warn("failed to import feed data", {
2596
2682
  feedObjectId: feed.feedObjectId,
2597
2683
  error: err
2598
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 400, S: this });
2684
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 404, S: this });
2599
2685
  }
2600
2686
  }
2601
2687
  }
2602
2688
  async _joinByAdmission(ctx, { credential }) {
2603
2689
  const assertion = getCredentialAssertion2(credential);
2604
- invariant6(assertion["@type"] === "dxos.halo.credentials.SpaceMember", "Invalid credential", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 409, S: this, A: ["assertion['@type'] === 'dxos.halo.credentials.SpaceMember'", "'Invalid credential'"] });
2690
+ invariant6(assertion["@type"] === "dxos.halo.credentials.SpaceMember", "Invalid credential", { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 413, S: this, A: ["assertion['@type'] === 'dxos.halo.credentials.SpaceMember'", "'Invalid credential'"] });
2605
2691
  const myIdentity = this._identityManager.identity;
2606
- invariant6(myIdentity && credential.subject.id.equals(myIdentity.identityKey), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 411, S: this, A: ["myIdentity && credential.subject.id.equals(myIdentity.identityKey)", ""] });
2692
+ invariant6(myIdentity && credential.subject.id.equals(myIdentity.identityKey), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 415, S: this, A: ["myIdentity && credential.subject.id.equals(myIdentity.identityKey)", ""] });
2607
2693
  const dataSpaceManager = await this._getDataSpaceManager();
2608
2694
  let dataSpace = dataSpaceManager.spaces.get(assertion.spaceKey);
2609
2695
  if (!dataSpace) {
@@ -3798,7 +3884,7 @@ function _ts_dispose_resources3(env) {
3798
3884
  var e = new Error(message);
3799
3885
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
3800
3886
  };
3801
- return (_ts_dispose_resources3 = function _ts_dispose_resources5(env2) {
3887
+ return (_ts_dispose_resources3 = function _ts_dispose_resources6(env2) {
3802
3888
  function fail(e) {
3803
3889
  env2.error = env2.hasError ? new _SuppressedError(e, env2.error, "An error was suppressed during disposal.") : e;
3804
3890
  env2.hasError = true;
@@ -4292,6 +4378,24 @@ var DataSpace = class {
4292
4378
  }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 563, S: this });
4293
4379
  this.stateUpdate.emit();
4294
4380
  }
4381
+ /**
4382
+ * Tombstones (soft-deletes) the space by moving it to a terminal state.
4383
+ * This is intentionally separate from teardown: the caller is responsible for {@link close}-ing the
4384
+ * space (teardown uses the resource lifecycle, distinct from this state transition).
4385
+ * Terminal: {@link activate} will not re-open a deleted space. Data is not removed until garbage
4386
+ * collection (future work).
4387
+ */
4388
+ async delete() {
4389
+ if (this._state === SpaceState3.SPACE_DELETED) {
4390
+ return;
4391
+ }
4392
+ await this._metadataStore.setSpaceState(this.key, SpaceState3.SPACE_DELETED);
4393
+ this._state = SpaceState3.SPACE_DELETED;
4394
+ log11("new state", {
4395
+ state: SpaceState3[this._state]
4396
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 580, S: this });
4397
+ this.stateUpdate.emit();
4398
+ }
4295
4399
  getEdgeReplicationSetting() {
4296
4400
  return this._metadataStore.getSpaceEdgeReplicationSetting(this.key);
4297
4401
  }
@@ -4353,6 +4457,9 @@ _ts_decorate6([
4353
4457
  _ts_decorate6([
4354
4458
  synchronized2
4355
4459
  ], DataSpace.prototype, "deactivate", null);
4460
+ _ts_decorate6([
4461
+ synchronized2
4462
+ ], DataSpace.prototype, "delete", null);
4356
4463
  DataSpace = _ts_decorate6([
4357
4464
  trackLeaks2("open", "close"),
4358
4465
  trace4.resource()
@@ -6163,143 +6270,596 @@ var locks_exports = {};
6163
6270
  __reExport(locks_exports, locks_platform_star);
6164
6271
  import * as locks_platform_star from "#locks-platform";
6165
6272
 
6166
- // src/packlets/agents/edge-agent-manager.ts
6167
- import { DeferredTask as DeferredTask2, Event as Event9, scheduleTask as scheduleTask8, synchronized as synchronized3 } from "@dxos/async";
6273
+ // src/packlets/services/feed-syncer.ts
6274
+ import { Encoder, decode as cborXdecode } from "cbor-x";
6275
+ import * as Effect from "effect/Effect";
6276
+ import * as Schema from "effect/Schema";
6277
+ import { AsyncTask, Mutex as Mutex4, scheduleTask as scheduleTask8 } from "@dxos/async";
6168
6278
  import { Resource as Resource7 } from "@dxos/context";
6279
+ import { MessageSchema } from "@dxos/edge-client";
6280
+ import { RuntimeProvider } from "@dxos/effect";
6281
+ import { SyncClient } from "@dxos/feed";
6169
6282
  import { invariant as invariant21 } from "@dxos/invariant";
6170
- import { PublicKey as PublicKey11 } from "@dxos/keys";
6283
+ import { SpaceId as SpaceId3 } from "@dxos/keys";
6171
6284
  import { log as log20 } from "@dxos/log";
6172
- import { EdgeAgentStatus, EdgeCallFailedError as EdgeCallFailedError3 } from "@dxos/protocols";
6173
- import { SpaceState as SpaceState4 } from "@dxos/protocols/proto/dxos/client/services";
6174
- import { EdgeReplicationSetting as EdgeReplicationSetting2 } from "@dxos/protocols/proto/dxos/echo/metadata";
6175
- var __dxlog_file25 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/agents/edge-agent-manager.ts";
6176
- function _ts_decorate10(decorators, target, key, desc) {
6177
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
6178
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
6179
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6180
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6181
- }
6182
- var AGENT_STATUS_QUERY_RETRY_INTERVAL = 5e3;
6183
- var AGENT_STATUS_QUERY_RETRY_JITTER = 1e3;
6184
- var AGENT_FEED_ADDED_CHECK_INTERVAL_MS = 3e3;
6185
- var EdgeAgentManager = class extends Resource7 {
6186
- _edgeFeatures;
6187
- _edgeHttpClient;
6188
- _dataSpaceManager;
6189
- _identity;
6190
- agentStatusChanged = new Event9();
6191
- _agentDeviceKey;
6192
- _agentStatus;
6193
- _lastKnownDeviceCount = 0;
6194
- _fetchAgentStatusTask;
6195
- constructor(_edgeFeatures, _edgeHttpClient, _dataSpaceManager, _identity) {
6196
- super(), this._edgeFeatures = _edgeFeatures, this._edgeHttpClient = _edgeHttpClient, this._dataSpaceManager = _dataSpaceManager, this._identity = _identity;
6197
- }
6198
- get agentStatus() {
6199
- return this._agentStatus;
6200
- }
6201
- get agentExists() {
6202
- return this._agentStatus && this._agentStatus !== EdgeAgentStatus.NOT_FOUND;
6203
- }
6204
- async createAgent(ctx) {
6205
- invariant21(this.isOpen, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 41, S: this, A: ["this.isOpen", ""] });
6206
- invariant21(this._edgeHttpClient, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 42, S: this, A: ["this._edgeHttpClient", ""] });
6207
- invariant21(this._edgeFeatures?.agents, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 43, S: this, A: ["this._edgeFeatures?.agents", ""] });
6208
- const response = await this._edgeHttpClient.createAgent(ctx, {
6209
- identityKey: this._identity.identityKey.toHex(),
6210
- haloSpaceId: this._identity.haloSpaceId,
6211
- haloSpaceKey: this._identity.haloSpaceKey.toHex()
6212
- });
6213
- const deviceKey = PublicKey11.fromHex(response.deviceKey);
6214
- if (await this._identity.authorizedDeviceKeys.has(deviceKey)) {
6215
- log20.info("agent was already added to HALO, ignoring response", {
6216
- response
6217
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 51, S: this });
6218
- this._updateStatus(EdgeAgentStatus.ACTIVE, deviceKey);
6219
- return;
6285
+ import { FeedProtocol as FeedProtocol3 } from "@dxos/protocols";
6286
+ import { EdgeService as EdgeService2 } from "@dxos/protocols";
6287
+ import { createBuf } from "@dxos/protocols/buf";
6288
+ import { bufferToArray as bufferToArray2 } from "@dxos/util";
6289
+ var __dxlog_file25 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/services/feed-syncer.ts";
6290
+ function _ts_add_disposable_resource4(env, value, async) {
6291
+ if (value !== null && value !== void 0) {
6292
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
6293
+ var dispose, inner;
6294
+ if (async) {
6295
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
6296
+ dispose = value[Symbol.asyncDispose];
6220
6297
  }
6221
- await this._identity.admitDevice({
6222
- deviceKey,
6223
- controlFeedKey: PublicKey11.fromHex(response.feedKey),
6224
- // TODO: agents don't have data feed, should be removed
6225
- dataFeedKey: PublicKey11.random()
6226
- });
6227
- log20("agent created", response, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 63, S: this });
6228
- this._updateStatus(EdgeAgentStatus.ACTIVE, deviceKey);
6229
- }
6230
- async _open() {
6231
- const isEnabled = this._edgeHttpClient && this._edgeFeatures?.agents;
6232
- log20("edge agent manager open", {
6233
- isEnabled
6234
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 68, S: this });
6235
- if (!isEnabled) {
6236
- return;
6298
+ if (dispose === void 0) {
6299
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
6300
+ dispose = value[Symbol.dispose];
6301
+ if (async) inner = dispose;
6237
6302
  }
6238
- this._lastKnownDeviceCount = this._identity.authorizedDeviceKeys.size;
6239
- this._fetchAgentStatusTask = new DeferredTask2(this._ctx, async () => {
6240
- await this._fetchAgentStatus(this._ctx);
6241
- });
6242
- this._fetchAgentStatusTask.schedule();
6243
- this._dataSpaceManager.updated.on(this._ctx, () => {
6244
- if (this._agentDeviceKey) {
6245
- this._ensureAgentIsInSpaces(this._agentDeviceKey);
6303
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
6304
+ if (inner) dispose = function() {
6305
+ try {
6306
+ inner.call(this);
6307
+ } catch (e) {
6308
+ return Promise.reject(e);
6246
6309
  }
6310
+ };
6311
+ env.stack.push({
6312
+ value,
6313
+ dispose,
6314
+ async
6247
6315
  });
6248
- this._identity.stateUpdate.on(this._ctx, () => {
6249
- const maybeAgentWasCreated = this._identity.authorizedDeviceKeys.size > this._lastKnownDeviceCount;
6250
- if (this.agentExists || !maybeAgentWasCreated) {
6251
- return;
6252
- }
6253
- this._lastKnownDeviceCount = this._identity.authorizedDeviceKeys.size;
6254
- this._fetchAgentStatusTask?.schedule();
6316
+ } else if (async) {
6317
+ env.stack.push({
6318
+ async: true
6255
6319
  });
6256
6320
  }
6257
- async _close() {
6258
- this._fetchAgentStatusTask = void 0;
6259
- this._lastKnownDeviceCount = 0;
6260
- }
6261
- async _fetchAgentStatus(ctx) {
6262
- invariant21(this._edgeHttpClient, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 98, S: this, A: ["this._edgeHttpClient", ""] });
6263
- try {
6264
- log20("fetching agent status", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 100, S: this });
6265
- const { agent } = await this._edgeHttpClient.getAgentStatus(ctx, {
6266
- ownerIdentityKey: this._identity.identityKey
6267
- });
6268
- const wasAgentCreatedDuringQuery = this._agentStatus === EdgeAgentStatus.ACTIVE;
6269
- if (!wasAgentCreatedDuringQuery) {
6270
- const deviceKey = agent.deviceKey ? PublicKey11.fromHex(agent.deviceKey) : void 0;
6271
- this._updateStatus(agent.status, deviceKey);
6272
- }
6273
- } catch (err) {
6274
- if (err instanceof EdgeCallFailedError3) {
6275
- if (!err.isRetryable) {
6276
- log20.warn("non retryable error on agent status fetch attempt", {
6277
- err
6278
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 112, S: this });
6279
- return;
6321
+ return value;
6322
+ }
6323
+ function _ts_dispose_resources4(env) {
6324
+ var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
6325
+ var e = new Error(message);
6326
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
6327
+ };
6328
+ return (_ts_dispose_resources4 = function _ts_dispose_resources6(env2) {
6329
+ function fail(e) {
6330
+ env2.error = env2.hasError ? new _SuppressedError(e, env2.error, "An error was suppressed during disposal.") : e;
6331
+ env2.hasError = true;
6332
+ }
6333
+ var r, s = 0;
6334
+ function next() {
6335
+ while (r = env2.stack.pop()) {
6336
+ try {
6337
+ if (!r.async && s === 1) return s = 0, env2.stack.push(r), Promise.resolve().then(next);
6338
+ if (r.dispose) {
6339
+ var result = r.dispose.call(r.value);
6340
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
6341
+ fail(e);
6342
+ return next();
6343
+ });
6344
+ } else s |= 1;
6345
+ } catch (e) {
6346
+ fail(e);
6280
6347
  }
6281
6348
  }
6282
- const retryAfterMs = AGENT_STATUS_QUERY_RETRY_INTERVAL + Math.random() * AGENT_STATUS_QUERY_RETRY_JITTER;
6283
- log20.info("agent status fetching failed", {
6284
- err,
6285
- retryAfterMs
6286
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 119, S: this });
6287
- scheduleTask8(this._ctx, () => this._fetchAgentStatusTask?.schedule(), retryAfterMs);
6349
+ if (s === 1) return env2.hasError ? Promise.reject(env2.error) : Promise.resolve();
6350
+ if (env2.hasError) throw env2.error;
6288
6351
  }
6352
+ return next();
6353
+ })(env);
6354
+ }
6355
+ var encoder = new Encoder({
6356
+ tagUint8Array: false,
6357
+ useRecords: false
6358
+ });
6359
+ var DEFAULT_MESSAGE_BLOCKS_LIMIT = 50;
6360
+ var DEFAULT_SYNC_CONCURRENCY = 5;
6361
+ var DEFAULT_POLLING_INTERVAL = 5e3;
6362
+ var DEFAULT_POLL_REQUEST_THROTTLE_MS = 250;
6363
+ var DEFAULT_PUSH_FAILURE_BACKOFF_MS = 250;
6364
+ var MAX_PUSH_FAILURE_BACKOFF_MS = 3e4;
6365
+ var MAX_BLOCKING_SYNC_ITERATIONS = 100;
6366
+ var FeedSyncer = class extends Resource7 {
6367
+ #syncNamespaces;
6368
+ #messageBlocksLimit;
6369
+ #syncConcurrency;
6370
+ #pollingInterval;
6371
+ #pollRequestThrottleMs;
6372
+ #backgroundSync;
6373
+ #runtime;
6374
+ #feedStore;
6375
+ #edgeClient;
6376
+ #syncClient;
6377
+ #getSpaceIds;
6378
+ #spacesToPoll = /* @__PURE__ */ new Set();
6379
+ /** Last time full poll was completed. */
6380
+ #lastFullPoll = null;
6381
+ #throttledPollScheduled = false;
6382
+ #lastRequestedPollAt = null;
6383
+ #feedStoreMutex = new Mutex4();
6384
+ #pushFailureBackoffMs = DEFAULT_PUSH_FAILURE_BACKOFF_MS;
6385
+ constructor(options) {
6386
+ super();
6387
+ this.#runtime = options.runtime;
6388
+ this.#feedStore = options.feedStore;
6389
+ this.#edgeClient = options.edgeClient;
6390
+ this.#syncClient = new SyncClient({
6391
+ peerId: options.peerId,
6392
+ feedStore: options.feedStore,
6393
+ sendMessage: this.#sendMessage.bind(this),
6394
+ rpcTimeoutMs: options.syncRpcTimeoutMs
6395
+ });
6396
+ this.#getSpaceIds = options.getSpaceIds;
6397
+ this.#syncNamespaces = options.syncNamespaces;
6398
+ this.#messageBlocksLimit = options.messageBlocksLimit ?? DEFAULT_MESSAGE_BLOCKS_LIMIT;
6399
+ this.#syncConcurrency = options.syncConcurrency ?? DEFAULT_SYNC_CONCURRENCY;
6400
+ this.#pollingInterval = options.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
6401
+ this.#pollRequestThrottleMs = options.pollRequestThrottleMs ?? DEFAULT_POLL_REQUEST_THROTTLE_MS;
6402
+ this.#backgroundSync = options.backgroundSync ?? true;
6289
6403
  }
6290
- /**
6291
- * We don't want notarization plugin to always actively poll edge looking for credentials to notarize,
6292
- * because most of the time we'll be getting an empty response.
6293
- * Instead, we stay in active polling mode while there are spaces where we don't see our agent's feed.
6294
- */
6295
- _ensureAgentIsInSpaces(agentDeviceKey) {
6296
- let activePollingEnabled = false;
6297
- for (const space of this._dataSpaceManager.spaces.values()) {
6298
- if (space.getEdgeReplicationSetting() === EdgeReplicationSetting2.DISABLED) {
6299
- space.notarizationPlugin.setActiveEdgePollingEnabled(false);
6300
- continue;
6301
- }
6302
- if ([
6404
+ async _open() {
6405
+ this._ctx.onDispose(this.#edgeClient.onMessage((msg) => {
6406
+ if (!msg.serviceId) {
6407
+ return;
6408
+ }
6409
+ const service = msg.serviceId.split(":")[0];
6410
+ if (service !== EdgeService2.QUEUE_REPLICATOR) {
6411
+ return;
6412
+ }
6413
+ log20("feed sync edge ingress", {
6414
+ serviceId: msg.serviceId,
6415
+ payloadByteLength: msg.payload?.value?.byteLength
6416
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 141, S: this });
6417
+ const handleMessageEffect = Effect.gen(this, function* () {
6418
+ const decoded = yield* Effect.try({
6419
+ try: () => cborXdecode(msg.payload.value),
6420
+ catch: (error) => new Error(`Failed to decode feed sync message: ${error}`)
6421
+ });
6422
+ const payload = yield* Schema.validate(FeedProtocol3.ProtocolMessage)(decoded);
6423
+ yield* this.#syncClient.handleMessage(payload);
6424
+ }).pipe(Effect.tapError((cause) => Effect.sync(() => log20("feed sync edge message handling failed", {
6425
+ serviceId: msg.serviceId,
6426
+ payloadByteLength: msg.payload?.value?.byteLength,
6427
+ cause: cause instanceof Error ? cause.message : String(cause)
6428
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 152, S: this }))));
6429
+ void this.#runSerialized(() => RuntimeProvider.runPromise(this.#runtime)(handleMessageEffect));
6430
+ }));
6431
+ if (this.#backgroundSync) {
6432
+ await this.#pollTask.open();
6433
+ await this.#pushTask.open();
6434
+ this.#feedStore.onNewBlocks.on(this._ctx, () => {
6435
+ this.#pushTask.schedule();
6436
+ });
6437
+ }
6438
+ this._ctx.onDispose(
6439
+ // NOTE: Fires immediately (as a microtask) if the connection is already open, and again
6440
+ // on every subsequent reconnect.
6441
+ this.#edgeClient.onReconnected(async () => {
6442
+ log20("feed sync edge reconnected", {
6443
+ peerKey: this.#edgeClient.peerKey,
6444
+ identityKey: this.#edgeClient.identityKey
6445
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 174, S: this });
6446
+ if (this.#backgroundSync) {
6447
+ this.#resetSpacesToPoll();
6448
+ this.#pollTask.schedule();
6449
+ this.#pushTask.schedule();
6450
+ }
6451
+ })
6452
+ );
6453
+ if (this.#backgroundSync) {
6454
+ this.#resetSpacesToPoll();
6455
+ this.#pollTask.schedule();
6456
+ this.#pushTask.schedule();
6457
+ }
6458
+ }
6459
+ async _close() {
6460
+ if (this.#backgroundSync) {
6461
+ await this.#pollTask.close();
6462
+ await this.#pushTask.close();
6463
+ }
6464
+ }
6465
+ /**
6466
+ * Schedules a best-effort pull without blocking the caller.
6467
+ */
6468
+ schedulePoll() {
6469
+ if (!this.#backgroundSync) {
6470
+ return;
6471
+ }
6472
+ this.#resetSpacesToPoll();
6473
+ if (this.#throttledPollScheduled) {
6474
+ return;
6475
+ }
6476
+ const now = Date.now();
6477
+ const delay = this.#lastRequestedPollAt == null ? 0 : Math.max(this.#pollRequestThrottleMs - (now - this.#lastRequestedPollAt), 0);
6478
+ this.#throttledPollScheduled = true;
6479
+ scheduleTask8(this._ctx, () => {
6480
+ this.#throttledPollScheduled = false;
6481
+ this.#lastRequestedPollAt = Date.now();
6482
+ this.#pollTask.schedule();
6483
+ }, delay);
6484
+ }
6485
+ /**
6486
+ * Returns per-namespace queue sync backlog for a space.
6487
+ * `blocksToPull` and `blocksToPush` of 0 mean caught up for that namespace.
6488
+ */
6489
+ async getSyncState(ctx, request) {
6490
+ const spaceId = request.spaceId;
6491
+ invariant21(SpaceId3.isValid(spaceId), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 222, S: this, A: ["SpaceId.isValid(spaceId)", ""] });
6492
+ const namespaces = request.namespaces != null && request.namespaces.length > 0 ? request.namespaces : this.#syncNamespaces;
6493
+ for (const feedNamespace of namespaces) {
6494
+ invariant21(FeedProtocol3.isWellKnownNamespace(feedNamespace), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 225, S: this, A: ["FeedProtocol.isWellKnownNamespace(feedNamespace)", ""] });
6495
+ }
6496
+ return this.#runSerialized(() => RuntimeProvider.runPromise(this.#runtime)(Effect.gen(this, function* () {
6497
+ const namespaceStates = yield* Effect.forEach(namespaces, (feedNamespace) => Effect.gen(this, function* () {
6498
+ const blocksToPush = yield* this.#feedStore.countUnpositionedBlocks({
6499
+ spaceId,
6500
+ feedNamespace
6501
+ });
6502
+ const totalBlocks = yield* this.#feedStore.countNamespaceBlocks({
6503
+ spaceId,
6504
+ feedNamespace
6505
+ });
6506
+ const { blocksToPull } = yield* this.#syncClient.peekPull(ctx, {
6507
+ spaceId,
6508
+ feedNamespace,
6509
+ limit: this.#messageBlocksLimit
6510
+ }).pipe(Effect.catchAll((cause) => Effect.gen(this, function* () {
6511
+ this.#logSyncFailure("peekPull", {
6512
+ spaceId,
6513
+ feedNamespace,
6514
+ cause
6515
+ });
6516
+ return {
6517
+ blocksToPull: 0
6518
+ };
6519
+ })));
6520
+ return {
6521
+ namespace: feedNamespace,
6522
+ blocksToPull: String(blocksToPull),
6523
+ blocksToPush: String(blocksToPush),
6524
+ totalBlocks: String(totalBlocks)
6525
+ };
6526
+ }), {
6527
+ concurrency: "unbounded"
6528
+ });
6529
+ return {
6530
+ namespaces: namespaceStates
6531
+ };
6532
+ })));
6533
+ }
6534
+ /**
6535
+ * Performs queue sync and blocks until there are no pending sync batches.
6536
+ */
6537
+ async syncBlocking(ctx, { spaceId, subspaceTag, shouldPush = true, shouldPull = true }) {
6538
+ invariant21(SpaceId3.isValid(spaceId), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 268, S: this, A: ["SpaceId.isValid(spaceId)", ""] });
6539
+ invariant21(FeedProtocol3.isWellKnownNamespace(subspaceTag), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 269, S: this, A: ["FeedProtocol.isWellKnownNamespace(subspaceTag)", ""] });
6540
+ if (!shouldPush && !shouldPull) {
6541
+ return;
6542
+ }
6543
+ await this.#runSerialized(() => RuntimeProvider.runPromise(this.#runtime)(Effect.gen(this, function* () {
6544
+ let done = false;
6545
+ let iterations = 0;
6546
+ while (!done) {
6547
+ done = true;
6548
+ if (shouldPull) {
6549
+ const pullResult = yield* this.#syncClient.pull(ctx, {
6550
+ spaceId,
6551
+ feedNamespace: subspaceTag,
6552
+ limit: this.#messageBlocksLimit
6553
+ });
6554
+ done &&= pullResult.done;
6555
+ }
6556
+ if (shouldPush) {
6557
+ const pushResult = yield* this.#syncClient.push(ctx, {
6558
+ spaceId,
6559
+ feedNamespace: subspaceTag,
6560
+ limit: this.#messageBlocksLimit
6561
+ });
6562
+ done &&= pushResult.done;
6563
+ }
6564
+ iterations++;
6565
+ if (iterations > MAX_BLOCKING_SYNC_ITERATIONS) {
6566
+ throw new Error("Blocking sync exceeded max iterations.");
6567
+ }
6568
+ }
6569
+ })));
6570
+ }
6571
+ async #runSerialized(run) {
6572
+ const env = {
6573
+ stack: [],
6574
+ error: void 0,
6575
+ hasError: false
6576
+ };
6577
+ try {
6578
+ const _guard = _ts_add_disposable_resource4(env, await this.#feedStoreMutex.acquire("feed-sync"), false);
6579
+ return run();
6580
+ } catch (e) {
6581
+ env.error = e;
6582
+ env.hasError = true;
6583
+ } finally {
6584
+ _ts_dispose_resources4(env);
6585
+ }
6586
+ }
6587
+ #schedulePushRetry({ hadFailure, needsMore }) {
6588
+ if (!needsMore) {
6589
+ this.#pushFailureBackoffMs = DEFAULT_PUSH_FAILURE_BACKOFF_MS;
6590
+ return;
6591
+ }
6592
+ if (hadFailure) {
6593
+ const delayMs = this.#pushFailureBackoffMs;
6594
+ this.#pushFailureBackoffMs = Math.min(this.#pushFailureBackoffMs * 2, MAX_PUSH_FAILURE_BACKOFF_MS);
6595
+ log20.info("feed sync push retry scheduled with backoff", {
6596
+ delayMs
6597
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 325, S: this });
6598
+ scheduleTask8(this._ctx, () => this.#pushTask.schedule(), delayMs);
6599
+ return;
6600
+ }
6601
+ this.#pushFailureBackoffMs = DEFAULT_PUSH_FAILURE_BACKOFF_MS;
6602
+ this.#pushTask.schedule();
6603
+ }
6604
+ #resetSpacesToPoll() {
6605
+ this.#spacesToPoll.clear();
6606
+ this.#getSpaceIds().forEach((spaceId) => {
6607
+ this.#spacesToPoll.add(spaceId);
6608
+ });
6609
+ this.#lastFullPoll = Date.now();
6610
+ }
6611
+ #sendMessage(ctx, message) {
6612
+ return Effect.gen(this, function* () {
6613
+ const encoded = encoder.encode(message);
6614
+ const serviceId = this.#getTargetServiceId(message);
6615
+ const rpcTag = "blocks" in message ? "AppendRequest" : "QueryRequest";
6616
+ log20("feed sync edge rpc outgoing", {
6617
+ tag: rpcTag,
6618
+ serviceId,
6619
+ payloadByteLength: encoded.byteLength,
6620
+ spaceId: message.spaceId,
6621
+ feedNamespace: message.feedNamespace,
6622
+ requestId: message.requestId
6623
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 346, S: this });
6624
+ yield* Effect.tryPromise(async () => this.#edgeClient.send(ctx, createBuf(MessageSchema, {
6625
+ source: {
6626
+ identityKey: this.#edgeClient.identityKey,
6627
+ peerKey: this.#edgeClient.peerKey
6628
+ },
6629
+ serviceId,
6630
+ payload: {
6631
+ value: bufferToArray2(encoded)
6632
+ }
6633
+ }))).pipe(Effect.tapError((cause) => Effect.sync(() => log20("feed sync edge send failed", {
6634
+ serviceId,
6635
+ tag: rpcTag,
6636
+ cause: cause instanceof Error ? cause.message : String(cause)
6637
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 363, S: this }))));
6638
+ });
6639
+ }
6640
+ #logSyncFailure(operation, { spaceId, feedNamespace, cause }) {
6641
+ log20("feed sync operation failed", {
6642
+ operation,
6643
+ spaceId,
6644
+ feedNamespace,
6645
+ cause: cause instanceof Error ? cause.message : String(cause),
6646
+ errorTag: cause instanceof Error ? cause.name : void 0
6647
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 371, S: this });
6648
+ }
6649
+ #getTargetServiceId(message) {
6650
+ return FeedProtocol3.encodeServiceId(message.feedNamespace, message.spaceId);
6651
+ }
6652
+ #pollTask = new AsyncTask(async () => Effect.gen(this, function* () {
6653
+ yield* Effect.forEach(this.#spacesToPoll, (spaceId) => Effect.gen(this, function* () {
6654
+ let doneForAllNamespaces = true;
6655
+ for (const feedNamespace of this.#syncNamespaces) {
6656
+ const { done } = yield* this.#syncClient.pull(this._ctx, {
6657
+ spaceId,
6658
+ feedNamespace,
6659
+ limit: this.#messageBlocksLimit
6660
+ }).pipe(Effect.catchAll((cause) => Effect.gen(this, function* () {
6661
+ this.#logSyncFailure("pull", {
6662
+ spaceId,
6663
+ feedNamespace,
6664
+ cause
6665
+ });
6666
+ return {
6667
+ done: false
6668
+ };
6669
+ })));
6670
+ if (!done) {
6671
+ doneForAllNamespaces = false;
6672
+ }
6673
+ }
6674
+ if (doneForAllNamespaces) {
6675
+ this.#spacesToPoll.delete(spaceId);
6676
+ }
6677
+ }), {
6678
+ concurrency: this.#syncConcurrency
6679
+ });
6680
+ if (this.#lastFullPoll == null || Date.now() - this.#lastFullPoll > this.#pollingInterval) {
6681
+ this.#resetSpacesToPoll();
6682
+ this.#pollTask.schedule();
6683
+ } else if (this.#spacesToPoll.size > 0) {
6684
+ this.#pollTask.schedule();
6685
+ } else {
6686
+ this.#resetSpacesToPoll();
6687
+ scheduleTask8(this._ctx, () => this.#pollTask.schedule(), Math.max(this.#pollingInterval - (Date.now() - (this.#lastFullPoll ?? 0)), 0));
6688
+ }
6689
+ }).pipe((effect) => this.#runSerialized(() => RuntimeProvider.runPromise(this.#runtime)(effect))));
6690
+ #pushTask = new AsyncTask(async () => Effect.gen(this, function* () {
6691
+ yield* Effect.forEach(this.#getSpaceIds(), (spaceId) => Effect.gen(this, function* () {
6692
+ let needsMorePush = false;
6693
+ let hadPushFailure = false;
6694
+ for (const feedNamespace of this.#syncNamespaces) {
6695
+ const { done } = yield* this.#syncClient.push(this._ctx, {
6696
+ spaceId,
6697
+ feedNamespace,
6698
+ limit: this.#messageBlocksLimit
6699
+ }).pipe(Effect.tap(() => Effect.sync(() => {
6700
+ this.#pushFailureBackoffMs = DEFAULT_PUSH_FAILURE_BACKOFF_MS;
6701
+ })), Effect.catchAll((cause) => Effect.gen(this, function* () {
6702
+ this.#logSyncFailure("push", {
6703
+ spaceId,
6704
+ feedNamespace,
6705
+ cause
6706
+ });
6707
+ hadPushFailure = true;
6708
+ return {
6709
+ done: false
6710
+ };
6711
+ })));
6712
+ if (!done) {
6713
+ needsMorePush = true;
6714
+ }
6715
+ }
6716
+ this.#schedulePushRetry({
6717
+ hadFailure: hadPushFailure,
6718
+ needsMore: needsMorePush
6719
+ });
6720
+ }), {
6721
+ concurrency: this.#syncConcurrency
6722
+ });
6723
+ }).pipe((effect) => this.#runSerialized(() => RuntimeProvider.runPromise(this.#runtime)(effect))));
6724
+ };
6725
+
6726
+ // src/packlets/agents/edge-agent-manager.ts
6727
+ import { DeferredTask as DeferredTask2, Event as Event9, scheduleTask as scheduleTask9, synchronized as synchronized3 } from "@dxos/async";
6728
+ import { Resource as Resource8 } from "@dxos/context";
6729
+ import { invariant as invariant22 } from "@dxos/invariant";
6730
+ import { PublicKey as PublicKey11 } from "@dxos/keys";
6731
+ import { log as log21 } from "@dxos/log";
6732
+ import { EdgeAgentStatus, EdgeCallFailedError as EdgeCallFailedError3 } from "@dxos/protocols";
6733
+ import { SpaceState as SpaceState4 } from "@dxos/protocols/proto/dxos/client/services";
6734
+ import { EdgeReplicationSetting as EdgeReplicationSetting2 } from "@dxos/protocols/proto/dxos/echo/metadata";
6735
+ var __dxlog_file26 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/agents/edge-agent-manager.ts";
6736
+ function _ts_decorate10(decorators, target, key, desc) {
6737
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
6738
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
6739
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6740
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6741
+ }
6742
+ var AGENT_STATUS_QUERY_RETRY_INTERVAL = 5e3;
6743
+ var AGENT_STATUS_QUERY_RETRY_JITTER = 1e3;
6744
+ var AGENT_FEED_ADDED_CHECK_INTERVAL_MS = 3e3;
6745
+ var EdgeAgentManager = class extends Resource8 {
6746
+ _edgeFeatures;
6747
+ _edgeHttpClient;
6748
+ _dataSpaceManager;
6749
+ _identity;
6750
+ agentStatusChanged = new Event9();
6751
+ _agentDeviceKey;
6752
+ _agentStatus;
6753
+ _lastKnownDeviceCount = 0;
6754
+ _fetchAgentStatusTask;
6755
+ constructor(_edgeFeatures, _edgeHttpClient, _dataSpaceManager, _identity) {
6756
+ super(), this._edgeFeatures = _edgeFeatures, this._edgeHttpClient = _edgeHttpClient, this._dataSpaceManager = _dataSpaceManager, this._identity = _identity;
6757
+ }
6758
+ get agentStatus() {
6759
+ return this._agentStatus;
6760
+ }
6761
+ get agentExists() {
6762
+ return this._agentStatus && this._agentStatus !== EdgeAgentStatus.NOT_FOUND;
6763
+ }
6764
+ async createAgent(ctx) {
6765
+ invariant22(this.isOpen, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 41, S: this, A: ["this.isOpen", ""] });
6766
+ invariant22(this._edgeHttpClient, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 42, S: this, A: ["this._edgeHttpClient", ""] });
6767
+ invariant22(this._edgeFeatures?.agents, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 43, S: this, A: ["this._edgeFeatures?.agents", ""] });
6768
+ const response = await this._edgeHttpClient.createAgent(ctx, {
6769
+ identityKey: this._identity.identityKey.toHex(),
6770
+ haloSpaceId: this._identity.haloSpaceId,
6771
+ haloSpaceKey: this._identity.haloSpaceKey.toHex()
6772
+ });
6773
+ const deviceKey = PublicKey11.fromHex(response.deviceKey);
6774
+ if (await this._identity.authorizedDeviceKeys.has(deviceKey)) {
6775
+ log21.info("agent was already added to HALO, ignoring response", {
6776
+ response
6777
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 51, S: this });
6778
+ this._updateStatus(EdgeAgentStatus.ACTIVE, deviceKey);
6779
+ return;
6780
+ }
6781
+ await this._identity.admitDevice({
6782
+ deviceKey,
6783
+ controlFeedKey: PublicKey11.fromHex(response.feedKey),
6784
+ // TODO: agents don't have data feed, should be removed
6785
+ dataFeedKey: PublicKey11.random()
6786
+ });
6787
+ log21("agent created", response, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 63, S: this });
6788
+ this._updateStatus(EdgeAgentStatus.ACTIVE, deviceKey);
6789
+ }
6790
+ async _open() {
6791
+ const isEnabled = this._edgeHttpClient && this._edgeFeatures?.agents;
6792
+ log21("edge agent manager open", {
6793
+ isEnabled
6794
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 68, S: this });
6795
+ if (!isEnabled) {
6796
+ return;
6797
+ }
6798
+ this._lastKnownDeviceCount = this._identity.authorizedDeviceKeys.size;
6799
+ this._fetchAgentStatusTask = new DeferredTask2(this._ctx, async () => {
6800
+ await this._fetchAgentStatus(this._ctx);
6801
+ });
6802
+ this._fetchAgentStatusTask.schedule();
6803
+ this._dataSpaceManager.updated.on(this._ctx, () => {
6804
+ if (this._agentDeviceKey) {
6805
+ this._ensureAgentIsInSpaces(this._agentDeviceKey);
6806
+ }
6807
+ });
6808
+ this._identity.stateUpdate.on(this._ctx, () => {
6809
+ const maybeAgentWasCreated = this._identity.authorizedDeviceKeys.size > this._lastKnownDeviceCount;
6810
+ if (this.agentExists || !maybeAgentWasCreated) {
6811
+ return;
6812
+ }
6813
+ this._lastKnownDeviceCount = this._identity.authorizedDeviceKeys.size;
6814
+ this._fetchAgentStatusTask?.schedule();
6815
+ });
6816
+ }
6817
+ async _close() {
6818
+ this._fetchAgentStatusTask = void 0;
6819
+ this._lastKnownDeviceCount = 0;
6820
+ }
6821
+ async _fetchAgentStatus(ctx) {
6822
+ invariant22(this._edgeHttpClient, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 98, S: this, A: ["this._edgeHttpClient", ""] });
6823
+ try {
6824
+ log21("fetching agent status", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 100, S: this });
6825
+ const { agent } = await this._edgeHttpClient.getAgentStatus(ctx, {
6826
+ ownerIdentityKey: this._identity.identityKey
6827
+ });
6828
+ const wasAgentCreatedDuringQuery = this._agentStatus === EdgeAgentStatus.ACTIVE;
6829
+ if (!wasAgentCreatedDuringQuery) {
6830
+ const deviceKey = agent.deviceKey ? PublicKey11.fromHex(agent.deviceKey) : void 0;
6831
+ this._updateStatus(agent.status, deviceKey);
6832
+ }
6833
+ } catch (err) {
6834
+ if (err instanceof EdgeCallFailedError3) {
6835
+ if (!err.isRetryable) {
6836
+ log21.warn("non retryable error on agent status fetch attempt", {
6837
+ err
6838
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 112, S: this });
6839
+ return;
6840
+ }
6841
+ }
6842
+ const retryAfterMs = AGENT_STATUS_QUERY_RETRY_INTERVAL + Math.random() * AGENT_STATUS_QUERY_RETRY_JITTER;
6843
+ log21.info("agent status fetching failed", {
6844
+ err,
6845
+ retryAfterMs
6846
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 119, S: this });
6847
+ scheduleTask9(this._ctx, () => this._fetchAgentStatusTask?.schedule(), retryAfterMs);
6848
+ }
6849
+ }
6850
+ /**
6851
+ * We don't want notarization plugin to always actively poll edge looking for credentials to notarize,
6852
+ * because most of the time we'll be getting an empty response.
6853
+ * Instead, we stay in active polling mode while there are spaces where we don't see our agent's feed.
6854
+ */
6855
+ _ensureAgentIsInSpaces(agentDeviceKey) {
6856
+ let activePollingEnabled = false;
6857
+ for (const space of this._dataSpaceManager.spaces.values()) {
6858
+ if (space.getEdgeReplicationSetting() === EdgeReplicationSetting2.DISABLED) {
6859
+ space.notarizationPlugin.setActiveEdgePollingEnabled(false);
6860
+ continue;
6861
+ }
6862
+ if ([
6303
6863
  SpaceState4.SPACE_INACTIVE,
6304
6864
  SpaceState4.SPACE_CLOSED
6305
6865
  ].includes(space.state)) {
@@ -6311,13 +6871,13 @@ var EdgeAgentManager = class extends Resource7 {
6311
6871
  ].some((feed) => feed.assertion.deviceKey.equals(agentDeviceKey));
6312
6872
  space.notarizationPlugin.setActiveEdgePollingEnabled(agentFeedNeedsNotarization);
6313
6873
  activePollingEnabled = activePollingEnabled || agentFeedNeedsNotarization;
6314
- log20.verbose("set active edge polling", {
6874
+ log21.verbose("set active edge polling", {
6315
6875
  enabled: agentFeedNeedsNotarization,
6316
6876
  spaceId: space.id
6317
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 149, S: this });
6877
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 149, S: this });
6318
6878
  }
6319
6879
  if (activePollingEnabled) {
6320
- scheduleTask8(this._ctx, () => this._ensureAgentIsInSpaces(agentDeviceKey), AGENT_FEED_ADDED_CHECK_INTERVAL_MS);
6880
+ scheduleTask9(this._ctx, () => this._ensureAgentIsInSpaces(agentDeviceKey), AGENT_FEED_ADDED_CHECK_INTERVAL_MS);
6321
6881
  }
6322
6882
  }
6323
6883
  _updateStatus(status, deviceKey) {
@@ -6327,9 +6887,9 @@ var EdgeAgentManager = class extends Resource7 {
6327
6887
  if (deviceKey) {
6328
6888
  this._ensureAgentIsInSpaces(deviceKey);
6329
6889
  }
6330
- log20.verbose("agent status update", {
6890
+ log21.verbose("agent status update", {
6331
6891
  status
6332
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file25, L: 166, S: this });
6892
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 166, S: this });
6333
6893
  }
6334
6894
  };
6335
6895
  _ts_decorate10([
@@ -6341,7 +6901,7 @@ import { Stream as Stream10 } from "@dxos/codec-protobuf/stream";
6341
6901
  import { Context as Context11 } from "@dxos/context";
6342
6902
  import { EdgeAgentStatus as EdgeAgentStatus2 } from "@dxos/protocols";
6343
6903
  import { EdgeStatus as EdgeStatus2, QueryAgentStatusResponse } from "@dxos/protocols/proto/dxos/client/services";
6344
- var __dxlog_file26 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/agents/edge-agent-service.ts";
6904
+ var __dxlog_file27 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/agents/edge-agent-service.ts";
6345
6905
  var EdgeAgentServiceImpl = class {
6346
6906
  _agentManagerProvider;
6347
6907
  _edgeConnection;
@@ -6370,7 +6930,7 @@ var EdgeAgentServiceImpl = class {
6370
6930
  });
6371
6931
  }
6372
6932
  async createAgent(_request, options) {
6373
- return (await this._agentManagerProvider()).createAgent(options?.ctx ?? Context11.default(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file26, L: 37 }));
6933
+ return (await this._agentManagerProvider()).createAgent(options?.ctx ?? Context11.default(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file27, L: 37 }));
6374
6934
  }
6375
6935
  queryAgentStatus() {
6376
6936
  return new Stream10(({ ctx, next }) => {
@@ -6404,7 +6964,7 @@ var mapStatus = (agentStatus) => {
6404
6964
  };
6405
6965
 
6406
6966
  // src/packlets/services/service-context.ts
6407
- import { Mutex as Mutex4, Trigger as Trigger6 } from "@dxos/async";
6967
+ import { Mutex as Mutex5, Trigger as Trigger6 } from "@dxos/async";
6408
6968
  import { Resource as Resource9 } from "@dxos/context";
6409
6969
  import { getCredentialAssertion as getCredentialAssertion5 } from "@dxos/credentials";
6410
6970
  import { failUndefined as failUndefined2, warnAfterTimeout as warnAfterTimeout2 } from "@dxos/debug";
@@ -6424,13 +6984,13 @@ import { safeInstanceof } from "@dxos/util";
6424
6984
  // src/packlets/identity/identity-recovery-manager.ts
6425
6985
  import { generateSeedPhrase, keyPairFromSeedPhrase } from "@dxos/credentials";
6426
6986
  import { sign as sign3 } from "@dxos/crypto";
6427
- import { invariant as invariant22 } from "@dxos/invariant";
6987
+ import { invariant as invariant23 } from "@dxos/invariant";
6428
6988
  import { PublicKey as PublicKey12 } from "@dxos/keys";
6429
- import { log as log21 } from "@dxos/log";
6989
+ import { log as log22 } from "@dxos/log";
6430
6990
  import { EdgeAuthChallengeError as EdgeAuthChallengeError2 } from "@dxos/protocols";
6431
6991
  import { schema as schema6 } from "@dxos/protocols/proto";
6432
6992
  import { Timeframe as Timeframe4 } from "@dxos/timeframe";
6433
- var __dxlog_file27 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/identity/identity-recovery-manager.ts";
6993
+ var __dxlog_file28 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/identity/identity-recovery-manager.ts";
6434
6994
  var EdgeIdentityRecoveryManager = class {
6435
6995
  _keyring;
6436
6996
  _edgeClient;
@@ -6444,7 +7004,7 @@ var EdgeIdentityRecoveryManager = class {
6444
7004
  }
6445
7005
  async createRecoveryCredential({ data }) {
6446
7006
  const identity = this._identityProvider();
6447
- invariant22(identity, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file27, L: 25, S: this, A: ["identity", ""] });
7007
+ invariant23(identity, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 25, S: this, A: ["identity", ""] });
6448
7008
  let recoveryKey;
6449
7009
  let lookupKey;
6450
7010
  let algorithm;
@@ -6487,7 +7047,7 @@ var EdgeIdentityRecoveryManager = class {
6487
7047
  };
6488
7048
  }
6489
7049
  async requestRecoveryChallenge(ctx) {
6490
- invariant22(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file27, L: 68, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
7050
+ invariant23(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 68, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
6491
7051
  const deviceKey = await this._keyring.createKey();
6492
7052
  const controlFeedKey = await this._keyring.createKey();
6493
7053
  const request = {
@@ -6509,7 +7069,7 @@ var EdgeIdentityRecoveryManager = class {
6509
7069
  }
6510
7070
  }
6511
7071
  async recoverIdentityWithExternalSignature(ctx, { lookupKey, deviceKey, controlFeedKey, signature, clientDataJson, authenticatorData }) {
6512
- invariant22(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file27, L: 90, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
7072
+ invariant23(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 90, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
6513
7073
  const request = {
6514
7074
  lookupKey: lookupKey.toHex(),
6515
7075
  deviceKey: deviceKey.toHex(),
@@ -6535,7 +7095,7 @@ var EdgeIdentityRecoveryManager = class {
6535
7095
  * Recovery identity using an opaque token sent to the user's email.
6536
7096
  */
6537
7097
  async recoverIdentityWithToken(ctx, { token }) {
6538
- invariant22(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file27, L: 115, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
7098
+ invariant23(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 115, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
6539
7099
  const deviceKey = await this._keyring.createKey();
6540
7100
  const controlFeedKey = await this._keyring.createKey();
6541
7101
  const request = {
@@ -6555,7 +7115,7 @@ var EdgeIdentityRecoveryManager = class {
6555
7115
  });
6556
7116
  }
6557
7117
  async recoverIdentity(ctx, { recoveryCode }) {
6558
- invariant22(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file27, L: 135, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
7118
+ invariant23(this._edgeClient, "Not connected to EDGE.", { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 135, S: this, A: ["this._edgeClient", "'Not connected to EDGE.'"] });
6559
7119
  const recoveryKeypair = keyPairFromSeedPhrase(recoveryCode);
6560
7120
  const recoveryKey = PublicKey12.from(recoveryKeypair.publicKey);
6561
7121
  const deviceKey = await this._keyring.createKey();
@@ -6578,7 +7138,7 @@ var EdgeIdentityRecoveryManager = class {
6578
7138
  signature: Buffer.from(signature).toString("base64")
6579
7139
  });
6580
7140
  }
6581
- log21.info("recovering identity", response, { "~LogMeta": "~LogMeta", F: __dxlog_file27, L: 158, S: this });
7141
+ log22.info("recovering identity", response, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 158, S: this });
6582
7142
  await this._acceptRecoveredIdentity({
6583
7143
  authorizedDeviceCredential: decodeCredential(response.deviceAuthCredential),
6584
7144
  haloGenesisFeedKey: PublicKey12.fromHex(response.genesisFeedKey),
@@ -6596,257 +7156,6 @@ var decodeCredential = (credentialBase64) => {
6596
7156
  return codec.decode(credentialBytes);
6597
7157
  };
6598
7158
 
6599
- // src/packlets/services/feed-syncer.ts
6600
- import { Encoder, decode as cborXdecode } from "cbor-x";
6601
- import * as Effect from "effect/Effect";
6602
- import * as Schema from "effect/Schema";
6603
- import { AsyncTask, scheduleTask as scheduleTask9 } from "@dxos/async";
6604
- import { Resource as Resource8 } from "@dxos/context";
6605
- import { MessageSchema } from "@dxos/edge-client";
6606
- import { RuntimeProvider } from "@dxos/effect";
6607
- import { SyncClient } from "@dxos/feed";
6608
- import { invariant as invariant23 } from "@dxos/invariant";
6609
- import { SpaceId as SpaceId3 } from "@dxos/keys";
6610
- import { log as log22 } from "@dxos/log";
6611
- import { FeedProtocol as FeedProtocol3 } from "@dxos/protocols";
6612
- import { EdgeService as EdgeService2 } from "@dxos/protocols";
6613
- import { createBuf } from "@dxos/protocols/buf";
6614
- import { bufferToArray as bufferToArray2 } from "@dxos/util";
6615
- var __dxlog_file28 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/services/feed-syncer.ts";
6616
- var encoder = new Encoder({
6617
- tagUint8Array: false,
6618
- useRecords: false
6619
- });
6620
- var DEFAULT_MESSAGE_BLOCKS_LIMIT = 50;
6621
- var DEFAULT_SYNC_CONCURRENCY = 5;
6622
- var DEFAULT_POLLING_INTERVAL = 5e3;
6623
- var DEFAULT_POLL_REQUEST_THROTTLE_MS = 250;
6624
- var MAX_BLOCKING_SYNC_ITERATIONS = 100;
6625
- var FeedSyncer = class extends Resource8 {
6626
- #syncNamespaces;
6627
- #messageBlocksLimit;
6628
- #syncConcurrency;
6629
- #pollingInterval;
6630
- #pollRequestThrottleMs;
6631
- #runtime;
6632
- #feedStore;
6633
- #edgeClient;
6634
- #syncClient;
6635
- #getSpaceIds;
6636
- #spacesToPoll = /* @__PURE__ */ new Set();
6637
- /** Last time full poll was completed. */
6638
- #lastFullPoll = null;
6639
- #throttledPollScheduled = false;
6640
- #lastRequestedPollAt = null;
6641
- constructor(options) {
6642
- super();
6643
- this.#runtime = options.runtime;
6644
- this.#feedStore = options.feedStore;
6645
- this.#edgeClient = options.edgeClient;
6646
- this.#syncClient = new SyncClient({
6647
- peerId: options.peerId,
6648
- feedStore: options.feedStore,
6649
- sendMessage: this.#sendMessage.bind(this)
6650
- });
6651
- this.#getSpaceIds = options.getSpaceIds;
6652
- this.#syncNamespaces = options.syncNamespaces;
6653
- this.#messageBlocksLimit = options.messageBlocksLimit ?? DEFAULT_MESSAGE_BLOCKS_LIMIT;
6654
- this.#syncConcurrency = options.syncConcurrency ?? DEFAULT_SYNC_CONCURRENCY;
6655
- this.#pollingInterval = options.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
6656
- this.#pollRequestThrottleMs = options.pollRequestThrottleMs ?? DEFAULT_POLL_REQUEST_THROTTLE_MS;
6657
- }
6658
- async _open() {
6659
- this._ctx.onDispose(this.#edgeClient.onMessage((msg) => {
6660
- if (!msg.serviceId) {
6661
- return;
6662
- }
6663
- const service = msg.serviceId.split(":")[0];
6664
- if (service !== EdgeService2.QUEUE_REPLICATOR) {
6665
- return;
6666
- }
6667
- log22("feed sync edge ingress", {
6668
- serviceId: msg.serviceId,
6669
- payloadByteLength: msg.payload?.value?.byteLength
6670
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 69, S: this });
6671
- const handleMessageEffect = Effect.gen(this, function* () {
6672
- const decoded = yield* Effect.try({
6673
- try: () => cborXdecode(msg.payload.value),
6674
- catch: (error) => new Error(`Failed to decode feed sync message: ${error}`)
6675
- });
6676
- const payload = yield* Schema.validate(FeedProtocol3.ProtocolMessage)(decoded);
6677
- yield* this.#syncClient.handleMessage(payload);
6678
- }).pipe(Effect.tapError((cause) => Effect.sync(() => log22("feed sync edge message handling failed", {
6679
- serviceId: msg.serviceId,
6680
- payloadByteLength: msg.payload?.value?.byteLength,
6681
- cause: cause instanceof Error ? cause.message : String(cause)
6682
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 80, S: this }))));
6683
- void RuntimeProvider.runPromise(this.#runtime)(handleMessageEffect);
6684
- }));
6685
- this._ctx.onDispose(
6686
- // NOTE: This will fire immediately if the connection is already open.
6687
- this.#edgeClient.onReconnected(async () => {
6688
- log22("feed sync edge reconnected", {
6689
- peerKey: this.#edgeClient.peerKey,
6690
- identityKey: this.#edgeClient.identityKey
6691
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 89, S: this });
6692
- })
6693
- );
6694
- this.#feedStore.onNewBlocks.on(this._ctx, () => {
6695
- this.#pushTask.schedule();
6696
- });
6697
- await this.#pollTask.open();
6698
- await this.#pushTask.open();
6699
- this.#resetSpacesToPoll();
6700
- this.#pollTask.schedule();
6701
- }
6702
- async _close() {
6703
- await this.#pollTask.close();
6704
- await this.#pushTask.close();
6705
- }
6706
- /**
6707
- * Schedules a best-effort pull without blocking the caller.
6708
- */
6709
- schedulePoll() {
6710
- this.#resetSpacesToPoll();
6711
- if (this.#throttledPollScheduled) {
6712
- return;
6713
- }
6714
- const now = Date.now();
6715
- const delay = this.#lastRequestedPollAt == null ? 0 : Math.max(this.#pollRequestThrottleMs - (now - this.#lastRequestedPollAt), 0);
6716
- this.#throttledPollScheduled = true;
6717
- scheduleTask9(this._ctx, () => {
6718
- this.#throttledPollScheduled = false;
6719
- this.#lastRequestedPollAt = Date.now();
6720
- this.#pollTask.schedule();
6721
- }, delay);
6722
- }
6723
- /**
6724
- * Performs queue sync and blocks until there are no pending sync batches.
6725
- */
6726
- async syncBlocking(ctx, { spaceId, subspaceTag, shouldPush = true, shouldPull = true }) {
6727
- invariant23(SpaceId3.isValid(spaceId), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 125, S: this, A: ["SpaceId.isValid(spaceId)", ""] });
6728
- invariant23(FeedProtocol3.isWellKnownNamespace(subspaceTag), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 126, S: this, A: ["FeedProtocol.isWellKnownNamespace(subspaceTag)", ""] });
6729
- if (!shouldPush && !shouldPull) {
6730
- return;
6731
- }
6732
- await RuntimeProvider.runPromise(this.#runtime)(Effect.gen(this, function* () {
6733
- let done = false;
6734
- let iterations = 0;
6735
- while (!done) {
6736
- done = true;
6737
- if (shouldPull) {
6738
- const pullResult = yield* this.#syncClient.pull(ctx, {
6739
- spaceId,
6740
- feedNamespace: subspaceTag,
6741
- limit: this.#messageBlocksLimit
6742
- });
6743
- done &&= pullResult.done;
6744
- }
6745
- if (shouldPush) {
6746
- const pushResult = yield* this.#syncClient.push(ctx, {
6747
- spaceId,
6748
- feedNamespace: subspaceTag,
6749
- limit: this.#messageBlocksLimit
6750
- });
6751
- done &&= pushResult.done;
6752
- }
6753
- iterations++;
6754
- if (iterations > MAX_BLOCKING_SYNC_ITERATIONS) {
6755
- throw new Error("Blocking sync exceeded max iterations.");
6756
- }
6757
- }
6758
- }));
6759
- }
6760
- #resetSpacesToPoll() {
6761
- this.#spacesToPoll.clear();
6762
- this.#getSpaceIds().forEach((spaceId) => {
6763
- this.#spacesToPoll.add(spaceId);
6764
- });
6765
- this.#lastFullPoll = Date.now();
6766
- }
6767
- #sendMessage(ctx, message) {
6768
- return Effect.gen(this, function* () {
6769
- const encoded = encoder.encode(message);
6770
- const serviceId = this.#getTargetServiceId(message);
6771
- const rpcTag = "blocks" in message ? "AppendRequest" : "QueryRequest";
6772
- log22("feed sync edge rpc outgoing", {
6773
- tag: rpcTag,
6774
- serviceId,
6775
- payloadByteLength: encoded.byteLength,
6776
- spaceId: message.spaceId,
6777
- feedNamespace: message.feedNamespace,
6778
- requestId: message.requestId
6779
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 170, S: this });
6780
- yield* Effect.tryPromise(async () => this.#edgeClient.send(ctx, createBuf(MessageSchema, {
6781
- source: {
6782
- identityKey: this.#edgeClient.identityKey,
6783
- peerKey: this.#edgeClient.peerKey
6784
- },
6785
- serviceId,
6786
- payload: {
6787
- value: bufferToArray2(encoded)
6788
- }
6789
- }))).pipe(Effect.tapError((cause) => Effect.sync(() => log22("feed sync edge send failed", {
6790
- serviceId,
6791
- tag: rpcTag,
6792
- cause: cause instanceof Error ? cause.message : String(cause)
6793
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file28, L: 187, S: this }))));
6794
- });
6795
- }
6796
- #getTargetServiceId(message) {
6797
- return FeedProtocol3.encodeServiceId(message.feedNamespace, message.spaceId);
6798
- }
6799
- #pollTask = new AsyncTask(async () => Effect.gen(this, function* () {
6800
- yield* Effect.forEach(this.#spacesToPoll, (spaceId) => Effect.gen(this, function* () {
6801
- let doneForAllNamespaces = true;
6802
- for (const feedNamespace of this.#syncNamespaces) {
6803
- const { done } = yield* this.#syncClient.pull(this._ctx, {
6804
- spaceId,
6805
- feedNamespace,
6806
- limit: this.#messageBlocksLimit
6807
- });
6808
- if (!done) {
6809
- doneForAllNamespaces = false;
6810
- }
6811
- }
6812
- if (doneForAllNamespaces) {
6813
- this.#spacesToPoll.delete(spaceId);
6814
- }
6815
- }), {
6816
- concurrency: this.#syncConcurrency
6817
- });
6818
- if (this.#lastFullPoll == null || Date.now() - this.#lastFullPoll > this.#pollingInterval) {
6819
- this.#resetSpacesToPoll();
6820
- this.#pollTask.schedule();
6821
- } else if (this.#spacesToPoll.size > 0) {
6822
- this.#pollTask.schedule();
6823
- } else {
6824
- this.#resetSpacesToPoll();
6825
- scheduleTask9(this._ctx, () => this.#pollTask.schedule(), Math.max(this.#pollingInterval - (Date.now() - (this.#lastFullPoll ?? 0)), 0));
6826
- }
6827
- }).pipe(RuntimeProvider.runPromise(this.#runtime)));
6828
- #pushTask = new AsyncTask(async () => Effect.gen(this, function* () {
6829
- yield* Effect.forEach(this.#getSpaceIds(), (spaceId) => Effect.gen(this, function* () {
6830
- let doneForAllNamespaces = true;
6831
- for (const feedNamespace of this.#syncNamespaces) {
6832
- const { done } = yield* this.#syncClient.push(this._ctx, {
6833
- spaceId,
6834
- feedNamespace,
6835
- limit: this.#messageBlocksLimit
6836
- });
6837
- if (!done) {
6838
- doneForAllNamespaces = false;
6839
- }
6840
- }
6841
- if (!doneForAllNamespaces) {
6842
- this.#pushTask.schedule();
6843
- }
6844
- }), {
6845
- concurrency: this.#syncConcurrency
6846
- });
6847
- }).pipe(RuntimeProvider.runPromise(this.#runtime)));
6848
- };
6849
-
6850
7159
  // src/packlets/services/service-context.ts
6851
7160
  var __dxlog_file29 = "/__w/dxos/dxos/packages/sdk/client-services/src/packlets/services/service-context.ts";
6852
7161
  function _ts_decorate11(decorators, target, key, desc) {
@@ -6855,7 +7164,7 @@ function _ts_decorate11(decorators, target, key, desc) {
6855
7164
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6856
7165
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6857
7166
  }
6858
- function _ts_add_disposable_resource4(env, value, async) {
7167
+ function _ts_add_disposable_resource5(env, value, async) {
6859
7168
  if (value !== null && value !== void 0) {
6860
7169
  if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
6861
7170
  var dispose, inner;
@@ -6888,12 +7197,12 @@ function _ts_add_disposable_resource4(env, value, async) {
6888
7197
  }
6889
7198
  return value;
6890
7199
  }
6891
- function _ts_dispose_resources4(env) {
7200
+ function _ts_dispose_resources5(env) {
6892
7201
  var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
6893
7202
  var e = new Error(message);
6894
7203
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
6895
7204
  };
6896
- return (_ts_dispose_resources4 = function _ts_dispose_resources5(env2) {
7205
+ return (_ts_dispose_resources5 = function _ts_dispose_resources6(env2) {
6897
7206
  function fail(e) {
6898
7207
  env2.error = env2.hasError ? new _SuppressedError(e, env2.error, "An error was suppressed during disposal.") : e;
6899
7208
  env2.hasError = true;
@@ -6930,7 +7239,7 @@ var ServiceContext = class extends Resource9 {
6930
7239
  _runtime;
6931
7240
  _runtimeProps;
6932
7241
  _edgeFeatures;
6933
- _edgeIdentityUpdateMutex = new Mutex4();
7242
+ _edgeIdentityUpdateMutex = new Mutex5();
6934
7243
  initialized = new Trigger6();
6935
7244
  metadataStore;
6936
7245
  blobStore;
@@ -6998,6 +7307,14 @@ var ServiceContext = class extends Resource9 {
6998
7307
  shouldPush: request.shouldPush,
6999
7308
  shouldPull: request.shouldPull
7000
7309
  });
7310
+ },
7311
+ getSyncState: async (ctx, request) => {
7312
+ if (!this._feedSyncer) {
7313
+ return {
7314
+ namespaces: []
7315
+ };
7316
+ }
7317
+ return this._feedSyncer.getSyncState(ctx, request);
7001
7318
  }
7002
7319
  });
7003
7320
  this.invitations = new InvitationsHandler(this.networkManager, this._edgeHttpClient, _runtimeProps?.invitationConnectionDefaultProps);
@@ -7035,67 +7352,67 @@ var ServiceContext = class extends Resource9 {
7035
7352
  }
7036
7353
  async _open(ctx) {
7037
7354
  await this._checkStorageVersion();
7038
- log23("opening...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 215, S: this });
7039
- log23("opening identityManager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 216, S: this });
7355
+ log23("opening...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 226, S: this });
7356
+ log23("opening identityManager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 227, S: this });
7040
7357
  await this.identityManager.open(ctx);
7041
7358
  log23("identityManager opened", {
7042
7359
  hasIdentity: !!this.identityManager.identity
7043
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 218, S: this });
7044
- log23("setting network identity...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 221, S: this });
7360
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 229, S: this });
7361
+ log23("setting network identity...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 232, S: this });
7045
7362
  await this._setNetworkIdentity({
7046
7363
  identity: this.identityManager.identity
7047
7364
  });
7048
- log23("network identity set", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 225, S: this });
7049
- log23("opening edge connection...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 226, S: this });
7365
+ log23("network identity set", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 236, S: this });
7366
+ log23("opening edge connection...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 237, S: this });
7050
7367
  await this._edgeConnection?.open(ctx);
7051
- log23("edge connection opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 228, S: this });
7052
- log23("opening signal manager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 229, S: this });
7368
+ log23("edge connection opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 239, S: this });
7369
+ log23("opening signal manager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 240, S: this });
7053
7370
  await this.signalManager.open(ctx);
7054
- log23("signal manager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 231, S: this });
7055
- log23("opening network manager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 232, S: this });
7371
+ log23("signal manager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 242, S: this });
7372
+ log23("opening network manager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 243, S: this });
7056
7373
  await this.networkManager.open();
7057
- log23("network manager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 234, S: this });
7058
- log23("opening echo host...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 235, S: this });
7374
+ log23("network manager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 245, S: this });
7375
+ log23("opening echo host...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 246, S: this });
7059
7376
  await this.echoHost.open(ctx);
7060
- log23("echo host opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 237, S: this });
7377
+ log23("echo host opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 248, S: this });
7061
7378
  if (this._meshReplicator) {
7062
- log23("adding mesh replicator...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 239, S: this });
7379
+ log23("adding mesh replicator...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 250, S: this });
7063
7380
  await this.echoHost.addReplicator(ctx, this._meshReplicator);
7064
- log23("mesh replicator added", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 241, S: this });
7381
+ log23("mesh replicator added", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 252, S: this });
7065
7382
  }
7066
7383
  if (this._echoEdgeReplicator) {
7067
- log23("adding edge replicator...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 244, S: this });
7384
+ log23("adding edge replicator...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 255, S: this });
7068
7385
  await this.echoHost.addReplicator(ctx, this._echoEdgeReplicator);
7069
- log23("edge replicator added", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 246, S: this });
7386
+ log23("edge replicator added", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 257, S: this });
7070
7387
  }
7071
- log23("loading metadata store...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 248, S: this });
7388
+ log23("loading metadata store...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 259, S: this });
7072
7389
  await this.metadataStore.load();
7073
- log23("metadata store loaded", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 250, S: this });
7074
- log23("opening space manager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 251, S: this });
7390
+ log23("metadata store loaded", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 261, S: this });
7391
+ log23("opening space manager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 262, S: this });
7075
7392
  await this.spaceManager.open();
7076
- log23("space manager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 253, S: this });
7393
+ log23("space manager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 264, S: this });
7077
7394
  if (this.identityManager.identity) {
7078
- log23("joining network...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 255, S: this });
7395
+ log23("joining network...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 266, S: this });
7079
7396
  await this.identityManager.identity.joinNetwork(ctx);
7080
- log23("network joined", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 257, S: this });
7081
- log23("initializing spaces...(calling _initialize)", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 258, S: this });
7397
+ log23("network joined", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 268, S: this });
7398
+ log23("initializing spaces...(calling _initialize)", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 269, S: this });
7082
7399
  await this._initialize(ctx);
7083
- log23("spaces initialized", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 260, S: this });
7400
+ log23("spaces initialized", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 271, S: this });
7084
7401
  } else {
7085
- log23("no identity, skipping network join and space initialization", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 262, S: this });
7402
+ log23("no identity, skipping network join and space initialization", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 273, S: this });
7086
7403
  }
7087
- log23("opening feed syncer...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 264, S: this });
7404
+ log23("opening feed syncer...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 275, S: this });
7088
7405
  await this._feedSyncer?.open(ctx);
7089
- log23("feed syncer opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 266, S: this });
7090
- log23("loading persistent invitations...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 267, S: this });
7406
+ log23("feed syncer opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 277, S: this });
7407
+ log23("loading persistent invitations...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 278, S: this });
7091
7408
  const loadedInvitations = await this.invitationsManager.loadPersistentInvitations(ctx);
7092
7409
  log23("loaded persistent invitations", {
7093
7410
  count: loadedInvitations.invitations?.length
7094
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 269, S: this });
7095
- log23("opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 272, S: this });
7411
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 280, S: this });
7412
+ log23("opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 283, S: this });
7096
7413
  }
7097
7414
  async _close(ctx) {
7098
- log23("closing...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 275, S: this });
7415
+ log23("closing...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 286, S: this });
7099
7416
  await this._feedSyncer?.close();
7100
7417
  if (this._deviceSpaceSync && this.identityManager.identity) {
7101
7418
  await this.identityManager.identity.space.spaceState.removeCredentialProcessor(this._deviceSpaceSync);
@@ -7110,7 +7427,7 @@ var ServiceContext = class extends Resource9 {
7110
7427
  await this._edgeConnection?.close();
7111
7428
  await this.feedStore.close();
7112
7429
  await this.metadataStore.close();
7113
- log23("closed", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 290, S: this });
7430
+ log23("closed", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 301, S: this });
7114
7431
  }
7115
7432
  async createIdentity(params = {}, ctx) {
7116
7433
  ctx ??= this._ctx;
@@ -7127,7 +7444,7 @@ var ServiceContext = class extends Resource9 {
7127
7444
  throw new Error("Identity must be created before joining a space.");
7128
7445
  }
7129
7446
  const factory = this._handlerFactories.get(invitation.kind);
7130
- invariant24(factory, `Unknown invitation kind: ${invitation.kind}`, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 307, S: this, A: ["factory", "`Unknown invitation kind: ${invitation.kind}`"] });
7447
+ invariant24(factory, `Unknown invitation kind: ${invitation.kind}`, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 318, S: this, A: ["factory", "`Unknown invitation kind: ${invitation.kind}`"] });
7131
7448
  return factory(invitation);
7132
7449
  }
7133
7450
  async broadcastProfileUpdate(profile) {
@@ -7157,7 +7474,7 @@ var ServiceContext = class extends Resource9 {
7157
7474
  }
7158
7475
  // Called when identity is created.
7159
7476
  async _initialize(ctx) {
7160
- log23("_initialize: start", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 338, S: this });
7477
+ log23("_initialize: start", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 349, S: this });
7161
7478
  const identity = this.identityManager.identity ?? failUndefined2();
7162
7479
  const signingContext = {
7163
7480
  credentialSigner: identity.getIdentityCredentialSigner(),
@@ -7172,7 +7489,7 @@ var ServiceContext = class extends Resource9 {
7172
7489
  });
7173
7490
  }
7174
7491
  };
7175
- log23("_initialize: creating DataSpaceManager", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 353, S: this });
7492
+ log23("_initialize: creating DataSpaceManager", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 364, S: this });
7176
7493
  this.dataSpaceManager = new DataSpaceManager({
7177
7494
  spaceManager: this.spaceManager,
7178
7495
  metadataStore: this.metadataStore,
@@ -7188,22 +7505,42 @@ var ServiceContext = class extends Resource9 {
7188
7505
  runtimeProps: this._runtimeProps,
7189
7506
  edgeFeatures: this._edgeFeatures
7190
7507
  });
7191
- log23("_initialize: opening DataSpaceManager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 369, S: this });
7508
+ log23("_initialize: opening DataSpaceManager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 380, S: this });
7192
7509
  await this.dataSpaceManager.open(ctx);
7193
- log23("_initialize: DataSpaceManager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 371, S: this });
7510
+ log23("_initialize: DataSpaceManager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 382, S: this });
7194
7511
  this.edgeAgentManager = new EdgeAgentManager(this._edgeFeatures, this._edgeHttpClient, this.dataSpaceManager, identity);
7195
- log23("_initialize: opening EdgeAgentManager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 373, S: this });
7512
+ log23("_initialize: opening EdgeAgentManager...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 384, S: this });
7196
7513
  await this.edgeAgentManager.open(ctx);
7197
- log23("_initialize: EdgeAgentManager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 375, S: this });
7514
+ log23("_initialize: EdgeAgentManager opened", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 386, S: this });
7198
7515
  this._handlerFactories.set(Invitation10.Kind.SPACE, (invitation) => {
7199
- invariant24(this.dataSpaceManager, "dataSpaceManager not initialized yet", { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 377, S: this, A: ["this.dataSpaceManager", "'dataSpaceManager not initialized yet'"] });
7516
+ invariant24(this.dataSpaceManager, "dataSpaceManager not initialized yet", { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 388, S: this, A: ["this.dataSpaceManager", "'dataSpaceManager not initialized yet'"] });
7200
7517
  return new SpaceInvitationProtocol(this.dataSpaceManager, signingContext, this.keyring, invitation.spaceKey);
7201
7518
  });
7202
7519
  this.initialized.wake();
7203
- log23("_initialize: initialized.wake() called", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 381, S: this });
7520
+ log23("_initialize: initialized.wake() called", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 392, S: this });
7204
7521
  this._deviceSpaceSync = {
7205
7522
  processCredential: async (credential) => {
7206
7523
  const assertion = getCredentialAssertion5(credential);
7524
+ if (assertion["@type"] === "dxos.halo.credentials.SpaceDeleted") {
7525
+ if (assertion.spaceKey.equals(identity.space.key)) {
7526
+ return;
7527
+ }
7528
+ if (!this.dataSpaceManager) {
7529
+ log23("dataSpaceManager not initialized yet, ignoring space deletion", {
7530
+ details: assertion
7531
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 403, S: this });
7532
+ return;
7533
+ }
7534
+ try {
7535
+ log23("tombstoning space recorded in halo", {
7536
+ details: assertion
7537
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 409, S: this });
7538
+ await this.dataSpaceManager.handleRemoteSpaceDeleted(this._ctx, assertion.spaceKey);
7539
+ } catch (err) {
7540
+ log23.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 414, S: this });
7541
+ }
7542
+ return;
7543
+ }
7207
7544
  if (assertion["@type"] !== "dxos.halo.credentials.SpaceMember") {
7208
7545
  return;
7209
7546
  }
@@ -7213,26 +7550,32 @@ var ServiceContext = class extends Resource9 {
7213
7550
  if (!this.dataSpaceManager) {
7214
7551
  log23("dataSpaceManager not initialized yet, ignoring space admission", {
7215
7552
  details: assertion
7216
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 393, S: this });
7553
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 426, S: this });
7554
+ return;
7555
+ }
7556
+ if (this.dataSpaceManager.isSpaceDeleted(assertion.spaceKey)) {
7557
+ log23("space is deleted, ignoring space admission", {
7558
+ details: assertion
7559
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 433, S: this });
7217
7560
  return;
7218
7561
  }
7219
7562
  if (this.dataSpaceManager.spaces.has(assertion.spaceKey)) {
7220
7563
  log23("space already exists, ignoring space admission", {
7221
7564
  details: assertion
7222
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 399, S: this });
7565
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 439, S: this });
7223
7566
  return;
7224
7567
  }
7225
7568
  try {
7226
7569
  log23("accepting space recorded in halo", {
7227
7570
  details: assertion
7228
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 405, S: this });
7571
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 445, S: this });
7229
7572
  await this.dataSpaceManager.acceptSpace(this._ctx, {
7230
7573
  spaceKey: assertion.spaceKey,
7231
7574
  genesisFeedKey: assertion.genesisFeedKey,
7232
7575
  tags: assertion.tags
7233
7576
  });
7234
7577
  } catch (err) {
7235
- log23.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 414, S: this });
7578
+ log23.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 454, S: this });
7236
7579
  }
7237
7580
  }
7238
7581
  };
@@ -7245,39 +7588,39 @@ var ServiceContext = class extends Resource9 {
7245
7588
  hasError: false
7246
7589
  };
7247
7590
  try {
7248
- log23("_setNetworkIdentity: acquiring mutex...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 427, S: this });
7249
- const _ = _ts_add_disposable_resource4(env, await this._edgeIdentityUpdateMutex.acquire(), false);
7250
- log23("_setNetworkIdentity: mutex acquired", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 429, S: this });
7591
+ log23("_setNetworkIdentity: acquiring mutex...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 467, S: this });
7592
+ const _ = _ts_add_disposable_resource5(env, await this._edgeIdentityUpdateMutex.acquire(), false);
7593
+ log23("_setNetworkIdentity: mutex acquired", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 469, S: this });
7251
7594
  let edgeIdentity;
7252
7595
  const identity = params?.identity;
7253
7596
  if (identity) {
7254
7597
  log23("_setNetworkIdentity: has identity", {
7255
7598
  identity: identity.identityKey.toHex(),
7256
7599
  hasDeviceCredential: !!params?.deviceCredential
7257
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 433, S: this });
7600
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 473, S: this });
7258
7601
  if (params?.deviceCredential) {
7259
- log23("_setNetworkIdentity: creating chain edge identity with device credential...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 438, S: this });
7602
+ log23("_setNetworkIdentity: creating chain edge identity with device credential...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 478, S: this });
7260
7603
  edgeIdentity = await createChainEdgeIdentity(identity.signer, identity.identityKey, identity.deviceKey, {
7261
7604
  credential: params.deviceCredential
7262
7605
  }, []);
7263
- log23("_setNetworkIdentity: chain edge identity created", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 442, S: this });
7606
+ log23("_setNetworkIdentity: chain edge identity created", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 482, S: this });
7264
7607
  } else {
7265
- log23("_setNetworkIdentity: waiting for identity.ready()...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 444, S: this });
7608
+ log23("_setNetworkIdentity: waiting for identity.ready()...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 484, S: this });
7266
7609
  await warnAfterTimeout2(1e4, "Waiting for identity to be ready for edge connection", async () => {
7267
7610
  await identity.ready();
7268
7611
  });
7269
7612
  log23("_setNetworkIdentity: identity.ready() resolved", {
7270
7613
  hasDeviceCredentialChain: !!identity.deviceCredentialChain
7271
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 449, S: this });
7272
- invariant24(identity.deviceCredentialChain, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 452, S: this, A: ["identity.deviceCredentialChain", ""] });
7273
- log23("_setNetworkIdentity: creating chain edge identity...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 453, S: this });
7614
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 489, S: this });
7615
+ invariant24(identity.deviceCredentialChain, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 492, S: this, A: ["identity.deviceCredentialChain", ""] });
7616
+ log23("_setNetworkIdentity: creating chain edge identity...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 493, S: this });
7274
7617
  edgeIdentity = await createChainEdgeIdentity(identity.signer, identity.identityKey, identity.deviceKey, identity.deviceCredentialChain, []);
7275
- log23("_setNetworkIdentity: chain edge identity created", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 455, S: this });
7618
+ log23("_setNetworkIdentity: chain edge identity created", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 495, S: this });
7276
7619
  }
7277
7620
  } else {
7278
- log23("_setNetworkIdentity: no identity, creating ephemeral edge identity...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 458, S: this });
7621
+ log23("_setNetworkIdentity: no identity, creating ephemeral edge identity...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 498, S: this });
7279
7622
  edgeIdentity = await createEphemeralEdgeIdentity();
7280
- log23("_setNetworkIdentity: ephemeral edge identity created", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 460, S: this });
7623
+ log23("_setNetworkIdentity: ephemeral edge identity created", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 500, S: this });
7281
7624
  }
7282
7625
  this._edgeConnection?.setIdentity(edgeIdentity);
7283
7626
  this._edgeHttpClient?.setIdentity(edgeIdentity);
@@ -7285,12 +7628,12 @@ var ServiceContext = class extends Resource9 {
7285
7628
  identityKey: edgeIdentity.identityKey,
7286
7629
  peerKey: edgeIdentity.peerKey
7287
7630
  });
7288
- log23("_setNetworkIdentity: done", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 468, S: this });
7631
+ log23("_setNetworkIdentity: done", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file29, L: 508, S: this });
7289
7632
  } catch (e) {
7290
7633
  env.error = e;
7291
7634
  env.hasError = true;
7292
7635
  } finally {
7293
- _ts_dispose_resources4(env);
7636
+ _ts_dispose_resources5(env);
7294
7637
  }
7295
7638
  }
7296
7639
  };
@@ -8218,6 +8561,7 @@ export {
8218
8561
  SpaceInvitationProtocol,
8219
8562
  InvitationsManager,
8220
8563
  locks_exports,
8564
+ FeedSyncer,
8221
8565
  EdgeAgentManager,
8222
8566
  EdgeAgentServiceImpl,
8223
8567
  ServiceContext,
@@ -8226,4 +8570,4 @@ export {
8226
8570
  ServiceRegistry,
8227
8571
  ClientServicesHost
8228
8572
  };
8229
- //# sourceMappingURL=chunk-NGONP3EI.mjs.map
8573
+ //# sourceMappingURL=chunk-YJFGXOFW.mjs.map