@agentunion/fastaun 0.4.13 → 0.5.1

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 (182) hide show
  1. package/CHANGELOG.md +547 -393
  2. package/_packed_docs/CHANGELOG-validators.md +144 -0
  3. package/_packed_docs/CHANGELOG.md +547 -393
  4. package/_packed_docs/INDEX.md +159 -84
  5. package/_packed_docs/KITE_DOCS_GUIDE.md +48 -31
  6. package/_packed_docs/agent.md/SCHEMA.md +2 -0
  7. package/_packed_docs/agent.md/examples/codeagent-claudecode.md +2 -0
  8. package/_packed_docs/agent.md/examples/human-developer.md +2 -0
  9. package/_packed_docs/agent.md/examples/openclaw-lobster.md +2 -0
  10. package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +2 -0
  11. package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +2 -0
  12. package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +266 -686
  13. package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +331 -0
  14. package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +2 -0
  15. package/_packed_docs/design/AUNClient/346/213/206/345/210/206/351/207/215/346/236/204/346/211/247/350/241/214/346/226/271/346/241/210.md +2 -0
  16. package/_packed_docs/design/E2EE_V2/347/256/200/345/214/226/344/270/2721DH/345/212/240Per-AID_Wrap/346/226/271/346/241/210.md +2 -0
  17. package/_packed_docs/design//350/267/250/350/257/255/350/250/200/345/256/271/345/231/250E2E/346/265/213/350/257/225/346/226/271/346/241/210.md +2 -0
  18. package/_packed_docs/protocol/00-/346/200/273/350/247/210/344/270/216/345/210/206/345/261/202.md +2 -0
  19. package/_packed_docs/protocol/00A-/350/256/276/350/256/241/345/216/237/345/210/231-/344/270/272Agent/350/200/214/347/224/237.md +2 -0
  20. package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +2 -0
  21. package/_packed_docs/protocol/02-/350/257/201/344/271/246/344/270/216/344/277/241/344/273/273/344/275/223/347/263/273.md +2 -0
  22. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +2 -0
  23. package/_packed_docs/protocol/04-Peer-/345/255/220/345/215/217/350/256/256.md +2 -0
  24. package/_packed_docs/protocol/05-Relay-/345/255/220/345/215/217/350/256/256.md +2 -0
  25. package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +2 -0
  26. package/_packed_docs/protocol/08-AUN-E2EE-Group.md +296 -900
  27. package/_packed_docs/protocol/08-AUN-E2EE.md +2 -0
  28. package/_packed_docs/protocol/09-/345/256/211/345/205/250/350/200/203/350/231/221.md +2 -0
  29. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +66 -173
  30. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +55 -0
  31. package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +2 -0
  32. package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +2 -0
  33. package/_packed_docs/protocol/14-/344/272/244/344/272/222/346/234/272/345/210/266-/345/223/215/345/272/224/346/250/241/345/274/217/344/270/216/350/207/252/344/270/273/346/250/241/345/274/217.md +2 -0
  34. package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +2 -0
  35. package/_packed_docs/protocol/16-/347/263/273/347/273/237/347/233/256/345/275/225/344/277/235/346/212/244/346/226/271/346/241/210.md +177 -0
  36. package/_packed_docs/protocol/README.md +4 -1
  37. package/_packed_docs/protocol/agent.md/SCHEMA.md +2 -0
  38. package/_packed_docs/protocol/agent.md/examples/codeagent-claudecode.md +2 -0
  39. package/_packed_docs/protocol/agent.md/examples/human-developer.md +2 -0
  40. package/_packed_docs/protocol/agent.md/examples/openclaw-lobster.md +2 -0
  41. package/_packed_docs/protocol/aun-docs-guide.md +2 -0
  42. package/_packed_docs/protocol/index.md +10 -3
  43. package/_packed_docs/protocol//350/215/211/346/241/210-agent.md/347/255/276/345/220/215/345/215/217/350/256/256.md +2 -0
  44. package/_packed_docs/protocol//350/215/211/346/241/210-/346/213/222/347/273/235/344/277/241/345/217/267/345/215/217/350/256/256.md +2 -0
  45. package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +2 -0
  46. package/_packed_docs/protocol//351/231/204/345/275/225B-/346/211/251/345/261/225/346/200/247/346/214/207/345/215/227.md +2 -0
  47. package/_packed_docs/protocol//351/231/204/345/275/225C-/347/247/201/351/222/245/347/256/241/347/220/206/344/270/216/350/272/253/344/273/275/346/201/242/345/244/215.md +2 -0
  48. package/_packed_docs/protocol//351/231/204/345/275/225D-Root_CA_/346/262/273/347/220/206/346/234/272/345/210/266.md +2 -0
  49. package/_packed_docs/protocol//351/231/204/345/275/225E-Root_CA_/345/207/206/345/205/245/346/265/201/347/250/213.md +2 -0
  50. package/_packed_docs/protocol//351/231/204/345/275/225F-Issuer_CA_/347/224/263/350/257/267/346/265/201/347/250/213.md +2 -0
  51. package/_packed_docs/protocol//351/231/204/345/275/225G-AID_/345/255/244/345/204/277/351/242/204/351/230/262/344/270/216/346/225/221/346/217/264/346/234/272/345/210/266.md +2 -0
  52. package/_packed_docs/protocol//351/231/204/345/275/225H-Identity/346/234/215/345/212/241/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  53. package/_packed_docs/protocol//351/231/204/345/275/225I-/350/267/250/345/237/237/346/266/210/346/201/257/350/267/257/347/224/261/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  54. package/_packed_docs/protocol//351/231/204/345/275/225J-/345/256/242/346/210/267/347/253/257/346/216/245/345/205/245/347/244/272/344/276/213.md +2 -0
  55. package/_packed_docs/protocol//351/231/204/345/275/225K-Agent_Web/345/217/221/347/216/260/345/215/217/350/256/256.md +2 -0
  56. package/_packed_docs/protocol//351/231/204/345/275/225L-E2EE/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  57. package/_packed_docs/protocol//351/231/204/345/275/225M-JWT/350/256/244/350/257/201/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  58. package/_packed_docs/protocol//351/231/204/345/275/225N-/345/210/206/345/270/203/345/274/217Trace/345/215/217/350/256/256.md +2 -0
  59. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +2 -0
  60. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +2 -0
  61. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +2 -0
  62. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +2 -0
  63. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +6 -252
  64. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +219 -177
  65. package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +4 -1
  66. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +2 -0
  67. package/_packed_docs/sdk/09-collab-rpc-manual.md +581 -0
  68. package/_packed_docs/sdk/09-custody-api-manual.md +2 -0
  69. package/_packed_docs/sdk/09-group-rpc-manual.md +301 -634
  70. package/_packed_docs/sdk/09-message-rpc-manual.md +2 -0
  71. package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -0
  72. package/_packed_docs/sdk/09-payload-reference.md +2 -0
  73. package/_packed_docs/sdk/09-proxy-rpc-manual.md +2 -0
  74. package/_packed_docs/sdk/09-storage-rpc-manual.md +984 -274
  75. package/_packed_docs/sdk/09-stream-rpc-manual.md +2 -0
  76. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +36 -23
  77. package/_packed_docs/sdk/E2EE_V2/346/266/210/346/201/257/351/200/232/344/277/241/346/227/266/345/272/217/345/233/276.md +2 -0
  78. package/_packed_docs/sdk/INDEX.md +47 -30
  79. package/_packed_docs/sdk/Notify/351/200/232/347/237/245/346/226/271/346/241/210.md +2 -0
  80. package/_packed_docs/sdk/README.md +17 -15
  81. package/dist/aid-store.d.ts +25 -0
  82. package/dist/aid-store.js +80 -0
  83. package/dist/aid-store.js.map +1 -1
  84. package/dist/client/delivery.d.ts +11 -0
  85. package/dist/client/delivery.js +208 -25
  86. package/dist/client/delivery.js.map +1 -1
  87. package/dist/client/group-state.js +33 -11
  88. package/dist/client/group-state.js.map +1 -1
  89. package/dist/client/rpc-pipeline.d.ts +1 -0
  90. package/dist/client/rpc-pipeline.js +177 -65
  91. package/dist/client/rpc-pipeline.js.map +1 -1
  92. package/dist/client/v2-e2ee.d.ts +6 -1
  93. package/dist/client/v2-e2ee.js +199 -130
  94. package/dist/client/v2-e2ee.js.map +1 -1
  95. package/dist/client.d.ts +37 -1
  96. package/dist/client.js +491 -44
  97. package/dist/client.js.map +1 -1
  98. package/dist/collab/client.d.ts +46 -0
  99. package/dist/collab/client.js +136 -0
  100. package/dist/collab/client.js.map +1 -0
  101. package/dist/collab/errors.d.ts +15 -0
  102. package/dist/collab/errors.js +60 -0
  103. package/dist/collab/errors.js.map +1 -0
  104. package/dist/collab/index.d.ts +3 -0
  105. package/dist/collab/index.js +4 -0
  106. package/dist/collab/index.js.map +1 -0
  107. package/dist/collab/types.d.ts +110 -0
  108. package/dist/collab/types.js +2 -0
  109. package/dist/collab/types.js.map +1 -0
  110. package/dist/crypto.d.ts +2 -0
  111. package/dist/crypto.js +6 -0
  112. package/dist/crypto.js.map +1 -1
  113. package/dist/errors.d.ts +0 -12
  114. package/dist/errors.js +9 -25
  115. package/dist/errors.js.map +1 -1
  116. package/dist/facades.d.ts +94 -0
  117. package/dist/facades.js +255 -0
  118. package/dist/facades.js.map +1 -0
  119. package/dist/group-fs.d.ts +122 -0
  120. package/dist/group-fs.js +467 -0
  121. package/dist/group-fs.js.map +1 -0
  122. package/dist/group-id.d.ts +9 -12
  123. package/dist/group-id.js +41 -63
  124. package/dist/group-id.js.map +1 -1
  125. package/dist/group-resources.d.ts +31 -0
  126. package/dist/group-resources.js +84 -0
  127. package/dist/group-resources.js.map +1 -0
  128. package/dist/index.d.ts +9 -3
  129. package/dist/index.js +11 -1
  130. package/dist/index.js.map +1 -1
  131. package/dist/keystore/aid-db.d.ts +1 -0
  132. package/dist/keystore/aid-db.js +43 -43
  133. package/dist/keystore/aid-db.js.map +1 -1
  134. package/dist/keystore/local-identity-store.d.ts +16 -0
  135. package/dist/keystore/local-identity-store.js +190 -18
  136. package/dist/keystore/local-identity-store.js.map +1 -1
  137. package/dist/keystore/local-token-store.d.ts +0 -13
  138. package/dist/keystore/local-token-store.js +0 -105
  139. package/dist/keystore/local-token-store.js.map +1 -1
  140. package/dist/logger.d.ts +2 -0
  141. package/dist/logger.js +4 -0
  142. package/dist/logger.js.map +1 -1
  143. package/dist/register-flow.d.ts +1 -0
  144. package/dist/register-flow.js +3 -0
  145. package/dist/register-flow.js.map +1 -1
  146. package/dist/service-proxy.d.ts +1 -0
  147. package/dist/service-proxy.js +17 -4
  148. package/dist/service-proxy.js.map +1 -1
  149. package/dist/storage/errors.d.ts +27 -0
  150. package/dist/storage/errors.js +65 -0
  151. package/dist/storage/errors.js.map +1 -0
  152. package/dist/storage/index.d.ts +1 -0
  153. package/dist/storage/index.js +2 -0
  154. package/dist/storage/index.js.map +1 -0
  155. package/dist/storage/lowlevel.d.ts +321 -0
  156. package/dist/storage/lowlevel.js +475 -0
  157. package/dist/storage/lowlevel.js.map +1 -0
  158. package/dist/storage/types.d.ts +57 -0
  159. package/dist/storage/types.js +116 -0
  160. package/dist/storage/types.js.map +1 -0
  161. package/dist/storage/vfs.d.ts +166 -0
  162. package/dist/storage/vfs.js +524 -0
  163. package/dist/storage/vfs.js.map +1 -0
  164. package/dist/tools/cross-sdk-agent.js +708 -1
  165. package/dist/tools/cross-sdk-agent.js.map +1 -1
  166. package/dist/transport.d.ts +5 -0
  167. package/dist/transport.js +124 -21
  168. package/dist/transport.js.map +1 -1
  169. package/dist/types.d.ts +38 -0
  170. package/dist/v2/session/session.d.ts +2 -0
  171. package/dist/v2/session/session.js +53 -23
  172. package/dist/v2/session/session.js.map +1 -1
  173. package/dist/v2/state/commitment.d.ts +1 -1
  174. package/dist/v2/state/commitment.js +4 -2
  175. package/dist/v2/state/commitment.js.map +1 -1
  176. package/dist/validators.d.ts +32 -0
  177. package/dist/validators.js +128 -0
  178. package/dist/validators.js.map +1 -0
  179. package/dist/version.d.ts +1 -1
  180. package/dist/version.js +1 -1
  181. package/dist/version.js.map +1 -1
  182. package/package.json +1 -1
