@agentvault/agentvault 0.19.35 → 0.19.37

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.
package/dist/index.js CHANGED
@@ -47250,7 +47250,8 @@ var init_channel = __esm({
47250
47250
  this._sessions.set(convId, {
47251
47251
  ownerDeviceId: sessionData.ownerDeviceId,
47252
47252
  ratchet,
47253
- activated: sessionData.activated ?? false
47253
+ activated: sessionData.activated ?? false,
47254
+ epoch: sessionData.epoch
47254
47255
  });
47255
47256
  }
47256
47257
  }
@@ -47289,7 +47290,8 @@ var init_channel = __esm({
47289
47290
  this._sessions.set(convId, {
47290
47291
  ownerDeviceId: sd.ownerDeviceId,
47291
47292
  ratchet: DoubleRatchet.deserialize(sd.ratchetState),
47292
- activated: sd.activated ?? false
47293
+ activated: sd.activated ?? false,
47294
+ epoch: sd.epoch
47293
47295
  });
47294
47296
  }
47295
47297
  }
@@ -47629,13 +47631,15 @@ var init_channel = __esm({
47629
47631
  this._sessions.set(conv.id, {
47630
47632
  ownerDeviceId: otherDeviceId,
47631
47633
  ratchet,
47632
- activated: isInitiator
47634
+ activated: isInitiator,
47633
47635
  // initiator can send immediately
47636
+ epoch: 1
47634
47637
  });
47635
47638
  this._persisted.sessions[conv.id] = {
47636
47639
  ownerDeviceId: otherDeviceId,
47637
47640
  ratchetState: ratchet.serialize(),
47638
- activated: isInitiator
47641
+ activated: isInitiator,
47642
+ epoch: 1
47639
47643
  };
47640
47644
  conversationIds.push(conv.id);
47641
47645
  console.log(
@@ -48730,12 +48734,14 @@ var init_channel = __esm({
48730
48734
  this._sessions.set(conv.conversation_id, {
48731
48735
  ownerDeviceId: conv.owner_device_id,
48732
48736
  ratchet,
48733
- activated: false
48737
+ activated: false,
48734
48738
  // Wait for owner's first message before sending to this session
48739
+ epoch: 1
48735
48740
  });
48736
48741
  sessions[conv.conversation_id] = {
48737
48742
  ownerDeviceId: conv.owner_device_id,
48738
- ratchetState: ratchet.serialize()
48743
+ ratchetState: ratchet.serialize(),
48744
+ epoch: 1
48739
48745
  };
48740
48746
  console.log(
48741
48747
  `[SecureChannel] Session initialized for conv ${conv.conversation_id.slice(0, 8)}... (owner ${conv.owner_device_id.slice(0, 8)}..., primary=${conv.is_primary})`
@@ -49234,8 +49240,9 @@ var init_channel = __esm({
49234
49240
  ownerDeviceId: "",
49235
49241
  // A2A sessions don't have an owner device
49236
49242
  ratchetState: ratchet.serialize(),
49237
- activated: activatedRole === "initiator"
49243
+ activated: activatedRole === "initiator",
49238
49244
  // initiator can send immediately
49245
+ epoch: 1
49239
49246
  };
49240
49247
  channelEntry.role = activatedRole;
49241
49248
  if (convId) channelEntry.conversationId = convId;
@@ -49420,7 +49427,8 @@ var init_channel = __esm({
49420
49427
  conversation_id: convId,
49421
49428
  reason: "no_session",
49422
49429
  identity_public_key: this._persisted.identityKeypair.publicKey,
49423
- ephemeral_public_key: this._persisted.ephemeralKeypair.publicKey
49430
+ ephemeral_public_key: this._persisted.ephemeralKeypair.publicKey,
49431
+ epoch: this._persisted.sessions[convId]?.epoch
49424
49432
  }
49425
49433
  })
49426
49434
  );
@@ -49459,7 +49467,8 @@ var init_channel = __esm({
49459
49467
  conversation_id: convId,
49460
49468
  reason: "decrypt_failure",
49461
49469
  identity_public_key: idPubHex,
49462
- ephemeral_public_key: ephPubHex
49470
+ ephemeral_public_key: ephPubHex,
49471
+ epoch: this._persisted?.sessions[convId]?.epoch
49463
49472
  }
49464
49473
  })
49465
49474
  );
@@ -49893,13 +49902,15 @@ ${messageText}`;
49893
49902
  this._sessions.set(event.conversation_id, {
49894
49903
  ownerDeviceId: event.owner_device_id,
49895
49904
  ratchet,
49896
- activated: false
49905
+ activated: false,
49897
49906
  // Wait for owner's first message
49907
+ epoch: 1
49898
49908
  });
49899
49909
  this._persisted.sessions[event.conversation_id] = {
49900
49910
  ownerDeviceId: event.owner_device_id,
49901
49911
  ratchetState: ratchet.serialize(),
49902
- activated: false
49912
+ activated: false,
49913
+ epoch: 1
49903
49914
  };
49904
49915
  if (event.owner_hub_id) {
49905
49916
  this._persisted.ownerHubId = event.owner_hub_id;
@@ -49946,17 +49957,21 @@ ${messageText}`;
49946
49957
  keyType: "ed25519"
49947
49958
  }, hexToBytes(data.identity_public_key));
49948
49959
  const existingSession = this._sessions.get(convId);
49960
+ const existingPersisted = this._persisted.sessions[convId];
49949
49961
  const ownerDeviceId = data.sender_device_id ?? existingSession?.ownerDeviceId ?? "";
49962
+ const newEpoch = (existingPersisted?.epoch ?? existingSession?.epoch ?? 0) + 1;
49950
49963
  this._sessions.set(convId, {
49951
49964
  ownerDeviceId,
49952
49965
  ratchet,
49953
- activated: false
49966
+ activated: false,
49954
49967
  // Wait for owner's encrypted session_init
49968
+ epoch: newEpoch
49955
49969
  });
49956
49970
  this._persisted.sessions[convId] = {
49957
49971
  ownerDeviceId,
49958
49972
  ratchetState: ratchet.serialize(),
49959
- activated: false
49973
+ activated: false,
49974
+ epoch: newEpoch
49960
49975
  };
49961
49976
  await this._persistState();
49962
49977
  if (this._ws) {
@@ -49966,7 +49981,8 @@ ${messageText}`;
49966
49981
  data: {
49967
49982
  conversation_id: convId,
49968
49983
  identity_public_key: identity.publicKey,
49969
- ephemeral_public_key: ephemeral.publicKey
49984
+ ephemeral_public_key: ephemeral.publicKey,
49985
+ epoch: newEpoch
49970
49986
  }
49971
49987
  })
49972
49988
  );
@@ -49980,6 +49996,32 @@ ${messageText}`;
49980
49996
  this.emit("error", err);
49981
49997
  }
49982
49998
  }
