@ibgib/space-gib 0.0.4 → 0.0.6

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 (42) hide show
  1. package/README.md +7 -0
  2. package/dist/client/bootstrap.mjs +1 -1
  3. package/dist/client/chunk-734MMI4C.mjs +42 -0
  4. package/dist/client/chunk-734MMI4C.mjs.map +7 -0
  5. package/dist/client/{chunk-ZUEU37Z5.mjs → chunk-SMOZ2D5E.mjs} +170 -41
  6. package/dist/client/chunk-SMOZ2D5E.mjs.map +7 -0
  7. package/dist/client/index.html +35 -14
  8. package/dist/client/index.mjs +1 -1
  9. package/dist/client/script.mjs +1 -1
  10. package/dist/client/style.css +29 -5
  11. package/dist/server/server.mjs +338 -31
  12. package/dist/server/server.mjs.map +3 -3
  13. package/package.json +4 -4
  14. package/src/client/AUTO-GENERATED-version.mts +1 -1
  15. package/src/client/components/identity-header/identity-header.css +40 -2
  16. package/src/client/components/identity-header/identity-header.html +3 -2
  17. package/src/client/components/identity-header/identity-header.mts +87 -26
  18. package/src/client/components/identity-manager/IMPLEMENTATION.md +10 -10
  19. package/src/client/components/identity-manager/identity-manager.css +39 -0
  20. package/src/client/components/identity-manager/identity-manager.html +20 -0
  21. package/src/client/components/identity-manager/identity-manager.mts +59 -0
  22. package/src/client/components/keystone-creator/keystone-creator.mts +88 -12
  23. package/src/client/dev-tools/common.mts +505 -10
  24. package/src/client/dev-tools/phase-4-1.mts +19 -4
  25. package/src/client/dev-tools/phase-4-10.mts +77 -305
  26. package/src/client/dev-tools/phase-4-2.mts +46 -212
  27. package/src/client/dev-tools/phase-4-3.mts +57 -198
  28. package/src/client/dev-tools/phase-4-4.mts +57 -170
  29. package/src/client/dev-tools/phase-4-5.mts +48 -204
  30. package/src/client/dev-tools/phase-4-6.mts +37 -103
  31. package/src/client/dev-tools/phase-4-7.mts +44 -228
  32. package/src/client/dev-tools/phase-4-8.mts +33 -136
  33. package/src/client/dev-tools/phase-4-9.mts +33 -137
  34. package/src/client/dev-tools/phase-4.mts +30 -6
  35. package/src/client/dev-tools.mts +18 -0
  36. package/src/client/index.html +35 -14
  37. package/src/client/style.css +29 -5
  38. package/src/client/types.mts +4 -1
  39. package/dist/client/chunk-NCXKCVYS.mjs +0 -42
  40. package/dist/client/chunk-NCXKCVYS.mjs.map +0 -7
  41. package/dist/client/chunk-ZUEU37Z5.mjs.map +0 -7
  42. package/dist/respec-gib.node.mjs +0 -5
@@ -17693,6 +17693,7 @@ var KeystoneVerb = {
17693
17693
  };
17694
17694
  var KEYSTONE_VERB_VALID_VALUES = Object.values(KeystoneVerb);
17695
17695
  var POOL_ID_REVOKE = KEYSTONE_VERB_REVOKE;
17696
+ var POOL_ID_MANAGE = KEYSTONE_VERB_MANAGE;
17696
17697
  var POOL_ID_CONNECT = KEYSTONE_VERB_CONNECT;
17697
17698
  var POOL_ID_SYNC = KEYSTONE_VERB_SYNC;
17698
17699
  var KEYSTONE_CONFIG_DEFAULT_SIZE = 200;
@@ -17940,6 +17941,14 @@ async function parseKeystoneIb({ ib }) {
17940
17941
  }
17941
17942
  }
17942
17943
  }
