@agentunion/fastaun-browser 0.4.8 → 0.4.10

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 (60) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/_packed_docs/CHANGELOG.md +33 -0
  3. package/_packed_docs/INDEX.md +43 -20
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +22 -15
  5. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +244 -16
  6. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +113 -27
  7. package/_packed_docs/sdk/09-group-rpc-manual.md +97 -0
  8. package/_packed_docs/sdk/09-proxy-rpc-manual.md +231 -0
  9. package/_packed_docs/sdk/09-storage-rpc-manual.md +117 -4
  10. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +18 -13
  11. package/_packed_docs/sdk/INDEX.md +26 -14
  12. package/_packed_docs/sdk/Notify/351/200/232/347/237/245/346/226/271/346/241/210.md +214 -0
  13. package/_packed_docs/sdk/README.md +9 -6
  14. package/dist/bundle.js +2015 -440
  15. package/dist/client/delivery.d.ts +4 -0
  16. package/dist/client/delivery.d.ts.map +1 -1
  17. package/dist/client/delivery.js +188 -15
  18. package/dist/client/delivery.js.map +1 -1
  19. package/dist/client/group-state.d.ts.map +1 -1
  20. package/dist/client/group-state.js +13 -21
  21. package/dist/client/group-state.js.map +1 -1
  22. package/dist/client/identity.d.ts.map +1 -1
  23. package/dist/client/identity.js +5 -11
  24. package/dist/client/identity.js.map +1 -1
  25. package/dist/client/lifecycle.d.ts +2 -0
  26. package/dist/client/lifecycle.d.ts.map +1 -1
  27. package/dist/client/lifecycle.js +86 -26
  28. package/dist/client/lifecycle.js.map +1 -1
  29. package/dist/client/rpc-pipeline.d.ts +4 -1
  30. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  31. package/dist/client/rpc-pipeline.js +131 -0
  32. package/dist/client/rpc-pipeline.js.map +1 -1
  33. package/dist/client/runtime.d.ts +84 -0
  34. package/dist/client/runtime.d.ts.map +1 -1
  35. package/dist/client/runtime.js +234 -0
  36. package/dist/client/runtime.js.map +1 -1
  37. package/dist/client/v2-e2ee.d.ts.map +1 -1
  38. package/dist/client/v2-e2ee.js +15 -15
  39. package/dist/client/v2-e2ee.js.map +1 -1
  40. package/dist/client.d.ts +20 -31
  41. package/dist/client.d.ts.map +1 -1
  42. package/dist/client.js +90 -300
  43. package/dist/client.js.map +1 -1
  44. package/dist/index.d.ts +2 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +2 -0
  47. package/dist/index.js.map +1 -1
  48. package/dist/service-proxy.d.ts +219 -0
  49. package/dist/service-proxy.d.ts.map +1 -0
  50. package/dist/service-proxy.js +1321 -0
  51. package/dist/service-proxy.js.map +1 -0
  52. package/dist/transport.d.ts +2 -0
  53. package/dist/transport.d.ts.map +1 -1
  54. package/dist/transport.js +34 -0
  55. package/dist/transport.js.map +1 -1
  56. package/dist/version.d.ts +1 -1
  57. package/dist/version.d.ts.map +1 -1
  58. package/dist/version.js +1 -1
  59. package/dist/version.js.map +1 -1
  60. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -81,6 +81,7 @@ const DEFAULT_SESSION_OPTIONS = {
81
81
  const RECONNECT_MIN_BASE_DELAY_SECONDS = 1.0;
82
82
  const RECONNECT_MAX_BASE_DELAY_SECONDS = 64.0;
83
83
  const TOKEN_REFRESH_CHECK_INTERVAL_MS = 30_000;
84
+ const MAX_NOTIFY_PAYLOAD_SIZE = 64 * 1024;
84
85
  // 心跳间隔下/上限(秒)。0 = 关闭心跳;负值视为 0;其余值 clamp 到 [10, 600]。
85
86
  // 服务端通过 hello.heartbeat_interval 与 meta.ping pong 中的同名字段下发。
86
87
  const HEARTBEAT_MIN_INTERVAL_SECONDS = 10;
@@ -102,7 +103,7 @@ const NON_IDEMPOTENT_METHODS = new Set([
102
103
  'group.kick', 'group.remove_member', 'group.leave', 'group.dissolve',
103
104
  'group.update_name', 'group.update_avatar', 'group.update_announcement',
104
105
  'group.update_settings',
105
- 'storage.upload', 'storage.complete_upload', 'storage.delete',
106
+ 'storage.create_upload_session', 'storage.complete_upload', 'storage.delete_object',
106
107
  'auth.create_aid', 'auth.renew_cert', 'auth.rekey',
107
108
  'message.thought.put', 'group.thought.put',
108
109
  'group.add_member',
@@ -146,7 +147,6 @@ function reconnectSleepDelaySeconds(baseDelay, maxBaseDelay) {
146
147
  }
147
148
  /** 对端证书缓存 TTL(秒) */
148
149
  const PEER_CERT_CACHE_TTL = 3600;
149
- const PEER_PREKEYS_CACHE_TTL = 3600;
150
150
  /**
151
151
  * 将 WebSocket URL 转为对应的 HTTP URL
152
152
  */
@@ -508,6 +508,8 @@ export class AUNClient {
508
508
  _pendingOrderedMsgs = new Map();
509
509
  /** Lazy group sync:首次发送群消息前自动拉取历史 */
510
510
  _groupSynced = new Set();
511
+ /** 群撤回去重:group_id|sorted(message_ids)|recalled_at -> 时间戳,保证应用层只回调一次 */
512
+ _groupRecallSeen = new Map();
511
513
  /** 在线未读 hint 队列:同一 group 只保留最后一条,延迟 drain 降低登录瞬时拉取压力。 */
512
514
  _onlineUnreadHintQueue = new Map();
513
515
  _onlineUnreadHintTimer = null;
@@ -661,6 +663,10 @@ export class AUNClient {
661
663
  this._dispatcher.subscribe('_raw.group.message_created', (data) => {
662
664
  this._onRawGroupMessageCreated(data);
663
665
  });
666
+ // 群组消息撤回推送:在线 push 通道,与 pull 双 tombstone 兜底互补(SDK 去重只回调一次)
667
+ this._dispatcher.subscribe('_raw.group.message_recalled', (data) => {
668
+ this._safeAsync(this._onRawGroupMessageRecalled(data));
669
+ });
664
670
  // 群组变更事件:验签 + 透传 + gap 检测
665
671
  this._dispatcher.subscribe('_raw.group.changed', (data) => {
666
672
  this._onRawGroupChanged(data);
@@ -928,66 +934,11 @@ export class AUNClient {
928
934
  }
929
935
  /** 断开连接但保留本地状态,可再次 connect */
930
936
  async disconnect() {
931
- const tStart = Date.now();
932
- this._clientLog.debug(`disconnect enter: state=${this._state}`);
933
- if (this._closing) {
934
- this._clientLog.debug(`disconnect exit: elapsed=${Date.now() - tStart}ms reason=closing`);
935
- return;
936
- }
937
- if (![
938
- ConnectionState.AUTHENTICATED,
939
- ConnectionState.CONNECTING,
940
- ConnectionState.READY,
941
- ConnectionState.RETRY_BACKOFF,
942
- ConnectionState.RECONNECTING,
943
- ConnectionState.CONNECTION_FAILED,
944
- ].includes(this.state)) {
945
- this._clientLog.debug(`disconnect exit: elapsed=${Date.now() - tStart}ms reason=not_connected`);
946
- return;
947
- }
948
- this._saveSeqTrackerState();
949
- this._stopBackgroundTasks();
950
- if (this._reconnectAbort) {
951
- this._reconnectAbort.abort();
952
- this._reconnectAbort = null;
953
- this._reconnectActive = false;
954
- }
955
- await this._transport.close();
956
- this._state = 'standby';
957
- await this._dispatcher.publish('state_change', { state: this._publicState(this._state) });
958
- this._clientLog.debug(`disconnect exit: elapsed=${Date.now() - tStart}ms`);
937
+ return this._lifecycle.disconnect();
959
938
  }
960
939
  /** 关闭连接 */
961
940
  async close() {
962
- const tStart = Date.now();
963
- this._clientLog.debug(`close enter: state=${this._state}`);
964
- this._closing = true;
965
- this._saveSeqTrackerState();
966
- this._stopBackgroundTasks();
967
- // 取消进行中的重连
968
- if (this._reconnectAbort) {
969
- this._reconnectAbort.abort();
970
- this._reconnectAbort = null;
971
- this._reconnectActive = false;
972
- }
973
- if (this._state === 'idle' || this._state === 'closed') {
974
- this._state = 'closed';
975
- this._resetSeqTrackingState();
976
- this._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms reason=already_idle`);
977
- return;
978
- }
979
- // 关闭前通知服务端主动退出(best-effort,失败不阻塞)
980
- try {
981
- await this._transport.call('auth.logout', {});
982
- }
983
- catch {
984
- // auth.logout 失败不影响关闭流程
985
- }
986
- await this._transport.close();
987
- this._state = 'closed';
988
- await this._dispatcher.publish('state_change', { state: this._publicState(this._state) });
989
- this._resetSeqTrackingState();
990
- this._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms`);
941
+ return this._lifecycle.close();
991
942
  }
992
943
  // ── RPC ───────────────────────────────────────────
993
944
  /**
@@ -997,136 +948,91 @@ export class AUNClient {
997
948
  * 自动解密 message.pull/group.pull、Group E2EE 生命周期编排。
998
949
  */
999
950
  async call(method, params) {
1000
- const tStart = Date.now();
1001
- this._clientLog.debug(`call enter: method=${method}`);
1002
- try {
1003
- const result = await this._callImpl(method, params);
1004
- this._clientLog.debug(`call exit: elapsed=${Date.now() - tStart}ms method=${method}`);
1005
- return result;
1006
- }
1007
- catch (err) {
1008
- this._clientLog.debug(`call exit (error): elapsed=${Date.now() - tStart}ms method=${method} err=${err instanceof Error ? err.message : String(err)}`);
1009
- throw err;
1010
- }
951
+ return await this._rpcPipeline.call(method, params);
1011
952
  }
1012
- async _callImpl(method, params) {
1013
- const p = this._rpcPipeline.preflight(method, params).params;
1014
- // 自动加密:message.send 默认加密(encrypt 默认 true)— V2-only
1015
- if (method === 'message.send') {
1016
- const encrypt = p.encrypt !== undefined ? p.encrypt : true;
1017
- delete p.encrypt;
1018
- if (encrypt) {
1019
- await this._ensureV2SessionReady('message.send', 'V2 session not initialized; encrypted message.send requires V2 (V1 E2EE removed)');
1020
- this._clientLog.debug('call route: message.send → V2 encrypted send');
1021
- return await this._sendV2(String(p.to ?? ''), p.payload ?? {}, {
1022
- messageId: String(p.message_id ?? '') || undefined,
1023
- timestamp: p.timestamp,
1024
- protectedHeaders: this._protectedHeadersFromParams(p),
1025
- context: isJsonObject(p.context) ? p.context : undefined,
1026
- });
1027
- }
1028
- // encrypt=false:明文走通用 RPC 路径;protected_headers/headers 是信封元数据,加密与否都保留
1029
- this._maybeAppendEchoTraceSend(p);
1030
- }
1031
- // 自动加密:group.send 默认加密(encrypt 默认 true)— V2-only
1032
- if (method === 'group.send') {
1033
- const encrypt = p.encrypt !== undefined ? p.encrypt : true;
1034
- delete p.encrypt;
1035
- if (encrypt) {
1036
- await this._ensureV2SessionReady('group.send', 'V2 session not initialized; encrypted group.send requires V2 (V1 E2EE removed)');
1037
- this._clientLog.debug('call route: group.send → V2 encrypted send');
1038
- return await this._sendGroupV2(String(p.group_id ?? ''), p.payload ?? {}, {
1039
- messageId: String(p.message_id ?? '') || undefined,
1040
- timestamp: p.timestamp,
1041
- protectedHeaders: this._protectedHeadersFromParams(p),
1042
- context: isJsonObject(p.context) ? p.context : undefined,
1043
- });
1044
- }
1045
- this._maybeAppendEchoTraceSend(p);
1046
- }
1047
- if (method === 'group.thought.put') {
1048
- const encrypt = p.encrypt !== undefined ? p.encrypt : true;
1049
- delete p.encrypt;
1050
- if (encrypt) {
1051
- await this._ensureV2SessionReady('group.thought.put', 'V2 session not initialized; encrypted group.thought.put requires V2 (V1 E2EE removed)');
1052
- this._clientLog.debug('call route: group.thought.put → V2 encrypted put');
1053
- return this._putGroupThoughtEncryptedV2(p);
1054
- }
953
+ static _notifyParamsSizeOk(params) {
954
+ return new TextEncoder().encode(JSON.stringify(params)).length <= MAX_NOTIFY_PAYLOAD_SIZE;
955
+ }
956
+ static _validateNotifyEventMethod(method) {
957
+ const normalized = String(method ?? '').trim();
958
+ if (!normalized.startsWith('event/app.') || normalized.length <= 'event/app.'.length) {
959
+ throw new ValidationError('routed notify method must be event/app.*');
1055
960
  }
1056
- if (method === 'message.thought.put') {
1057
- const encrypt = p.encrypt !== undefined ? p.encrypt : true;
1058
- delete p.encrypt;
1059
- if (encrypt) {
1060
- await this._ensureV2SessionReady('message.thought.put', 'V2 session not initialized; encrypted message.thought.put requires V2 (V1 E2EE removed)');
1061
- this._clientLog.debug('call route: message.thought.put → V2 encrypted put');
1062
- return this._putMessageThoughtEncryptedV2(p);
1063
- }
961
+ return normalized;
962
+ }
963
+ static _normalizeNotifyTtl(value) {
964
+ if (value === undefined || value === null)
965
+ return undefined;
966
+ const ttl = Number(value);
967
+ if (!Number.isInteger(ttl)) {
968
+ throw new ValidationError('ttl_ms must be an integer');
1064
969
  }
1065
- // Pull Gate:序列化同一 key pull 操作,防止并发重复拉取
1066
- const pullGateKey = this._pullGateKeyForCall(method, p);
1067
- if (pullGateKey) {
1068
- return await this._runPullSerialized(pullGateKey, async () => {
1069
- return await this._callImplInner(method, p);
1070
- });
970
+ if (ttl < 0 || ttl > 60000) {
971
+ throw new ValidationError('ttl_ms must be between 0 and 60000');
1071
972
  }
1072
- return await this._callImplInner(method, p);
973
+ return ttl;
1073
974
  }
1074
975
  /**
1075
- * _callImpl 的内层:pull gate 之后的实际 RPC 分发逻辑。
1076
- * 拆分出来以便 pull gate 包裹整个操作。
976
+ * 发送轻量在线通知,不走离线存储、seq/pull ack。
1077
977
  */
1078
- async _callImplInner(method, p) {
1079
- // message.pull:V2-only,按需初始化后走 V2 pull
1080
- if (method === 'message.pull') {
1081
- await this._ensureV2SessionReady('message.pull');
1082
- this._clientLog.debug('call route: message.pull V2 pull');
1083
- const messages = await this._pullV2(Number(p.after_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, { force: p.force === true });
1084
- return { messages };
1085
- }
1086
- // message.ack:V2-only,按需初始化后走 V2 ack
1087
- if (method === 'message.ack') {
1088
- await this._ensureV2SessionReady('message.ack');
1089
- this._clientLog.debug('call route: message.ack V2 ack');
1090
- return await this._ackV2(Number(p.seq ?? p.up_to_seq ?? 0) || undefined);
1091
- }
1092
- // group.pull:V2-only,按需初始化后走 V2 pull
1093
- if (method === 'group.pull' && p.group_id) {
1094
- await this._ensureV2SessionReady('group.pull');
1095
- this._clientLog.debug('call route: group.pull V2 pull');
1096
- const hasExplicitAfterSeq = 'after_seq' in p || 'after_message_seq' in p;
1097
- const cursorParams = this._explicitGroupCursorParams(p);
1098
- const ownsCursor = Object.keys(cursorParams).length === 0 || this._groupCursorTargetsCurrentInstance(cursorParams);
1099
- const pullOpts = {};
1100
- if (hasExplicitAfterSeq)
1101
- pullOpts.explicitAfterSeq = true;
1102
- if (Object.keys(cursorParams).length > 0)
1103
- pullOpts.cursorParams = cursorParams;
1104
- if (!ownsCursor)
1105
- pullOpts.ownsCursor = false;
1106
- const messages = await this._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);
1107
- return { messages };
1108
- }
1109
- // group.ack_messages:V2-only,按需初始化后走 V2 ack
1110
- if (method === 'group.ack_messages' && p.group_id) {
1111
- await this._ensureV2SessionReady('group.ack_messages');
1112
- this._clientLog.debug('call route: group.ack_messages → V2 ack');
1113
- const cursorParams = this._explicitGroupCursorParams(p);
1114
- const ownsCursor = Object.keys(cursorParams).length === 0 || this._groupCursorTargetsCurrentInstance(cursorParams);
1115
- if (!ownsCursor) {
1116
- return await this._rawGroupAckMessages(p);
978
+ async notify(method, params, options = {}) {
979
+ if (params !== undefined && params !== null && !isJsonObject(params)) {
980
+ throw new ValidationError('notify params must be an object');
981
+ }
982
+ const payload = { ...(params ?? {}) };
983
+ if (!AUNClient._notifyParamsSizeOk(payload)) {
984
+ throw new ValidationError('notify payload is too large');
985
+ }
986
+ const targetAid = String(options.to ?? '').trim();
987
+ const targetGroupId = String(options.group_id ?? options.groupId ?? '').trim();
988
+ const targetDeviceId = String(options.device_id ?? options.deviceId ?? '').trim();
989
+ const targetSlotId = String(options.slot_id ?? options.slotId ?? '').trim();
990
+ const ttl = AUNClient._normalizeNotifyTtl(options.ttl_ms ?? options.ttlMs);
991
+ if (targetAid && targetGroupId) {
992
+ throw new ValidationError('notify() cannot set both to and group_id');
993
+ }
994
+ if (targetSlotId && !targetDeviceId) {
995
+ throw new ValidationError('slot_id requires device_id for notify target');
996
+ }
997
+ if (targetAid) {
998
+ const eventMethod = AUNClient._validateNotifyEventMethod(method);
999
+ const target = { type: 'aid', aid: targetAid };
1000
+ if (targetDeviceId)
1001
+ target.device_id = targetDeviceId;
1002
+ if (targetSlotId)
1003
+ target.slot_id = targetSlotId;
1004
+ const routeParams = {
1005
+ target,
1006
+ deliver: { method: eventMethod, params: payload },
1007
+ };
1008
+ if (ttl !== undefined)
1009
+ routeParams.ttl_ms = ttl;
1010
+ await this._transport.notify('notification/route', routeParams);
1011
+ return;
1012
+ }
1013
+ if (targetGroupId) {
1014
+ const eventMethod = AUNClient._validateNotifyEventMethod(method);
1015
+ const normalizedGroupId = normalizeGroupId(targetGroupId);
1016
+ if (!normalizedGroupId) {
1017
+ throw new ValidationError('group_id is required for group notify');
1117
1018
  }
1118
- return await this._ackGroupV2(String(p.group_id), Number(p.seq ?? p.msg_seq ?? p.up_to_seq ?? 0) || undefined);
1119
- }
1120
- // 关键操作自动附加客户端签名
1121
- await this._rpcPipeline.applyClientSignature(method, p);
1122
- // P1-23: 非幂等方法使用更长超时
1123
- const callTimeout = NON_IDEMPOTENT_METHODS.has(method) ? NON_IDEMPOTENT_TIMEOUT : undefined;
1124
- let result = callTimeout
1125
- ? await this._transport.call(method, p, callTimeout)
1126
- : await this._transport.call(method, p);
1127
- result = await this._rpcPipeline.postprocessResult(method, p, result);
1128
- // ── Group E2EE 自动编排已移除(V2-only:由 group.v2.bootstrap 驱动)────────
1129
- return result;
1019
+ const routeParams = {
1020
+ group_id: normalizedGroupId,
1021
+ deliver: { method: eventMethod, params: payload },
1022
+ };
1023
+ if (ttl !== undefined)
1024
+ routeParams.ttl_ms = ttl;
1025
+ await this._transport.notify('notification/group.route', routeParams);
1026
+ return;
1027
+ }
1028
+ if (targetDeviceId || targetSlotId) {
1029
+ throw new ValidationError('device_id and slot_id require to');
1030
+ }
1031
+ const directMethod = String(method ?? '').trim();
1032
+ if (!directMethod.startsWith('notification/')) {
1033
+ throw new ValidationError('direct notify method must start with notification/');
1034
+ }
1035
+ await this._transport.notify(directMethod, payload);
1130
1036
  }
1131
1037
  async _callRawV2Rpc(method, params) {
1132
1038
  const p = { ...(params ?? {}) };
@@ -1170,55 +1076,30 @@ export class AUNClient {
1170
1076
  _onRawMessageReceived(data) {
1171
1077
  this._delivery.onRawMessageReceived(data);
1172
1078
  }
1173
- /** 实际处理推送消息的异步任务(V2-only:明文消息直接透传,V2 加密消息走 _onV2PushNotification) */
1174
- async _processAndPublishMessage(data) {
1175
- return this._delivery.processAndPublishMessage(data);
1176
- }
1177
1079
  /** 处理群组消息推送:re-publish(V2 加密消息走 V2 push 路径) */
1178
1080
  _onRawGroupMessageCreated(data) {
1179
1081
  return this._delivery.onRawGroupMessageCreated(data);
1180
1082
  }
1083
+ async _onRawGroupMessageRecalled(data) {
1084
+ return this._delivery.onRawGroupMessageRecalled(data);
1085
+ }
1181
1086
  /** 处理 V2 群消息通知:主动 pull V2 envelope,由 pullGroupV2 解密并发布。 */
1182
1087
  async _onRawGroupV2MessageCreated(data) {
1183
1088
  return this._delivery.onRawGroupV2MessageCreated(data);
1184
1089
  }
1185
- /**
1186
- * 处理群组推送消息的异步任务(V2-only:明文消息直接透传)。
1187
- *
1188
- * 带 payload 的事件(消息推送):直接 re-publish。
1189
- * 不带 payload 的事件(通知):自动 pull 最新消息。
1190
- */
1191
- async _processAndPublishGroupMessage(data) {
1192
- return this._delivery.processAndPublishGroupMessage(data);
1193
- }
1194
1090
  async _publishEncryptedPushMessage(normalEvent, undecryptableEvent, ns, seq, msg, group) {
1195
1091
  return await this._v2E2EE.publishEncryptedPushMessage(normalEvent, undecryptableEvent, ns, seq, msg, group);
1196
1092
  }
1197
1093
  async _decryptV2PushMessage(data) {
1198
1094
  return await this._v2E2EE.decryptV2PushMessage(data);
1199
1095
  }
1200
- /** 后台补齐群消息空洞 */
1201
- async _fillGroupGap(groupId) {
1202
- return this._delivery.fillGroupGap(groupId);
1203
- }
1204
- /** 后台补齐群事件空洞 */
1205
- async _fillGroupEventGap(groupId) {
1206
- return this._delivery.fillGroupEventGap(groupId);
1207
- }
1208
1096
  /** 后台补齐 P2P 消息空洞 */
1209
1097
  async _fillP2pGap() {
1210
1098
  return this._delivery.fillP2pGap();
1211
1099
  }
1212
- /** 只按硬上限裁剪 published guard,不能按 contiguousSeq 清理。 */
1213
- _prunePushedSeqs(ns) {
1214
- this._delivery.prunePushedSeqs(ns);
1215
- }
1216
1100
  _markPublishedSeq(ns, seq) {
1217
1101
  this._delivery.markPublishedSeq(ns, seq);
1218
1102
  }
1219
- _attachCurrentInstanceContext(payload) {
1220
- return this._delivery.attachCurrentInstanceContext(payload);
1221
- }
1222
1103
  async _publishAppEvent(event, payload) {
1223
1104
  await this._delivery.publishAppEvent(event, payload);
1224
1105
  }
@@ -1261,9 +1142,6 @@ export class AUNClient {
1261
1142
  const trace = `${this._echoTimestamp()} [AUN-SDK.receive] aid=${this._aid ?? '-'} conn_uptime=${uptime}s`;
1262
1143
  msg.payload = { ...payload, text: payload.text + '\n' + trace };
1263
1144
  }
1264
- _messageTargetsCurrentInstance(message) {
1265
- return this._delivery.messageTargetsCurrentInstance(message);
1266
- }
1267
1145
  async _drainOrderedMessages(ns, beforeSeq) {
1268
1146
  await this._delivery.drainOrderedMessages(ns, beforeSeq);
1269
1147
  }
@@ -1420,82 +1298,6 @@ export class AUNClient {
1420
1298
  const digest = await crypto.subtle.digest('SHA-256', certBytes);
1421
1299
  return 'sha256:' + Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, '0')).join('');
1422
1300
  }
1423
- /**
1424
- * 从 X.509 DER 证书中提取 SubjectPublicKeyInfo 并计算其 SHA-256 指纹。
1425
- * 返回 "sha256:<hex>",提取失败返回空串。
1426
- * 用于 H7 指纹校验(DER 证书指纹 OR SPKI 指纹任一匹配)。
1427
- */
1428
- async _spkiFingerprint(certPem) {
1429
- try {
1430
- const der = new Uint8Array(pemToArrayBuffer(certPem));
1431
- // X.509: Certificate ::= SEQUENCE { tbsCertificate, signatureAlgorithm, signatureValue }
1432
- // tbsCertificate ::= SEQUENCE { version?, serialNumber, signature, issuer, validity, subject, subjectPublicKeyInfo, ... }
1433
- // 逐级解析 SEQUENCE 并定位 SPKI (第 7 个或第 6 个子元素,取决于 version 是否 [0] explicit)。
1434
- const readLen = (buf, pos) => {
1435
- const first = buf[pos];
1436
- if (first < 0x80)
1437
- return { len: first, next: pos + 1 };
1438
- const n = first & 0x7f;
1439
- let len = 0;
1440
- for (let i = 0; i < n; i++)
1441
- len = (len << 8) | buf[pos + 1 + i];
1442
- return { len, next: pos + 1 + n };
1443
- };
1444
- // 外层 SEQUENCE
1445
- if (der[0] !== 0x30)
1446
- return '';
1447
- const outer = readLen(der, 1);
1448
- // tbsCertificate SEQUENCE 起点
1449
- const tbsStart = outer.next;
1450
- if (der[tbsStart] !== 0x30)
1451
- return '';
1452
- const tbsLen = readLen(der, tbsStart + 1);
1453
- let p = tbsLen.next;
1454
- const tbsEnd = tbsLen.next + tbsLen.len;
1455
- // 跳过 [0] EXPLICIT Version(可选)
1456
- if (der[p] === 0xa0) {
1457
- const lv = readLen(der, p + 1);
1458
- p = lv.next + lv.len;
1459
- }
1460
- // 跳过 serialNumber (INTEGER)
1461
- if (der[p] !== 0x02)
1462
- return '';
1463
- let lv = readLen(der, p + 1);
1464
- p = lv.next + lv.len;
1465
- // 跳过 signature (SEQUENCE)
1466
- if (der[p] !== 0x30)
1467
- return '';
1468
- lv = readLen(der, p + 1);
1469
- p = lv.next + lv.len;
1470
- // 跳过 issuer (SEQUENCE)
1471
- if (der[p] !== 0x30)
1472
- return '';
1473
- lv = readLen(der, p + 1);
1474
- p = lv.next + lv.len;
1475
- // 跳过 validity (SEQUENCE)
1476
- if (der[p] !== 0x30)
1477
- return '';
1478
- lv = readLen(der, p + 1);
1479
- p = lv.next + lv.len;
1480
- // 跳过 subject (SEQUENCE)
1481
- if (der[p] !== 0x30)
1482
- return '';
1483
- lv = readLen(der, p + 1);
1484
- p = lv.next + lv.len;
1485
- // subjectPublicKeyInfo (SEQUENCE) — 连同 tag+length+value 全部即 SPKI DER
1486
- if (der[p] !== 0x30 || p >= tbsEnd)
1487
- return '';
1488
- const spkiStart = p;
1489
- const spkiLV = readLen(der, p + 1);
1490
- const spkiEnd = spkiLV.next + spkiLV.len;
1491
- const spkiDer = der.subarray(spkiStart, spkiEnd);
1492
- const digest = await crypto.subtle.digest('SHA-256', spkiDer);
1493
- return 'sha256:' + Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, '0')).join('');
1494
- }
1495
- catch {
1496
- return '';
1497
- }
1498
- }
1499
1301
  async _decryptGroupThoughts(result) {
1500
1302
  return await this._v2E2EE.decryptGroupThoughts(result);
1501
1303
  }
@@ -2046,12 +1848,6 @@ export class AUNClient {
2046
1848
  _validateMessageRecipient(toAid) {
2047
1849
  this._rpcPipeline.validateMessageRecipient(toAid);
2048
1850
  }
2049
- _validateOutboundCall(method, params) {
2050
- this._rpcPipeline.validateOutboundCall(method, params);
2051
- }
2052
- _injectMessageCursorContext(method, params) {
2053
- this._rpcPipeline.injectMessageCursorContext(method, params);
2054
- }
2055
1851
  // ── 内部:断线重连 ────────────────────────────────
2056
1852
  /** 不重连 close code 集合:认证失败/权限错误/被踢等,重连无意义 */
2057
1853
  static _NO_RECONNECT_CODES = new Set([4001, 4003, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015]);
@@ -2454,9 +2250,6 @@ export class AUNClient {
2454
2250
  _scheduleV2SenderIKPending(args) {
2455
2251
  return this._v2E2EE.scheduleSenderIKPending(args);
2456
2252
  }
2457
- async _resolveV2SenderIKPending(fromAid, senderDeviceId, groupId, fetchKey) {
2458
- return await this._v2E2EE.resolveSenderIKPending(fromAid, senderDeviceId, groupId, fetchKey);
2459
- }
2460
2253
  /**
2461
2254
  * V2 P2P 加密发送(推测性:用缓存 bootstrap 直接发,失败刷新重试一次)。
2462
2255
  *
@@ -2826,9 +2619,6 @@ export class AUNClient {
2826
2619
  && (!slotId || slotId === (this._slotId ?? ''));
2827
2620
  }
2828
2621
  // ── Pull Gate(序列化同一 key 的并发 pull)──────────────────
2829
- _pullGateKeyForCall(method, params) {
2830
- return this._rpcPipeline.pullGateKeyForCall(method, params);
2831
- }
2832
2622
  async _runPullSerialized(key, operation) {
2833
2623
  return await this._rpcPipeline.runPullSerialized(key, operation);
2834
2624
  }