@@ -6,6 +6,7 @@ import { V2Session } from '../v2/session/index.js';
6
6
  import { isJsonObject } from '../types.js';
7
7
  const V2_BOOTSTRAP_TTL_MS = 60 * 60 * 1000;
8
8
  const V2_RETRYABLE_CODES = new Set([-33011, -33012, -33050, -33052, -33054]);
9
+ const V2_GROUP_STALE_BOOTSTRAP_CODE = -33054;
9
10
  const MEMBERSHIP_ACTIONS = new Set([
10
11
  'member_added',
11
12
  'member_left',
@@ -134,6 +135,7 @@ function applyV2WrapPolicyToTargets(targets, policy) {
134
135
  export class V2E2EECoordinator {
135
136
  runtime;
136
137
  _initSessionPromise = null;
138
+ targetSetCache = new Map();
137
139
  constructor(runtime) {
138
140
  this.runtime = runtime;
139
141
  }
@@ -155,16 +157,48 @@ export class V2E2EECoordinator {
155
157
  }
156
158
  deleteBootstrapCacheEntry(key) {
157
159
  this.bootstrapCache.delete(key);
160
+ this.targetSetCache.delete(key);
158
161
  }
159
162
  clearBootstrapCache() {
160
163
  this.bootstrapCache.clear();
164
+ this.targetSetCache.clear();
161
165
  }
162
166
  pruneExpiredBootstrapCache(ttlMs, now = Date.now()) {
163
167
  for (const [key, entry] of this.bootstrapCache) {
164
168
  if (now - Number(entry.cachedAt ?? 0) >= ttlMs) {
165
169
  this.bootstrapCache.delete(key);
170
+ this.targetSetCache.delete(key);
166
171
  }
167
172
  }
173
+ for (const [key, entry] of this.targetSetCache) {
174
+ if (now - Number(entry.cachedAt ?? 0) >= ttlMs) {
175
+ this.targetSetCache.delete(key);
176
+ }
177
+ }
178
+ }
179
+ getTargetSetCache(key) {
180
+ const cached = this.targetSetCache.get(key);
181
+ if (!cached || Date.now() - cached.cachedAt >= V2_BOOTSTRAP_TTL_MS) {
182
+ if (cached)
183
+ this.targetSetCache.delete(key);
184
+ return undefined;
185
+ }
186
+ return cached.value;
187
+ }
188
+ setTargetSetCache(key, value) {
189
+ this.targetSetCache.set(key, { cachedAt: Date.now(), value });
190
+ return value;
191
+ }
192
+ cloneP2PTargetSet(value) {
193
+ return {
194
+ targets: value.targets.map((target) => ({ ...target })),
195
+ auditRecipients: value.auditRecipients.map((target) => ({ ...target })),
196
+ };
197
+ }
198
+ cloneGroupTargetSet(value) {
199
+ return {
200
+ targets: value.targets.map((target) => ({ ...target })),
201
+ };
168
202
  }
169
203
  async onConnected(opts) {
170
204
  const client = this.client;
@@ -453,6 +487,7 @@ export class V2E2EECoordinator {
453
487
  client._clientLog.debug(`message.v2.bootstrap cache hit: to=${to}, devices=${peerDevices.length}, audit=${auditRaw.length}`);
454
488
  }
455
489
  else {
490
+ this.targetSetCache.delete(to);
456
491
  const bs = await client.call('message.v2.bootstrap', {
457
492
  peer_aid: to,
458
493
  e2ee_wrap_capabilities: v2WrapCapabilities(),
@@ -464,7 +499,7 @@ export class V2E2EECoordinator {
464
499
  peerDevices = (Array.isArray(bs?.peer_devices) ? bs.peer_devices : []);
465
500
  auditRaw = (Array.isArray(bs?.audit_recipients) ? bs.audit_recipients : []);
466
501
  client._clientLog.debug(`message.v2.bootstrap fetched: to=${to}, devices=${peerDevices.length}, audit=${auditRaw.length}`);
467
- if (peerDevices.length > 0 && !this.getBootstrapCacheEntry(to)) {
502
+ if (peerDevices.length > 0) {
468
503
  this.setBootstrapCacheEntry(to, {
469
504
  devices: peerDevices,
470
505
  auditRecipients: auditRaw,
@@ -476,83 +511,92 @@ export class V2E2EECoordinator {
476
511
  if (peerDevices.length === 0) {
477
512
  throw new E2EEError(`V2 bootstrap: no devices found for ${to}`);
478
513
  }
479
- const targets = [];
480
- for (const dev of peerDevices) {
481
- const devId = getV2DeviceId(dev);
482
- const target = await client._v2BuildTargetFromDevice({
483
- dev,
484
- aid: to,
485
- deviceId: devId.value,
486
- role: 'peer',
487
- defaultKeySource: 'peer_device_prekey',
488
- });
489
- if (target)
490
- targets.push(target);
491
- }
492
- const auditTargets = [];
493
- for (const dev of auditRaw) {
494
- const target = await client._v2BuildTargetFromDevice({
495
- dev,
496
- aid: String(dev.aid ?? ''),
497
- deviceId: String(dev.device_id ?? ''),
498
- role: 'audit',
499
- defaultKeySource: 'peer_device_prekey',
500
- });
501
- if (target)
502
- auditTargets.push(target);
514
+ let targetSet = useCache ? this.getTargetSetCache(to) : undefined;
515
+ if (targetSet) {
516
+ targetSet = this.cloneP2PTargetSet(targetSet);
503
517
  }
504
- if (client._aid && client._aid !== to) {
505
- try {
506
- const selfCached = this.getBootstrapCacheEntry(client._aid);
507
- let selfDevices = [];
508
- if (selfCached && Date.now() - Number(selfCached.cachedAt ?? 0) < V2_BOOTSTRAP_TTL_MS) {
509
- selfDevices = (selfCached.devices ?? []);
510
- }
511
- else {
512
- const selfBs = await client.call('message.v2.bootstrap', {
513
- peer_aid: client._aid,
514
- e2ee_wrap_capabilities: v2WrapCapabilities(),
515
- });
516
- if (typeof client._primeBootstrapPeerCerts === 'function') {
517
- await client._primeBootstrapPeerCerts(selfBs, client._aid);
518
+ else {
519
+ const targets = [];
520
+ for (const dev of peerDevices) {
521
+ const devId = getV2DeviceId(dev);
522
+ const target = await client._v2BuildTargetFromDevice({
523
+ dev,
524
+ aid: to,
525
+ deviceId: devId.value,
526
+ role: 'peer',
527
+ defaultKeySource: 'peer_device_prekey',
528
+ });
529
+ if (target)
530
+ targets.push(target);
531
+ }
532
+ const auditTargets = [];
533
+ for (const dev of auditRaw) {
534
+ const target = await client._v2BuildTargetFromDevice({
535
+ dev,
536
+ aid: String(dev.aid ?? ''),
537
+ deviceId: String(dev.device_id ?? ''),
538
+ role: 'audit',
539
+ defaultKeySource: 'peer_device_prekey',
540
+ });
541
+ if (target)
542
+ auditTargets.push(target);
543
+ }
544
+ if (client._aid && client._aid !== to) {
545
+ try {
546
+ const selfCached = this.getBootstrapCacheEntry(client._aid);
547
+ let selfDevices = [];
548
+ if (selfCached && Date.now() - Number(selfCached.cachedAt ?? 0) < V2_BOOTSTRAP_TTL_MS) {
549
+ selfDevices = (selfCached.devices ?? []);
518
550
  }
519
- selfDevices = (Array.isArray(selfBs?.peer_devices) ? selfBs.peer_devices : []);
520
- const selfWrapPolicy = normalizeV2WrapPolicy(selfBs.e2ee_wrap_policy);
521
- if (selfDevices.length > 0) {
522
- this.setBootstrapCacheEntry(client._aid, {
523
- devices: selfDevices,
524
- auditRecipients: [],
525
- cachedAt: Date.now(),
526
- wrapPolicy: selfWrapPolicy,
551
+ else {
552
+ this.targetSetCache.delete(client._aid);
553
+ const selfBs = await client.call('message.v2.bootstrap', {
554
+ peer_aid: client._aid,
555
+ e2ee_wrap_capabilities: v2WrapCapabilities(),
527
556
  });
557
+ if (typeof client._primeBootstrapPeerCerts === 'function') {
558
+ await client._primeBootstrapPeerCerts(selfBs, client._aid);
559
+ }
560
+ selfDevices = (Array.isArray(selfBs?.peer_devices) ? selfBs.peer_devices : []);
561
+ const selfWrapPolicy = normalizeV2WrapPolicy(selfBs.e2ee_wrap_policy);
562
+ if (selfDevices.length > 0) {
563
+ this.setBootstrapCacheEntry(client._aid, {
564
+ devices: selfDevices,
565
+ auditRecipients: [],
566
+ cachedAt: Date.now(),
567
+ wrapPolicy: selfWrapPolicy,
568
+ });
569
+ }
570
+ }
571
+ for (const dev of selfDevices) {
572
+ const devId = getV2DeviceId(dev);
573
+ if (!devId.present || devId.value === client._deviceId)
574
+ continue;
575
+ const target = await client._v2BuildTargetFromDevice({
576
+ dev,
577
+ aid: client._aid,
578
+ deviceId: devId.value,
579
+ role: 'self_sync',
580
+ defaultKeySource: 'peer_device_prekey',
581
+ });
582
+ if (target)
583
+ targets.push(target);
528
584
  }
529
585
  }
530
- for (const dev of selfDevices) {
531
- const devId = getV2DeviceId(dev);
532
- if (!devId.present || devId.value === client._deviceId)
533
- continue;
534
- const target = await client._v2BuildTargetFromDevice({
535
- dev,
536
- aid: client._aid,
537
- deviceId: devId.value,
538
- role: 'self_sync',
539
- defaultKeySource: 'peer_device_prekey',
540
- });
541
- if (target)
542
- targets.push(target);
586
+ catch (exc) {
587
+ client._clientLog.debug(`V2 self-sync bootstrap failed (non-fatal): ${formatE2EEError(exc)}`);
543
588
  }
544
589
  }
545
- catch (exc) {
546
- client._clientLog.debug(`V2 self-sync bootstrap failed (non-fatal): ${formatE2EEError(exc)}`);
547
- }
590
+ targetSet = this.setTargetSetCache(to, {
591
+ targets: applyV2WrapPolicyToTargets(targets, wrapPolicy),
592
+ auditRecipients: applyV2WrapPolicyToTargets(auditTargets, wrapPolicy),
593
+ });
594
+ targetSet = this.cloneP2PTargetSet(targetSet);
548
595
  }
549
- if (targets.length === 0) {
596
+ if (targetSet.targets.length === 0) {
550
597
  throw new E2EEError(`V2 bootstrap: no usable devices found for ${to}`);
551
598
  }
552
- const envelope = encryptP2PMessage(session.getSenderIdentity(), {
553
- targets: applyV2WrapPolicyToTargets(targets, wrapPolicy),
554
- auditRecipients: applyV2WrapPolicyToTargets(auditTargets, wrapPolicy),
555
- }, opts.payload, {
599
+ const envelope = encryptP2PMessage(session.getSenderIdentity(), targetSet, opts.payload, {
556
600
  messageId: opts.messageId,
557
601
  timestamp: opts.timestamp,
558
602
  protectedHeaders: opts.protectedHeaders,
@@ -569,8 +613,8 @@ export class V2E2EECoordinator {
569
613
  payloadOverride: envelope,
570
614
  extra: {
571
615
  plaintext_payload: opts.payload,
572
- target_count: targets.length,
573
- audit_count: auditTargets.length,
616
+ target_count: targetSet.targets.length,
617
+ audit_count: targetSet.auditRecipients.length,
574
618
  use_cache: useCache,
575
619
  },
576
620
  });
@@ -652,6 +696,7 @@ export class V2E2EECoordinator {
652
696
  const decrypted = [];
653
697
  let nextAfterSeq = opts?.force ? afterSeq : (afterSeq || (ns ? client._seqTracker.getContiguousSeq(ns) : 0));
654
698
  let pageCount = 0;
699
+ let lastAutoAckSeq = 0;
655
700
  const maxPages = 100;
656
701
  while (pageCount < maxPages) {
657
702
  pageCount += 1;
@@ -661,8 +706,12 @@ export class V2E2EECoordinator {
661
706
  limit,
662
707
  ...(opts?.force ? { force: true } : {}),
663
708
  });
664
- const messages = (Array.isArray(result?.messages) ? result.messages : []);
665
- client._clientLog.debug(`message.v2.pull page response: page=${pageCount}, raw_count=${messages.length}, has_more=${String(result.has_more ?? '')}, server_ack_seq=${String(result.server_ack_seq ?? '')}`);
709
+ const pageMessages = (Array.isArray(result?.messages) ? result.messages : []);
710
+ const messages = pageMessages.filter((msg) => {
711
+ const seq = Number(msg.seq ?? 0);
712
+ return Number.isFinite(seq) && seq > nextAfterSeq;
713
+ });
714
+ client._clientLog.debug(`message.v2.pull page response: page=${pageCount}, raw_count=${messages.length}, stale_count=${Math.max(0, pageMessages.length - messages.length)}, has_more=${String(result.has_more ?? '')}, server_ack_seq=${String(result.server_ack_seq ?? '')}`);
666
715
  for (const msg of messages) {
667
716
  client._logMessageDebug('pull-raw', 'message.v2.pull', 'message.received', msg);
668
717
  }
@@ -752,19 +801,21 @@ export class V2E2EECoordinator {
752
801
  const contigAdvanced = ackSeq !== pageContigBefore;
753
802
  if (contigAdvanced) {
754
803
  await client._drainOrderedMessages(ns, undefined, true);
755
- client._saveSeqTrackerState();
804
+ client._persistSeq(ns);
756
805
  }
757
- const ackNeeded = messages.length > 0
806
+ const ackNeeded = pageMessages.length > 0
758
807
  && ackSeq > 0
808
+ && ackSeq > lastAutoAckSeq
759
809
  && !opts?.skipAutoAck
760
810
  && (contigAdvanced || (hasServerAckSeq && ackSeq > serverAckSeq));
761
811
  if (ackNeeded) {
762
812
  client._clientLog.debug(`message.v2.pull sending auto-ack: ns=${ns}, ack_seq=${ackSeq}, raw_count=${messages.length}`);
763
813
  await this.ackV2(ackSeq);
814
+ lastAutoAckSeq = ackSeq;
764
815
  }
765
816
  }
766
817
  const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
767
- if (messages.length === 0 || nextAfter <= nextAfterSeq || result.has_more === false)
818
+ if (messages.length === 0 || nextAfter <= nextAfterSeq)
768
819
  break;
769
820
  nextAfterSeq = nextAfter;
770
821
  }
@@ -895,7 +946,8 @@ export class V2E2EECoordinator {
895
946
  if (!client._v2Session)
896
947
  throw new StateError('V2 session not initialized');
897
948
  const session = client._v2Session;
898
- const groupId = normalizeGroupId(opts.groupId) || String(opts.groupId ?? '').trim();
949
+ const rawGroupId = String(opts.groupId ?? '').trim();
950
+ const groupId = normalizeGroupId(rawGroupId) || rawGroupId;
899
951
  if (!groupId)
900
952
  throw new ValidationError("group.send requires 'group_id'");
901
953
  const cacheKey = `group:${groupId}`;
@@ -905,16 +957,27 @@ export class V2E2EECoordinator {
905
957
  let epoch = 0;
906
958
  let stateCommitment = { state_version: 0, state_hash: '', state_chain: '' };
907
959
  let wrapPolicy = normalizeV2WrapPolicy(undefined);
908
- const cached = useCache ? this.getBootstrapCacheEntry(cacheKey) : undefined;
960
+ let usedCachedBootstrap = false;
961
+ let cached = useCache ? this.getBootstrapCacheEntry(cacheKey) : undefined;
962
+ if (!cached && useCache && rawGroupId && rawGroupId !== groupId) {
963
+ const legacyCacheKey = `group:${rawGroupId}`;
964
+ cached = this.getBootstrapCacheEntry(legacyCacheKey);
965
+ if (cached) {
966
+ this.setBootstrapCacheEntry(cacheKey, cached);
967
+ this.deleteBootstrapCacheEntry(legacyCacheKey);
968
+ }
969
+ }
909
970
  if (cached && Date.now() - Number(cached.cachedAt ?? 0) < V2_BOOTSTRAP_TTL_MS) {
910
971
  allDevices = (cached.devices ?? []);
911
972
  auditRecipientsRaw = (cached.auditRecipients ?? []);
912
973
  epoch = Number(cached.epoch ?? 0) || 0;
913
974
  stateCommitment = cached.stateCommitment ?? stateCommitment;
914
975
  wrapPolicy = cached.wrapPolicy ?? wrapPolicy;
976
+ usedCachedBootstrap = true;
915
977
  client._clientLog.debug(`group.v2.bootstrap cache hit: group=${groupId}, devices=${allDevices.length}, audit=${auditRecipientsRaw.length}, epoch=${epoch}, state_version=${stateCommitment.state_version}`);
916
978
  }
917
979
  else {
980
+ this.targetSetCache.delete(cacheKey);
918
981
  const bs = await client.call('group.v2.bootstrap', {
919
982
  group_id: groupId,
920
983
  e2ee_wrap_capabilities: v2WrapCapabilities(),
@@ -951,38 +1014,63 @@ export class V2E2EECoordinator {
951
1014
  if (allDevices.length === 0) {
952
1015
  throw new E2EEError(`V2 group bootstrap: no devices found for group ${groupId}`);
953
1016
  }
954
- const targets = [];
955
- for (const dev of allDevices) {
956
- const devAid = String(dev.aid ?? '').trim();
957
- const devId = getV2DeviceId(dev);
958
- if (devAid === client._aid && devId.present && devId.value === client._deviceId)
959
- continue;
960
- const role = devAid === client._aid ? 'self_sync' : 'member';
961
- const target = await client._v2BuildTargetFromDevice({
962
- dev,
963
- aid: devAid,
964
- deviceId: devId.value,
965
- role,
966
- defaultKeySource: 'peer_device_prekey',
1017
+ let targetSet = useCache ? this.getTargetSetCache(cacheKey) : undefined;
1018
+ if (targetSet) {
1019
+ targetSet = this.cloneGroupTargetSet(targetSet);
1020
+ }
1021
+ else {
1022
+ const targets = [];
1023
+ for (const dev of allDevices) {
1024
+ const devAid = String(dev.aid ?? '').trim();
1025
+ const devId = getV2DeviceId(dev);
1026
+ if (devAid === client._aid && devId.present && devId.value === client._deviceId)
1027
+ continue;
1028
+ const role = devAid === client._aid ? 'self_sync' : 'member';
1029
+ const target = await client._v2BuildTargetFromDevice({
1030
+ dev,
1031
+ aid: devAid,
1032
+ deviceId: devId.value,
1033
+ role,
1034
+ defaultKeySource: 'peer_device_prekey',
1035
+ });
1036
+ if (target)
1037
+ targets.push(target);
1038
+ }
1039
+ if (targets.length === 0) {
1040
+ if (usedCachedBootstrap) {
1041
+ throw new E2EEError(`V2 group: no target devices for group ${groupId}; bootstrap may be stale`, {
1042
+ code: V2_GROUP_STALE_BOOTSTRAP_CODE,
1043
+ data: { expected_peer_aids: [] },
1044
+ });
1045
+ }
1046
+ throw new E2EEError(`V2 group: no target devices for group ${groupId}`);
1047
+ }
1048
+ for (const dev of auditRecipientsRaw) {
1049
+ const target = await client._v2BuildTargetFromDevice({
1050
+ dev,
1051
+ aid: String(dev.aid ?? ''),
1052
+ deviceId: String(dev.device_id ?? ''),
1053
+ role: 'audit',
1054
+ defaultKeySource: 'peer_device_prekey',
1055
+ });
1056
+ if (target)
1057
+ targets.push(target);
1058
+ }
1059
+ targetSet = this.setTargetSetCache(cacheKey, {
1060
+ targets: applyV2WrapPolicyToTargets(targets, wrapPolicy),
967
1061
  });
968
- if (target)
969
- targets.push(target);
1062
+ targetSet = this.cloneGroupTargetSet(targetSet);
970
1063
  }
971
- if (targets.length === 0) {
1064
+ if (targetSet.targets.length === 0) {
1065
+ if (usedCachedBootstrap) {
1066
+ throw new E2EEError(`V2 group: no target devices for group ${groupId}; bootstrap may be stale`, {
1067
+ code: V2_GROUP_STALE_BOOTSTRAP_CODE,
1068
+ data: { expected_peer_aids: [] },
1069
+ });
1070
+ }
972
1071
  throw new E2EEError(`V2 group: no target devices for group ${groupId}`);
973
1072
  }
974
- for (const dev of auditRecipientsRaw) {
975
- const target = await client._v2BuildTargetFromDevice({
976
- dev,
977
- aid: String(dev.aid ?? ''),
978
- deviceId: String(dev.device_id ?? ''),
979
- role: 'audit',
980
- defaultKeySource: 'peer_device_prekey',
981
- });
982
- if (target)
983
- targets.push(target);
984
- }
985
- const envelope = encryptGroupMessage(session.getSenderIdentity(), groupId, epoch, applyV2WrapPolicyToTargets(targets, wrapPolicy), opts.payload, {
1073
+ const envelope = encryptGroupMessage(session.getSenderIdentity(), groupId, epoch, targetSet.targets, opts.payload, {
986
1074
  messageId: opts.messageId,
987
1075
  timestamp: opts.timestamp,
988
1076
  protectedHeaders: opts.protectedHeaders,
@@ -1000,7 +1088,7 @@ export class V2E2EECoordinator {
1000
1088
  extra: {
1001
1089
  plaintext_payload: opts.payload,
1002
1090
  epoch,
1003
- target_count: targets.length,
1091
+ target_count: targetSet.targets.length,
1004
1092
  audit_count: auditRecipientsRaw.length,
1005
1093
  state_version: stateCommitment.state_version,
1006
1094
  use_cache: useCache,
@@ -1026,6 +1114,7 @@ export class V2E2EECoordinator {
1026
1114
  }));
1027
1115
  }
1028
1116
  const decrypted = [];
1117
+ const wireGroupId = String(opts?.wireGroupId ?? groupId ?? '').trim() || gid;
1029
1118
  const cursorParams = opts?.cursorParams ?? {};
1030
1119
  const ownsCursor = opts?.ownsCursor !== false;
1031
1120
  let nextAfterSeq = opts?.explicitAfterSeq ? afterSeq : (afterSeq || client._seqTracker.getContiguousSeq(ns));
@@ -1035,7 +1124,8 @@ export class V2E2EECoordinator {
1035
1124
  pageCount += 1;
1036
1125
  client._clientLog.debug(`group.v2.pull page request: group=${gid}, page=${pageCount}, after_seq=${nextAfterSeq}, limit=${limit}, ns=${ns}`);
1037
1126
  const result = await client._callRawV2Rpc('group.v2.pull', {
1038
- group_id: gid,
1127
+ group_id: wireGroupId,
1128
+ group_aid: gid,
1039
1129
  after_seq: nextAfterSeq,
1040
1130
  limit,
1041
1131
  ...cursorParams,
@@ -1139,7 +1229,7 @@ export class V2E2EECoordinator {
1139
1229
  const contigAdvanced = ackSeq !== pageContigBefore;
1140
1230
  if (contigAdvanced) {
1141
1231
  await client._drainOrderedMessages(ns, undefined, true);
1142
- client._saveSeqTrackerState();
1232
+ client._persistSeq(ns);
1143
1233
  }
1144
1234
  const ackNeeded = messages.length > 0
1145
1235
  && ackSeq > 0
@@ -1175,7 +1265,7 @@ export class V2E2EECoordinator {
1175
1265
  }
1176
1266
  seq = client._clampAckSeq('group.v2.ack', 'up_to_seq', ns, seq);
1177
1267
  client._clientLog.debug(`group.v2.ack send: group=${gid}, ns=${ns}, up_to_seq=${seq}`);
1178
- const result = await client._callRawV2Rpc('group.v2.ack', { group_id: gid, up_to_seq: seq });
1268
+ const result = await client._callRawV2Rpc('group.v2.ack', { group_id: gid, group_aid: gid, up_to_seq: seq });
1179
1269
  client._clientLog.debug(`group.v2.ack ok: group=${gid}, ns=${ns}, requested=${seq}, result=${client._debugJson(result)}`);
1180
1270
  return result;
1181
1271
  }
@@ -1698,26 +1788,5 @@ export class V2E2EECoordinator {
1698
1788
  this.scheduleGroupSpkRotation(groupId, { reason: `group_changed:${action}` });
1699
1789
  }
1700
1790
  }
1701
- async handleV2EpochRotated(data) {
1702
- const client = this.client;
1703
- if (!data || typeof data !== 'object' || Array.isArray(data))
1704
- return;
1705
- const d = data;
1706
- const groupId = String(d.group_id ?? '').trim();
1707
- if (!groupId)
1708
- return;
1709
- const epoch = d.epoch ?? 0;
1710
- client._clientLog.debug(`_onV2EpochRotated: group=${groupId} epoch=${String(epoch)}`);
1711
- this.deleteBootstrapCacheEntry(`group:${groupId}`);
1712
- if (!client._v2Session)
1713
- return;
1714
- try {
1715
- await client._v2Session.rotateSPK(client._v2CallFn());
1716
- client._clientLog.info(`SPK rotated after V2 epoch change: group=${groupId} epoch=${String(epoch)}`);
1717
- }
1718
- catch (exc) {
1719
- client._clientLog.debug(`SPK rotation after V2 epoch change failed (non-fatal): ${formatE2EEError(exc)}`);
1720
- }
1721
- }
1722
1791
  }
1723
1792
  //# sourceMappingURL=v2-e2ee.js.map