17944
+ async function validateKeystoneIb({ ib }) {
17945
+ try {
17946
+ await parseKeystoneIb({ ib });
17947
+ return true;
17948
+ } catch {
17949
+ return false;
17950
+ }
17951
+ }
17943
17952
  async function getDeterministicRequirements({ pool, requiredChallengeIds, targetAddr }) {
17944
17953
  const behavior = pool.config.behavior;
17945
17954
  const mandatory = /* @__PURE__ */ new Set();
@@ -18267,6 +18276,10 @@ async function validateGenesisKeystone({ keystoneIbGib }) {
18267
18276
  }
18268
18277
  const errors = [];
18269
18278
  const { data, rel8ns } = keystoneIbGib;
18279
+ const isValidIb = await validateKeystoneIb({ ib: keystoneIbGib.ib });
18280
+ if (!isValidIb) {
18281
+ errors.push(`${lc2} invalid keystone ib (${keystoneIbGib.ib}). (E: ad7a88bc38c290a184dfbd42be48f526)`);
18282
+ }
18270
18283
  const metadataErrors = validateKeystoneMetadata({ data });
18271
18284
  metadataErrors.forEach((x) => errors.push(x));
18272
18285
  if (data.proofs && data.proofs.length > 0) {
@@ -18292,6 +18305,54 @@ async function validateGenesisKeystone({ keystoneIbGib }) {
18292
18305
  }
18293
18306
  }
18294
18307
  }
