@agentunion/fastaun-browser 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 (223) hide show
  1. package/CHANGELOG.md +536 -386
  2. package/_packed_docs/CHANGELOG-validators.md +144 -0
  3. package/_packed_docs/CHANGELOG.md +536 -386
  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.d.ts.map +1 -1
  83. package/dist/aid-store.js +89 -8
  84. package/dist/aid-store.js.map +1 -1
  85. package/dist/bundle.js +19615 -16870
  86. package/dist/client/delivery.d.ts +15 -2
  87. package/dist/client/delivery.d.ts.map +1 -1
  88. package/dist/client/delivery.js +303 -54
  89. package/dist/client/delivery.js.map +1 -1
  90. package/dist/client/group-state.d.ts.map +1 -1
  91. package/dist/client/group-state.js +36 -14
  92. package/dist/client/group-state.js.map +1 -1
  93. package/dist/client/lifecycle.js +2 -2
  94. package/dist/client/lifecycle.js.map +1 -1
  95. package/dist/client/rpc-pipeline.d.ts +2 -0
  96. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  97. package/dist/client/rpc-pipeline.js +235 -82
  98. package/dist/client/rpc-pipeline.js.map +1 -1
  99. package/dist/client/v2-e2ee.d.ts +14 -1
  100. package/dist/client/v2-e2ee.d.ts.map +1 -1
  101. package/dist/client/v2-e2ee.js +300 -121
  102. package/dist/client/v2-e2ee.js.map +1 -1
  103. package/dist/client.d.ts +36 -4
  104. package/dist/client.d.ts.map +1 -1
  105. package/dist/client.js +460 -57
  106. package/dist/client.js.map +1 -1
  107. package/dist/collab/client.d.ts +47 -0
  108. package/dist/collab/client.d.ts.map +1 -0
  109. package/dist/collab/client.js +136 -0
  110. package/dist/collab/client.js.map +1 -0
  111. package/dist/collab/errors.d.ts +16 -0
  112. package/dist/collab/errors.d.ts.map +1 -0
  113. package/dist/collab/errors.js +60 -0
  114. package/dist/collab/errors.js.map +1 -0
  115. package/dist/collab/index.d.ts +4 -0
  116. package/dist/collab/index.d.ts.map +1 -0
  117. package/dist/collab/index.js +4 -0
  118. package/dist/collab/index.js.map +1 -0
  119. package/dist/collab/types.d.ts +111 -0
  120. package/dist/collab/types.d.ts.map +1 -0
  121. package/dist/collab/types.js +2 -0
  122. package/dist/collab/types.js.map +1 -0
  123. package/dist/crypto.d.ts +6 -0
  124. package/dist/crypto.d.ts.map +1 -1
  125. package/dist/crypto.js +6 -0
  126. package/dist/crypto.js.map +1 -1
  127. package/dist/errors.d.ts +0 -20
  128. package/dist/errors.d.ts.map +1 -1
  129. package/dist/errors.js +9 -37
  130. package/dist/errors.js.map +1 -1
  131. package/dist/facades.d.ts +94 -0
  132. package/dist/facades.d.ts.map +1 -0
  133. package/dist/facades.js +389 -0
  134. package/dist/facades.js.map +1 -0
  135. package/dist/group-fs.d.ts +120 -0
  136. package/dist/group-fs.d.ts.map +1 -0
  137. package/dist/group-fs.js +539 -0
  138. package/dist/group-fs.js.map +1 -0
  139. package/dist/group-id.d.ts +9 -12
  140. package/dist/group-id.d.ts.map +1 -1
  141. package/dist/group-id.js +41 -63
  142. package/dist/group-id.js.map +1 -1
  143. package/dist/group-resources.d.ts +98 -0
  144. package/dist/group-resources.d.ts.map +1 -0
  145. package/dist/group-resources.js +635 -0
  146. package/dist/group-resources.js.map +1 -0
  147. package/dist/index.d.ts +8 -3
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +10 -1
  150. package/dist/index.js.map +1 -1
  151. package/dist/keystore/index.d.ts +2 -54
  152. package/dist/keystore/index.d.ts.map +1 -1
  153. package/dist/keystore/indexeddb-identity-store.d.ts +3 -0
  154. package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
  155. package/dist/keystore/indexeddb-identity-store.js +65 -0
  156. package/dist/keystore/indexeddb-identity-store.js.map +1 -1
  157. package/dist/keystore/indexeddb-shared.d.ts +3 -17
  158. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  159. package/dist/keystore/indexeddb-shared.js +4 -47
  160. package/dist/keystore/indexeddb-shared.js.map +1 -1
  161. package/dist/keystore/indexeddb-token-store.d.ts +1 -64
  162. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  163. package/dist/keystore/indexeddb-token-store.js +45 -774
  164. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  165. package/dist/logger.d.ts +2 -0
  166. package/dist/logger.d.ts.map +1 -1
  167. package/dist/logger.js +4 -0
  168. package/dist/logger.js.map +1 -1
  169. package/dist/register-flow.d.ts +1 -0
  170. package/dist/register-flow.d.ts.map +1 -1
  171. package/dist/register-flow.js +3 -0
  172. package/dist/register-flow.js.map +1 -1
  173. package/dist/service-proxy.d.ts +1 -0
  174. package/dist/service-proxy.d.ts.map +1 -1
  175. package/dist/service-proxy.js +15 -3
  176. package/dist/service-proxy.js.map +1 -1
  177. package/dist/storage/errors.d.ts +28 -0
  178. package/dist/storage/errors.d.ts.map +1 -0
  179. package/dist/storage/errors.js +65 -0
  180. package/dist/storage/errors.js.map +1 -0
  181. package/dist/storage/index.d.ts +2 -0
  182. package/dist/storage/index.d.ts.map +1 -0
  183. package/dist/storage/index.js +2 -0
  184. package/dist/storage/index.js.map +1 -0
  185. package/dist/storage/lowlevel.d.ts +322 -0
  186. package/dist/storage/lowlevel.d.ts.map +1 -0
  187. package/dist/storage/lowlevel.js +471 -0
  188. package/dist/storage/lowlevel.js.map +1 -0
  189. package/dist/storage/types.d.ts +59 -0
  190. package/dist/storage/types.d.ts.map +1 -0
  191. package/dist/storage/types.js +113 -0
  192. package/dist/storage/types.js.map +1 -0
  193. package/dist/storage/vfs.d.ts +166 -0
  194. package/dist/storage/vfs.d.ts.map +1 -0
  195. package/dist/storage/vfs.js +457 -0
  196. package/dist/storage/vfs.js.map +1 -0
  197. package/dist/tools/cross-sdk-agent.d.ts +3 -0
  198. package/dist/tools/cross-sdk-agent.d.ts.map +1 -0
  199. package/dist/tools/cross-sdk-agent.js +1376 -0
  200. package/dist/tools/cross-sdk-agent.js.map +1 -0
  201. package/dist/transport.d.ts +5 -0
  202. package/dist/transport.d.ts.map +1 -1
  203. package/dist/transport.js +125 -12
  204. package/dist/transport.js.map +1 -1
  205. package/dist/types.d.ts +39 -56
  206. package/dist/types.d.ts.map +1 -1
  207. package/dist/v2/session/session.d.ts +2 -0
  208. package/dist/v2/session/session.d.ts.map +1 -1
  209. package/dist/v2/session/session.js +58 -22
  210. package/dist/v2/session/session.js.map +1 -1
  211. package/dist/v2/state/commitment.d.ts +1 -1
  212. package/dist/v2/state/commitment.d.ts.map +1 -1
  213. package/dist/v2/state/commitment.js +5 -3
  214. package/dist/v2/state/commitment.js.map +1 -1
  215. package/dist/validators.d.ts +35 -0
  216. package/dist/validators.d.ts.map +1 -0
  217. package/dist/validators.js +127 -0
  218. package/dist/validators.js.map +1 -0
  219. package/dist/version.d.ts +1 -1
  220. package/dist/version.d.ts.map +1 -1
  221. package/dist/version.js +1 -1
  222. package/dist/version.js.map +1 -1
  223. package/package.json +44 -44
