@voidly/agent-sdk 3.2.5 → 3.2.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.
package/dist/index.js CHANGED
@@ -4362,14 +4362,16 @@ var VoidlyAgent = class _VoidlyAgent {
4362
4362
  method: "PUT",
4363
4363
  headers: { "Content-Type": "application/json", "X-Agent-Key": this.apiKey },
4364
4364
  body: JSON.stringify({ value: blob })
4365
- }).catch(() => {
4365
+ }).catch((e) => {
4366
+ console.warn(`[voidly] \u26A0 Relay ratchet persist failed: ${e instanceof Error ? e.message : e}`);
4366
4367
  });
4367
4368
  break;
4368
4369
  case "custom":
4369
4370
  if (this._onPersist) await this._onPersist(blob);
4370
4371
  break;
4371
4372
  }
4372
- } catch {
4373
+ } catch (e) {
4374
+ console.warn(`[voidly] \u26A0 Ratchet state persistence failed (${this._persistMode}): ${e instanceof Error ? e.message : e}`);
4373
4375
  }
4374
4376
  }
4375
4377
  /** Load persisted ratchet state and restore into memory */
@@ -4404,14 +4406,16 @@ var VoidlyAgent = class _VoidlyAgent {
4404
4406
  const data = await res.json();
4405
4407
  blob = data.value;
4406
4408
  }
4407
- } catch {
4409
+ } catch (e) {
4410
+ console.warn(`[voidly] \u26A0 Relay ratchet load failed: ${e instanceof Error ? e.message : e}`);
4408
4411
  }
4409
4412
  break;
4410
4413
  case "custom":
4411
4414
  if (this._onLoad) blob = await this._onLoad();
4412
4415
  break;
4413
4416
  }
4414
- } catch {
4417
+ } catch (e) {
4418
+ console.warn(`[voidly] \u26A0 Ratchet state load failed (${this._persistMode}): ${e instanceof Error ? e.message : e}`);
4415
4419
  return;
4416
4420
  }
4417
4421
  if (!blob) return;