18308
+ function isDelegatesChanged({ currDelegates, prevDelegates }) {
18309
+ const curr = currDelegates || {};
18310
+ const prev = prevDelegates || {};
18311
+ const currKeys = Object.keys(curr);
18312
+ const prevKeys = Object.keys(prev);
18313
+ if (currKeys.length !== prevKeys.length) {
18314
+ return true;
18315
+ }
18316
+ for (const key of currKeys) {
18317
+ const currVal = curr[key];
18318
+ const prevVal = prev[key];
18319
+ if (!prevVal) {
18320
+ return true;
18321
+ }
18322
+ if (currVal.delegateTjpAddr !== prevVal.delegateTjpAddr || currVal.delegateAddr !== prevVal.delegateAddr || currVal.thisAddr !== prevVal.thisAddr) {
18323
+ return true;
18324
+ }
18325
+ }
18326
+ return false;
18327
+ }
18328
+ async function validateDelegates({ currDelegates, prevIbGib, lc: lc2, errors }) {
18329
+ const currKeys = Object.keys(currDelegates);
18330
+ const prevAddr = getIbGibAddr({ ibGib: prevIbGib });
18331
+ for (const key of currKeys) {
18332
+ const info = currDelegates[key];
18333
+ if (key !== info.delegateTjpAddr) {
18334
+ errors.push(`${lc2} Invalid delegate mapping: Key '${key}' does not match delegateTjpAddr '${info.delegateTjpAddr}'. (E: 9c8da8bc38c290a184dfbd42be48f526)`);
18335
+ }
18336
+ const [parsedDelegateTjp, parsedDelegate, parsedThis] = await Promise.all([
18337
+ validateKeystoneIb({ ib: info.delegateTjpAddr.split("^")[0] }),
18338
+ validateKeystoneIb({ ib: info.delegateAddr.split("^")[0] }),
18339
+ validateKeystoneIb({ ib: info.thisAddr.split("^")[0] })
18340
+ ]);
18341
+ if (!parsedDelegateTjp) {
18342
+ errors.push(`${lc2} Delegate delegateTjpAddr '${info.delegateTjpAddr}' is not a valid keystone address. (E: 10d8a8bc38c290a184dfbd42be48f526)`);
18343
+ }
18344
+ if (!parsedDelegate) {
18345
+ errors.push(`${lc2} Delegate delegateAddr '${info.delegateAddr}' is not a valid keystone address. (E: 20d8a8bc38c290a184dfbd42be48f526)`);
18346
+ }
18347
+ if (!parsedThis) {
18348
+ errors.push(`${lc2} Delegate thisAddr '${info.thisAddr}' is not a valid keystone address. (E: 30d8a8bc38c290a184dfbd42be48f526)`);
18349
+ }
18350
+ const isHistoricalParent = info.thisAddr === prevAddr || (prevIbGib.rel8ns?.past || []).includes(info.thisAddr);
18351
+ if (!isHistoricalParent) {
18352
+ errors.push(`${lc2} Delegate thisAddr '${info.thisAddr}' is not a valid historical address in the parent keystone timeline. (E: 40d8a8bc38c290a184dfbd42be48f526)`);
18353
+ }
18354
+ }
18355
+ }
18295
18356
  async function validateKeystoneTransition({ currentIbGib, prevIbGib }) {
18296
18357
  const lc2 = `[${validateKeystoneTransition.name}]`;
18297
18358
  const errors = [];
@@ -18308,23 +18369,37 @@ async function validateKeystoneTransition({ currentIbGib, prevIbGib }) {
18308
18369
  }
18309
18370
  const currData = currentIbGib.data;
18310
18371
  const prevData = prevIbGib.data;
18372
+ const isValidIb = await validateKeystoneIb({ ib: currentIbGib.ib });
18373
+ if (!isValidIb) {
18374
+ errors.push(`${lc2} invalid keystone ib (${currentIbGib.ib}). (E: a98dc8bc38c290a184dfbd42be48f526)`);
18375
+ }
18311
18376
  const metadataErrors = validateKeystoneMetadata({ data: currData });
18312
18377
  metadataErrors.forEach((x) => errors.push(x));
18378
+ const currDelegates = currData.delegates || {};
18379
+ const prevDelegates = prevData.delegates || {};
18380
+ const delegatesChanged = isDelegatesChanged({ currDelegates, prevDelegates });
18381
+ if (delegatesChanged) {
18382
+ const hasManageProof = currData.proofs?.some((proof) => proof.claim?.verb === KEYSTONE_VERB_MANAGE);
18383
+ if (!hasManageProof) {
18384
+ errors.push(`${lc2} Policy Violation: Delegates map was mutated but no proof for manage verb ('${KEYSTONE_VERB_MANAGE}') is present. (E: 819fa8cb28c9b60e68994511a5825)`);
18385
+ }
18386
+ }
18387
+ await validateDelegates({ currDelegates, prevIbGib, lc: lc2, errors });
18313
18388
  const currDataN = currData.n ?? -2;
18314
18389
  const prevDataN = prevData.n ?? -2;
18315
18390
  if (currDataN < 0) {
18316
- errors.push("invalid keystone.currData.n is undefined or null.");
18391
+ errors.push("invalid keystone.currData.n is undefined or null. (E: 9fbe38704b68829d18ea1d0940d0aa26)");
18317
18392
  }
18318
18393
  if (prevDataN < 0) {
18319
- errors.push("invalid keystone.prevData.n is undefined or null.");
18394
+ errors.push("invalid keystone.prevData.n is undefined or null. (E: 6dc5aa9c87017db6080ed4268b07af26)");
18320
18395
  }
18321
18396
  ;
18322
18397
  if (currDataN !== prevDataN + 1) {
18323
- errors.push(`keystone data.n values are not sequential. prevData.n: ${prevDataN}, currData.n: ${currDataN}. `);
18398
+ errors.push(`keystone data.n values are not sequential. prevData.n: ${prevDataN}, currData.n: ${currDataN}. (E: 5ae12809f2c67216d38d8ba8d6c42826)`);
18324
18399
  }
18325
18400
  for (const proof of currData.proofs) {
18326
18401
  if (proof.solutions.length === 0) {
18327
- errors.push(`Proof ${proof.id || "unknown"} has no solutions.`);
18402
+ errors.push(`Proof ${proof.id || "unknown"} has no solutions. (E: e2b4683ce0ce30f798ec77841e88c826)`);
18328
18403
  continue;
18329
18404
  }
18330
18405
  const poolId = proof.solutions[0].poolId;
@@ -18432,6 +18507,9 @@ async function evolvePersistAndRegisterKeystone({ prevIbGib, newData, metaspace,
18432
18507
  if (prevData.checkpointDetails) {
18433
18508
  dataToRemove.checkpointDetails = {};
18434
18509
  }
18510
+ if (prevData.delegates) {
18511
+ dataToRemove.delegates = "remove";
18512
+ }
18435
18513
  if (Object.keys(dataToRemove).length === 0) {
18436
18514
  dataToRemove = void 0;
18437
18515
  }
@@ -18694,7 +18772,7 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18694
18772
  *
18695
18773
  * todo: wrap this and other entire keystone sign/method implementations in locks on the keystone's tjpGib.
18696
18774
  */
18697
- async sign({ latestKeystone, masterSecret, claim, poolId, poolFilter, requiredChallengeIds = [], frameDetails, metaspace, space }) {
18775
+ async sign({ latestKeystone, masterSecret, claim, poolId, poolFilter, requiredChallengeIds = [], frameDetails, metaspace, space, dataToPatch }) {
18698
18776
  const lc2 = `${this.lc}[${this.sign.name}]`;
18699
18777
  try {
18700
18778
  if (logalot41) {
@@ -18743,7 +18821,9 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18743
18821
  challengePools: nextPools,
18744
18822
  proofs: [proof],
18745
18823
  frameDetails,
18746
- checkpointDetails
18824
+ checkpointDetails,
18825
+ ...prevData.delegates ? { delegates: prevData.delegates } : {},
18826
+ ...dataToPatch
18747
18827
  };
18748
18828
  const resKeystone = await evolvePersistAndRegisterKeystone({
18749
18829
  prevIbGib: latestKeystone,
@@ -18776,6 +18856,157 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18776
18856
  const errors = await validateKeystoneTransition({ currentIbGib, prevIbGib });
18777
18857
  return errors;
18778
18858
  }
18859
+ /**
18860
+ * Registers a delegate keystone on the parent keystone by appending its information
18861
+ * to the parent's `delegates` map. This operation is signed using the parent's `manage` pool.
18862
+ * Validates the delegate keystone's entire graph/timeline before registering.
18863
+ */
18864
+ async registerDelegate({ parentKeystone, delegateKeystone, masterSecret, frameDetails, metaspace, space, allowedVerbs }) {
18865
+ const lc2 = `${this.lc}[${this.registerDelegate.name}]`;
18866
+ try {
18867
+ if (logalot41) {
18868
+ console.log(`${lc2} starting...`);
18869
+ }
18870
+ const validationErrors = await validateKeystoneGraph({
18871
+ keystoneIbGib: delegateKeystone,
18872
+ getLatest: true,
18873
+ invalidIfMoreRecentKeystoneFoundInSpace: false,
18874
+ space
18875
+ });
18876
+ if (validationErrors.length > 0) {
18877
+ throw new Error(`Delegate keystone validation failed: ${validationErrors.join(", ")} (E: 88fa8ab28c9b60e68994511a5825)`);
18878
+ }
18879
+ const prevData = parentKeystone.data;
18880
+ const hasManagePool = prevData.challengePools.some((p) => p.id === POOL_ID_MANAGE);
18881
+ if (!hasManagePool) {
18882
+ throw new Error(`Parent keystone does not support delegation. Manage pool is required. (E: 818fa8ab28c9b60e68994511a5825)`);
18883
+ }
18884
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
18885
+ if (!delegateTjpAddr) {
18886
+ throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: d4d6e8ad03c8925d4838b9a87b8f2826)`);
18887
+ }
18888
+ const claim = {
18889
+ target: delegateTjpAddr,
18890
+ verb: KEYSTONE_VERB_MANAGE
18891
+ };
18892
+ const currentDelegates = prevData.delegates ? { ...prevData.delegates } : {};
18893
+ currentDelegates[delegateTjpAddr] = {
18894
+ delegateTjpAddr,
18895
+ delegateAddr: getIbGibAddr({ ibGib: delegateKeystone }),
18896
+ thisAddr: getIbGibAddr({ ibGib: parentKeystone }),
18897
+ // allowedVerbs: allowedVerbs ?? [KEYSTONE_VERB_SYNC], // NO! We cannot default to sync just to get things to work right now
18898
+ allowedVerbs
18899
+ };
18900
+ const evolved = await this.sign({
18901
+ latestKeystone: parentKeystone,
18902
+ masterSecret,
18903
+ claim,
18904
+ poolId: POOL_ID_MANAGE,
18905
+ frameDetails,
18906
+ metaspace,
18907
+ space,
18908
+ dataToPatch: {
18909
+ delegates: currentDelegates
18910
+ }
18911
+ });
18912
+ return evolved;
18913
+ } catch (error) {
18914
+ console.error(`${lc2} ${extractErrorMsg(error)}`);
18915
+ throw error;
18916
+ } finally {
18917
+ if (logalot41) {
18918
+ console.log(`${lc2} complete.`);
18919
+ }
18920
+ }
18921
+ }
18922
+ /**
18923
+ * Unregisters a delegate keystone from the parent keystone by removing its entry
18924
+ * from the parent's `delegates` map. This operation is signed using the parent's `manage` pool.
18925
+ */
18926
+ async unregisterDelegate({ parentKeystone, delegateTjpAddr, masterSecret, frameDetails, metaspace, space }) {
18927
+ const lc2 = `${this.lc}[${this.unregisterDelegate.name}]`;
18928
+ try {
18929
+ if (logalot41) {
18930
+ console.log(`${lc2} starting...`);
18931
+ }
18932
+ const prevData = parentKeystone.data;
18933
+ const hasManagePool = prevData.challengePools.some((p) => p.id === POOL_ID_MANAGE);
18934
+ if (!hasManagePool) {
18935
+ throw new Error(`Parent keystone does not support delegation. Manage pool is required. (E: 3889f8ab28c9b60e68994511a5825)`);
18936
+ }
18937
+ const claim = {
18938
+ target: delegateTjpAddr,
18939
+ verb: KEYSTONE_VERB_MANAGE
18940
+ };
18941
+ const currentDelegates = prevData.delegates ? { ...prevData.delegates } : {};
18942
+ if (!currentDelegates[delegateTjpAddr]) {
18943
+ throw new Error(`Delegate ${delegateTjpAddr} is not registered on this parent. (E: 81d9f8ab28c9b60e68994511a5825)`);
18944
+ }
18945
+ delete currentDelegates[delegateTjpAddr];
18946
+ const evolved = await this.sign({
18947
+ latestKeystone: parentKeystone,
18948
+ masterSecret,
18949
+ claim,
18950
+ poolId: POOL_ID_MANAGE,
18951
+ frameDetails,
18952
+ metaspace,
18953
+ space,
18954
+ dataToPatch: {
18955
+ delegates: currentDelegates
18956
+ }
18957
+ });
18958
+ return evolved;
18959
+ } catch (error) {
18960
+ console.error(`${lc2} ${extractErrorMsg(error)}`);
18961
+ throw error;
18962
+ } finally {
18963
+ if (logalot41) {
18964
+ console.log(`${lc2} complete.`);
18965
+ }
18966
+ }
18967
+ }
18968
+ /**
18969
+ * Gets the registration status of a delegate keystone from the parent's latest tip frame.
18970
+ */
18971
+ async getDelegateStatus({ parentTjpAddr, delegateTjpAddr, metaspace, space }) {
18972
+ const lc2 = `${this.lc}[${this.getDelegateStatus.name}]`;
18973
+ try {
18974
+ if (logalot41) {
18975
+ console.log(`${lc2} starting...`);
18976
+ }
18977
+ const { ib, gib } = getIbAndGib({ ibGibAddr: parentTjpAddr });
18978
+ const parentIbGib = { ib, gib };
18979
+ const resGetLatest = await getLatestAddrs({
18980
+ ibGibs: [parentIbGib],
18981
+ space
18982
+ });
18983
+ if (!resGetLatest.data?.latestAddrsMap) {
18984
+ return { registered: false };
18985
+ }
18986
+ const latestAddr = resGetLatest.data.latestAddrsMap[parentTjpAddr];
18987
+ if (!latestAddr) {
18988
+ return { registered: false };
18989
+ }
18990
+ const resGet = await metaspace.get({ addr: latestAddr, space });
18991
+ const latestParent = resGet.ibGibs?.at(0);
18992
+ if (!latestParent || !latestParent.data) {
18993
+ return { registered: false };
18994
+ }
18995
+ const delegates = latestParent.data.delegates || {};
18996
+ const delegateInfo = delegates[delegateTjpAddr];
18997
+ return {
18998
+ registered: !!delegateInfo,
18999
+ delegateInfo
19000
+ };
19001
+ } catch (error) {
19002
+ console.error(`${lc2} ${extractErrorMsg(error)}`);
19003
+ throw error;
19004
+ } finally {
19005
+ if (logalot41) {
19006
+ console.log(`${lc2} complete.`);
19007
+ }
19008
+ }
19009
+ }
18779
19010
  /**
18780
19011
  * Validates a genesis keystone.
18781
19012
  *
@@ -18909,7 +19140,8 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18909
19140
  proofs: [proof],
18910
19141
  revocationInfo,
18911
19142
  frameDetails,
18912
- checkpointDetails
19143
+ checkpointDetails,
19144
+ ...prevData.delegates ? { delegates: prevData.delegates } : {}
18913
19145
  };
18914
19146
  const newKeystone = await evolvePersistAndRegisterKeystone({
18915
19147
  prevIbGib: latestKeystone,
@@ -19002,7 +19234,8 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
19002
19234
  challengePools: finalPools,
19003
19235
  proofs: [proof],
19004
19236
  // The proof authorizes the structure change
19005
- checkpointDetails
19237
+ checkpointDetails,
19238
+ ...prevData.delegates ? { delegates: prevData.delegates } : {}
19006
19239
  };
19007
19240
  const newKeystone = await evolvePersistAndRegisterKeystone({
19008
19241
  prevIbGib: latestKeystone,
@@ -19246,30 +19479,64 @@ async function validateAndRegisterEvolveKeystone({ domainAddr, keystoneIbGib, re
19246
19479
  if (intrinsicErrors && intrinsicErrors.length > 0) {
19247
19480
  throw new Error(`Intrinsic keystone validation failed: ${intrinsicErrors.join(", ")} (E: 38ea984585edc6ee88d2a698c7895826)`);
19248
19481
  }
19249
- const infoAddr = getGibInfo({ ibGibAddr: addr });
19250
- const tjpGib = infoAddr.tjpGib ?? infoAddr.punctiliarHash;
19251
- const infoDomain = getGibInfo({ ibGibAddr: domainAddr });
19252
- const expectedTjpGib = infoDomain.tjpGib ?? infoDomain.punctiliarHash;
19253
- if (tjpGib !== expectedTjpGib) {
19254
- throw new Error(`Keystone tjpGib (${tjpGib}) does not match URL domainAddr tjpGib (${expectedTjpGib})`);
19255
- }
19256
19482
  const keystoneService = new KeystoneService_V1();
19257
- let prevIbGib;
19483
+ let parentKeystone;
19258
19484
  try {
19259
- prevIbGib = await keystoneService.getLatestKeystone({
19485
+ parentKeystone = await keystoneService.getLatestKeystone({
19260
19486
  addr: domainAddr,
19261
19487
  metaspace,
19262
19488
  space
19263
19489
  });
19264
19490
  } catch (error) {
19265
- throw new Error(`Could not retrieve previous keystone tip for ${domainAddr}: ${extractErrorMsg(error)} (E: b73ed8aeb0d837d248718b487345d326)`);
19491
+ throw new Error(`Could not retrieve root Domain Identity tip for ${domainAddr}: ${extractErrorMsg(error)} (E: b73ed8aeb0d837d248718b487345d326)`);
19266
19492
  }
19267
- const validationErrors = await keystoneService.validate({
19268
- currentIbGib: keystoneIbGib,
19269
- prevIbGib
19270
- });
19271
- if (validationErrors && validationErrors.length > 0) {
19272
- throw new Error(`Keystone evolution validation failed: ${validationErrors.join(", ")} (E: 5212f8492ac839953842631834bcd826)`);
19493
+ const parentTjpAddr = getTjpAddr({ ibGib: parentKeystone });
19494
+ const incomingTjpAddr = getTjpAddr({ ibGib: keystoneIbGib });
19495
+ if (!incomingTjpAddr) {
19496
+ throw new Error(`Incoming keystone does not have a TJP address (E: d288fae39b7d825d)`);
19497
+ }
19498
+ const isDelegate = incomingTjpAddr !== parentTjpAddr;
19499
+ let prevIbGib;
19500
+ if (isDelegate) {
19501
+ const delegateInfo = parentKeystone.data?.delegates?.[incomingTjpAddr];
19502
+ if (!delegateInfo) {
19503
+ throw new Error(`Incoming delegate keystone (${incomingTjpAddr}) is not registered under parent Domain Identity (${parentTjpAddr}) (E: c288fae39b7d82fe)`);
19504
+ }
19505
+ const allowedVerbs = delegateInfo.allowedVerbs ?? [];
19506
+ if (!allowedVerbs.includes(KEYSTONE_VERB_SYNC)) {
19507
+ throw new Error(`Incoming delegate keystone is not authorized for sync. Allowed verbs: ${allowedVerbs.join(", ")} (E: a288fae39b7d82ff)`);
19508
+ }
19509
+ const delegateLatestAddr = await metaspace.getLatestAddr({
19510
+ addr: incomingTjpAddr,
19511
+ space
19512
+ });
19513
+ if (delegateLatestAddr) {
19514
+ const resGet = await metaspace.get({ addr: delegateLatestAddr, space });
19515
+ if (resGet.success && resGet.ibGibs && resGet.ibGibs.length > 0) {
19516
+ prevIbGib = resGet.ibGibs[0];
19517
+ }
19518
+ }
19519
+ } else {
19520
+ prevIbGib = parentKeystone;
19521
+ }
19522
+ if (prevIbGib) {
19523
+ const validationErrors = await keystoneService.validate({
19524
+ currentIbGib: keystoneIbGib,
19525
+ prevIbGib
19526
+ });
19527
+ if (validationErrors && validationErrors.length > 0) {
19528
+ throw new Error(`Keystone evolution validation failed: ${validationErrors.join(", ")} (E: 5212f8492ac839953842631834bcd826)`);
19529
+ }
19530
+ } else {
19531
+ const validationErrors = await keystoneService.validateKeystoneGraph({
19532
+ keystoneIbGib,
19533
+ getLatest: false,
19534
+ invalidIfMoreRecentKeystoneFoundInSpace: false,
19535
+ space
19536
+ });
19537
+ if (validationErrors && validationErrors.length > 0) {
19538
+ throw new Error(`Keystone graph validation failed: ${validationErrors.join(", ")} (E: 3a288fae39b7d82e)`);
19539
+ }
19273
19540
  }
19274
19541
  const proofs = keystoneIbGib.data?.proofs ?? [];
19275
19542
  if (proofs.length === 0) {
@@ -19297,8 +19564,36 @@ async function validateAndRegisterEvolveKeystone({ domainAddr, keystoneIbGib, re
19297
19564
  if (!verb) {
19298
19565
  throw new Error(`claim.verb is falsy (E: 92cf38af58db2cd90e7132b8940fe326)`);
19299
19566
  }
19567
+ if (verb === "manage") {
19568
+ const prevDelegates = prevIbGib?.data?.delegates ?? {};
19569
+ const currDelegates = keystoneIbGib.data?.delegates ?? {};
19570
+ for (const [delegateTjpAddr, delegateInfo] of Object.entries(currDelegates)) {
19571
+ if (!prevDelegates[delegateTjpAddr]) {
19572
+ const delegateAddr = delegateInfo.delegateAddr;
19573
+ const delegateIbGib = relatedIbGibs.find((ibGib) => getIbGibAddr({ ibGib }) === delegateAddr);
19574
+ if (!delegateIbGib) {
19575
+ throw new Error(`Evolved delegate keystone ${delegateAddr} must be provided in relatedIbGibs (E: 1fe5a68438e288ab4e86c90d81d142826)`);
19576
+ }
19577
+ const delegateErrors = await keystoneService.validateGenesisKeystone({ keystoneIbGib: delegateIbGib });
19578
+ if (delegateErrors && delegateErrors.length > 0) {
19579
+ throw new Error(`Genesis validation failed for delegate keystone ${delegateAddr}: ${delegateErrors.join(", ")} (E: d8afdc1dbed48c000455b35585dc26826)`);
19580
+ }
19581
+ }
19582
+ }
19583
+ await metaspace.put({ ibGibs: [keystoneIbGib, ...relatedIbGibs], space });
19584
+ await metaspace.registerNewIbGib({ ibGib: keystoneIbGib, space });
19585
+ for (const related of relatedIbGibs) {
19586
+ if (related.ib?.startsWith("keystone")) {
19587
+ await metaspace.registerNewIbGib({ ibGib: related, space });
19588
+ }
19589
+ }
19590
+ return;
19591
+ }
19300
19592
  if (verb !== "sync") {
19301
- throw new Error(`non-sync keystone evolution not yet implemented (E: eca4681b05486d1f784c0cb815ef9926)`);
19593
+ throw new Error(`non-sync/non-manage keystone evolution not yet implemented (E: eca4681b05486d1f784c0cb815ef9926)`);
19594
+ }
19595
+ if (!isDelegate) {
19596
+ throw new Error(`Root Domain Identity (${parentTjpAddr}) is not allowed to sync directly. A delegate must be used. (E: 2c88fae39b7d82fd)`);
19302
19597
  }
19303
19598
  const sAddr = claim.target;
19304
19599
  if (!sAddr) {
@@ -21390,13 +21685,16 @@ var SyncPeer_V1 = class _SyncPeer_V1 extends LightWitnessBase_V1 {
21390
21685
  if (!this.opts) {
21391
21686
  throw new Error(`(UNEXPECTED) this.opts falsy? Call initializeOpts first. (E: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c526)`);
21392
21687
  }
21393
- const { senderIdentity, fnSenderSecret, sagaId, localMetaspace, localSpace } = this.opts;
21688
+ const { senderIdentity, fnSenderSecret, senderDomainAddr, sagaId, localMetaspace, localSpace } = this.opts;
21394
21689
  if (!senderIdentity || !fnSenderSecret) {
21395
21690
  if (logalot54) {
21396
21691
  console.log(`${lc2} no senderIdentity/fnSenderSecret \u2014 skipping establish (I: f29348a77d1542326d14043ea4b69126)`);
21397
21692
  }
21398
21693
  return void 0;
21399
21694
  }
21695
+ if (!senderDomainAddr) {
21696
+ throw new Error(`(UNEXPECTED) senderDomainAddr falsy but senderIdentity/fnSenderSecret truthy? if identity is used, senderDomainAddr must be provided. (E: c288fa8e9d3d82fc)`);
21697
+ }
21400
21698
  const senderIdentityAddr = getIbGibAddr({ ibGib: senderIdentity });
21401
21699
  const senderIdentityTjpAddr = getTjpAddr({ ibGib: senderIdentity });
21402
21700
  if (!senderIdentityTjpAddr) {
@@ -22680,7 +22978,7 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
22680
22978
  * **Execution Context**: **Sender (Local)**.
22681
22979
  * This method is the entry point for starting a sync saga.
22682
22980
  */
22683
- async sync({ peer, domainIbGibs, senderIdentity, fnSenderSecret, conflictStrategy = SyncConflictStrategy.abort, metaspace, localSpace }) {
22981
+ async sync({ peer, domainIbGibs, senderIdentityInfo, fnSenderSecret, conflictStrategy = SyncConflictStrategy.abort, metaspace, localSpace }) {
22684
22982
  const lc2 = `${this.lc}[${this.sync.name}]`;
22685
22983
  if (logalot58) {
22686
22984
  console.log(`${lc2} starting...`);
@@ -22689,14 +22987,22 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
22689
22987
  debugger;
22690
22988
  throw new Error(`${lc2} source (or localSpace) required (E: 25df3761f7686a1099a552f83c95d326)`);
22691
22989
  }
22692
- if (senderIdentity || fnSenderSecret) {
22693
- if (!senderIdentity) {
22694
- throw new Error(`(UNEXPECTED) senderIdentity falsy but fnSenderSecret truthy? if either is used, both must be truthy. (E: e366628a4919c7d727d2cbd8e5b75e26)`);
22990
+ if (senderIdentityInfo || fnSenderSecret) {
22991
+ if (!senderIdentityInfo) {
22992
+ throw new Error(`(UNEXPECTED) senderIdentityInfo falsy but fnSenderSecret truthy? if either is used, both must be truthy. (E: e366628a4919c7d727d2cbd8e5b75e26)`);
22695
22993
  }
22696
22994
  if (!fnSenderSecret) {
22697
- throw new Error(`(UNEXPECTED) fnSenderSecret falsy but senderIdentity truthy? if either is used, both must be truthy. (E: 7d55ce37ae482fec48e3398158161926)`);
22995
+ throw new Error(`(UNEXPECTED) fnSenderSecret falsy but senderIdentityInfo truthy? if either is used, both must be truthy. (E: 7d55ce37ae482fec48e3398158161926)`);
22996
+ }
22997
+ const { senderIdentity: senderIdentity2, senderDomainAddr: senderDomainAddr2 } = senderIdentityInfo;
22998
+ if (!senderIdentity2) {
22999
+ throw new Error(`(UNEXPECTED) senderIdentity falsy in senderIdentityInfo? if senderIdentityInfo is provided, both senderIdentity and senderDomainAddr must be truthy. (E: a3c17fae2978926d)`);
23000
+ }
23001
+ if (!senderDomainAddr2) {
23002
+ throw new Error(`(UNEXPECTED) senderDomainAddr falsy in senderIdentityInfo? if senderIdentityInfo is provided, both senderIdentity and senderDomainAddr must be truthy. (E: d288fae39b7d825c)`);
22698
23003
  }
22699
23004
  }
23005
+ const { senderIdentity, senderDomainAddr } = senderIdentityInfo ?? {};
22700
23006
  const sagaId = await getUUID();
22701
23007
  const updates$ = await newupSubject();
22702
23008
  if (!updates$.next) {
@@ -22729,6 +23035,7 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
22729
23035
  peer.setOptionalOpts({
22730
23036
  sagaId,
22731
23037
  senderIdentity,
23038
+ senderDomainAddr,
22732
23039
  fnSenderSecret,
22733
23040
  sessionConnectPoolConfig: this.defaultSessionConnectPoolConfig(),
22734
23041
  sessionSyncPoolConfig: this.defaultSessionSyncPoolConfig(),