49999
+ /**
50000
+ * Send a resync_request for a room conversation if the cooldown has elapsed.
50001
+ * Shared by all room ratchet failure paths to avoid code duplication.
50002
+ */
50003
+ _sendRoomResyncIfCooled(convId, reason, session) {
50004
+ const RESYNC_COOLDOWN_MS = 5 * 60 * 1e3;
50005
+ const lastResync = this._lastResyncRequest.get(convId) ?? 0;
50006
+ if (Date.now() - lastResync > RESYNC_COOLDOWN_MS && this._ws && this._persisted) {
50007
+ this._lastResyncRequest.set(convId, Date.now());
50008
+ this._ws.send(
50009
+ JSON.stringify({
50010
+ event: "resync_request",
50011
+ data: {
50012
+ conversation_id: convId,
50013
+ reason,
50014
+ identity_public_key: this._persisted.identityKeypair.publicKey,
50015
+ ephemeral_public_key: this._persisted.ephemeralKeypair.publicKey,
50016
+ epoch: session?.epoch
50017
+ }
50018
+ })
50019
+ );
50020
+ console.log(
50021
+ `[SecureChannel] Room resync requested for conv ${convId.slice(0, 8)} (${reason})`
50022
+ );
50023
+ }
50024
+ }
49983
50025
  /**
49984
50026
  * Handle an incoming room message. Finds the pairwise conversation
49985
50027
  * for the sender, decrypts, and emits a room_message event.
@@ -50116,12 +50158,14 @@ ${messageText}`;
50116
50158
  `[SecureChannel] Room re-init retry failed for conv ${convId.slice(0, 8)} (msgNum=${incomingMsgNum}):`,
50117
50159
  retryErr
50118
50160
  );
50161
+ this._sendRoomResyncIfCooled(convId, "room_reinit_retry_failed", session);
50119
50162
  return;
50120
50163
  }
50121
50164
  } else {
50122
50165
  console.log(
50123
50166
  `[SecureChannel] Room re-init: skipping message with msgNum=${incomingMsgNum} for conv ${convId.slice(0, 8)} (too far ahead for fresh ratchet)`
50124
50167
  );
50168
+ this._sendRoomResyncIfCooled(convId, "room_message_skip");
50125
50169
  return;
50126
50170
  }
50127
50171
  } catch (reinitErr) {
@@ -50129,6 +50173,7 @@ ${messageText}`;
50129
50173
  `[SecureChannel] Room ratchet re-init failed for conv ${convId.slice(0, 8)}...:`,
50130
50174
  reinitErr
50131
50175
  );
50176
+ this._sendRoomResyncIfCooled(convId, "room_reinit_failed");
50132
50177
  return;
50133
50178
  }
50134
50179
  }