@ibgib/space-gib 0.0.3 → 0.0.4

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 (62) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/IMPLEMENTATION.md +9 -13
  3. package/dist/client/bootstrap.mjs +1 -1
  4. package/dist/client/bootstrap.mjs.map +1 -1
  5. package/dist/client/chunk-NCXKCVYS.mjs +42 -0
  6. package/dist/client/chunk-NCXKCVYS.mjs.map +7 -0
  7. package/dist/client/chunk-ZUEU37Z5.mjs +1920 -0
  8. package/dist/client/chunk-ZUEU37Z5.mjs.map +7 -0
  9. package/dist/client/index.html +103 -5
  10. package/dist/client/index.mjs +1 -1
  11. package/dist/client/script.mjs +1 -1
  12. package/dist/client/style.css +466 -61
  13. package/dist/respec-gib.node.mjs +5 -0
  14. package/dist/server/server.mjs +294 -225
  15. package/dist/server/server.mjs.map +2 -2
  16. package/package.json +6 -6
  17. package/src/client/AUTO-GENERATED-version.mts +1 -1
  18. package/src/client/components/identity-header/IMPLEMENTATION.md +45 -0
  19. package/src/client/components/identity-header/identity-header.css +74 -0
  20. package/src/client/components/identity-header/identity-header.html +10 -0
  21. package/src/client/components/identity-header/identity-header.mts +361 -0
  22. package/src/client/components/identity-manager/IMPLEMENTATION.md +100 -0
  23. package/src/client/components/identity-manager/identity-manager.css +467 -0
  24. package/src/client/components/identity-manager/identity-manager.html +113 -0
  25. package/src/client/components/identity-manager/identity-manager.mts +767 -0
  26. package/src/client/components/keystone-creator/keystone-creator.css +2 -76
  27. package/src/client/components/keystone-creator/keystone-creator.html +41 -26
  28. package/src/client/components/keystone-creator/keystone-creator.mts +178 -41
  29. package/src/client/dev-tools/base-tools.mts +252 -0
  30. package/src/client/dev-tools/common.mts +217 -0
  31. package/src/client/dev-tools/phase-1.mts +156 -0
  32. package/src/client/dev-tools/phase-2.mts +143 -0
  33. package/src/client/dev-tools/phase-3.mts +189 -0
  34. package/src/client/dev-tools/phase-4-1.mts +197 -0
  35. package/src/client/dev-tools/phase-4-10.mts +884 -0
  36. package/src/client/dev-tools/phase-4-2.mts +388 -0
  37. package/src/client/dev-tools/phase-4-3.mts +391 -0
  38. package/src/client/dev-tools/phase-4-4.mts +374 -0
  39. package/src/client/dev-tools/phase-4-5.mts +376 -0
  40. package/src/client/dev-tools/phase-4-6.mts +273 -0
  41. package/src/client/dev-tools/phase-4-7.mts +399 -0
  42. package/src/client/dev-tools/phase-4-8.mts +430 -0
  43. package/src/client/dev-tools/phase-4-9.mts +398 -0
  44. package/src/client/dev-tools/phase-4.mts +1302 -0
  45. package/src/client/dev-tools.mts +52 -1194
  46. package/src/client/index.html +103 -5
  47. package/src/client/style.css +466 -61
  48. package/src/client/ui/shell/space-gib-shell-constants.mts +0 -2
  49. package/src/client/ui/shell/space-gib-shell-service.mts +82 -10
  50. package/src/common/common-constants.mts +0 -0
  51. package/src/common/keystone-policies.json +40 -43
  52. package/src/common/keystone-policies.mts +3 -5
  53. package/src/server/path-helper.respec.mts +99 -94
  54. package/src/server/serve-gib/README.md +9 -0
  55. package/src/server/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +1 -1
  56. package/src/server/serve-gib/handlers/api/keystone/keystone-get.respec.mts +1 -1
  57. package/src/server/serve-gib/handlers/ws/sync-upgrade-handler-base.mts +31 -3
  58. package/src/server/serve-gib/handlers/ws/ws-helper.mts +73 -45
  59. package/dist/client/chunk-2KJC5XKE.mjs +0 -31
  60. package/dist/client/chunk-2KJC5XKE.mjs.map +0 -7
  61. package/dist/client/chunk-QNIXTRFO.mjs +0 -235
  62. package/dist/client/chunk-QNIXTRFO.mjs.map +0 -7