@@ -1,8 +1,9 @@
1
1
  import { normalizeSlotId, slotIsolationKey } from '../config.js';
2
2
  import { ClientSignatureError, ConnectionError, PermissionError, StateError, ValidationError } from '../errors.js';
3
3
  import { normalizeGroupId } from '../group-id.js';
4
+ import { validateAIDFormat, validateGroupIDFormat } from '../validators.js';
4
5
  import { p1363ToDer, pemToArrayBuffer, uint8ToBase64 } from '../crypto.js';
5
- import { isJsonObject, } from '../types.js';
6
+ import { ConnectionState, isJsonObject, } from '../types.js';
6
7
  const INTERNAL_ONLY_METHODS = new Set([
7
8
  'auth.login1',
8
9
  'auth.aid_login1',
@@ -12,9 +13,6 @@ const INTERNAL_ONLY_METHODS = new Set([
12
13
  'auth.refresh_token',
13
14
  'initialize',
14
15
  ]);
15
- const REMOVED_E2EE_METHODS = new Set([
16
- 'group.rotate_epoch',
17
- ]);
18
16
  const PROTECTED_HEADERS_METHODS = new Set([
19
17
  'message.send',
20
18
  'group.send',
@@ -32,40 +30,101 @@ const SIGNED_METHODS = new Set([
32
30
  'group.v2.propose_state', 'group.v2.confirm_state',
33
31
  'group.v2.get_proposal',
34
32
  'group.kick', 'group.add_member',
35
- 'group.leave', 'group.remove_member', 'group.update_rules',
36
- 'group.update', 'group.update_announcement',
37
- 'group.update_join_requirements', 'group.set_role',
38
- 'group.transfer_owner', 'group.review_join_request',
33
+ 'group.leave', 'group.remove_member',
34
+ 'group.update',
35
+ 'group.set_role',
36
+ 'group.transfer_owner', 'group.bind_group_aid', 'group.renew_group_aid', 'group.complete_transfer',
37
+ 'group.review_join_request',
39
38
  'group.batch_review_join_request',
40
39
  'group.request_join', 'group.use_invite_code',
41
40
  'group.thought.put',
42
41
  'message.thought.put',
43
42
  'group.set_settings',
44
- 'group.resources.put', 'group.resources.create_folder',
45
- 'group.resources.rename', 'group.resources.move',
46
- 'group.resources.mount_object', 'group.resources.update',
47
- 'group.resources.delete', 'group.resources.cleanup_by_storage_ref',
48
- 'group.resources.request_add', 'group.resources.request_mount_object',
49
- 'group.resources.direct_add', 'group.resources.approve_request',
50
- 'group.resources.reject_request', 'group.resources.unmount',
51
- 'group.resources.get_access', 'group.resources.resolve_access_ticket',
43
+ 'group.update_announcement',
44
+ 'group.update_rules',
45
+ 'group.fs.mkdir', 'group.fs.rm', 'group.fs.cp', 'group.fs.mv',
46
+ 'group.fs.set_acl', 'group.fs.remove_acl',
47
+ 'group.fs.mount', 'group.fs.umount',
48
+ 'group.fs.check_upload', 'group.fs.create_upload_session',
49
+ 'group.fs.complete_upload', 'group.fs.create_download_ticket',
52
50
  'storage.put_object', 'storage.delete_object', 'storage.get_by_share',
53
51
  'storage.create_share_link', 'storage.revoke_share_link',
54
52
  'storage.create_upload_session', 'storage.complete_upload',
55
53
  'storage.create_folder', 'storage.rename_folder', 'storage.move_folder',
56
54
  'storage.delete_folder', 'storage.move_object', 'storage.copy_object',
57
55
  'storage.batch_delete', 'storage.set_object_meta', 'storage.append_object',
56
+ 'storage.set_acl', 'storage.remove_acl', 'storage.set_visibility',
57
+ 'storage.check_access',
58
+ 'storage.issue_token', 'storage.revoke_token',
59
+ 'storage.create_symlink', 'storage.atomic_repoint',
60
+ 'storage.rename_symlink', 'storage.delete_symlink',
61
+ 'storage.fs.mkdir', 'storage.fs.remove', 'storage.fs.rename', 'storage.fs.copy',
62
+ 'storage.fs.mount', 'storage.fs.approve', 'storage.fs.reject', 'storage.fs.unmount',
63
+ 'storage.fs.invalidate_membership',
64
+ 'storage.volume.create', 'storage.volume.renew', 'storage.volume.expire_due',
65
+ 'collab.create', 'collab.commit', 'collab.clone',
66
+ 'collab.prune', 'collab.unregister',
67
+ 'collab.tag.create', 'collab.tag.restore',
68
+ 'collab.tag.rm', 'collab.tag.prune',
58
69
  'group.commit_state',
59
70
  'group.ban', 'group.unban',
60
71
  'group.dissolve', 'group.suspend', 'group.resume',
61
72
  ]);
73
+ const SIGNING_KEY_CACHE_MAX = 32;
74
+ const signingKeyCache = new Map();
75
+ const certFingerprintCache = new Map();
76
+ function cacheGet(cache, key) {
77
+ const value = cache.get(key);
78
+ if (value !== undefined) {
79
+ cache.delete(key);
80
+ cache.set(key, value);
81
+ }
82
+ return value;
83
+ }
84
+ function cachePut(cache, key, value) {
85
+ cache.set(key, value);
86
+ while (cache.size > SIGNING_KEY_CACHE_MAX) {
87
+ const first = cache.keys().next().value;
88
+ if (first === undefined)
89
+ break;
90
+ cache.delete(first);
91
+ }
92
+ return value;
93
+ }
94
+ async function sha256HexText(text) {
95
+ const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));
96
+ return Array.from(new Uint8Array(digest)).map(b => b.toString(16).padStart(2, '0')).join('');
97
+ }
98
+ async function signingPrivateKey(privateKeyPem) {
99
+ const key = await sha256HexText(privateKeyPem);
100
+ let cached = cacheGet(signingKeyCache, key);
101
+ if (!cached) {
102
+ const pkcs8 = pemToArrayBuffer(privateKeyPem);
103
+ cached = crypto.subtle.importKey('pkcs8', pkcs8, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign']);
104
+ cachePut(signingKeyCache, key, cached);
105
+ }
106
+ return await cached;
107
+ }
108
+ async function signingCertFingerprint(certPem) {
109
+ const key = await sha256HexText(certPem);
110
+ let cached = cacheGet(certFingerprintCache, key);
111
+ if (!cached) {
112
+ cached = (async () => {
113
+ const certDer = pemToArrayBuffer(certPem);
114
+ const fpBuf = await crypto.subtle.digest('SHA-256', certDer);
115
+ return 'sha256:' + Array.from(new Uint8Array(fpBuf)).map(b => b.toString(16).padStart(2, '0')).join('');
116
+ })();
117
+ cachePut(certFingerprintCache, key, cached);
118
+ }
119
+ return await cached;
120
+ }
62
121
  const PULL_GATE_STALE_MS = 30000;
63
122
  const NON_IDEMPOTENT_TIMEOUT = 35;
64
123
  const NON_IDEMPOTENT_METHODS = new Set([
65
124
  'message.send', 'group.send', 'group.create', 'group.invite',
66
125
  'group.kick', 'group.remove_member', 'group.leave', 'group.dissolve',
67
- 'group.update_name', 'group.update_avatar', 'group.update_announcement',
68
- 'group.update_settings',
126
+ 'group.set_settings',
127
+ 'group.update_announcement', 'group.update_rules',
69
128
  'storage.put_object', 'storage.delete_object',
70
129
  'storage.create_share_link', 'storage.revoke_share_link',
71
130
  'storage.get_by_share',
@@ -73,19 +132,39 @@ const NON_IDEMPOTENT_METHODS = new Set([
73
132
  'storage.create_folder', 'storage.rename_folder', 'storage.move_folder',
74
133
  'storage.delete_folder', 'storage.move_object', 'storage.copy_object',
75
134
  'storage.batch_delete', 'storage.set_object_meta', 'storage.append_object',
135
+ 'storage.set_acl', 'storage.remove_acl', 'storage.set_visibility',
136
+ 'storage.issue_token', 'storage.revoke_token',
137
+ 'storage.create_symlink', 'storage.atomic_repoint',
138
+ 'storage.rename_symlink', 'storage.delete_symlink',
139
+ 'storage.fs.mkdir', 'storage.fs.remove', 'storage.fs.rename', 'storage.fs.copy',
140
+ 'storage.fs.mount', 'storage.fs.approve', 'storage.fs.reject', 'storage.fs.unmount',
141
+ 'storage.fs.invalidate_membership',
142
+ 'storage.volume.create', 'storage.volume.renew', 'storage.volume.expire_due',
76
143
  'auth.create_aid', 'auth.renew_cert', 'auth.rekey',
77
144
  'message.thought.put', 'group.thought.put',
78
- 'group.add_member',
79
- 'group.resources.put', 'group.resources.create_folder',
80
- 'group.resources.rename', 'group.resources.move',
81
- 'group.resources.mount_object', 'group.resources.update',
82
- 'group.resources.delete', 'group.resources.cleanup_by_storage_ref',
83
- 'group.resources.request_add', 'group.resources.request_mount_object',
84
- 'group.resources.direct_add', 'group.resources.approve_request',
85
- 'group.resources.reject_request', 'group.resources.unmount',
86
- 'group.resources.get_access',
87
- 'group.resources.resolve_access_ticket',
145
+ 'group.add_member', 'group.bind_group_aid', 'group.complete_transfer',
146
+ 'group.fs.mkdir', 'group.fs.rm', 'group.fs.cp', 'group.fs.mv',
147
+ 'group.fs.set_acl', 'group.fs.remove_acl',
148
+ 'group.fs.mount', 'group.fs.umount',
149
+ 'group.fs.check_upload', 'group.fs.create_upload_session',
150
+ 'group.fs.complete_upload', 'group.fs.create_download_ticket',
151
+ 'collab.create', 'collab.commit', 'collab.clone',
152
+ 'collab.prune', 'collab.unregister',
153
+ 'collab.tag.create', 'collab.tag.restore',
154
+ 'collab.tag.rm', 'collab.tag.prune',
88
155
  ]);
156
+ function hasMatchingV2Session(client) {
157
+ const session = client._v2Session;
158
+ if (!session)
159
+ return false;
160
+ if (session.currentIkPubDer === undefined)
161
+ return true;
162
+ return session.aid === client._aid && session.deviceId === client._deviceId;
163
+ }
164
+ function isTransientV2PullFallbackError(error) {
165
+ const text = (error instanceof Error ? error.message : String(error)).toLowerCase();
166
+ return text.includes('no_service') || text.includes('service plane unavailable');
167
+ }
89
168
  export class RpcPipeline {
90
169
  runtime;
91
170
  constructor(runtime) {
@@ -107,7 +186,14 @@ export class RpcPipeline {
107
186
  }
108
187
  async callImpl(method, params) {
109
188
  const client = this.runtime.client;
110
- const p = this.preflight(method, params).params;
189
+ const preflight = this.preflight(method, params);
190
+ const p = preflight.params;
191
+ const rpcBackground = preflight.rpcBackground;
192
+ const runWithRpcPriority = async (operation) => {
193
+ if (!rpcBackground)
194
+ return await operation();
195
+ return await client._withBackgroundRpc(operation);
196
+ };
111
197
  const skipSendResultEnvelope = Boolean(p._skip_send_result_envelope);
112
198
  delete p._skip_send_result_envelope;
113
199
  if (method === 'message.send') {
@@ -131,7 +217,7 @@ export class RpcPipeline {
131
217
  if (encrypt) {
132
218
  await client._ensureV2SessionReady('group.send', 'V2 session not initialized; encrypted group.send requires V2 (V1 E2EE removed)');
133
219
  client._clientLog.debug('call route: group.send -> V2 encrypted send');
134
- return await client._sendGroupV2(String(p.group_id ?? ''), p.payload ?? {}, {
220
+ return await client._sendGroupV2(String(p.group_aid ?? p.group_id ?? ''), p.payload ?? {}, {
135
221
  messageId: String(p.message_id ?? '') || undefined,
136
222
  timestamp: p.timestamp,
137
223
  protectedHeaders: client._protectedHeadersFromParams(p),
@@ -161,27 +247,35 @@ export class RpcPipeline {
161
247
  const pullGateKey = this.pullGateKeyForCall(method, p);
162
248
  if (pullGateKey) {
163
249
  return await this.runPullSerialized(pullGateKey, async () => {
164
- return await this.callImplInner(method, p, skipSendResultEnvelope);
250
+ return await runWithRpcPriority(() => this.callImplInner(method, p, skipSendResultEnvelope));
165
251
  });
166
252
  }
167
- return await this.callImplInner(method, p, skipSendResultEnvelope);
253
+ return await runWithRpcPriority(() => this.callImplInner(method, p, skipSendResultEnvelope));
168
254
  }
169
255
  async callImplInner(method, p, skipSendResultEnvelope = false) {
170
256
  const client = this.runtime.client;
171
- if (method === 'message.pull') {
172
- await client._ensureV2SessionReady('message.pull');
173
- client._clientLog.debug('call route: message.pull -> V2 pull');
174
- const messages = await client._pullV2(Number(p.after_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, { force: p.force === true });
175
- return { messages };
257
+ if (method === 'message.v2.pull' || (method === 'message.pull' && hasMatchingV2Session(client))) {
258
+ try {
259
+ await client._ensureV2SessionReady('message.pull');
260
+ client._clientLog.debug(`call route: ${method} -> V2 pull`);
261
+ const messages = await client._pullV2(Number(p.after_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, { force: p.force === true });
262
+ return { messages };
263
+ }
264
+ catch (exc) {
265
+ if (method !== 'message.pull' || !isTransientV2PullFallbackError(exc)) {
266
+ throw exc;
267
+ }
268
+ client._clientLog.warn(`message.pull V2 route unavailable, fallback to plain pull: ${exc instanceof Error ? exc.message : String(exc)}`);
269
+ }
176
270
  }
177
- if (method === 'message.ack') {
271
+ if (method === 'message.v2.ack' || (method === 'message.ack' && hasMatchingV2Session(client))) {
178
272
  await client._ensureV2SessionReady('message.ack');
179
- client._clientLog.debug('call route: message.ack -> V2 ack');
273
+ client._clientLog.debug(`call route: ${method} -> V2 ack`);
180
274
  return await client._ackV2(Number(p.seq ?? p.up_to_seq ?? 0) || undefined);
181
275
  }
182
- if (method === 'group.pull' && p.group_id) {
276
+ if ((method === 'group.v2.pull' || method === 'group.pull') && p.group_id && (method === 'group.v2.pull' || hasMatchingV2Session(client))) {
183
277
  await client._ensureV2SessionReady('group.pull');
184
- client._clientLog.debug('call route: group.pull -> V2 pull');
278
+ client._clientLog.debug(`call route: ${method} -> V2 pull`);
185
279
  const hasExplicitAfterSeq = 'after_seq' in p || 'after_message_seq' in p;
186
280
  const cursorParams = client._explicitGroupCursorParams(p);
187
281
  const ownsCursor = Object.keys(cursorParams).length === 0 || client._groupCursorTargetsCurrentInstance(cursorParams);
@@ -192,24 +286,27 @@ export class RpcPipeline {
192
286
  pullOpts.cursorParams = cursorParams;
193
287
  if (!ownsCursor)
194
288
  pullOpts.ownsCursor = false;
195
- const messages = await client._pullGroupV2(String(p.group_id), Number(p.after_seq ?? p.after_message_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, Object.keys(pullOpts).length > 0 ? pullOpts : undefined);
289
+ if (String(p.group_id ?? '').trim())
290
+ pullOpts.wireGroupId = String(p.group_id).trim();
291
+ const messages = await client._pullGroupV2(String(p.group_aid ?? p.group_id), Number(p.after_seq ?? p.after_message_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, Object.keys(pullOpts).length > 0 ? pullOpts : undefined);
196
292
  return { messages };
197
293
  }
198
- if (method === 'group.ack_messages' && p.group_id) {
294
+ if ((method === 'group.v2.ack' || method === 'group.ack_messages') && p.group_id && (method === 'group.v2.ack' || hasMatchingV2Session(client))) {
199
295
  await client._ensureV2SessionReady('group.ack_messages');
200
- client._clientLog.debug('call route: group.ack_messages -> V2 ack');
296
+ client._clientLog.debug(`call route: ${method} -> V2 ack`);
201
297
  const cursorParams = client._explicitGroupCursorParams(p);
202
298
  const ownsCursor = Object.keys(cursorParams).length === 0 || client._groupCursorTargetsCurrentInstance(cursorParams);
203
299
  if (!ownsCursor) {
204
300
  return await client._rawGroupAckMessages(p);
205
301
  }
206
- return await client._ackGroupV2(String(p.group_id), Number(p.seq ?? p.msg_seq ?? p.up_to_seq ?? 0) || undefined);
302
+ return await client._ackGroupV2(String(p.group_aid ?? p.group_id), Number(p.seq ?? p.msg_seq ?? p.up_to_seq ?? 0) || undefined);
207
303
  }
208
304
  await this.applyClientSignature(method, p);
209
305
  const callTimeout = NON_IDEMPOTENT_METHODS.has(method) ? NON_IDEMPOTENT_TIMEOUT : undefined;
306
+ const rpcBackground = client._backgroundRpcDepth > 0;
210
307
  let result = callTimeout
211
- ? await client._transport.call(method, p, callTimeout)
212
- : await client._transport.call(method, p);
308
+ ? await client._transport.call(method, p, callTimeout, undefined, rpcBackground)
309
+ : await client._transport.call(method, p, undefined, undefined, rpcBackground);
213
310
  result = await this.postprocessResult(method, p, result);
214
311
  if (!skipSendResultEnvelope) {
215
312
  result = client._delivery.attachSendResultEnvelope(method, p, result, Boolean(p.encrypted));
@@ -218,20 +315,20 @@ export class RpcPipeline {
218
315
  }
219
316
  preflight(method, params) {
220
317
  const client = this.runtime.client;
221
- if (client._state !== 'connected') {
318
+ if (client.state !== ConnectionState.READY) {
222
319
  throw new ConnectionError('client is not connected');
223
320
  }
224
321
  if (INTERNAL_ONLY_METHODS.has(method)) {
225
322
  throw new PermissionError(`method is internal_only: ${method}`);
226
323
  }
227
- if (method.startsWith('message.e2ee.') || method.startsWith('group.e2ee.') || REMOVED_E2EE_METHODS.has(method)) {
228
- throw new PermissionError(`legacy E2EE method is removed in this SDK: ${method}`);
229
- }
230
324
  const p = { ...(params ?? {}) };
231
325
  this.mergeInstanceProtectedHeaders(method, p);
326
+ const rpcBackground = Boolean(p._rpc_background) || client._backgroundRpcDepth > 0;
327
+ delete p._rpc_background;
232
328
  if (method === 'message.send' || method === 'group.send') {
233
329
  this.normalizeOutboundMessagePayload(p, method);
234
330
  }
331
+ this.normalizeGroupCallIdentifier(method, p);
235
332
  this.validateOutboundCall(method, p);
236
333
  this.injectMessageCursorContext(method, p);
237
334
  this.captureGroupCursorParams(method, p);
@@ -239,7 +336,7 @@ export class RpcPipeline {
239
336
  const clampedParams = typeof client._clampAckParams === 'function'
240
337
  ? client._clampAckParams(method, p)
241
338
  : p;
242
- return { params: clampedParams };
339
+ return { params: clampedParams, rpcBackground };
243
340
  }
244
341
  mergeInstanceProtectedHeaders(method, params) {
245
342
  const client = this.runtime.client;
@@ -264,6 +361,8 @@ export class RpcPipeline {
264
361
  validateOutboundCall(method, params) {
265
362
  if (method === 'message.send') {
266
363
  this.validateMessageRecipient(params.to);
364
+ // 校验目标 AID 格式(拒绝 __system__ 等非法格式)
365
+ validateAIDFormat(params.to, 'message.send.to');
267
366
  if ('persist' in params) {
268
367
  throw new ValidationError("message.send no longer accepts 'persist'; configure delivery_mode during connect");
269
368
  }
@@ -272,6 +371,8 @@ export class RpcPipeline {
272
371
  }
273
372
  }
274
373
  if (method === 'group.send') {
374
+ // 校验目标 Group ID 格式
375
+ validateGroupIDFormat(params.group_id, 'group.send.group_id');
275
376
  if ('persist' in params) {
276
377
  throw new ValidationError("group.send does not accept 'persist'; group messages are always fanout");
277
378
  }
@@ -289,17 +390,33 @@ export class RpcPipeline {
289
390
  throw new ValidationError(`${method} requires context.type + context.id`);
290
391
  }
291
392
  }
292
- if (method === 'group.thought.get' && !String(params.sender_aid ?? '').trim()) {
293
- throw new ValidationError('group.thought.get requires sender_aid');
393
+ if (method === 'group.thought.put') {
394
+ // 校验目标 Group ID 格式
395
+ validateGroupIDFormat(params.group_id, 'group.thought.put.group_id');
396
+ }
397
+ if (method === 'group.thought.get') {
398
+ if (!String(params.sender_aid ?? '').trim()) {
399
+ throw new ValidationError('group.thought.get requires sender_aid');
400
+ }
401
+ // 校验 sender_aid 格式
402
+ validateAIDFormat(params.sender_aid, 'group.thought.get.sender_aid');
403
+ // 校验目标 Group ID 格式
404
+ validateGroupIDFormat(params.group_id, 'group.thought.get.group_id');
294
405
  }
295
406
  if (method === 'message.thought.put') {
296
407
  this.validateMessageRecipient(params.to);
297
408
  if (!String(params.to ?? '').trim()) {
298
409
  throw new ValidationError('message.thought.put requires to');
299
410
  }
411
+ // 校验目标 AID 格式
412
+ validateAIDFormat(params.to, 'message.thought.put.to');
300
413
  }
301
- if (method === 'message.thought.get' && !String(params.sender_aid ?? '').trim()) {
302
- throw new ValidationError('message.thought.get requires sender_aid');
414
+ if (method === 'message.thought.get') {
415
+ if (!String(params.sender_aid ?? '').trim()) {
416
+ throw new ValidationError('message.thought.get requires sender_aid');
417
+ }
418
+ // 校验 sender_aid 格式
419
+ validateAIDFormat(params.sender_aid, 'message.thought.get.sender_aid');
303
420
  }
304
421
  }
305
422
  injectMessageCursorContext(method, params) {
@@ -318,14 +435,19 @@ export class RpcPipeline {
318
435
  params.slot_id = client._slotId;
319
436
  }
320
437
  async applyClientSignature(method, params) {
321
- if (!SIGNED_METHODS.has(method)) {
322
- return;
438
+ try {
439
+ if (!SIGNED_METHODS.has(method)) {
440
+ return;
441
+ }
442
+ if (this.shouldSkipClientSignature(method, params)) {
443
+ delete params.client_signature;
444
+ return;
445
+ }
446
+ await this.runtime.client._signClientOperation(method, params);
323
447
  }
324
- if (this.shouldSkipClientSignature(method, params)) {
325
- delete params.client_signature;
326
- return;
448
+ finally {
449
+ delete params._client_signature_identity;
327
450
  }
328
- await this.runtime.client._signClientOperation(method, params);
329
451
  }
330
452
  shouldSkipClientSignature(method, params) {
331
453
  if (method !== 'message.send' && method !== 'group.send')
@@ -335,7 +457,10 @@ export class RpcPipeline {
335
457
  return this.runtime.client._isEchoPayload(params.payload);
336
458
  }
337
459
  async signClientOperation(method, params) {
338
- const currentAid = this.runtime.client._currentAid;
460
+ const internal = params._client_signature_identity;
461
+ const currentAid = (internal && typeof internal === 'object')
462
+ ? internal
463
+ : this.runtime.client._currentAid;
339
464
  if (!currentAid?.privateKeyPem)
340
465
  return;
341
466
  try {
@@ -353,16 +478,13 @@ export class RpcPipeline {
353
478
  .map(b => b.toString(16).padStart(2, '0'))
354
479
  .join('');
355
480
  const signData = new TextEncoder().encode(`${method}|${aid}|${ts}|${paramsHash}`);
356
- const pkcs8 = pemToArrayBuffer(currentAid.privateKeyPem);
357
- const cryptoKey = await crypto.subtle.importKey('pkcs8', pkcs8, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign']);
481
+ const cryptoKey = await signingPrivateKey(currentAid.privateKeyPem);
358
482
  const sigP1363 = await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, cryptoKey, signData);
359
483
  const sigDer = p1363ToDer(new Uint8Array(sigP1363));
360
484
  let certFingerprint = '';
361
485
  const certPem = currentAid.certPem;
362
486
  if (certPem) {
363
- const certDer = pemToArrayBuffer(certPem);
364
- const fpBuf = await crypto.subtle.digest('SHA-256', certDer);
365
- certFingerprint = 'sha256:' + Array.from(new Uint8Array(fpBuf)).map(b => b.toString(16).padStart(2, '0')).join('');
487
+ certFingerprint = await signingCertFingerprint(certPem);
366
488
  }
367
489
  params.client_signature = {
368
490
  aid,
@@ -383,11 +505,11 @@ export class RpcPipeline {
383
505
  return client._aid ? `p2p:${client._aid}` : '';
384
506
  }
385
507
  if (method === 'group.pull' || method === 'group.v2.pull') {
386
- const gid = String(params.group_id ?? '').trim();
508
+ const gid = String(params.group_aid ?? params.group_id ?? '').trim();
387
509
  return gid ? `group:${gid}` : '';
388
510
  }
389
511
  if (method === 'group.pull_events') {
390
- const gid = String(params.group_id ?? '').trim();
512
+ const gid = String(params.group_aid ?? params.group_id ?? '').trim();
391
513
  return gid ? `group_event:${gid}` : '';
392
514
  }
393
515
  return '';
@@ -441,12 +563,14 @@ export class RpcPipeline {
441
563
  async rawCall(method, params, options) {
442
564
  const client = this.runtime.client;
443
565
  const payload = { ...(params ?? {}) };
566
+ const rpcBackground = Boolean(payload._rpc_background) || client._backgroundRpcDepth > 0 || options?.background === true;
567
+ delete payload._rpc_background;
444
568
  const signed = options?.signed ?? true;
445
569
  if (signed) {
446
570
  await this.applyClientSignature(method, payload);
447
571
  }
448
572
  const timeout = options?.timeout;
449
- if (options?.background) {
573
+ if (rpcBackground) {
450
574
  return await client._transport.call(method, payload, timeout, options?.trace, true);
451
575
  }
452
576
  if (options?.trace !== undefined) {
@@ -501,13 +625,13 @@ export class RpcPipeline {
501
625
  }
502
626
  }
503
627
  if (client._seqTracker.getContiguousSeq(ns) !== contigBefore) {
504
- client._saveSeqTrackerState?.();
628
+ client._persistSeq?.(ns);
505
629
  }
506
630
  result._contig_before = contigBefore;
507
631
  }
508
632
  postprocessGroupPull(params, result) {
509
633
  const client = this.runtime.client;
510
- const gid = String(params.group_id ?? '').trim();
634
+ const gid = String(params.group_aid ?? params.group_id ?? '').trim();
511
635
  if (!gid || !client._seqTracker) {
512
636
  return;
513
637
  }
@@ -528,7 +652,7 @@ export class RpcPipeline {
528
652
  }
529
653
  }
530
654
  if (client._seqTracker.getContiguousSeq(ns) !== contigBefore) {
531
- client._saveSeqTrackerState?.();
655
+ client._persistSeq?.(ns);
532
656
  }
533
657
  result._contig_before = contigBefore;
534
658
  }
@@ -548,14 +672,7 @@ export class RpcPipeline {
548
672
  return;
549
673
  }
550
674
  const client = this.runtime.client;
551
- if (params.group_id !== undefined && params.group_id !== null) {
552
- const rawGroupId = String(params.group_id);
553
- const normalizedGroupId = normalizeGroupId(rawGroupId);
554
- if (normalizedGroupId && normalizedGroupId !== rawGroupId) {
555
- client._clientLog?.debug?.(`call group_id normalized: ${rawGroupId} -> ${normalizedGroupId} method=${method}`);
556
- }
557
- params.group_id = normalizedGroupId;
558
- }
675
+ this.normalizeGroupCallIdentifier(method, params);
559
676
  if (params.device_id === undefined) {
560
677
  params.device_id = client._deviceId;
561
678
  }
@@ -563,6 +680,42 @@ export class RpcPipeline {
563
680
  params.slot_id = client._slotId;
564
681
  }
565
682
  }
683
+ normalizeGroupCallIdentifier(method, params) {
684
+ if (!method.startsWith('group.')) {
685
+ return;
686
+ }
687
+ const record = params;
688
+ const rawEntries = [
689
+ ['group_aid', record.group_aid],
690
+ ['groupAid', record.groupAid],
691
+ ['group_id', record.group_id],
692
+ ['groupId', record.groupId],
693
+ ];
694
+ const found = rawEntries.find(([, value]) => String(value ?? '').trim());
695
+ if (found) {
696
+ const [key, raw] = found;
697
+ const rawGroupId = String(raw).trim();
698
+ const normalizedGroupId = normalizeGroupId(rawGroupId);
699
+ if (normalizedGroupId) {
700
+ if (normalizedGroupId !== rawGroupId) {
701
+ this.runtime.client._clientLog?.debug?.(`call group identifier normalized: ${key}=${rawGroupId} -> ${normalizedGroupId} method=${method}`);
702
+ }
703
+ const existingGroupId = String(record.group_id ?? record.groupId ?? '').trim();
704
+ if (key === 'group_id' || key === 'groupId') {
705
+ params.group_id = rawGroupId;
706
+ }
707
+ else if (existingGroupId) {
708
+ params.group_id = existingGroupId;
709
+ }
710
+ else {
711
+ params.group_id = normalizedGroupId;
712
+ }
713
+ params.group_aid = normalizedGroupId;
714
+ }
715
+ }
716
+ delete record.groupAid;
717
+ delete record.groupId;
718
+ }
566
719
  groupCursorParams(params) {
567
720
  const cursorParams = {};
568
721
  for (const key of ['device_id', 'slot_id', 'device_name', 'device_type']) {