@@ -4423,6 +4427,12 @@ var VoidlyAgent = class _VoidlyAgent {
4423
4427
  const states = JSON.parse((0, import_tweetnacl_util.encodeUTF8)(decrypted));
4424
4428
  for (const [pairId, rs] of Object.entries(states)) {
4425
4429
  if (this._ratchetStates.has(pairId)) continue;
4430
+ if (!rs || typeof rs.sendStep !== "number" || typeof rs.recvStep !== "number" || typeof rs.sendChainKey !== "string" || typeof rs.recvChainKey !== "string") {
4431
+ continue;
4432
+ }
4433
+ if (rs.sendStep < 0 || rs.recvStep < 0 || rs.sendStep > 4294967295 || rs.recvStep > 4294967295) {
4434
+ continue;
4435
+ }
4426
4436
  const state = {
4427
4437
  sendChainKey: (0, import_tweetnacl_util.decodeBase64)(rs.sendChainKey),
4428
4438
  sendStep: rs.sendStep,
@@ -4430,20 +4440,21 @@ var VoidlyAgent = class _VoidlyAgent {
4430
4440
  recvStep: rs.recvStep,
4431
4441
  skippedKeys: /* @__PURE__ */ new Map()
4432
4442
  };
4433
- if (rs.rootKey) state.rootKey = (0, import_tweetnacl_util.decodeBase64)(rs.rootKey);
4434
- if (rs.dhSendSecretKey && rs.dhSendPublicKey) {
4443
+ if (rs.rootKey && typeof rs.rootKey === "string") state.rootKey = (0, import_tweetnacl_util.decodeBase64)(rs.rootKey);
4444
+ if (typeof rs.dhSendSecretKey === "string" && typeof rs.dhSendPublicKey === "string") {
4435
4445
  state.dhSendKeyPair = {
4436
4446
  secretKey: (0, import_tweetnacl_util.decodeBase64)(rs.dhSendSecretKey),
4437
4447
  publicKey: (0, import_tweetnacl_util.decodeBase64)(rs.dhSendPublicKey)
4438
4448
  };
4439
4449
  }
4440
- if (rs.dhRecvPubKey) state.dhRecvPubKey = (0, import_tweetnacl_util.decodeBase64)(rs.dhRecvPubKey);
4441
- if (rs.prevSendStep !== void 0) state.prevSendStep = rs.prevSendStep;
4450
+ if (typeof rs.dhRecvPubKey === "string") state.dhRecvPubKey = (0, import_tweetnacl_util.decodeBase64)(rs.dhRecvPubKey);
4451
+ if (typeof rs.prevSendStep === "number" && rs.prevSendStep >= 0) state.prevSendStep = rs.prevSendStep;
4442
4452
  if (state.sendChainKey.length === 32 && state.recvChainKey.length === 32) {
4443
4453
  this._ratchetStates.set(pairId, state);
4444
4454
  }
4445
4455
  }
4446
- } catch {
4456
+ } catch (e) {
4457
+ console.warn(`[voidly] \u26A0 Ratchet state restore failed (corrupt data, starting fresh): ${e instanceof Error ? e.message : e}`);
4447
4458
  }
4448
4459
  }
4449
4460
  /** IndexedDB put helper (browser only) */
@@ -4768,16 +4779,16 @@ var VoidlyAgent = class _VoidlyAgent {
4768
4779
  if (msg.envelope) {
4769
4780
  try {
4770
4781
  const env = JSON.parse(msg.envelope);
4771
- if (typeof env.ratchet_step === "number") {
4782
+ if (typeof env.ratchet_step === "number" && Number.isInteger(env.ratchet_step) && env.ratchet_step >= 0 && env.ratchet_step <= 4294967295) {
4772
4783
  envelopeRatchetStep = env.ratchet_step;
4773
4784
  }
4774
- if (typeof env.pq_ciphertext === "string") {
4785
+ if (typeof env.pq_ciphertext === "string" && env.pq_ciphertext.length <= 65536) {
4775
4786
  envelopePqCiphertext = env.pq_ciphertext;
4776
4787
  }
4777
- if (typeof env.dh_ratchet_key === "string") {
4788
+ if (typeof env.dh_ratchet_key === "string" && env.dh_ratchet_key.length <= 256) {
4778
4789
  envelopeDhRatchetKey = env.dh_ratchet_key;
4779
4790
  }
4780
- if (typeof env.pn === "number") {
4791
+ if (typeof env.pn === "number" && Number.isInteger(env.pn) && env.pn >= 0 && env.pn <= 4294967295) {
4781
4792
  envelopePn = env.pn;
4782
4793
  }
4783
4794
  } catch {
@@ -4842,9 +4853,10 @@ var VoidlyAgent = class _VoidlyAgent {
4842
4853
  if (!state.dhSkippedKeys) state.dhSkippedKeys = /* @__PURE__ */ new Map();
4843
4854
  state.dhSkippedKeys.set(skipKey, skippedMk);
4844
4855
  ck = nextChainKey;
4845
- if (state.dhSkippedKeys.size > MAX_SKIP) {
4856
+ while (state.dhSkippedKeys.size > MAX_SKIP) {
4846
4857
  const oldest = state.dhSkippedKeys.keys().next().value;
4847
4858
  if (oldest !== void 0) state.dhSkippedKeys.delete(oldest);
4859
+ else break;
4848
4860
  }
4849
4861
  }
4850
4862
  }
@@ -4877,16 +4889,18 @@ var VoidlyAgent = class _VoidlyAgent {
4877
4889
  } else if (targetStep > state.recvStep) {
4878
4890
  const skip = targetStep - state.recvStep;
4879
4891
  if (skip > MAX_SKIP) {
4880
- rawPlaintext = import_tweetnacl.default.box.open(ciphertext, nonce, senderEncPub, this.encryptionKeyPair.secretKey);
4892
+ this._decryptFailCount++;
4893
+ continue;
4881
4894
  } else {
4882
4895
  let ck = state.recvChainKey;
4883
4896
  for (let i = state.recvStep + 1; i < targetStep; i++) {
4884
4897
  const { nextChainKey: nextChainKey2, messageKey: skippedMk } = await ratchetStep(ck);
4885
4898
  state.skippedKeys.set(i, skippedMk);
4886
4899
  ck = nextChainKey2;
4887
- if (state.skippedKeys.size > MAX_SKIP) {
4900
+ while (state.skippedKeys.size > MAX_SKIP) {
4888
4901
  const oldest = state.skippedKeys.keys().next().value;
4889
4902
  if (oldest !== void 0) state.skippedKeys.delete(oldest);
4903
+ else break;
4890
4904
  }
4891
4905
  }
4892
4906
  const { nextChainKey, messageKey } = await ratchetStep(ck);
@@ -4973,8 +4987,11 @@ var VoidlyAgent = class _VoidlyAgent {
4973
4987
  }
4974
4988
  this._seenMessageIds.add(msg.id);
4975
4989
  if (this._seenMessageIds.size > 1e4) {
4976
- const first = this._seenMessageIds.values().next().value;
4977
- if (first !== void 0) this._seenMessageIds.delete(first);
4990
+ const iter = this._seenMessageIds.values();
4991
+ for (let i = 0; i < 1e3; i++) {
4992
+ const v = iter.next().value;
4993
+ if (v !== void 0) this._seenMessageIds.delete(v);
4994
+ }
4978
4995
  }
4979
4996
  decrypted.push({
4980
4997
  id: msg.id,
@@ -5055,8 +5072,12 @@ var VoidlyAgent = class _VoidlyAgent {
5055
5072
  const profile = await res.json();
5056
5073
  this._identityCache.set(did, { profile, cachedAt: Date.now() });
5057
5074
  if (this._identityCache.size > 500) {
5058
- const oldest = this._identityCache.keys().next().value;
5059
- if (oldest !== void 0) this._identityCache.delete(oldest);
5075
+ const excess = this._identityCache.size - 400;
5076
+ const iter = this._identityCache.keys();
5077
+ for (let i = 0; i < excess; i++) {
5078
+ const key = iter.next().value;
5079
+ if (key !== void 0) this._identityCache.delete(key);
5080
+ }
5060
5081
  }
5061
5082
  return profile;
5062
5083
  }
package/dist/index.mjs CHANGED
@@ -4352,14 +4352,16 @@ var VoidlyAgent = class _VoidlyAgent {
4352
4352
  method: "PUT",
4353
4353
  headers: { "Content-Type": "application/json", "X-Agent-Key": this.apiKey },
4354
4354
  body: JSON.stringify({ value: blob })
4355
- }).catch(() => {
4355
+ }).catch((e) => {
4356
+ console.warn(`[voidly] \u26A0 Relay ratchet persist failed: ${e instanceof Error ? e.message : e}`);
4356
4357
  });
4357
4358
  break;
4358
4359
  case "custom":
4359
4360
  if (this._onPersist) await this._onPersist(blob);
4360
4361
  break;
4361
4362
  }
4362
- } catch {
4363
+ } catch (e) {
4364
+ console.warn(`[voidly] \u26A0 Ratchet state persistence failed (${this._persistMode}): ${e instanceof Error ? e.message : e}`);
4363
4365
  }
4364
4366
  }
4365
4367
  /** Load persisted ratchet state and restore into memory */
@@ -4394,14 +4396,16 @@ var VoidlyAgent = class _VoidlyAgent {
4394
4396
  const data = await res.json();
4395
4397
  blob = data.value;
4396
4398
  }
4397
- } catch {
4399
+ } catch (e) {
4400
+ console.warn(`[voidly] \u26A0 Relay ratchet load failed: ${e instanceof Error ? e.message : e}`);
4398
4401
  }
4399
4402
  break;
4400
4403
  case "custom":
4401
4404
  if (this._onLoad) blob = await this._onLoad();
4402
4405
  break;
4403
4406
  }
4404
- } catch {
4407
+ } catch (e) {
4408
+ console.warn(`[voidly] \u26A0 Ratchet state load failed (${this._persistMode}): ${e instanceof Error ? e.message : e}`);
4405
4409
  return;
4406
4410
  }
4407
4411
  if (!blob) return;
@@ -4413,6 +4417,12 @@ var VoidlyAgent = class _VoidlyAgent {
4413
4417
  const states = JSON.parse((0, import_tweetnacl_util.encodeUTF8)(decrypted));
4414
4418
  for (const [pairId, rs] of Object.entries(states)) {
4415
4419
  if (this._ratchetStates.has(pairId)) continue;
4420
+ if (!rs || typeof rs.sendStep !== "number" || typeof rs.recvStep !== "number" || typeof rs.sendChainKey !== "string" || typeof rs.recvChainKey !== "string") {
4421
+ continue;
4422
+ }
4423
+ if (rs.sendStep < 0 || rs.recvStep < 0 || rs.sendStep > 4294967295 || rs.recvStep > 4294967295) {
4424
+ continue;
4425
+ }
4416
4426
  const state = {
4417
4427
  sendChainKey: (0, import_tweetnacl_util.decodeBase64)(rs.sendChainKey),
4418
4428
  sendStep: rs.sendStep,
@@ -4420,20 +4430,21 @@ var VoidlyAgent = class _VoidlyAgent {
4420
4430
  recvStep: rs.recvStep,
4421
4431
  skippedKeys: /* @__PURE__ */ new Map()
4422
4432
  };
4423
- if (rs.rootKey) state.rootKey = (0, import_tweetnacl_util.decodeBase64)(rs.rootKey);
4424
- if (rs.dhSendSecretKey && rs.dhSendPublicKey) {
4433
+ if (rs.rootKey && typeof rs.rootKey === "string") state.rootKey = (0, import_tweetnacl_util.decodeBase64)(rs.rootKey);
4434
+ if (typeof rs.dhSendSecretKey === "string" && typeof rs.dhSendPublicKey === "string") {
4425
4435
  state.dhSendKeyPair = {
4426
4436
  secretKey: (0, import_tweetnacl_util.decodeBase64)(rs.dhSendSecretKey),
4427
4437
  publicKey: (0, import_tweetnacl_util.decodeBase64)(rs.dhSendPublicKey)
4428
4438
  };
4429
4439
  }
4430
- if (rs.dhRecvPubKey) state.dhRecvPubKey = (0, import_tweetnacl_util.decodeBase64)(rs.dhRecvPubKey);
4431
- if (rs.prevSendStep !== void 0) state.prevSendStep = rs.prevSendStep;
4440
+ if (typeof rs.dhRecvPubKey === "string") state.dhRecvPubKey = (0, import_tweetnacl_util.decodeBase64)(rs.dhRecvPubKey);
4441
+ if (typeof rs.prevSendStep === "number" && rs.prevSendStep >= 0) state.prevSendStep = rs.prevSendStep;
4432
4442
  if (state.sendChainKey.length === 32 && state.recvChainKey.length === 32) {
4433
4443
  this._ratchetStates.set(pairId, state);
4434
4444
  }
4435
4445
  }
4436
- } catch {
4446
+ } catch (e) {
4447
+ console.warn(`[voidly] \u26A0 Ratchet state restore failed (corrupt data, starting fresh): ${e instanceof Error ? e.message : e}`);
4437
4448
  }
4438
4449
  }
4439
4450
  /** IndexedDB put helper (browser only) */
@@ -4758,16 +4769,16 @@ var VoidlyAgent = class _VoidlyAgent {
4758
4769
  if (msg.envelope) {
4759
4770
  try {
4760
4771
  const env = JSON.parse(msg.envelope);
4761
- if (typeof env.ratchet_step === "number") {
4772
+ if (typeof env.ratchet_step === "number" && Number.isInteger(env.ratchet_step) && env.ratchet_step >= 0 && env.ratchet_step <= 4294967295) {
4762
4773
  envelopeRatchetStep = env.ratchet_step;
4763
4774
  }
4764
- if (typeof env.pq_ciphertext === "string") {
4775
+ if (typeof env.pq_ciphertext === "string" && env.pq_ciphertext.length <= 65536) {
4765
4776
  envelopePqCiphertext = env.pq_ciphertext;
4766
4777
  }
4767
- if (typeof env.dh_ratchet_key === "string") {
4778
+ if (typeof env.dh_ratchet_key === "string" && env.dh_ratchet_key.length <= 256) {
4768
4779
  envelopeDhRatchetKey = env.dh_ratchet_key;
4769
4780
  }
4770
- if (typeof env.pn === "number") {
4781
+ if (typeof env.pn === "number" && Number.isInteger(env.pn) && env.pn >= 0 && env.pn <= 4294967295) {
4771
4782
  envelopePn = env.pn;
4772
4783
  }
4773
4784
  } catch {
@@ -4832,9 +4843,10 @@ var VoidlyAgent = class _VoidlyAgent {
4832
4843
  if (!state.dhSkippedKeys) state.dhSkippedKeys = /* @__PURE__ */ new Map();
4833
4844
  state.dhSkippedKeys.set(skipKey, skippedMk);
4834
4845
  ck = nextChainKey;
4835
- if (state.dhSkippedKeys.size > MAX_SKIP) {
4846
+ while (state.dhSkippedKeys.size > MAX_SKIP) {
4836
4847
  const oldest = state.dhSkippedKeys.keys().next().value;
4837
4848
  if (oldest !== void 0) state.dhSkippedKeys.delete(oldest);
4849
+ else break;
4838
4850
  }
4839
4851
  }
4840
4852
  }
@@ -4867,16 +4879,18 @@ var VoidlyAgent = class _VoidlyAgent {
4867
4879
  } else if (targetStep > state.recvStep) {
4868
4880
  const skip = targetStep - state.recvStep;
4869
4881
  if (skip > MAX_SKIP) {
4870
- rawPlaintext = import_tweetnacl.default.box.open(ciphertext, nonce, senderEncPub, this.encryptionKeyPair.secretKey);
4882
+ this._decryptFailCount++;
4883
+ continue;
4871
4884
  } else {
4872
4885
  let ck = state.recvChainKey;
4873
4886
  for (let i = state.recvStep + 1; i < targetStep; i++) {
4874
4887
  const { nextChainKey: nextChainKey2, messageKey: skippedMk } = await ratchetStep(ck);
4875
4888
  state.skippedKeys.set(i, skippedMk);
4876
4889
  ck = nextChainKey2;
4877
- if (state.skippedKeys.size > MAX_SKIP) {
4890
+ while (state.skippedKeys.size > MAX_SKIP) {
4878
4891
  const oldest = state.skippedKeys.keys().next().value;
4879
4892
  if (oldest !== void 0) state.skippedKeys.delete(oldest);
4893
+ else break;
4880
4894
  }
4881
4895
  }
4882
4896
  const { nextChainKey, messageKey } = await ratchetStep(ck);
@@ -4963,8 +4977,11 @@ var VoidlyAgent = class _VoidlyAgent {
4963
4977
  }
4964
4978
  this._seenMessageIds.add(msg.id);
4965
4979
  if (this._seenMessageIds.size > 1e4) {
4966
- const first = this._seenMessageIds.values().next().value;
4967
- if (first !== void 0) this._seenMessageIds.delete(first);
4980
+ const iter = this._seenMessageIds.values();
4981
+ for (let i = 0; i < 1e3; i++) {
4982
+ const v = iter.next().value;
4983
+ if (v !== void 0) this._seenMessageIds.delete(v);
4984
+ }
4968
4985
  }
4969
4986
  decrypted.push({
4970
4987
  id: msg.id,
@@ -5045,8 +5062,12 @@ var VoidlyAgent = class _VoidlyAgent {
5045
5062
  const profile = await res.json();
5046
5063
  this._identityCache.set(did, { profile, cachedAt: Date.now() });
5047
5064
  if (this._identityCache.size > 500) {
5048
- const oldest = this._identityCache.keys().next().value;
5049
- if (oldest !== void 0) this._identityCache.delete(oldest);
5065
+ const excess = this._identityCache.size - 400;
5066
+ const iter = this._identityCache.keys();
5067
+ for (let i = 0; i < excess; i++) {
5068
+ const key = iter.next().value;
5069
+ if (key !== void 0) this._identityCache.delete(key);
5070
+ }
5050
5071
  }
5051
5072
  return profile;
5052
5073
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voidly/agent-sdk",
3
- "version": "3.2.5",
3
+ "version": "3.2.6",
4
4
  "description": "E2E encrypted agent-to-agent communication SDK — Double Ratchet, X3DH, deniable auth, ML-KEM-768 post-quantum, SSE streaming, ratchet persistence, multi-relay federation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",