@@ -7261,7 +7261,7 @@ async function getGraphProjection_Live({ ibGibs, ibGibAddrs, gotten, tjpAddrsAlr
7261
7261
  rel8nNames.forEach((rel8nName) => {
7262
7262
  const rel8dAddrs = rel8ns[rel8nName] ?? [];
7263
7263
  rel8dAddrs.forEach((rel8dAddr) => {
7264
- if (!rel8dAddrsNotYetGotten.includes(rel8dAddr) && !ibGibs.some((x) => getIbGibAddr({ ibGib: x }) === rel8dAddr)) {
7264
+ if (!rel8dAddrsNotYetGotten.includes(rel8dAddr) && !ibGibs.some((x) => getIbGibAddr({ ibGib: x }) === rel8dAddr) && !isPrimitive({ gib: getIbAndGib({ ibGibAddr: rel8dAddr }).gib })) {
7265
7265
  rel8dAddrsNotYetGotten.push(rel8dAddr);
7266
7266
  }
7267
7267
  });
@@ -17650,6 +17650,8 @@ var KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES = Object.values(KeystoneReplenishSt
17650
17650
  var KEYSTONE_ATOM = "keystone";
17651
17651
  var KEYSTONE_POOL_ID_REGEXP = /^\w[\w\-.]*$/;
17652
17652
  var KEYSTONE_SALT_REGEXP = /^[a-zA-Z0-9\-_]{1,64}$/;
17653
+ var KEYSTONE_USERNAME_REGEXP = /^[a-zA-Z0-9_\-.]{1,63}$/;
17654
+ var KEYSTONE_DESCRIPTION_REGEXP = /^[a-zA-Z0-9\s.,!?:;'"\-()[\]_+=@#$%&*\/]{0,128}$/;
17653
17655
  var KEYSTONE_HASH_MAX_ROUNDS = 1e3;
17654
17656
  var KEYSTONE_VERB_REVOKE = "revoke";
17655
17657
  var KEYSTONE_VERB_MANAGE = "manage";
@@ -17938,7 +17940,7 @@ async function parseKeystoneIb({ ib }) {
17938
17940
  }
17939
17941
  }
17940
17942
  }
17941
- function getDeterministicRequirements({ pool, requiredChallengeIds, targetAddr }) {
17943
+ async function getDeterministicRequirements({ pool, requiredChallengeIds, targetAddr }) {
17942
17944
  const behavior = pool.config.behavior;
17943
17945
  const mandatory = /* @__PURE__ */ new Set();
17944
17946
  let available = Object.keys(pool.challenges);
@@ -17954,19 +17956,20 @@ function getDeterministicRequirements({ pool, requiredChallengeIds, targetAddr }
17954
17956
  }
17955
17957
  available = available.filter((id) => !mandatory.has(id));
17956
17958
  }
17957
- if (behavior.targetBindingChars > 0 && targetAddr) {
17958
- const { gib } = getIbAndGib({ ibGibAddr: targetAddr });
17959
- if (gib) {
17960
- const prefixes = gib !== GIB ? gib.substring(0, behavior.targetBindingChars).toLowerCase() : "abc";
17961
- for (const char of prefixes) {
17962
- const bucket = pool.bindingMap[char] || [];
17963
- const match = bucket.find((id) => available.includes(id));
17964
- if (!match) {
17965
- throw new Error(`Entropy Exhaustion. Cannot satisfy binding for char '${char}'. (E: 341b95dc3a58be3e083d1d9c4a0c4925)`);
17966
- }
17967
- mandatory.add(match);
17968
- available = available.filter((id) => id !== match);
17959
+ if (behavior.targetBindingCount > 0 && targetAddr) {
17960
+ let sortedAvailable = [...available].sort();
17961
+ let currentHash = await hash({ s: targetAddr });
17962
+ for (let i = 0; i < behavior.targetBindingCount; i++) {
17963
+ if (sortedAvailable.length === 0) {
17964
+ throw new Error(`Entropy Exhaustion. Cannot satisfy target binding. Sorted available pool is empty. (E: 341b95dc3a58be3e083d1d9c4a0c4925)`);
17969
17965
  }
17966
+ const hashBigInt = BigInt("0x" + currentHash);
17967
+ const index = Number(hashBigInt % BigInt(sortedAvailable.length));
17968
+ const selectedId = sortedAvailable[index];
17969
+ mandatory.add(selectedId);
17970
+ sortedAvailable.splice(index, 1);
17971
+ available = available.filter((id) => id !== selectedId);
17972
+ currentHash = await hash({ s: currentHash });
17970
17973
  }
17971
17974
  }
17972
17975
  if (behavior.selectSequentially > 0) {
@@ -17980,22 +17983,6 @@ function getDeterministicRequirements({ pool, requiredChallengeIds, targetAddr }
17980
17983
  }
17981
17984
  return { mandatoryIds: mandatory, availableIds: available };
17982
17985
  }
17983
- function addToBindingMap(map, challengeId) {
17984
- const firstChar = challengeId.charAt(0).toLowerCase();
17985
- if (/[0-9a-f]/.test(firstChar)) {
17986
- if (!map[firstChar]) {
17987
- map[firstChar] = [];
17988
- }
17989
- map[firstChar].push(challengeId);
17990
- } else {
17991
- throw new Error(`invalid challengeId (${challengeId}). Must start with a hex character. (E: c96ed8460de89e28c801370a0f07f826)`);
17992
- }
17993
- }
17994
- function removeFromBindingMap(map, challengeId) {
17995
- for (const key of Object.keys(map)) {
17996
- map[key] = map[key].filter((id) => id !== challengeId);
17997
- }
17998
- }
17999
17986
  function resolveTargetPool({ pools, poolId, poolFilter, verb }) {
18000
17987
  const lc2 = `[resolveTargetPool]`;
18001
17988
  try {
@@ -18034,10 +18021,10 @@ function resolveTargetPool({ pools, poolId, poolFilter, verb }) {
18034
18021
  throw error;
18035
18022
  }
18036
18023
  }
18037
- function selectChallengeIds({ pool, targetAddr, requiredChallengeIds }) {
18024
+ async function selectChallengeIds({ pool, targetAddr, requiredChallengeIds }) {
18038
18025
  const lc2 = `[selectChallengeIds]`;
18039
18026
  try {
18040
- const { mandatoryIds, availableIds } = getDeterministicRequirements({
18027
+ const { mandatoryIds, availableIds } = await getDeterministicRequirements({
18041
18028
  pool,
18042
18029
  requiredChallengeIds,
18043
18030
  targetAddr
@@ -18073,11 +18060,6 @@ async function applyReplenishmentStrategy({ prevPools, targetPoolId, consumedIds
18073
18060
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
18074
18061
  const timestamp = Date.now().toString();
18075
18062
  const strategyType = config.behavior.replenish;
18076
- consumedIds.forEach((id) => {
18077
- if (pool.bindingMap) {
18078
- removeFromBindingMap(pool.bindingMap, id);
18079
- }
18080
- });
18081
18063
  if (strategyType === KeystoneReplenishStrategy.topUp) {
18082
18064
  consumedIds.forEach((id) => delete pool.challenges[id]);
18083
18065
  for (let i = 0; i < consumedIds.length; i++) {
@@ -18092,14 +18074,9 @@ async function applyReplenishmentStrategy({ prevPools, targetPoolId, consumedIds
18092
18074
  challengeId: newId
18093
18075
  });
18094
18076
  pool.challenges[newId] = await strategy.generateChallenge({ solution });
18095
- if (!pool.bindingMap) {
18096
- pool.bindingMap = {};
18097
- }
18098
- addToBindingMap(pool.bindingMap, newId);
18099
18077
  }
18100
18078
  } else if (strategyType === KeystoneReplenishStrategy.replaceAll) {
18101
18079
  pool.challenges = {};
18102
- pool.bindingMap = {};
18103
18080
  for (let i = 0; i < config.behavior.size; i++) {
18104
18081
  const newId = await generateOpaqueChallengeId({
18105
18082
  salt: config.salt,
@@ -18112,13 +18089,11 @@ async function applyReplenishmentStrategy({ prevPools, targetPoolId, consumedIds
18112
18089
  challengeId: newId
18113
18090
  });
18114
18091
  pool.challenges[newId] = await strategy.generateChallenge({ solution });
18115
- addToBindingMap(pool.bindingMap, newId);
18116
18092
  }
18117
18093
  } else if (strategyType === KeystoneReplenishStrategy.consume) {
18118
18094
  consumedIds.forEach((id) => delete pool.challenges[id]);
18119
18095
  } else if (strategyType === KeystoneReplenishStrategy.deleteAll) {
18120
18096
  pool.challenges = {};
18121
- pool.bindingMap = {};
18122
18097
  } else {
18123
18098
  throw new Error(`Unknown replenish strategy: ${strategyType}. Valid list: ${pretty(KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES)} (E: 0acf56f1e1486240080e11e8046d0825)`);
18124
18099
  }
@@ -18230,10 +18205,14 @@ async function validateChallengePool({ pool }) {
18230
18205
  errors.push(`${lc2} pool.config.id falsy (E: 31d7943d95f877326d5f4ea14463d626)`);
18231
18206
  }
18232
18207
  if (pool.config.behavior) {
18233
- const { size } = pool.config.behavior;
18208
+ const { size, selectSequentially, selectRandomly, targetBindingCount } = pool.config.behavior;
18234
18209
  if (!size || size === 0) {
18235
18210
  errors.push(`${lc2} invalid pool.config.behavior.size (${size}). Must be positive integer. (E: b221e36ec102bdc944552248ce8fe626)`);
18236
18211
  }
18212
+ const totalRequested = (selectSequentially || 0) + (selectRandomly || 0) + (targetBindingCount || 0);
18213
+ if (totalRequested >= size) {
18214
+ errors.push(`${lc2} Total requested challenges (${totalRequested}) cannot equal or exceed pool size (${size}) to prevent full pool exposure and selection exhaustion. (E: 81cb834f826315264bca81c15fca58f1)`);
18215
+ }
18237
18216
  } else {
18238
18217
  errors.push(`${lc2} pool.config.behavior falsy (E: bede081c066c39732eefe2f92e296326)`);
18239
18218
  }
@@ -18259,6 +18238,27 @@ async function validateChallengePool({ pool }) {
18259
18238
  }
18260
18239
  }
18261
18240
  }
18241
+ function validateKeystoneMetadata({ data }) {
18242
+ const lc2 = `[validateKeystoneMetadata]`;
18243
+ const errors = [];
18244
+ const checkDetails = (details, source) => {
18245
+ if (!details)
18246
+ return;
18247
+ if (details.username !== void 0) {
18248
+ if (typeof details.username !== "string" || !KEYSTONE_USERNAME_REGEXP.test(details.username)) {
18249
+ errors.push(`${lc2} invalid username in ${source} (${details.username}). Must match ${KEYSTONE_USERNAME_REGEXP}`);
18250
+ }
18251
+ }
18252
+ if (details.description !== void 0) {
18253
+ if (typeof details.description !== "string" || !KEYSTONE_DESCRIPTION_REGEXP.test(details.description)) {
18254
+ errors.push(`${lc2} invalid description in ${source} (${details.description}). Must match ${KEYSTONE_DESCRIPTION_REGEXP}`);
18255
+ }
18256
+ }
18257
+ };
18258
+ checkDetails(data.frameDetails, "frameDetails");
18259
+ checkDetails(data.checkpointDetails, "checkpointDetails");
18260
+ return errors;
18261
+ }
18262
18262
  async function validateGenesisKeystone({ keystoneIbGib }) {
18263
18263
  const lc2 = `[${validateGenesisKeystone.name}]`;
18264
18264
  try {
@@ -18267,6 +18267,8 @@ async function validateGenesisKeystone({ keystoneIbGib }) {
18267
18267
  }
18268
18268
  const errors = [];
18269
18269
  const { data, rel8ns } = keystoneIbGib;
18270
+ const metadataErrors = validateKeystoneMetadata({ data });
18271
+ metadataErrors.forEach((x) => errors.push(x));
18270
18272
  if (data.proofs && data.proofs.length > 0) {
18271
18273
  errors.push(`${lc2} proofs already exist on genesis keystone. (E: 7a5e15f20918f1bbd8ffb62857dcd526)`);
18272
18274
  }
@@ -18306,6 +18308,8 @@ async function validateKeystoneTransition({ currentIbGib, prevIbGib }) {
18306
18308
  }
18307
18309
  const currData = currentIbGib.data;
18308
18310
  const prevData = prevIbGib.data;
18311
+ const metadataErrors = validateKeystoneMetadata({ data: currData });
18312
+ metadataErrors.forEach((x) => errors.push(x));
18309
18313
  const currDataN = currData.n ?? -2;
18310
18314
  const prevDataN = prevData.n ?? -2;
18311
18315
  if (currDataN < 0) {
@@ -18359,7 +18363,7 @@ async function verifyProofAgainstPool({ proof, pool, errors }) {
18359
18363
  errors.push(`Policy Violation: Pool ${pool.id} used for unauthorized verb ${proof.claim.verb}`);
18360
18364
  }
18361
18365
  }
18362
- const { mandatoryIds, availableIds } = getDeterministicRequirements({
18366
+ const { mandatoryIds, availableIds } = await getDeterministicRequirements({
18363
18367
  pool,
18364
18368
  requiredChallengeIds: proof.requiredChallengeIds,
18365
18369
  targetAddr: proof.claim.target
@@ -18641,7 +18645,6 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18641
18645
  const strategy = KeystoneStrategyFactory.create({ config });
18642
18646
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
18643
18647
  const challenges = {};
18644
- const bindingMap = {};
18645
18648
  const targetSize = config.behavior.size;
18646
18649
  const timestamp = Date.now().toString();
18647
18650
  for (let i = 0; i < targetSize; i++) {
@@ -18657,13 +18660,11 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18657
18660
  });
18658
18661
  const challenge = await strategy.generateChallenge({ solution });
18659
18662
  challenges[challengeId] = challenge;
18660
- addToBindingMap(bindingMap, challengeId);
18661
18663
  }
18662
18664
  challengePools.push({
18663
18665
  id: config.id,
18664
18666
  config,
18665
- challenges,
18666
- bindingMap
18667
+ challenges
18667
18668
  });
18668
18669
  }
18669
18670
  if (challengePools.length === 0) {
@@ -18712,7 +18713,7 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18712
18713
  if (logalot41) {
18713
18714
  console.log(`${lc2} Selected pool: ${pool.id} (size: ${Object.keys(pool.challenges).length}) (I: 6b26d6f4aad18380f2b3a0989b592826)`);
18714
18715
  }
18715
- const idsToSolve = selectChallengeIds({
18716
+ const idsToSolve = await selectChallengeIds({
18716
18717
  pool,
18717
18718
  targetAddr: claim.target,
18718
18719
  requiredChallengeIds
@@ -18870,7 +18871,7 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18870
18871
  verb: KEYSTONE_VERB_REVOKE,
18871
18872
  target: getIbGibAddr({ ibGib: latestKeystone })
18872
18873
  };
18873
- const idsToSolve = selectChallengeIds({
18874
+ const idsToSolve = await selectChallengeIds({
18874
18875
  pool,
18875
18876
  targetAddr: claim.target,
18876
18877
  requiredChallengeIds: []
@@ -18966,7 +18967,7 @@ var KeystoneService_V1 = class _KeystoneService_V1 {
18966
18967
  // Scope creates a cryptographic commitment to WHICH pools are being added
18967
18968
  scope: JSON.stringify({ add: newPools.map((p) => p.id) })
18968
18969
  };
18969
- const idsToSolve = selectChallengeIds({
18970
+ const idsToSolve = await selectChallengeIds({
18970
18971
  pool: adminPool,
18971
18972
  targetAddr: target
18972
18973
  });
@@ -19080,7 +19081,7 @@ var SESSION_KEYSTONE_POLICY = {
19080
19081
  SIZE: 10,
19081
19082
  SELECT_SEQUENTIALLY: 2,
19082
19083
  SELECT_RANDOMLY: 2,
19083
- TARGET_BINDING_CHARS: 0,
19084
+ TARGET_BINDING_COUNT: 0,
19084
19085
  SERVER_DEMAND_COUNT: 3
19085
19086
  }
19086
19087
  };
@@ -19245,8 +19246,10 @@ async function validateAndRegisterEvolveKeystone({ domainAddr, keystoneIbGib, re
19245
19246
  if (intrinsicErrors && intrinsicErrors.length > 0) {
19246
19247
  throw new Error(`Intrinsic keystone validation failed: ${intrinsicErrors.join(", ")} (E: 38ea984585edc6ee88d2a698c7895826)`);
19247
19248
  }
19248
- const { tjpGib } = getGibInfo({ ibGibAddr: addr });
19249
- const expectedTjpGib = getGibInfo({ ibGibAddr: domainAddr }).punctiliarHash;
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;
19250
19253
  if (tjpGib !== expectedTjpGib) {
19251
19254
  throw new Error(`Keystone tjpGib (${tjpGib}) does not match URL domainAddr tjpGib (${expectedTjpGib})`);
19252
19255
  }
@@ -19579,9 +19582,6 @@ var KeystoneGenesisHandler = class _KeystoneGenesisHandler extends ServeGibHandl
19579
19582
  await metaspace.put({ ibGibs: [keystoneIbGib], space });
19580
19583
  await metaspace.registerNewIbGib({ ibGib: keystoneIbGib, space });
19581
19584
  console.log(`${lc2} domain created and keystone persisted: ${addr}`);
19582
- if (logalot45) {
19583
- console.log(`${lc2} keystoneIbGib: ${pretty(keystoneIbGib)} (I: d598c6ff7a48997d585b84c19c464826)`);
19584
- }
19585
19585
  return this.ok({ success: true, addr }, 201);
19586
19586
  } catch (error) {
19587
19587
  const emsg = extractErrorMsg(error);
@@ -19820,64 +19820,82 @@ function performConnect(req, socket) {
19820
19820
  }
19821
19821
  var WebSocketFrameDecoder = class {
19822
19822
  buffer = Buffer.alloc(0);
19823
+ fragments = [];
19823
19824
  /** Adds new data chunk from TCP socket. */
19824
19825
  addChunk(chunk) {
19825
19826
  this.buffer = Buffer.concat([this.buffer, chunk]);
19826
19827
  }
19827
19828
  /**
19828
- * Parses the next complete text frame from the accumulated buffer.
19829
+ * Parses the next complete text message, assembling fragments if necessary.
19829
19830
  * Returns:
19830
- * - `string` if a complete text frame was decoded successfully (and consumes those bytes).
19831
+ * - `string` if a complete text message was assembled/decoded (and consumes those bytes).
19831
19832
  * - `null` if the buffer is incomplete or we need more data.
19832
19833
  * - `throws Error` on protocol errors or close frames.
19833
19834
  */
19834
19835
  nextFrame() {
19835
- if (this.buffer.length < 2) {
19836
- return null;
19837
- }
19838
- const opcode = this.buffer[0] & 15;
19839
- if (opcode === 8) {
19840
- throw new Error("Close frame received");
19841
- }
19842
- if (opcode !== 1) {
19843
- throw new Error(`Unsupported WebSocket opcode: 0x${opcode.toString(16)}`);
19844
- }
19845
- const secondByte = this.buffer[1];
19846
- const masked = (secondByte & 128) !== 0;
19847
- let payloadLen = secondByte & 127;
19848
- let headerLen = 2;
19849
- if (payloadLen === 126) {
19850
- if (this.buffer.length < 4) {
19836
+ while (true) {
19837
+ if (this.buffer.length < 2) {
19851
19838
  return null;
19852
19839
  }
19853
- payloadLen = this.buffer.readUInt16BE(2);
19854
- headerLen = 4;
19855
- } else if (payloadLen === 127) {
19856
- if (this.buffer.length < 10) {
19840
+ const firstByte = this.buffer[0];
19841
+ const fin = (firstByte & 128) !== 0;
19842
+ const opcode = firstByte & 15;
19843
+ if (opcode === 8) {
19844
+ throw new Error("Close frame received");
19845
+ }
19846
+ const isContinuation = opcode === 0;
19847
+ const isText = opcode === 1;
19848
+ if (!isContinuation && !isText) {
19849
+ throw new Error(`Unsupported WebSocket opcode: 0x${opcode.toString(16)}`);
19850
+ }
19851
+ if (isContinuation && this.fragments.length === 0) {
19852
+ throw new Error("Continuation frame received without an active message.");
19853
+ }
19854
+ if (isText && this.fragments.length > 0) {
19855
+ throw new Error("New message frame received before previous one completed.");
19856
+ }
19857
+ const secondByte = this.buffer[1];
19858
+ const masked = (secondByte & 128) !== 0;
19859
+ let payloadLen = secondByte & 127;
19860
+ let headerLen = 2;
19861
+ if (payloadLen === 126) {
19862
+ if (this.buffer.length < 4) {
19863
+ return null;
19864
+ }
19865
+ payloadLen = this.buffer.readUInt16BE(2);
19866
+ headerLen = 4;
19867
+ } else if (payloadLen === 127) {
19868
+ if (this.buffer.length < 10) {
19869
+ return null;
19870
+ }
19871
+ payloadLen = Number(this.buffer.readBigUInt64BE(2));
19872
+ headerLen = 10;
19873
+ }
19874
+ const maskLen = masked ? 4 : 0;
19875
+ const totalFrameLen = headerLen + maskLen + payloadLen;
19876
+ if (this.buffer.length < totalFrameLen) {
19857
19877
  return null;
19858
19878
  }
19859
- payloadLen = Number(this.buffer.readBigUInt64BE(2));
19860
- headerLen = 10;
19861
- }
19862
- const maskLen = masked ? 4 : 0;
19863
- const totalFrameLen = headerLen + maskLen + payloadLen;
19864
- if (this.buffer.length < totalFrameLen) {
19865
- return null;
19866
- }
19867
- const frameData = this.buffer.subarray(0, totalFrameLen);
19868
- this.buffer = this.buffer.subarray(totalFrameLen);
19869
- let payloadStart = headerLen;
19870
- if (masked) {
19871
- const mask = frameData.subarray(payloadStart, payloadStart + 4);
19872
- payloadStart += 4;
19873
- const payload = Buffer.from(frameData.subarray(payloadStart));
19874
- for (let i = 0; i < payload.length; i++) {
19875
- payload[i] ^= mask[i % 4];
19876
- }
19877
- return payload.toString("utf-8");
19878
- } else {
19879
- const payload = frameData.subarray(payloadStart);
19880
- return payload.toString("utf-8");
19879
+ const frameData = this.buffer.subarray(0, totalFrameLen);
19880
+ this.buffer = this.buffer.subarray(totalFrameLen);
19881
+ let payloadStart = headerLen;
19882
+ let payload;
19883
+ if (masked) {
19884
+ const mask = frameData.subarray(payloadStart, payloadStart + 4);
19885
+ payloadStart += 4;
19886
+ payload = Buffer.from(frameData.subarray(payloadStart));
19887
+ for (let i = 0; i < payload.length; i++) {
19888
+ payload[i] ^= mask[i % 4];
19889
+ }
19890
+ } else {
19891
+ payload = Buffer.from(frameData.subarray(payloadStart));
19892
+ }
19893
+ this.fragments.push(payload);
19894
+ if (fin) {
19895
+ const completePayload = Buffer.concat(this.fragments);
19896
+ this.fragments = [];
19897
+ return completePayload.toString("utf-8");
19898
+ }
19881
19899
  }
19882
19900
  }
19883
19901
  };
@@ -20063,12 +20081,10 @@ async function applyTransforms({ src, createdIbGibs_Running, dnaAddrsToApplyToSt
20063
20081
  const dnaAddrToApply = dnaAddrsToApplyToStoreVersion_MUTATES_IN_PLACE.splice(0, 1)[0];
20064
20082
  const dnaIbGib_IntermediateArray = allLocalIbGibs.filter((x) => getIbGibAddr({ ibGib: x }) === dnaAddrToApply);
20065
20083
  let dnaIbGib;
20066
- if (dnaIbGib_IntermediateArray.length === 1) {
20084
+ if (dnaIbGib_IntermediateArray.length > 0) {
20067
20085
  dnaIbGib = dnaIbGib_IntermediateArray[0];
20068
- } else if (dnaIbGib_IntermediateArray.length === 0) {
20069
- throw new Error(`dna ibGib not found in supplied allLocalIbGibs. dnaAddr: ${dnaAddrToApply}. (E: 7f56826852cf48a79ab8af16bf27e284)`);
20070
20086
  } else {
20071
- throw new Error(`More than one ibGib in allLocalIbGibs with the dna address of ${dnaAddrToApply}? (E: a726134f4cc14a4fb2ed2d39d22af17c)(UNEXPECTED)`);
20087
+ throw new Error(`dna ibGib not found in supplied allLocalIbGibs. dnaAddr: ${dnaAddrToApply}. (E: 7f56826852cf48a79ab8af16bf27e284)`);
20072
20088
  }
20073
20089
  let argTransform = clone(dnaIbGib.data);
20074
20090
  argTransform.src = src;
@@ -21666,6 +21682,7 @@ var SyncPeerWebSocketReceiver_V1 = class _SyncPeerWebSocketReceiver_V1 extends S
21666
21682
  pendingContext;
21667
21683
  pendingPayloadAddrs;
21668
21684
  pendingResponsePayloadsToSend = [];
21685
+ receivedPayloads = [];
21669
21686
  constructor(initialData, initialRel8ns) {
21670
21687
  super(initialData, initialRel8ns);
21671
21688
  }
@@ -21764,14 +21781,18 @@ var SyncPeerWebSocketReceiver_V1 = class _SyncPeerWebSocketReceiver_V1 extends S
21764
21781
  if (validationErrors.length > 0) {
21765
21782
  throw new Error(`controlIbGibs invalid intrinsically. validationErrors: ${validationErrors.join("|")} (E: 5ee1787d4cc53d3d2c55f3d4f2865226)`);
21766
21783
  }
21767
- if (this.pendingContext && this.pendingPayloadAddrs) {
21784
+ const pendingPayloadAddrs = this.pendingPayloadAddrs;
21785
+ if (this.pendingContext && pendingPayloadAddrs) {
21768
21786
  const addr = getIbGibAddr({ ibGib });
21769
- if (this.pendingPayloadAddrs.has(addr)) {
21787
+ if (pendingPayloadAddrs.has(addr)) {
21770
21788
  const tempSpace = await this.ensureLocalTempSpace();
21771
21789
  await putInSpace({ space: tempSpace, ibGibs: [ibGib] });
21772
- this.pendingPayloadAddrs.delete(addr);
21773
- if (this.pendingPayloadAddrs.size === 0) {
21790
+ this.receivedPayloads.push(ibGib);
21791
+ pendingPayloadAddrs.delete(addr);
21792
+ if (pendingPayloadAddrs.size === 0 && this.pendingPayloadAddrs !== void 0) {
21774
21793
  const context = this.pendingContext;
21794
+ context.payloadIbGibsDomain = this.receivedPayloads;
21795
+ this.receivedPayloads = [];
21775
21796
  this.pendingContext = void 0;
21776
21797
  this.pendingPayloadAddrs = void 0;
21777
21798
  await this.executeIncomingSyncRequestAndRespond({ context });
@@ -21805,6 +21826,7 @@ var SyncPeerWebSocketReceiver_V1 = class _SyncPeerWebSocketReceiver_V1 extends S
21805
21826
  if (expectedPayloadAddrs.length > 0) {
21806
21827
  this.pendingContext = context;
21807
21828
  this.pendingPayloadAddrs = new Set(expectedPayloadAddrs);
21829
+ this.receivedPayloads = [];
21808
21830
  this.socketWrapper.send(JSON.stringify({
21809
21831
  type: SyncWebSocketMsgType.sync_frame_authenticated,
21810
21832
  contextAddr: getIbGibAddr({ ibGib: context })
@@ -21821,6 +21843,8 @@ var SyncPeerWebSocketReceiver_V1 = class _SyncPeerWebSocketReceiver_V1 extends S
21821
21843
  ibGib
21822
21844
  }));
21823
21845
  }
21846
+ } else {
21847
+ throw new Error(`(UNEXPECTED) msg.type is ${msg.type}? not expected at this time (E: bad7c4fa1958b1976904cb884e624826)`);
21824
21848
  }
21825
21849
  } catch (error) {
21826
21850
  console.error(`${lc2} message frame handling failed: ${extractErrorMsg(error)}`);
@@ -22042,7 +22066,7 @@ async function appendToTimeline({ timeline, rel8nInfos, rel8nRemovalInfos, timel
22042
22066
  skipLock
22043
22067
  });
22044
22068
  }
22045
- metaspace.registerNewIbGib({ ibGib: newTimelineIbGib2, space });
22069
+ await metaspace.registerNewIbGib({ ibGib: newTimelineIbGib2, space });
22046
22070
  return newTimelineIbGib2;
22047
22071
  };
22048
22072
  const newTimelineIbGib = skipLock ? await fn() : await execInSpaceWithLocking({
@@ -22509,7 +22533,7 @@ var KeystoneConfigBuilderBase = class {
22509
22533
  replenish: this._replenish,
22510
22534
  selectSequentially: this._seq,
22511
22535
  selectRandomly: this._rand,
22512
- targetBindingChars: this._targetBinding
22536
+ targetBindingCount: this._targetBinding
22513
22537
  };
22514
22538
  }
22515
22539
  /**
@@ -22858,112 +22882,116 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
22858
22882
  await subscription.unsubscribe();
22859
22883
  }
22860
22884
  }));
22861
- const requestCtx = await this.createSyncSagaContext({
22862
- sagaFrame: currentFrame,
22863
- /**
22864
- * init frame: empty
22865
- * ack frame: possible push offers
22866
- * delta frame: requested ibgibs or commit offer
22867
- * commit frame: empty
22868
- */
22869
- payloadIbGibsDomain: nextDomainIbGibs,
22870
- localSpace,
22871
- metaspace,
22872
- sessionIdentityAddr: peer.currentSessionIdentityAddr,
22873
- peer
22874
- });
22875
- if (logalotControlDomain) {
22876
- const domainAddrs = nextDomainIbGibs.map((p) => getIbGibAddr({ ibGib: p }));
22877
- console.log(`${lc2}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: 5b0081803698770f0bf64992220b312)`);
22878
- console.log(`${lc2}${lcControlDomain} Context: ${getIbGibAddr({ ibGib: requestCtx })}`);
22879
- console.log(`${lc2}${lcControlDomain} Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
22880
- console.log(`${lc2}${lcControlDomain} DOMAIN Payloads (${domainAddrs.length}): ${domainAddrs.join(", ") || "(none)"}`);
22881
- }
22882
- updates$.next(requestCtx);
22883
- peer.setOptionalOpts({ localSpace, localTempSpace: tempSpace });
22884
- const responseCtx = await peer.witness(requestCtx);
22885
- if (!responseCtx) {
22886
- if (currentFrame) {
22887
- const msg = await getSyncSagaMessageFromFrame({ frameIbGib: currentFrame, space: localSpace });
22888
- if (msg?.data?.stage === SyncStage.commit) {
22889
- if (logalot58) {
22890
- console.log(`${lc2} Sender sent Commit. Peer returned no response. Saga Complete. (I: 26f9ee073858ca78b8284753368b5226)`);
22885
+ try {
22886
+ const requestCtx = await this.createSyncSagaContext({
22887
+ sagaFrame: currentFrame,
22888
+ /**
22889
+ * init frame: empty
22890
+ * ack frame: possible push offers
22891
+ * delta frame: requested ibgibs or commit offer
22892
+ * commit frame: empty
22893
+ */
22894
+ payloadIbGibsDomain: nextDomainIbGibs,
22895
+ localSpace,
22896
+ metaspace,
22897
+ sessionIdentityAddr: peer.currentSessionIdentityAddr,
22898
+ peer
22899
+ });
22900
+ if (logalotControlDomain) {
22901
+ const domainAddrs = nextDomainIbGibs.map((p) => getIbGibAddr({ ibGib: p }));
22902
+ console.log(`${lc2}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: 5b0081803698770f0bf64992220b312)`);
22903
+ console.log(`${lc2}${lcControlDomain} Context: ${getIbGibAddr({ ibGib: requestCtx })}`);
22904
+ console.log(`${lc2}${lcControlDomain} Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
22905
+ console.log(`${lc2}${lcControlDomain} DOMAIN Payloads (${domainAddrs.length}): ${domainAddrs.join(", ") || "(none)"}`);
22906
+ }
22907
+ updates$.next(requestCtx);
22908
+ peer.setOptionalOpts({ localSpace, localTempSpace: tempSpace });
22909
+ const responseCtx = await peer.witness(requestCtx);
22910
+ if (!responseCtx) {
22911
+ if (currentFrame) {
22912
+ const msg = await getSyncSagaMessageFromFrame({ frameIbGib: currentFrame, space: localSpace });
22913
+ if (msg?.data?.stage === SyncStage.commit) {
22914
+ if (logalot58) {
22915
+ console.log(`${lc2} Sender sent Commit. Peer returned no response. Saga Complete. (I: 26f9ee073858ca78b8284753368b5226)`);
22916
+ }
22917
+ currentFrame = null;
22918
+ break;
22919
+ } else {
22920
+ throw new Error(`(UNEXPECTED) responseCtx falsy and currentFrame truthy, but we're not in the commit stage? This may be expected ultimately, but atow I am not seeing this as being expected. (E: cc34498962bd370deeff351fac939f26)`);
22891
22921
  }
22892
- currentFrame = null;
22893
- break;
22894
22922
  } else {
22895
- throw new Error(`(UNEXPECTED) responseCtx falsy and currentFrame truthy, but we're not in the commit stage? This may be expected ultimately, but atow I am not seeing this as being expected. (E: cc34498962bd370deeff351fac939f26)`);
22923
+ throw new Error(`(UNEXPECTED) no response and currentFrame falsy? (E: 8d1085ea2f28cfc3f9c922649864a826)`);
22896
22924
  }
22897
- } else {
22898
- throw new Error(`(UNEXPECTED) no response and currentFrame falsy? (E: 8d1085ea2f28cfc3f9c922649864a826)`);
22899
22925
  }
22900
- }
22901
- if (!responseCtx.data) {
22902
- throw new Error(`(UNEXPECTED) responseCtx.data falsy? (E: a969992bae53ab18a827ec58aec15826)`);
22903
- }
22904
- updates$.next(responseCtx);
22905
- const contextAndSagaFrameValidationErrors = await validateContextAndSagaFrame({ context: responseCtx });
22906
- if (contextAndSagaFrameValidationErrors.length > 0) {
22907
- throw new Error(`contextAndSagaFrameValidationErrors: ${contextAndSagaFrameValidationErrors} (E: 6eebe8e7fa437c00a8cde3ada3c66826)`);
22908
- }
22909
- const returnContextErrors = await this.validateReturnContext({
22910
- requestCtx,
22911
- responseCtx,
22912
- localSpace
22913
- });
22914
- if (returnContextErrors.length > 0) {
22915
- throw new Error(`validateReturnContext errors: ${returnContextErrors.join(", ")} (E: cb8a023b9d0728cceb09fa3da0bb8226)`);
22916
- }
22917
- const responsePayloadAddrsDomain = responseCtx.data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] || [];
22918
- if (responsePayloadAddrsDomain.length > 0) {
22919
- responseCtx.payloadIbGibsDomain = await this.pollForDomainPayloads({
22920
- expectedAddrs: responsePayloadAddrsDomain,
22921
- pollIntervalMs: 20,
22922
- // relatively arbitrary right now
22923
- domainPayloadsMap,
22924
- tempSpace
22926
+ if (!responseCtx.data) {
22927
+ throw new Error(`(UNEXPECTED) responseCtx.data falsy? (E: a969992bae53ab18a827ec58aec15826)`);
22928
+ }
22929
+ updates$.next(responseCtx);
22930
+ const contextAndSagaFrameValidationErrors = await validateContextAndSagaFrame({ context: responseCtx });
22931
+ if (contextAndSagaFrameValidationErrors.length > 0) {
22932
+ throw new Error(`contextAndSagaFrameValidationErrors: ${contextAndSagaFrameValidationErrors} (E: 6eebe8e7fa437c00a8cde3ada3c66826)`);
22933
+ }
22934
+ const returnContextErrors = await this.validateReturnContext({
22935
+ requestCtx,
22936
+ responseCtx,
22937
+ localSpace
22925
22938
  });
22926
- }
22927
- if (!responseCtx.sagaFrame) {
22928
- throw new Error(`(UNEXPECTED) responseCtx.sagaFrame falsy? the Peer should have set this when it got the response back from the remote. (E: e650adadf9a2063ec6764a1e31d3d826)`);
22929
- }
22930
- if (logalotControlDomain) {
22931
- const responseControlAddrs = responseCtx.data?.["@payloadAddrsControl"] || [];
22932
- console.log(`${lc2}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: 3dc76a9744d89a4fc3e2f076c2be4826)`);
22933
- console.log(`${lc2}${lcControlDomain} Response Context: ${getIbGibAddr({ ibGib: responseCtx })}`);
22934
- console.log(`${lc2}${lcControlDomain} Response Saga Frame: ${getIbGibAddr({ ibGib: responseCtx.sagaFrame })}`);
22935
- console.log(`${lc2}${lcControlDomain} CONTROL Payloads (${responseControlAddrs.length}): ${responseControlAddrs.join(", ") || "(none)"}`);
22936
- console.log(`${lc2}${lcControlDomain} DOMAIN Payloads (${responsePayloadAddrsDomain.length}): ${responsePayloadAddrsDomain.join(", ") || "(none)"}`);
22937
- }
22938
- const contextResult = await this.handleResponseSagaContext({
22939
- sagaContext: responseCtx,
22940
- initDomainGraph,
22941
- mySpace: localSpace,
22942
- myTempSpace: tempSpace,
22943
- metaspace
22944
- });
22945
- if (!contextResult) {
22946
- console.error(`${lc2} NAG ERROR (DOES NOT THROW): does this ever hit now? (E: e04d02efc2a8e72a88b79f1f0f95ca26)`);
22947
- break;
22948
- } else if (contextResult.nextFrameInfo?.sagaComplete) {
22949
- if (logalot58) {
22950
- console.log(`${lc2} Handler returned null (Saga End). (I: 123bf9e7dca8886de72553a8d4f29e26)`);
22939
+ if (returnContextErrors.length > 0) {
22940
+ throw new Error(`validateReturnContext errors: ${returnContextErrors.join(", ")} (E: cb8a023b9d0728cceb09fa3da0bb8226)`);
22941
+ }
22942
+ const responsePayloadAddrsDomain = responseCtx.data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] || [];
22943
+ if (responsePayloadAddrsDomain.length > 0) {
22944
+ responseCtx.payloadIbGibsDomain = await this.pollForDomainPayloads({
22945
+ expectedAddrs: responsePayloadAddrsDomain,
22946
+ pollIntervalMs: 20,
22947
+ // relatively arbitrary right now
22948
+ domainPayloadsMap,
22949
+ tempSpace
22950
+ });
22951
22951
  }
22952
- break;
22953
- }
22954
- if (contextResult.errorMsg) {
22955
- throw new Error(`Couldn't handle response saga context. errorMsg: ${contextResult.errorMsg} (E: c948e81d513b2a0eb8b8afa878edc626)`);
22956
- } else if (!contextResult.nextFrameInfo) {
22957
- throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
22958
- }
22959
- const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
22960
- currentFrame = frame;
22961
- nextDomainIbGibs = [...payloadIbGibsDomain || []];
22962
- if (logalotControlDomain) {
22963
- const handlerDomainAddrs = nextDomainIbGibs.map((p) => getIbGibAddr({ ibGib: p }));
22964
- console.log(`${lc2}${lcControlDomain} HANDLER RESULT -> next iteration (I: 6b0d88c4c28857ccd812381515bd7826)`);
22965
- console.log(`${lc2}${lcControlDomain} Next Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
22966
- console.log(`${lc2}${lcControlDomain} DOMAIN for next (${handlerDomainAddrs.length}): ${handlerDomainAddrs.join(", ") || "(none)"}`);
22952
+ if (!responseCtx.sagaFrame) {
22953
+ throw new Error(`(UNEXPECTED) responseCtx.sagaFrame falsy? the Peer should have set this when it got the response back from the remote. (E: e650adadf9a2063ec6764a1e31d3d826)`);
22954
+ }
22955
+ if (logalotControlDomain) {
22956
+ const responseControlAddrs = responseCtx.data?.["@payloadAddrsControl"] || [];
22957
+ console.log(`${lc2}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: 3dc76a9744d89a4fc3e2f076c2be4826)`);
22958
+ console.log(`${lc2}${lcControlDomain} Response Context: ${getIbGibAddr({ ibGib: responseCtx })}`);
22959
+ console.log(`${lc2}${lcControlDomain} Response Saga Frame: ${getIbGibAddr({ ibGib: responseCtx.sagaFrame })}`);
22960
+ console.log(`${lc2}${lcControlDomain} CONTROL Payloads (${responseControlAddrs.length}): ${responseControlAddrs.join(", ") || "(none)"}`);
22961
+ console.log(`${lc2}${lcControlDomain} DOMAIN Payloads (${responsePayloadAddrsDomain.length}): ${responsePayloadAddrsDomain.join(", ") || "(none)"}`);
22962
+ }
22963
+ const contextResult = await this.handleResponseSagaContext({
22964
+ sagaContext: responseCtx,
22965
+ initDomainGraph,
22966
+ mySpace: localSpace,
22967
+ myTempSpace: tempSpace,
22968
+ metaspace
22969
+ });
22970
+ if (!contextResult) {
22971
+ console.error(`${lc2} NAG ERROR (DOES NOT THROW): does this ever hit now? (E: e04d02efc2a8e72a88b79f1f0f95ca26)`);
22972
+ break;
22973
+ } else if (contextResult.nextFrameInfo?.sagaComplete) {
22974
+ if (logalot58) {
22975
+ console.log(`${lc2} Handler returned null (Saga End). (I: 123bf9e7dca8886de72553a8d4f29e26)`);
22976
+ }
22977
+ break;
22978
+ }
22979
+ if (contextResult.errorMsg) {
22980
+ throw new Error(`Couldn't handle response saga context. errorMsg: ${contextResult.errorMsg} (E: c948e81d513b2a0eb8b8afa878edc626)`);
22981
+ } else if (!contextResult.nextFrameInfo) {
22982
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
22983
+ }
22984
+ const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
22985
+ currentFrame = frame;
22986
+ nextDomainIbGibs = [...payloadIbGibsDomain || []];
22987
+ if (logalotControlDomain) {
22988
+ const handlerDomainAddrs = nextDomainIbGibs.map((p) => getIbGibAddr({ ibGib: p }));
22989
+ console.log(`${lc2}${lcControlDomain} HANDLER RESULT -> next iteration (I: 6b0d88c4c28857ccd812381515bd7826)`);
22990
+ console.log(`${lc2}${lcControlDomain} Next Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
22991
+ console.log(`${lc2}${lcControlDomain} DOMAIN for next (${handlerDomainAddrs.length}): ${handlerDomainAddrs.join(", ") || "(none)"}`);
22992
+ }
22993
+ } finally {
22994
+ await subscription.unsubscribe();
22967
22995
  }
22968
22996
  }
22969
22997
  }
@@ -23233,7 +23261,8 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
23233
23261
  console.log(`${lc2} starting... (I: 26dce86bfca572939885798802d6e926)`);
23234
23262
  }
23235
23263
  let resultDomainPayloads = [];
23236
- let pending = [...expectedAddrs];
23264
+ const uniqueExpectedAddrs = [...new Set(expectedAddrs)];
23265
+ let pending = [...uniqueExpectedAddrs];
23237
23266
  const start = Date.now();
23238
23267
  const timeoutMs = 5 * 60 * 1e3;
23239
23268
  while (pending.length > 0) {
@@ -23259,8 +23288,8 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
23259
23288
  await delay(pollIntervalMs);
23260
23289
  }
23261
23290
  }
23262
- if (expectedAddrs.length !== resultDomainPayloads.length) {
23263
- throw new Error(`(UNEXPECTED) expectedAddrs.length !== resultDomainPayloads.length? at this point, we expect all of the payload ibgibs to have been received. (E: 03749a7478c4b8b28bfc86951887a826)`);
23291
+ if (uniqueExpectedAddrs.length !== resultDomainPayloads.length) {
23292
+ throw new Error(`(UNEXPECTED) uniqueExpectedAddrs.length !== resultDomainPayloads.length? at this point, we expect all of the payload ibgibs to have been received. (E: 03749a7478c4b8b28bfc86951887a826)`);
23264
23293
  }
23265
23294
  return resultDomainPayloads;
23266
23295
  } catch (error) {
@@ -23710,11 +23739,11 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
23710
23739
  throw new Error(`${lc2} Peer reported terminal conflicts. (E: 23a0096ee05a2ccfa89334e8f156b426)`);
23711
23740
  }
23712
23741
  const outgoingPayloadIbGibsDomain_conflicts = [];
23742
+ const activeConflicts = [];
23713
23743
  if (conflicts.length > 0) {
23714
23744
  if (logalot58) {
23715
23745
  console.log(`${lc2} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
23716
23746
  }
23717
- proposeCommit = false;
23718
23747
  for (const conflict of conflicts) {
23719
23748
  const {
23720
23749
  receiverTipAddr,
@@ -23773,13 +23802,26 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
23773
23802
  const deltaPayloadIbGib = deltaGraph[deltaPayloadAddr];
23774
23803
  outgoingPayloadIbGibsDomain_conflicts.push(deltaPayloadIbGib);
23775
23804
  });
23776
- if (conflict.accretivePayloadAddrs) {
23777
- throw new Error(`(UNEXPECTED) conflict.accretivePayloadAddrs already truthy? This is expected to be falsy at this point in the sync. (E: 6b6b1846779867849cbde208f4374326)`);
23805
+ const isFastForward = latestCommonFrameAddr === receiverTipAddr;
23806
+ if (isFastForward) {
23807
+ if (logalot58) {
23808
+ console.log(`${lc2} [CONFLICT DEBUG] TJP ${tjpAddr}: Fast-forward detected (receiver behind sender). Excluding from active conflicts and sending delta payload.`);
23809
+ }
23810
+ } else {
23811
+ if (conflict.accretivePayloadAddrs) {
23812
+ throw new Error(`(UNEXPECTED) conflict.accretivePayloadAddrs already truthy? This is expected to be falsy at this point in the sync. (E: 6b6b1846779867849cbde208f4374326)`);
23813
+ }
23814
+ conflict.accretivePayloadAddrs = accretivePayloadAddrs;
23815
+ activeConflicts.push(conflict);
23778
23816
  }
23779
- conflict.accretivePayloadAddrs = accretivePayloadAddrs;
23817
+ }
23818
+ if (activeConflicts.length > 0) {
23819
+ proposeCommit = false;
23820
+ } else {
23821
+ proposeCommit = true;
23780
23822
  }
23781
23823
  if (logalot58) {
23782
- console.log(`${lc2} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. outgoingPayloadIbGibsDomain_conflicts.length (total outgoing payload ibgibs for ALL conflicts): ${outgoingPayloadIbGibsDomain_conflicts.length}`);
23824
+ console.log(`${lc2} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. Active (divergent) conflicts: ${activeConflicts.length}. outgoingPayloadIbGibsDomain_conflicts.length (total outgoing payload ibgibs for ALL conflicts): ${outgoingPayloadIbGibsDomain_conflicts.length}`);
23783
23825
  }
23784
23826
  } else {
23785
23827
  if (logalot58) {
@@ -23808,7 +23850,7 @@ var SyncSagaCoordinator = class _SyncSagaCoordinator {
23808
23850
  /**
23809
23851
  * these are the modified conflicts with additional information.
23810
23852
  */
23811
- conflicts,
23853
+ conflicts: activeConflicts,
23812
23854
  /**
23813
23855
  * we're sending these domain ibgibs as payload (they were
23814
23856
  * requested by receiver and/or they are being sent as delta
@@ -24738,9 +24780,26 @@ var SyncUpgradeHandlerBase = class _SyncUpgradeHandlerBase extends ServeGibHandl
24738
24780
  sagaId: void 0
24739
24781
  // Resolved dynamically inside runtime turns
24740
24782
  });
24783
+ socket.on("error", (err) => {
24784
+ if (logalot59) {
24785
+ console.warn(`[SyncUpgradeHandlerBase] Socket error: ${extractErrorMsg(err)}`);
24786
+ }
24787
+ try {
24788
+ socket.destroy();
24789
+ } catch (e) {
24790
+ }
24791
+ });
24741
24792
  const socketWrapper = {
24742
24793
  send(data) {
24743
- socket.write(encodeTextFrame(data));
24794
+ if (socket.writable) {
24795
+ try {
24796
+ socket.write(encodeTextFrame(data));
24797
+ } catch (e) {
24798
+ if (logalot59) {
24799
+ console.warn(`[SyncUpgradeHandlerBase] failed to write message frame: ${extractErrorMsg(e)}`);
24800
+ }
24801
+ }
24802
+ }
24744
24803
  },
24745
24804
  onMessage(callback) {
24746
24805
  const decoder = new WebSocketFrameDecoder();
@@ -24756,7 +24815,12 @@ var SyncUpgradeHandlerBase = class _SyncUpgradeHandlerBase extends ServeGibHandl
24756
24815
  if (logalot59) {
24757
24816
  console.warn(`[SyncUpgradeHandlerBase] closing connection due to decoder error: ${extractErrorMsg(error)}`);
24758
24817
  }
24759
- socket.write(encodeCloseFrame());
24818
+ if (socket.writable) {
24819
+ try {
24820
+ socket.write(encodeCloseFrame());
24821
+ } catch (e) {
24822
+ }
24823
+ }
24760
24824
  socket.end();
24761
24825
  }
24762
24826
  });
@@ -24765,7 +24829,12 @@ var SyncUpgradeHandlerBase = class _SyncUpgradeHandlerBase extends ServeGibHandl
24765
24829
  socket.on("close", callback);
24766
24830
  },
24767
24831
  close() {
24768
- socket.write(encodeCloseFrame());
24832
+ if (socket.writable) {
24833
+ try {
24834
+ socket.write(encodeCloseFrame());
24835
+ } catch (e) {
24836
+ }
24837
+ }
24769
24838
  socket.end();
24770
24839
  }
24771
24840
  };