@agentunion/fastaun 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -542,23 +542,20 @@ export class AUNClient {
542
542
  _lastDisconnectInfo = null;
543
543
  _logger;
544
544
  _clientLog;
545
- constructor(first, second) {
546
- if (typeof first === 'string') {
545
+ constructor(aid) {
546
+ if (typeof aid === 'string') {
547
547
  throw new ValidationError('AUNClient aid must be an AID object, not a string');
548
548
  }
549
- if (typeof second === 'boolean') {
550
- throw new ValidationError('AUNClient debug must be passed as options.debug');
551
- }
552
- const inputAid = first instanceof AID ? first : null;
553
- if (!inputAid && second !== undefined) {
554
- throw new ValidationError('AUNClient options-only construction accepts a single options object');
555
- }
556
- const options = inputAid ? (second ?? {}) : (first ?? {});
557
- assertClientOptions(options, 'AUNClient options');
549
+ const inputAid = aid instanceof AID ? aid : null;
550
+ const options = {};
558
551
  const rawConfig = clientOptionsConfig(options);
559
- if (inputAid)
552
+ if (inputAid) {
560
553
  rawConfig.aun_path = inputAid.aunPath;
561
- const debug = !!options?.debug;
554
+ rawConfig.verify_ssl = inputAid.verifySsl;
555
+ if (inputAid.rootCaPath)
556
+ rawConfig.root_ca_path = inputAid.rootCaPath;
557
+ rawConfig.debug = inputAid.debug;
558
+ }
562
559
  this._configModel = configFromMap(rawConfig);
563
560
  const initAid = inputAid ? inputAid.aid : null;
564
561
  this._agentMdPath = path.join(this._configModel.aunPath, 'AIDs');
@@ -569,7 +566,7 @@ export class AUNClient {
569
566
  };
570
567
  this._deviceId = (inputAid?.deviceId) || getDeviceId(this._configModel.aunPath);
571
568
  // 初始化 Logger(per-client 单例,必须最早创建)
572
- const debugFlag = this._configModel.debug || debug;
569
+ const debugFlag = this._configModel.debug;
573
570
  this._logger = new AUNLogger({
574
571
  debug: debugFlag,
575
572
  aunPath: this._configModel.aunPath,
@@ -641,9 +638,6 @@ export class AUNClient {
641
638
  };
642
639
  this._state = 'standby';
643
640
  }
644
- if (options?.protected_headers !== undefined) {
645
- this.setProtectedHeaders(options.protected_headers);
646
- }
647
641
  // 内部订阅:推送消息自动解密后 re-publish 给用户
648
642
  this._dispatcher.subscribe('_raw.message.received', (data) => this._onRawMessageReceived(data));
649
643
  // V2 P2P 推送通知:收到通知后自动走 message.v2.pull 拉取并解密
@@ -1026,7 +1020,8 @@ export class AUNClient {
1026
1020
  const result = peer.verifyAgentMd(content);
1027
1021
  if (!result.ok)
1028
1022
  throw new AUNError(result.error.message);
1029
- return { ...result.data, verified: result.data.status === 'verified' };
1023
+ const vd = result.data;
1024
+ return { ...vd, verified: vd.status === 'verified' };
1030
1025
  }
1031
1026
  /**
1032
1027
  * 读取 {agentMdPath}/{self_aid}/agent.md,签名后上传,并把签名结果原子写回本地。
@@ -1121,44 +1116,6 @@ export class AUNClient {
1121
1116
  this._agentMdCache.clear();
1122
1117
  return this._agentMdPath;
1123
1118
  }
1124
- /**
1125
- * 记录本地 agent.md 文件路径并一次性计算 etag(quoted sha256,与服务端一致)。
1126
- *
1127
- * - path 为空字符串:清除本地 path 与 etag。
1128
- * - 文件不存在 / 读取失败:清除 etag 并返回空串,不抛异常(应用可读 getLocalAgentMdEtag()
1129
- * 为空判断)。
1130
- * - 浏览器环境无文件系统:直接返回空串,记录 warn 日志。
1131
- * - 文件变更后需要重新调用 setLocalAgentMdPath() 触发重算(按设计:设置时一次性计算)。
1132
- *
1133
- * 返回当前 etag(quoted hex 或空串)。
1134
- */
1135
- setLocalAgentMdPath(path) {
1136
- const rawPath = String(path ?? '').trim();
1137
- if (!rawPath) {
1138
- this._localAgentMdPath = '';
1139
- this._localAgentMdEtag = '';
1140
- return '';
1141
- }
1142
- // 浏览器环境没有 fs,直接退回空串。Node 环境才尝试读文件。
1143
- const isNode = typeof process !== 'undefined' && !!process.versions?.node;
1144
- if (!isNode) {
1145
- this._clientLog.warn(`setLocalAgentMdPath skipped: not running in Node.js (path=${rawPath})`);
1146
- this._localAgentMdPath = rawPath;
1147
- this._localAgentMdEtag = '';
1148
- return '';
1149
- }
1150
- this._localAgentMdPath = rawPath;
1151
- try {
1152
- const data = fs.readFileSync(rawPath);
1153
- const digest = crypto.createHash('sha256').update(data).digest('hex');
1154
- this._localAgentMdEtag = `"${digest}"`;
1155
- }
1156
- catch (err) {
1157
- this._clientLog.warn(`setLocalAgentMdPath 读取失败 path=${rawPath} err=${err instanceof Error ? err.message : String(err)}`);
1158
- this._localAgentMdEtag = '';
1159
- }
1160
- return this._localAgentMdEtag;
1161
- }
1162
1119
  /** 返回 setLocalAgentMdPath 计算的 etag;未设置或读取失败时返回空串。 */
1163
1120
  getLocalAgentMdEtag() {
1164
1121
  return this._localAgentMdEtag;
@@ -1618,7 +1575,7 @@ export class AUNClient {
1618
1575
  throw new StateError('authenticate requires a loaded AID with a valid private key');
1619
1576
  }
1620
1577
  const publicState = this.state;
1621
- if (publicState !== ConnectionState.STANDBY && publicState !== ConnectionState.AUTHENTICATED) {
1578
+ if (publicState !== ConnectionState.STANDBY) {
1622
1579
  throw new StateError(`authenticate not allowed in state ${publicState}`);
1623
1580
  }
1624
1581
  if ('aid' in options || 'access_token' in options || 'token' in options || 'kite_token' in options) {
@@ -1645,13 +1602,31 @@ export class AUNClient {
1645
1602
  }
1646
1603
  }
1647
1604
  /** 连接到 Gateway;身份来自构造函数或 loadIdentity(aid),认证由 SDK 内部自动完成。 */
1648
- async connect(options = {}) {
1605
+ async connect(opts) {
1649
1606
  const tStart = Date.now();
1650
- if (arguments.length > 1) {
1651
- throw new ValidationError('connect accepts a single options object');
1607
+ if (opts !== undefined && typeof opts === 'object') {
1608
+ const raw = opts;
1609
+ if ('gateway' in raw || 'access_token' in raw || 'aid' in raw || 'token' in raw) {
1610
+ throw new ValidationError('connect options must not include gateway/access_token/aid; these are managed internally');
1611
+ }
1612
+ }
1613
+ const options = {};
1614
+ if (opts?.auto_reconnect !== undefined)
1615
+ options.auto_reconnect = opts.auto_reconnect;
1616
+ if (opts?.heartbeat_interval !== undefined)
1617
+ options.heartbeat_interval = opts.heartbeat_interval;
1618
+ if (opts?.connect_timeout !== undefined || opts?.call_timeout !== undefined) {
1619
+ options.timeouts = {
1620
+ ...(opts.connect_timeout !== undefined ? { connect: opts.connect_timeout } : {}),
1621
+ ...(opts.call_timeout !== undefined ? { call: opts.call_timeout } : {}),
1622
+ };
1652
1623
  }
1653
- if ('aid' in options || 'access_token' in options || 'token' in options || 'kite_token' in options) {
1654
- throw new ValidationError('connect options must not include aid or token fields; load an AID object first');
1624
+ if (opts?.retry_initial_delay !== undefined || opts?.retry_max_delay !== undefined || opts?.retry_max_attempts !== undefined) {
1625
+ options.retry = {
1626
+ initial_delay: opts.retry_initial_delay ?? 1,
1627
+ max_delay: opts.retry_max_delay ?? 64,
1628
+ max_attempts: opts.retry_max_attempts ?? 0,
1629
+ };
1655
1630
  }
1656
1631
  const target = this._currentAid?.aid ?? this._aid ?? '';
1657
1632
  if (!target || !this._currentAid?.isPrivateKeyValid()) {
@@ -1670,8 +1645,12 @@ export class AUNClient {
1670
1645
  if (publicState === ConnectionState.RETRY_BACKOFF) {
1671
1646
  this._stopReconnect();
1672
1647
  }
1648
+ // gateway 来自 authenticate() 缓存的 this._gatewayUrl;未认证则自动 authenticate()
1649
+ if (!this._gatewayUrl) {
1650
+ await this.authenticate();
1651
+ }
1673
1652
  this._state = 'connecting';
1674
- const gateway = String(options.gateway ?? this._gatewayUrl ?? await this._resolveGatewayForAid(target)).trim();
1653
+ const gateway = String(this._gatewayUrl ?? '').trim();
1675
1654
  const params = { ...options, gateway };
1676
1655
  const normalized = this._normalizeConnectParams(params);
1677
1656
  this._captureCapabilitiesFromConnect(normalized);
@@ -1733,7 +1712,7 @@ export class AUNClient {
1733
1712
  closableKeyStore.close?.();
1734
1713
  this._state = 'closed';
1735
1714
  this._logger.close();
1736
- await this._dispatcher.publish('connection.state', { state: this._publicState(this._state) });
1715
+ await this._dispatcher.publish('state_change', { state: this._publicState(this._state) });
1737
1716
  this._resetSeqTrackingState();
1738
1717
  this._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms`);
1739
1718
  }
@@ -1771,7 +1750,7 @@ export class AUNClient {
1771
1750
  this._stopReconnect();
1772
1751
  await this._transport.close();
1773
1752
  this._state = 'standby';
1774
- await this._dispatcher.publish('connection.state', { state: this._publicState(this._state) });
1753
+ await this._dispatcher.publish('state_change', { state: this._publicState(this._state) });
1775
1754
  this._clientLog.debug(`disconnect exit: elapsed=${Date.now() - tStart}ms`);
1776
1755
  }
1777
1756
  catch (err) {
@@ -4044,7 +4023,7 @@ export class AUNClient {
4044
4023
  this._state = 'ready';
4045
4024
  this._connectedAt = Date.now();
4046
4025
  this._clientLog.debug(`auth complete, connection ready: aid=${this._aid ?? ''}, gateway=${gatewayUrl}`);
4047
- await this._dispatcher.publish('connection.state', { state: this._publicState(this._state), gateway: gatewayUrl });
4026
+ await this._dispatcher.publish('state_change', { state: this._publicState(this._state), gateway: gatewayUrl });
4048
4027
  // auth 阶段 aid 可能被 identity 覆盖(上方 this._aid = identity.aid);
4049
4028
  // 若 context 发生变化,重新 refresh + restore,保持 tracker 与真实身份一致。
4050
4029
  if (this._seqTrackerContext !== this._currentSeqTrackerContext()) {
@@ -6910,7 +6889,7 @@ export class AUNClient {
6910
6889
  this._clientLog.warn(`transport disconnected: closeCode=${closeCode ?? 'none'}, error=${error ? formatCaughtError(error) : 'none'}`);
6911
6890
  this._state = 'standby';
6912
6891
  this._stopBackgroundTasks();
6913
- await this._dispatcher.publish('connection.state', { state: this._publicState(this._state), error });
6892
+ await this._dispatcher.publish('state_change', { state: this._publicState(this._state), error });
6914
6893
  if (!this._sessionOptions.auto_reconnect)
6915
6894
  return;
6916
6895
  if (this._reconnectActive)
@@ -6931,7 +6910,7 @@ export class AUNClient {
6931
6910
  if (disconnectInfo.code !== undefined && disconnectInfo.code !== null) {
6932
6911
  eventPayload.code = disconnectInfo.code;
6933
6912
  }
6934
- await this._dispatcher.publish('connection.state', eventPayload);
6913
+ await this._dispatcher.publish('state_change', eventPayload);
6935
6914
  return;
6936
6915
  }
6937
6916
  // 1000 = 正常关闭, 1006 = 网络异常断开(无 close frame),其他 code = 服务端主动关闭
@@ -6963,7 +6942,7 @@ export class AUNClient {
6963
6942
  // max_attempts 检查在循环顶部,覆盖所有路径(含 health-fail)
6964
6943
  if (maxAttempts > 0 && attempt > maxAttempts) {
6965
6944
  this._state = 'connection_failed';
6966
- await this._dispatcher.publish('connection.state', {
6945
+ await this._dispatcher.publish('state_change', {
6967
6946
  state: this._publicState(this._state),
6968
6947
  attempt: attempt - 1,
6969
6948
  reason: 'max_attempts_exhausted',
@@ -6973,7 +6952,7 @@ export class AUNClient {
6973
6952
  this._retryAttempt = attempt;
6974
6953
  this._nextRetryAt = Date.now() + reconnectSleepDelayMs(delay, maxBaseDelay);
6975
6954
  this._state = 'retry_backoff';
6976
- await this._dispatcher.publish('connection.state', {
6955
+ await this._dispatcher.publish('state_change', {
6977
6956
  state: this._publicState(this._state),
6978
6957
  attempt,
6979
6958
  next_retry_at: this._nextRetryAt,
@@ -6984,7 +6963,7 @@ export class AUNClient {
6984
6963
  if (this._reconnectAbort?.signal.aborted || this._closing)
6985
6964
  break;
6986
6965
  this._state = 'reconnecting';
6987
- await this._dispatcher.publish('connection.state', {
6966
+ await this._dispatcher.publish('state_change', {
6988
6967
  state: this._publicState(this._state),
6989
6968
  attempt,
6990
6969
  });
@@ -7015,7 +6994,7 @@ export class AUNClient {
7015
6994
  });
7016
6995
  if (!AUNClient._shouldRetryReconnect(exc)) {
7017
6996
  this._state = 'connection_failed';
7018
- await this._dispatcher.publish('connection.state', {
6997
+ await this._dispatcher.publish('state_change', {
7019
6998
  state: this._publicState(this._state),
7020
6999
  error: formatCaughtError(exc),
7021
7000
  attempt,