@agentunion/fastaun 0.4.12 → 0.5.0
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/CHANGELOG.md +488 -366
- package/_packed_docs/CHANGELOG.md +488 -366
- package/_packed_docs/INDEX.md +111 -53
- package/_packed_docs/KITE_DOCS_GUIDE.md +43 -29
- package/_packed_docs/agent.md/SCHEMA.md +2 -0
- package/_packed_docs/agent.md/examples/codeagent-claudecode.md +2 -0
- package/_packed_docs/agent.md/examples/human-developer.md +2 -0
- package/_packed_docs/agent.md/examples/openclaw-lobster.md +2 -0
- package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +2 -0
- 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
- package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +265 -686
- package/_packed_docs/collab-gateway-boundary-test-report.md +164 -0
- package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +2 -0
- 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
- 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
- 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
- package/_packed_docs/protocol/00-/346/200/273/350/247/210/344/270/216/345/210/206/345/261/202.md +2 -0
- 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
- 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
- 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
- package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +2 -0
- package/_packed_docs/protocol/04-Peer-/345/255/220/345/215/217/350/256/256.md +2 -0
- package/_packed_docs/protocol/05-Relay-/345/255/220/345/215/217/350/256/256.md +2 -0
- 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
- package/_packed_docs/protocol/08-AUN-E2EE-Group.md +2 -0
- package/_packed_docs/protocol/08-AUN-E2EE.md +2 -0
- package/_packed_docs/protocol/09-/345/256/211/345/205/250/350/200/203/350/231/221.md +2 -0
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +28 -85
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +49 -0
- package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +2 -0
- package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +2 -0
- 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
- 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
- package/_packed_docs/protocol/README.md +2 -0
- package/_packed_docs/protocol/agent.md/SCHEMA.md +2 -0
- package/_packed_docs/protocol/agent.md/examples/codeagent-claudecode.md +2 -0
- package/_packed_docs/protocol/agent.md/examples/human-developer.md +2 -0
- package/_packed_docs/protocol/agent.md/examples/openclaw-lobster.md +2 -0
- package/_packed_docs/protocol/aun-docs-guide.md +2 -0
- package/_packed_docs/protocol/index.md +3 -1
- 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
- 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
- package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +2 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +2 -0
- package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +2 -0
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +2 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +2 -0
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +2 -0
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +283 -267
- package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +4 -1
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +2 -0
- package/_packed_docs/sdk/09-collab-rpc-manual.md +550 -0
- package/_packed_docs/sdk/09-custody-api-manual.md +2 -0
- package/_packed_docs/sdk/09-group-rpc-manual.md +197 -445
- package/_packed_docs/sdk/09-message-rpc-manual.md +8 -7
- package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -0
- package/_packed_docs/sdk/09-payload-reference.md +2 -0
- package/_packed_docs/sdk/09-proxy-rpc-manual.md +2 -0
- package/_packed_docs/sdk/09-storage-rpc-manual.md +952 -279
- package/_packed_docs/sdk/09-stream-rpc-manual.md +2 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +33 -20
- 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
- package/_packed_docs/sdk/INDEX.md +46 -29
- package/_packed_docs/sdk/Notify/351/200/232/347/237/245/346/226/271/346/241/210.md +2 -0
- package/_packed_docs/sdk/README.md +17 -15
- package/dist/aid-store.d.ts +25 -0
- package/dist/aid-store.js +80 -0
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +99 -8
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +5 -0
- package/dist/client/delivery.js +169 -8
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.js +58 -26
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.js +67 -8
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +29 -0
- package/dist/client.js +301 -20
- package/dist/client.js.map +1 -1
- package/dist/collab/client.d.ts +38 -0
- package/dist/collab/client.js +124 -0
- package/dist/collab/client.js.map +1 -0
- package/dist/collab/errors.d.ts +15 -0
- package/dist/collab/errors.js +60 -0
- package/dist/collab/errors.js.map +1 -0
- package/dist/collab/index.d.ts +3 -0
- package/dist/collab/index.js +4 -0
- package/dist/collab/index.js.map +1 -0
- package/dist/collab/types.d.ts +110 -0
- package/dist/collab/types.js +2 -0
- package/dist/collab/types.js.map +1 -0
- package/dist/crypto.d.ts +2 -0
- package/dist/crypto.js +6 -0
- package/dist/crypto.js.map +1 -1
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +30 -1
- package/dist/errors.js.map +1 -1
- package/dist/facades.d.ts +89 -0
- package/dist/facades.js +133 -0
- package/dist/facades.js.map +1 -0
- package/dist/group-fs.d.ts +105 -0
- package/dist/group-fs.js +467 -0
- package/dist/group-fs.js.map +1 -0
- package/dist/group-resources.d.ts +31 -0
- package/dist/group-resources.js +84 -0
- package/dist/group-resources.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/register-flow.d.ts +1 -0
- package/dist/register-flow.js +3 -0
- package/dist/register-flow.js.map +1 -1
- package/dist/service-proxy.d.ts +1 -0
- package/dist/service-proxy.js +17 -4
- package/dist/service-proxy.js.map +1 -1
- package/dist/storage/errors.d.ts +27 -0
- package/dist/storage/errors.js +65 -0
- package/dist/storage/errors.js.map +1 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/lowlevel.d.ts +313 -0
- package/dist/storage/lowlevel.js +464 -0
- package/dist/storage/lowlevel.js.map +1 -0
- package/dist/storage/types.d.ts +58 -0
- package/dist/storage/types.js +116 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/storage/vfs.d.ts +147 -0
- package/dist/storage/vfs.js +489 -0
- package/dist/storage/vfs.js.map +1 -0
- package/dist/tools/cross-sdk-agent.js +421 -1
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +3 -0
- package/dist/transport.js +76 -22
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -16,6 +16,7 @@ import * as https from 'node:https';
|
|
|
16
16
|
import { URL } from 'node:url';
|
|
17
17
|
import { configFromMap, getDeviceId, normalizeSlotId } from './config.js';
|
|
18
18
|
import { CryptoProvider } from './crypto.js';
|
|
19
|
+
import { AIDStore } from './aid-store.js';
|
|
19
20
|
import { GatewayDiscovery } from './discovery.js';
|
|
20
21
|
import { DnsResilientNet } from './net.js';
|
|
21
22
|
import { AUNError, AuthError, ConnectionError, E2EEError, NotFoundError, PermissionError, StateError, TimeoutError, ValidationError, } from './errors.js';
|
|
@@ -33,6 +34,9 @@ import { IdentityRuntimeManager } from './client/identity.js';
|
|
|
33
34
|
import { LifecycleController } from './client/lifecycle.js';
|
|
34
35
|
import { PeerDirectory } from './client/peers.js';
|
|
35
36
|
import { RpcPipeline } from './client/rpc-pipeline.js';
|
|
37
|
+
import { CollabClient } from './collab/client.js';
|
|
38
|
+
import { GroupFacade, MessageFacade, StreamFacade } from './facades.js';
|
|
39
|
+
import { StorageVFS } from './storage/vfs.js';
|
|
36
40
|
import { V2E2EECoordinator } from './client/v2-e2ee.js';
|
|
37
41
|
import { GroupStateCoordinator } from './client/group-state.js';
|
|
38
42
|
import { decryptMessage, } from './v2/e2ee/index.js';
|
|
@@ -142,18 +146,25 @@ const NON_IDEMPOTENT_METHODS = new Set([
|
|
|
142
146
|
'storage.create_folder', 'storage.rename_folder', 'storage.move_folder',
|
|
143
147
|
'storage.delete_folder', 'storage.move_object', 'storage.copy_object',
|
|
144
148
|
'storage.batch_delete', 'storage.set_object_meta', 'storage.append_object',
|
|
149
|
+
'storage.set_acl', 'storage.remove_acl', 'storage.set_visibility',
|
|
150
|
+
'storage.issue_token', 'storage.revoke_token',
|
|
151
|
+
'storage.create_symlink', 'storage.atomic_repoint',
|
|
152
|
+
'storage.rename_symlink', 'storage.delete_symlink',
|
|
153
|
+
'storage.fs.mkdir', 'storage.fs.remove', 'storage.fs.rename', 'storage.fs.copy',
|
|
154
|
+
'storage.fs.mount', 'storage.fs.approve', 'storage.fs.reject', 'storage.fs.unmount',
|
|
155
|
+
'storage.fs.invalidate_membership',
|
|
156
|
+
'storage.volume.create', 'storage.volume.renew', 'storage.volume.expire_due',
|
|
157
|
+
'group.fs.mkdir', 'group.fs.rm', 'group.fs.cp', 'group.fs.mv',
|
|
158
|
+
'group.fs.mount', 'group.fs.umount',
|
|
159
|
+
'group.fs.check_upload', 'group.fs.create_upload_session',
|
|
160
|
+
'group.fs.complete_upload', 'group.fs.create_download_ticket',
|
|
145
161
|
'auth.create_aid', 'auth.renew_cert', 'auth.rekey',
|
|
146
162
|
'message.thought.put', 'group.thought.put',
|
|
147
|
-
'group.add_member',
|
|
148
|
-
'
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'
|
|
152
|
-
'group.resources.request_add', 'group.resources.request_mount_object',
|
|
153
|
-
'group.resources.direct_add', 'group.resources.approve_request',
|
|
154
|
-
'group.resources.reject_request', 'group.resources.unmount',
|
|
155
|
-
'group.resources.get_access',
|
|
156
|
-
'group.resources.resolve_access_ticket',
|
|
163
|
+
'group.add_member', 'group.bind_group_aid', 'group.complete_transfer',
|
|
164
|
+
'collab.create', 'collab.commit', 'collab.clone',
|
|
165
|
+
'collab.prune', 'collab.unregister',
|
|
166
|
+
'collab.tag.create', 'collab.tag.restore',
|
|
167
|
+
'collab.tag.rm', 'collab.tag.prune',
|
|
157
168
|
]);
|
|
158
169
|
/** 需要客户端签名的关键方法。运行时逻辑已迁入 RpcPipeline,此处保留给源码审计测试。 */
|
|
159
170
|
const SIGNED_METHODS = new Set([
|
|
@@ -170,26 +181,36 @@ const SIGNED_METHODS = new Set([
|
|
|
170
181
|
'group.leave', 'group.remove_member', 'group.update_rules',
|
|
171
182
|
'group.update', 'group.update_announcement',
|
|
172
183
|
'group.update_join_requirements', 'group.set_role',
|
|
173
|
-
'group.transfer_owner', 'group.
|
|
184
|
+
'group.transfer_owner', 'group.bind_group_aid', 'group.complete_transfer',
|
|
185
|
+
'group.review_join_request',
|
|
174
186
|
'group.batch_review_join_request',
|
|
175
187
|
'group.request_join', 'group.use_invite_code',
|
|
176
188
|
'group.thought.put',
|
|
177
189
|
'message.thought.put',
|
|
178
190
|
'group.set_settings',
|
|
179
|
-
'group.resources.put', 'group.resources.create_folder',
|
|
180
|
-
'group.resources.rename', 'group.resources.move',
|
|
181
|
-
'group.resources.mount_object', 'group.resources.update',
|
|
182
|
-
'group.resources.delete', 'group.resources.cleanup_by_storage_ref',
|
|
183
|
-
'group.resources.request_add', 'group.resources.request_mount_object',
|
|
184
|
-
'group.resources.direct_add', 'group.resources.approve_request',
|
|
185
|
-
'group.resources.reject_request', 'group.resources.unmount',
|
|
186
|
-
'group.resources.get_access', 'group.resources.resolve_access_ticket',
|
|
187
191
|
'storage.put_object', 'storage.delete_object', 'storage.get_by_share',
|
|
188
192
|
'storage.create_share_link', 'storage.revoke_share_link',
|
|
189
193
|
'storage.create_upload_session', 'storage.complete_upload',
|
|
190
194
|
'storage.create_folder', 'storage.rename_folder', 'storage.move_folder',
|
|
191
195
|
'storage.delete_folder', 'storage.move_object', 'storage.copy_object',
|
|
192
196
|
'storage.batch_delete', 'storage.set_object_meta', 'storage.append_object',
|
|
197
|
+
'storage.set_acl', 'storage.remove_acl', 'storage.set_visibility',
|
|
198
|
+
'storage.check_access',
|
|
199
|
+
'storage.issue_token', 'storage.revoke_token',
|
|
200
|
+
'storage.create_symlink', 'storage.atomic_repoint',
|
|
201
|
+
'storage.rename_symlink', 'storage.delete_symlink',
|
|
202
|
+
'storage.fs.mkdir', 'storage.fs.remove', 'storage.fs.rename', 'storage.fs.copy',
|
|
203
|
+
'storage.fs.mount', 'storage.fs.approve', 'storage.fs.reject', 'storage.fs.unmount',
|
|
204
|
+
'storage.fs.invalidate_membership',
|
|
205
|
+
'storage.volume.create', 'storage.volume.renew', 'storage.volume.expire_due',
|
|
206
|
+
'group.fs.mkdir', 'group.fs.rm', 'group.fs.cp', 'group.fs.mv',
|
|
207
|
+
'group.fs.mount', 'group.fs.umount',
|
|
208
|
+
'group.fs.check_upload', 'group.fs.create_upload_session',
|
|
209
|
+
'group.fs.complete_upload', 'group.fs.create_download_ticket',
|
|
210
|
+
'collab.create', 'collab.commit', 'collab.clone',
|
|
211
|
+
'collab.prune', 'collab.unregister',
|
|
212
|
+
'collab.tag.create', 'collab.tag.restore',
|
|
213
|
+
'collab.tag.rm', 'collab.tag.prune',
|
|
193
214
|
'group.commit_state',
|
|
194
215
|
'group.ban', 'group.unban',
|
|
195
216
|
'group.dissolve', 'group.suspend', 'group.resume',
|
|
@@ -226,6 +247,22 @@ function _v2BytesEqual(a, b) {
|
|
|
226
247
|
function formatCaughtError(error) {
|
|
227
248
|
return error instanceof Error ? error : String(error);
|
|
228
249
|
}
|
|
250
|
+
const RELOGIN_REFRESH_ERRORS = new Set([
|
|
251
|
+
'missing refresh_token',
|
|
252
|
+
'invalid_or_expired_refresh_token',
|
|
253
|
+
'refresh not supported',
|
|
254
|
+
]);
|
|
255
|
+
function authErrorRequiresRelogin(error) {
|
|
256
|
+
const data = error.data;
|
|
257
|
+
if (isJsonObject(data)) {
|
|
258
|
+
if (data.relogin_required === true)
|
|
259
|
+
return true;
|
|
260
|
+
const code = String(data.error ?? '').trim().toLowerCase();
|
|
261
|
+
if (RELOGIN_REFRESH_ERRORS.has(code))
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
return RELOGIN_REFRESH_ERRORS.has(error.message.trim().toLowerCase());
|
|
265
|
+
}
|
|
229
266
|
function normalizeDeliveryModeConfig(raw, opts = {}) {
|
|
230
267
|
const defaultMode = String(opts.defaultMode ?? 'fanout').trim().toLowerCase() || 'fanout';
|
|
231
268
|
const defaultRouting = String(opts.defaultRouting ?? 'round_robin').trim().toLowerCase() || 'round_robin';
|
|
@@ -497,6 +534,11 @@ export class AUNClient {
|
|
|
497
534
|
_delivery;
|
|
498
535
|
_v2E2EE;
|
|
499
536
|
_groupState;
|
|
537
|
+
_storage;
|
|
538
|
+
_collab;
|
|
539
|
+
_message;
|
|
540
|
+
_group;
|
|
541
|
+
_stream;
|
|
500
542
|
constructor(aid) {
|
|
501
543
|
if (aid !== null && aid !== undefined && !isAIDObject(aid)) {
|
|
502
544
|
throw new ValidationError('AUNClient only accepts an AID object or no argument');
|
|
@@ -635,6 +677,36 @@ export class AUNClient {
|
|
|
635
677
|
get aid() {
|
|
636
678
|
return this._aid;
|
|
637
679
|
}
|
|
680
|
+
/** AUN Storage VFS 入口 */
|
|
681
|
+
get storage() {
|
|
682
|
+
if (!this._storage)
|
|
683
|
+
this._storage = new StorageVFS(this);
|
|
684
|
+
return this._storage;
|
|
685
|
+
}
|
|
686
|
+
/** AUN Collab 入口 */
|
|
687
|
+
get collab() {
|
|
688
|
+
if (!this._collab)
|
|
689
|
+
this._collab = new CollabClient(this);
|
|
690
|
+
return this._collab;
|
|
691
|
+
}
|
|
692
|
+
/** Message facade 入口 */
|
|
693
|
+
get message() {
|
|
694
|
+
if (!this._message)
|
|
695
|
+
this._message = new MessageFacade(this);
|
|
696
|
+
return this._message;
|
|
697
|
+
}
|
|
698
|
+
/** Group facade 入口 */
|
|
699
|
+
get group() {
|
|
700
|
+
if (!this._group)
|
|
701
|
+
this._group = new GroupFacade(this);
|
|
702
|
+
return this._group;
|
|
703
|
+
}
|
|
704
|
+
/** Stream facade 入口 */
|
|
705
|
+
get stream() {
|
|
706
|
+
if (!this._stream)
|
|
707
|
+
this._stream = new StreamFacade(this);
|
|
708
|
+
return this._stream;
|
|
709
|
+
}
|
|
638
710
|
/** 当前 AID 值对象 */
|
|
639
711
|
get currentAid() {
|
|
640
712
|
return this._currentAid;
|
|
@@ -882,6 +954,201 @@ export class AUNClient {
|
|
|
882
954
|
async call(method, params) {
|
|
883
955
|
return await this._rpcPipeline.call(method, params);
|
|
884
956
|
}
|
|
957
|
+
async createGroup(params = {}) {
|
|
958
|
+
if (!isJsonObject(params)) {
|
|
959
|
+
throw new ValidationError('createGroup params must be an object');
|
|
960
|
+
}
|
|
961
|
+
const payload = { ...params };
|
|
962
|
+
const groupName = String(payload.group_name ?? payload.groupName ?? '').trim();
|
|
963
|
+
if (!groupName) {
|
|
964
|
+
return await this.call('group.create', payload);
|
|
965
|
+
}
|
|
966
|
+
const keyPair = new CryptoProvider().generateIdentity();
|
|
967
|
+
payload.public_key = keyPair.public_key_der_b64;
|
|
968
|
+
payload.curve = keyPair.curve;
|
|
969
|
+
const result = await this.call('group.create', payload);
|
|
970
|
+
const resultMap = isJsonObject(result) ? result : {};
|
|
971
|
+
const group = isJsonObject(resultMap.group) ? resultMap.group : {};
|
|
972
|
+
const aidCert = isJsonObject(resultMap.aid_cert) ? resultMap.aid_cert : {};
|
|
973
|
+
const groupAid = String(group.group_aid ?? resultMap.group_aid ?? '').trim();
|
|
974
|
+
const certPem = String(aidCert.cert ?? aidCert.cert_pem ?? resultMap.cert ?? resultMap.cert_pem ?? '').trim();
|
|
975
|
+
if (!groupAid || !certPem) {
|
|
976
|
+
throw new ValidationError('group.create named group response missing group.group_aid or aid_cert.cert');
|
|
977
|
+
}
|
|
978
|
+
const store = new AIDStore({
|
|
979
|
+
aunPath: this._configModel.aunPath,
|
|
980
|
+
encryptionSeed: this._configModel.seedPassword ?? '',
|
|
981
|
+
slotId: this._slotId,
|
|
982
|
+
verifySsl: this._configModel.verifySsl,
|
|
983
|
+
rootCaPath: this._configModel.rootCaPath,
|
|
984
|
+
debug: this._configModel.debug,
|
|
985
|
+
});
|
|
986
|
+
try {
|
|
987
|
+
const imported = store.importGroupIdentity(groupAid, {
|
|
988
|
+
private_key_pem: keyPair.private_key_pem,
|
|
989
|
+
public_key_der_b64: keyPair.public_key_der_b64,
|
|
990
|
+
curve: keyPair.curve,
|
|
991
|
+
cert_pem: certPem,
|
|
992
|
+
});
|
|
993
|
+
if (!imported.ok) {
|
|
994
|
+
throw new ValidationError(imported.error.message);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
finally {
|
|
998
|
+
store.close();
|
|
999
|
+
}
|
|
1000
|
+
return result;
|
|
1001
|
+
}
|
|
1002
|
+
async bindGroupAid(params = {}, options = {}) {
|
|
1003
|
+
if (!isJsonObject(params)) {
|
|
1004
|
+
throw new ValidationError('bindGroupAid params must be an object');
|
|
1005
|
+
}
|
|
1006
|
+
const store = options.aidStore;
|
|
1007
|
+
if (!store) {
|
|
1008
|
+
throw new ValidationError('bindGroupAid requires aidStore');
|
|
1009
|
+
}
|
|
1010
|
+
const keyPair = new CryptoProvider().generateIdentity();
|
|
1011
|
+
const payload = { ...params };
|
|
1012
|
+
payload.public_key = keyPair.public_key_der_b64;
|
|
1013
|
+
payload.curve = keyPair.curve;
|
|
1014
|
+
const result = await this.call('group.bind_group_aid', payload);
|
|
1015
|
+
const resultMap = isJsonObject(result) ? result : {};
|
|
1016
|
+
const group = isJsonObject(resultMap.group) ? resultMap.group : {};
|
|
1017
|
+
const aidCert = isJsonObject(resultMap.aid_cert) ? resultMap.aid_cert : {};
|
|
1018
|
+
const groupAid = String(group.group_aid ?? resultMap.group_aid ?? '').trim();
|
|
1019
|
+
const certPem = String(aidCert.cert ?? aidCert.cert_pem ?? resultMap.cert ?? resultMap.cert_pem ?? '').trim();
|
|
1020
|
+
if (!groupAid || !certPem) {
|
|
1021
|
+
throw new ValidationError('group.bind_group_aid response missing group.group_aid or aid_cert.cert');
|
|
1022
|
+
}
|
|
1023
|
+
const imported = store.importGroupIdentity(groupAid, {
|
|
1024
|
+
private_key_pem: keyPair.private_key_pem,
|
|
1025
|
+
public_key_der_b64: keyPair.public_key_der_b64,
|
|
1026
|
+
curve: keyPair.curve,
|
|
1027
|
+
cert_pem: certPem,
|
|
1028
|
+
});
|
|
1029
|
+
if (!imported.ok) {
|
|
1030
|
+
throw new ValidationError(imported.error.message);
|
|
1031
|
+
}
|
|
1032
|
+
return result;
|
|
1033
|
+
}
|
|
1034
|
+
async startGroupTransfer(params = {}, options = {}) {
|
|
1035
|
+
if (!isJsonObject(params)) {
|
|
1036
|
+
throw new ValidationError('startGroupTransfer params must be an object');
|
|
1037
|
+
}
|
|
1038
|
+
const store = options.aidStore;
|
|
1039
|
+
if (!store) {
|
|
1040
|
+
throw new ValidationError('startGroupTransfer requires aidStore');
|
|
1041
|
+
}
|
|
1042
|
+
const groupId = String(params.group_id ?? '').trim();
|
|
1043
|
+
const newOwner = String(params.new_owner ?? '').trim();
|
|
1044
|
+
if (!groupId || !newOwner) {
|
|
1045
|
+
throw new ValidationError('startGroupTransfer requires group_id and new_owner');
|
|
1046
|
+
}
|
|
1047
|
+
let groupAid = String(params.group_aid ?? '').trim();
|
|
1048
|
+
if (!groupAid) {
|
|
1049
|
+
const info = await this.call('group.get', { group_id: groupId });
|
|
1050
|
+
const infoMap = isJsonObject(info) ? info : {};
|
|
1051
|
+
const grp = isJsonObject(infoMap.group) ? infoMap.group : infoMap;
|
|
1052
|
+
groupAid = String(grp.group_aid ?? '').trim();
|
|
1053
|
+
}
|
|
1054
|
+
if (!groupAid) {
|
|
1055
|
+
throw new ValidationError('startGroupTransfer: unable to determine group_aid');
|
|
1056
|
+
}
|
|
1057
|
+
const loaded = store.load(groupAid);
|
|
1058
|
+
if (!loaded.ok || !loaded.data) {
|
|
1059
|
+
throw new ValidationError(`startGroupTransfer: group_aid identity not found: ${groupAid}`);
|
|
1060
|
+
}
|
|
1061
|
+
const aidObj = loaded.data.aid;
|
|
1062
|
+
if (!aidObj.isPrivateKeyValid() || !aidObj.privateKeyPem) {
|
|
1063
|
+
throw new ValidationError(`startGroupTransfer: group_aid private key not found: ${groupAid}`);
|
|
1064
|
+
}
|
|
1065
|
+
const nonce = crypto.randomUUID().replace(/-/g, '');
|
|
1066
|
+
const issuedMs = Date.now();
|
|
1067
|
+
const canonical = [
|
|
1068
|
+
'aun-group-owner-transfer-v1',
|
|
1069
|
+
groupId.toLowerCase(),
|
|
1070
|
+
groupAid.toLowerCase(),
|
|
1071
|
+
newOwner.toLowerCase(),
|
|
1072
|
+
nonce,
|
|
1073
|
+
String(issuedMs),
|
|
1074
|
+
].join('|');
|
|
1075
|
+
const signed = aidObj.sign(canonical);
|
|
1076
|
+
if (!signed.ok) {
|
|
1077
|
+
throw new ValidationError(`startGroupTransfer: sign failed: ${signed.error.message}`);
|
|
1078
|
+
}
|
|
1079
|
+
const payload = { ...params, group_aid: groupAid };
|
|
1080
|
+
payload.transfer_auth = { nonce, issued_ms: issuedMs, signature: signed.data.signature };
|
|
1081
|
+
return await this.call('group.transfer_owner', payload);
|
|
1082
|
+
}
|
|
1083
|
+
async completeGroupTransfer(params = {}, options = {}) {
|
|
1084
|
+
if (!isJsonObject(params)) {
|
|
1085
|
+
throw new ValidationError('completeGroupTransfer params must be an object');
|
|
1086
|
+
}
|
|
1087
|
+
const store = options.aidStore;
|
|
1088
|
+
if (!store) {
|
|
1089
|
+
throw new ValidationError('completeGroupTransfer requires aidStore');
|
|
1090
|
+
}
|
|
1091
|
+
const keyPair = new CryptoProvider().generateIdentity();
|
|
1092
|
+
const payload = { ...params };
|
|
1093
|
+
const groupId = String(params.group_id ?? '').trim();
|
|
1094
|
+
if (!groupId) {
|
|
1095
|
+
throw new ValidationError('completeGroupTransfer requires group_id');
|
|
1096
|
+
}
|
|
1097
|
+
let groupAid = String(params.group_aid ?? '').trim();
|
|
1098
|
+
if (!groupAid) {
|
|
1099
|
+
const info = await this.call('group.get', { group_id: groupId });
|
|
1100
|
+
const infoMap = isJsonObject(info) ? info : {};
|
|
1101
|
+
const grp = isJsonObject(infoMap.group) ? infoMap.group : infoMap;
|
|
1102
|
+
groupAid = String(grp.group_aid ?? '').trim();
|
|
1103
|
+
}
|
|
1104
|
+
if (!groupAid) {
|
|
1105
|
+
throw new ValidationError('completeGroupTransfer: unable to determine group_aid');
|
|
1106
|
+
}
|
|
1107
|
+
const current = this.currentAid;
|
|
1108
|
+
const newOwner = String(current?.aid ?? '').trim();
|
|
1109
|
+
if (!current || !newOwner || !current.isPrivateKeyValid()) {
|
|
1110
|
+
throw new ValidationError('completeGroupTransfer requires current new-owner AID with private key');
|
|
1111
|
+
}
|
|
1112
|
+
const nonce = crypto.randomUUID().replace(/-/g, '');
|
|
1113
|
+
const issuedMs = Date.now();
|
|
1114
|
+
const publicKeyHash = crypto.createHash('sha256').update(keyPair.public_key_der_b64, 'utf8').digest('hex');
|
|
1115
|
+
const canonical = [
|
|
1116
|
+
'aun-group-owner-transfer-accept-v1',
|
|
1117
|
+
groupId.toLowerCase(),
|
|
1118
|
+
groupAid.toLowerCase(),
|
|
1119
|
+
newOwner.toLowerCase(),
|
|
1120
|
+
publicKeyHash,
|
|
1121
|
+
nonce,
|
|
1122
|
+
String(issuedMs),
|
|
1123
|
+
].join('|');
|
|
1124
|
+
const signed = current.sign(canonical);
|
|
1125
|
+
if (!signed.ok) {
|
|
1126
|
+
throw new ValidationError(`completeGroupTransfer: accept sign failed: ${signed.error.message}`);
|
|
1127
|
+
}
|
|
1128
|
+
payload.group_aid = groupAid;
|
|
1129
|
+
payload.public_key = keyPair.public_key_der_b64;
|
|
1130
|
+
payload.curve = keyPair.curve;
|
|
1131
|
+
payload.transfer_accept = { nonce, issued_ms: issuedMs, signature: signed.data.signature };
|
|
1132
|
+
const result = await this.call('group.complete_transfer', payload);
|
|
1133
|
+
const resultMap = isJsonObject(result) ? result : {};
|
|
1134
|
+
const group = isJsonObject(resultMap.group) ? resultMap.group : {};
|
|
1135
|
+
const aidCert = isJsonObject(resultMap.aid_cert) ? resultMap.aid_cert : {};
|
|
1136
|
+
const returnedGroupAid = String(group.group_aid ?? resultMap.group_aid ?? '').trim();
|
|
1137
|
+
const certPem = String(aidCert.cert ?? aidCert.cert_pem ?? resultMap.cert ?? resultMap.cert_pem ?? '').trim();
|
|
1138
|
+
if (!returnedGroupAid || !certPem) {
|
|
1139
|
+
throw new ValidationError('group.complete_transfer response missing group.group_aid or aid_cert.cert');
|
|
1140
|
+
}
|
|
1141
|
+
const imported = store.importGroupIdentity(returnedGroupAid, {
|
|
1142
|
+
private_key_pem: keyPair.private_key_pem,
|
|
1143
|
+
public_key_der_b64: keyPair.public_key_der_b64,
|
|
1144
|
+
curve: keyPair.curve,
|
|
1145
|
+
cert_pem: certPem,
|
|
1146
|
+
});
|
|
1147
|
+
if (!imported.ok) {
|
|
1148
|
+
throw new ValidationError(imported.error.message);
|
|
1149
|
+
}
|
|
1150
|
+
return result;
|
|
1151
|
+
}
|
|
885
1152
|
static _notifyParamsSizeOk(params) {
|
|
886
1153
|
return new TextEncoder().encode(JSON.stringify(params)).length <= MAX_NOTIFY_PAYLOAD_SIZE;
|
|
887
1154
|
}
|
|
@@ -2624,6 +2891,18 @@ export class AUNClient {
|
|
|
2624
2891
|
}
|
|
2625
2892
|
catch (exc) {
|
|
2626
2893
|
if (exc instanceof AuthError) {
|
|
2894
|
+
if (authErrorRequiresRelogin(exc)) {
|
|
2895
|
+
this._clientLog.warn(`token refresh requires relogin, stopping refresh loop and triggering reconnect: ${exc.message}`);
|
|
2896
|
+
await this._dispatcher.publish('token.refresh_exhausted', {
|
|
2897
|
+
aid: this._identity?.aid ?? null,
|
|
2898
|
+
consecutive_failures: 1,
|
|
2899
|
+
last_error: String(exc),
|
|
2900
|
+
relogin_required: true,
|
|
2901
|
+
});
|
|
2902
|
+
this._tokenRefreshFailures = 0;
|
|
2903
|
+
await this._handleTransportDisconnect(new Error('token refresh relogin required, triggering reconnect'));
|
|
2904
|
+
return;
|
|
2905
|
+
}
|
|
2627
2906
|
this._tokenRefreshFailures++;
|
|
2628
2907
|
if (this._tokenRefreshFailures >= 3) {
|
|
2629
2908
|
this._clientLog.warn(`token refresh failed ${this._tokenRefreshFailures} consecutive times, stopping refresh loop and triggering reconnect`);
|
|
@@ -2633,7 +2912,7 @@ export class AUNClient {
|
|
|
2633
2912
|
last_error: String(exc),
|
|
2634
2913
|
});
|
|
2635
2914
|
this._tokenRefreshFailures = 0;
|
|
2636
|
-
this._handleTransportDisconnect(new Error('token refresh exhausted, triggering reconnect'));
|
|
2915
|
+
await this._handleTransportDisconnect(new Error('token refresh exhausted, triggering reconnect'));
|
|
2637
2916
|
return;
|
|
2638
2917
|
}
|
|
2639
2918
|
this._clientLog.debug(`token refresh failed (${this._tokenRefreshFailures}/3), will retry: ${exc}`);
|
|
@@ -2750,10 +3029,12 @@ export class AUNClient {
|
|
|
2750
3029
|
eventPayload.code = disconnectInfo.code;
|
|
2751
3030
|
}
|
|
2752
3031
|
await this._dispatcher.publish('state_change', eventPayload);
|
|
3032
|
+
this._reconnectActive = false;
|
|
2753
3033
|
return;
|
|
2754
3034
|
}
|
|
2755
3035
|
// 1000 = 正常关闭, 1006 = 网络异常断开(无 close frame),其他 code = 服务端主动关闭
|
|
2756
3036
|
const serverInitiated = closeCode !== undefined && closeCode !== 1000 && closeCode !== 1006;
|
|
3037
|
+
this._reconnectActive = false;
|
|
2757
3038
|
this._startReconnect(serverInitiated);
|
|
2758
3039
|
}
|
|
2759
3040
|
/** 启动重连循环(默认无限重试 + 指数退避 + 固定上限抖动,仅在不可重试错误、close() 或 max_attempts 耗尽时终止) */
|