@agentunion/fastaun 0.5.33 → 0.5.35

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 (113) hide show
  1. package/CHANGELOG.md +59 -2
  2. package/README.md +28 -26
  3. package/_packed_docs/CHANGELOG.md +59 -2
  4. package/_packed_docs/INDEX.md +26 -12
  5. package/_packed_docs/KITE_DOCS_GUIDE.md +17 -11
  6. package/_packed_docs/agent.md/SCHEMA.md +1 -1
  7. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +2 -2
  8. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +58 -8
  9. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +17 -17
  10. package/_packed_docs/protocol/echo-probe-gateway.md +99 -0
  11. package/_packed_docs/protocol/echo-probe-sdk.md +91 -0
  12. package/_packed_docs/sdk/0.5.33-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +464 -316
  13. package/_packed_docs/sdk/0.5.33-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +499 -304
  14. package/_packed_docs/sdk/0.5.34-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +133 -0
  15. package/_packed_docs/sdk/0.5.34-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +107 -0
  16. package/_packed_docs/sdk/0.5.35-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +189 -0
  17. package/_packed_docs/sdk/0.5.35-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +204 -0
  18. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +16 -13
  19. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +13 -1
  20. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +19 -9
  21. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +87 -20
  22. package/_packed_docs/sdk/09-collab-rpc-manual.md +48 -30
  23. package/_packed_docs/sdk/09-custody-api-manual.md +3 -3
  24. package/_packed_docs/sdk/09-group-rpc-manual.md +60 -13
  25. package/_packed_docs/sdk/09-message-rpc-manual.md +22 -0
  26. package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -1
  27. package/_packed_docs/sdk/09-payload-reference.md +9 -8
  28. package/_packed_docs/sdk/09-proxy-rpc-manual.md +20 -14
  29. package/_packed_docs/sdk/09-storage-rpc-manual.md +1698 -1659
  30. package/_packed_docs/sdk/09-stream-rpc-manual.md +33 -20
  31. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +19 -17
  32. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +125 -30
  33. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/274/200/345/217/221/347/247/273/346/244/215/346/214/207/345/215/227.md +109 -33
  34. package/_packed_docs/sdk/INDEX.md +30 -18
  35. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +1 -1
  36. package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +5 -5
  37. package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +5 -5
  38. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +9 -9
  39. package/_packed_docs/sdk/README.md +11 -6
  40. package/_packed_docs//346/266/210/346/201/257/345/274/271/346/200/247/350/241/245/346/213/211/351/200/232/351/201/223/345/256/236/346/226/275/350/256/241/345/210/222.md +400 -0
  41. package/_packed_docs//346/266/210/346/201/257/345/274/271/346/200/247/350/241/245/346/213/211/351/200/232/351/201/223/346/226/271/346/241/210.md +485 -0
  42. package/dist/auth.js +39 -45
  43. package/dist/auth.js.map +1 -1
  44. package/dist/client/control-messages.js +2 -2
  45. package/dist/client/control-messages.js.map +1 -1
  46. package/dist/client/delivery.d.ts +12 -1
  47. package/dist/client/delivery.js +281 -46
  48. package/dist/client/delivery.js.map +1 -1
  49. package/dist/client/lifecycle.js +13 -1
  50. package/dist/client/lifecycle.js.map +1 -1
  51. package/dist/client/rpc-budget.d.ts +21 -0
  52. package/dist/client/rpc-budget.js +82 -0
  53. package/dist/client/rpc-budget.js.map +1 -0
  54. package/dist/client/rpc-pipeline.d.ts +5 -0
  55. package/dist/client/rpc-pipeline.js +227 -63
  56. package/dist/client/rpc-pipeline.js.map +1 -1
  57. package/dist/client/sync-channels.d.ts +90 -0
  58. package/dist/client/sync-channels.js +508 -0
  59. package/dist/client/sync-channels.js.map +1 -0
  60. package/dist/client/v2-e2ee.d.ts +5 -1
  61. package/dist/client/v2-e2ee.js +420 -303
  62. package/dist/client/v2-e2ee.js.map +1 -1
  63. package/dist/client.d.ts +17 -0
  64. package/dist/client.js +373 -50
  65. package/dist/client.js.map +1 -1
  66. package/dist/events.d.ts +1 -0
  67. package/dist/events.js +5 -0
  68. package/dist/events.js.map +1 -1
  69. package/dist/index.d.ts +3 -1
  70. package/dist/index.js +1 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/mail-client.d.ts +101 -0
  73. package/dist/mail-client.js +369 -0
  74. package/dist/mail-client.js.map +1 -0
  75. package/dist/pubsub/binding.js +23 -3
  76. package/dist/pubsub/binding.js.map +1 -1
  77. package/dist/pubsub/channel.d.ts +15 -3
  78. package/dist/pubsub/channel.js +114 -7
  79. package/dist/pubsub/channel.js.map +1 -1
  80. package/dist/pubsub/client.d.ts +17 -2
  81. package/dist/pubsub/client.js +205 -40
  82. package/dist/pubsub/client.js.map +1 -1
  83. package/dist/pubsub/credentials.d.ts +3 -0
  84. package/dist/pubsub/credentials.js +57 -20
  85. package/dist/pubsub/credentials.js.map +1 -1
  86. package/dist/pubsub/index.d.ts +5 -2
  87. package/dist/pubsub/index.js +70 -54
  88. package/dist/pubsub/index.js.map +1 -1
  89. package/dist/pubsub/service.d.ts +9 -0
  90. package/dist/pubsub/service.js +266 -20
  91. package/dist/pubsub/service.js.map +1 -1
  92. package/dist/pubsub/types.d.ts +13 -1
  93. package/dist/storage/lowlevel.d.ts +3 -1
  94. package/dist/storage/lowlevel.js +13 -0
  95. package/dist/storage/lowlevel.js.map +1 -1
  96. package/dist/storage/types.d.ts +10 -0
  97. package/dist/storage/types.js.map +1 -1
  98. package/dist/storage/vfs.d.ts +3 -1
  99. package/dist/storage/vfs.js +2 -2
  100. package/dist/storage/vfs.js.map +1 -1
  101. package/dist/tools/cross-sdk-agent.d.ts +55 -5
  102. package/dist/tools/cross-sdk-agent.js +88 -21
  103. package/dist/tools/cross-sdk-agent.js.map +1 -1
  104. package/dist/transport.d.ts +16 -0
  105. package/dist/transport.js +129 -7
  106. package/dist/transport.js.map +1 -1
  107. package/dist/udp-standby.d.ts +89 -0
  108. package/dist/udp-standby.js +487 -0
  109. package/dist/udp-standby.js.map +1 -0
  110. package/dist/version.d.ts +1 -1
  111. package/dist/version.js +1 -1
  112. package/package.json +5 -1
  113. package/scripts/patch-imapflow-external.mjs +69 -0
@@ -11,6 +11,7 @@ import type { EventDispatcher } from './events.js';
11
11
  import { type ModuleLogger } from './logger.js';
12
12
  import { type JsonObject, type RpcMessage, type RpcParams, type RpcResult } from './types.js';
13
13
  import { type ServiceEventVerificationResult } from './org-protocol.js';
14
+ import { RpcBudget } from './client/rpc-budget.js';
14
15
  export type RpcBackground = false | true | 'event' | 'pull';
15
16
  /** 断线回调,closeCode 为 WebSocket close code(1006 = 网络异常断开,其他 = 服务端主动关闭) */
16
17
  export type DisconnectCallback = (error: Error | null, closeCode?: number) => void | Promise<void>;
@@ -26,6 +27,7 @@ export declare function shortRpcViaNetworkActor(url: string, method: string, par
26
27
  * WebSocket JSON-RPC 2.0 传输层
27
28
  */
28
29
  export declare class RPCTransport {
30
+ readonly rpcBudget: RpcBudget;
29
31
  private _logger;
30
32
  private _dispatcher;
31
33
  private _serviceEventVerifier;
@@ -67,8 +69,15 @@ export declare class RPCTransport {
67
69
  private _riskDeliveries;
68
70
  private _idCounter;
69
71
  private _metaObserver;
72
+ private _syncControlObserver;
73
+ private _syncAdmission;
74
+ private _syncAuxiliary;
75
+ private readonly _budgetWaiters;
70
76
  private _requestAdmission;
71
77
  private _requestCheck;
78
+ private _standbyGate;
79
+ private _businessActivity;
80
+ private _standbyAuthParams;
72
81
  private _riskControlHandler;
73
82
  private _classMessageHandler;
74
83
  private _protocolMetaObserver;
@@ -100,6 +109,8 @@ export declare class RPCTransport {
100
109
  };
101
110
  constructor(opts: {
102
111
  eventDispatcher: EventDispatcher;
112
+ rpcBudget?: RpcBudget;
113
+ syncAuxiliary?: boolean;
103
114
  timeout?: number;
104
115
  onDisconnect?: DisconnectCallback | null;
105
116
  verifySsl?: boolean;
@@ -121,6 +132,7 @@ export declare class RPCTransport {
121
132
  setConnectTimeout(timeout: number): void;
122
133
  /** 当前是否仍有可用的 WebSocket。 */
123
134
  isConnected(): boolean;
135
+ setStandbyGate(gate: ((method: string, deadline: number, signal?: AbortSignal) => Promise<() => void>) | null, inbound?: (() => void) | null, authentication?: ((params: RpcParams) => RpcParams) | null): void;
124
136
  /**
125
137
  * 注册 RPC envelope _meta 字段观察者;observer(meta) 在每次成功 RPC 时调用。
126
138
  *
@@ -137,6 +149,9 @@ export declare class RPCTransport {
137
149
  private _finishRiskDelivery;
138
150
  private _receiveRiskControl;
139
151
  private _dispatchRiskControl;
152
+ setSyncControlObserver(observer: ((meta: Record<string, unknown>, method: string, params: JsonObject) => void) | null): void;
153
+ setSyncAdmission(policy: JsonObject | null): void;
154
+ private _checkSyncAdmission;
140
155
  setProtocolMetaObserver(observer: MetaObserver | null): void;
141
156
  setProtocolDisconnectCallback(callback: DisconnectCallback | null): void;
142
157
  waitForPending(timeoutMs: number, signal?: AbortSignal): Promise<void>;
@@ -177,6 +192,7 @@ export declare class RPCTransport {
177
192
  call(method: string, params?: RpcParams, timeout?: number, trace?: string, background?: RpcBackground): Promise<RpcResult>;
178
193
  private _callWithSent;
179
194
  private _call;
195
+ private _callWithAdmission;
180
196
  private _callAdmitted;
181
197
  private _callLocal;
182
198
  /** 发送 JSON-RPC 2.0 Notification,不分配 id,也不等待响应。 */
package/dist/transport.js CHANGED
@@ -16,6 +16,7 @@ import { isJsonObject } from './types.js';
16
16
  import { parseJsonStrict, validateOrgRequestJSON } from './org-protocol.js';
17
17
  import { RiskController } from './risk-control.js';
18
18
  import { messageClassOf } from './client/control-messages.js';
19
+ import { RpcBudget } from './client/rpc-budget.js';
19
20
  const MAX_WS_PAYLOAD_SIZE = 1_000_000;
20
21
  const MAX_RPC_INFLIGHT = 16;
21
22
  const MAX_BACKGROUND_RPC_INFLIGHT = 8;
@@ -550,6 +551,7 @@ export function shortRpcViaNetworkActor(url, method, params, verifySsl = false)
550
551
  * WebSocket JSON-RPC 2.0 传输层
551
552
  */
552
553
  export class RPCTransport {
554
+ rpcBudget;
553
555
  _logger;
554
556
  _dispatcher;
555
557
  _serviceEventVerifier = null;
@@ -593,8 +595,15 @@ export class RPCTransport {
593
595
  // Gateway 在 RPC envelope 注入 _meta 字段(与 result 同级),由 client 层 observer 接收。
594
596
  // observer 抛异常会被吞掉,不影响 RPC result 返回。
595
597
  _metaObserver = null;
598
+ _syncControlObserver = null;
599
+ _syncAdmission = null;
600
+ _syncAuxiliary = false;
601
+ _budgetWaiters = new Set();
596
602
  _requestAdmission = null;
597
603
  _requestCheck = null;
604
+ _standbyGate = null;
605
+ _businessActivity = null;
606
+ _standbyAuthParams = null;
598
607
  _riskControlHandler = null;
599
608
  _classMessageHandler = null;
600
609
  _protocolMetaObserver = false;
@@ -626,11 +635,13 @@ export class RPCTransport {
626
635
  };
627
636
  }
628
637
  get foregroundWaiting() {
629
- return this._rpcQueue.length;
638
+ return this._rpcQueue.length + this.rpcBudget.foregroundWaiting;
630
639
  }
631
640
  _eventBackpressure(timeout = 30_000) { if (this._worker)
632
641
  return this._workerCommand({ type: 'event_backpressure', timeout }); return Promise.resolve(this.foregroundWaiting > 0 || Number(this._ws?.bufferedAmount ?? 0) >= 65536); }
633
642
  constructor(opts) {
643
+ this.rpcBudget = opts.rpcBudget ?? new RpcBudget();
644
+ this._syncAuxiliary = opts.syncAuxiliary ?? false;
634
645
  this._logger = opts.logger ?? _noopLogger;
635
646
  this._dispatcher = opts.eventDispatcher;
636
647
  this._timeout = opts.timeout ?? 35_000;
@@ -687,6 +698,7 @@ export class RPCTransport {
687
698
  aunTransportWorker: true,
688
699
  timeout: opts.timeout ?? 35_000,
689
700
  verifySsl: opts.verifySsl ?? true,
701
+ syncAuxiliary: this._syncAuxiliary,
690
702
  },
691
703
  });
692
704
  this._worker = worker;
@@ -712,7 +724,7 @@ export class RPCTransport {
712
724
  return;
713
725
  }
714
726
  if (message.type === 'foreground_drained') {
715
- if (this._workerConnected && message.generation === this._workerGeneration)
727
+ if (this._workerConnected && message.generation === this._workerGeneration && !this.rpcBudget.foregroundWaiting)
716
728
  this._onForegroundDrained?.();
717
729
  return;
718
730
  }
@@ -818,6 +830,9 @@ export class RPCTransport {
818
830
  pending.reject(error);
819
831
  }
820
832
  this._workerPending.clear();
833
+ for (const request of this._budgetWaiters)
834
+ request.cancel?.();
835
+ this._budgetWaiters.clear();
821
836
  void worker.terminate().catch(() => { });
822
837
  if (wasConnected) {
823
838
  this._dispatcher.enqueueProtocol('connection.error', { error });
@@ -864,6 +879,13 @@ export class RPCTransport {
864
879
  }
865
880
  if (this._workerGeneration === null || message.generation !== this._workerGeneration)
866
881
  return;
882
+ if (message.event && !['_transport.disconnect', '_transport.observer', '_transport.sync_control', '_transport.rate_limit'].includes(message.event))
883
+ this._businessActivity?.();
884
+ if (message.event === '_transport.sync_control') {
885
+ const value = message.payload;
886
+ this._syncControlObserver?.(value.meta, value.method, value.params ?? {});
887
+ return;
888
+ }
867
889
  if (message.event === '_transport.rate_limit') {
868
890
  const until = Number(message.payload?.until_ms);
869
891
  if (Number.isFinite(until))
@@ -1040,6 +1062,11 @@ export class RPCTransport {
1040
1062
  return this._workerConnected;
1041
1063
  return !this._closed && this._ws !== null && this._ws.readyState === WebSocket.OPEN;
1042
1064
  }
1065
+ setStandbyGate(gate, inbound = null, authentication = null) {
1066
+ this._standbyGate = gate;
1067
+ this._businessActivity = inbound;
1068
+ this._standbyAuthParams = authentication;
1069
+ }
1043
1070
  /**
1044
1071
  * 注册 RPC envelope _meta 字段观察者;observer(meta) 在每次成功 RPC 时调用。
1045
1072
  *
@@ -1110,6 +1137,23 @@ export class RPCTransport {
1110
1137
  this._worker.postMessage({ type: 'risk_release', generation: this._workerGeneration ?? undefined });
1111
1138
  });
1112
1139
  }
1140
+ setSyncControlObserver(observer) {
1141
+ this._syncControlObserver = observer;
1142
+ }
1143
+ setSyncAdmission(policy) {
1144
+ this._syncAdmission = policy ? { ...policy } : null;
1145
+ this._worker?.postMessage({ type: 'sync_admission', syncAdmission: this._syncAdmission });
1146
+ }
1147
+ _checkSyncAdmission(guard) {
1148
+ if (!isJsonObject(guard))
1149
+ return;
1150
+ const value = guard;
1151
+ const policy = this._syncAdmission;
1152
+ if (!policy || policy.parent_connection_id !== value.parent_connection_id || policy.version !== value.version
1153
+ || Number(policy.max_history_pull_inflight) <= 0 || Number(policy.max_history_inflight_bytes) <= 0) {
1154
+ throw new StateError('history sync policy changed before send', { data: { sync_policy_changed: true }, retryable: true });
1155
+ }
1156
+ }
1113
1157
  setProtocolMetaObserver(observer) {
1114
1158
  this._metaObserver = observer;
1115
1159
  this._protocolMetaObserver = true;
@@ -1528,6 +1572,9 @@ export class RPCTransport {
1528
1572
  }
1529
1573
  /** 关闭连接 */
1530
1574
  async close() {
1575
+ for (const request of this._budgetWaiters)
1576
+ request.cancel?.();
1577
+ this._budgetWaiters.clear();
1531
1578
  if (this._worker) {
1532
1579
  const worker = this._worker;
1533
1580
  this._workerConnected = false;
@@ -1672,7 +1719,48 @@ export class RPCTransport {
1672
1719
  const result = Promise.all([request, sent]).then(([response]) => response);
1673
1720
  return Object.assign(result, { cancel: request.cancel });
1674
1721
  }
1675
- _call(method, params, timeout, trace, background = false, onSent, sentCheckpoint) {
1722
+ _call(method, params, timeout, trace, background = false, onSent, sentCheckpoint, bypassStandby = false) {
1723
+ if (method === 'auth.connect' && this._standbyAuthParams)
1724
+ params = this._standbyAuthParams(params ?? {});
1725
+ if (this._standbyGate && !bypassStandby && !method.startsWith('gateway.standby.')
1726
+ && !['auth.aid_login1', 'auth.aid_login2', 'auth.connect'].includes(method)) {
1727
+ const deadline = Math.min(typeof params?._rpc_deadline === 'number' ? params._rpc_deadline : Infinity, Date.now() + (timeout ?? this._timeout));
1728
+ const abort = new AbortController();
1729
+ let active;
1730
+ const gate = this._standbyGate;
1731
+ const waiting = (async () => {
1732
+ const release = await gate(method, deadline, abort.signal);
1733
+ try {
1734
+ if (abort.signal.aborted || Date.now() >= deadline)
1735
+ throw new TimeoutError('rpc timeout during standby recovery', { retryable: true });
1736
+ active = this._call(method, params, deadline - Date.now(), trace, background, onSent, sentCheckpoint, true);
1737
+ return await active;
1738
+ }
1739
+ finally {
1740
+ release();
1741
+ }
1742
+ })();
1743
+ return Object.assign(waiting, { cancel: () => { abort.abort(); active?.cancel?.(); } });
1744
+ }
1745
+ const selected = normalizeRpcBackground(background !== false ? background : params?._rpc_background);
1746
+ const kind = selected === true && ['message.peers', 'message.pull', 'message.v2.pull', 'message.ack', 'message.v2.ack', 'group.pull', 'group.v2.pull', 'group.pull_events', 'group.ack_messages', 'group.v2.ack'].includes(method) ? 'pull' : selected;
1747
+ const deadline = Math.min(typeof params?._rpc_deadline === 'number' ? params._rpc_deadline : Infinity, Date.now() + (timeout ?? this._timeout));
1748
+ if (method === 'gateway.risk_ack')
1749
+ return this._callWithAdmission(method, params, Math.max(1, deadline - Date.now()), trace, background, onSent, sentCheckpoint);
1750
+ let started = false;
1751
+ let request;
1752
+ request = this.rpcBudget.run(kind, () => {
1753
+ started = true;
1754
+ this._budgetWaiters.delete(request);
1755
+ return this._callWithAdmission(method, params, Math.max(1, deadline - Date.now()), trace, background, onSent, sentCheckpoint);
1756
+ }, deadline, this._messagePriority(params?.message_class), method);
1757
+ if (!started) {
1758
+ this._budgetWaiters.add(request);
1759
+ void request.then(() => this._budgetWaiters.delete(request), () => this._budgetWaiters.delete(request));
1760
+ }
1761
+ return request;
1762
+ }
1763
+ _callWithAdmission(method, params, timeout, trace, background = false, onSent, sentCheckpoint) {
1676
1764
  if (!this._requestAdmission)
1677
1765
  return this._callAdmitted(method, params, timeout, trace, background, onSent, sentCheckpoint);
1678
1766
  let release;
@@ -1687,6 +1775,7 @@ export class RPCTransport {
1687
1775
  }
1688
1776
  }
1689
1777
  _callAdmitted(method, params, timeout, trace, background = false, onSent, sentCheckpoint) {
1778
+ this._checkSyncAdmission(params?._rpc_sync_guard);
1690
1779
  if (this._worker) {
1691
1780
  const requestContext = trafficLogContext('outbound', params ?? {});
1692
1781
  const requestLog = withLogContext(this._logger, requestContext);
@@ -1726,6 +1815,10 @@ export class RPCTransport {
1726
1815
  const backgroundRpc = selectedBackground === true && ['message.peers', 'message.pull', 'message.v2.pull', 'message.ack', 'message.v2.ack', 'group.pull', 'group.v2.pull', 'group.pull_events', 'group.ack_messages', 'group.v2.ack'].includes(method) ? 'pull' : selectedBackground;
1727
1816
  delete localParams._rpc_background;
1728
1817
  delete localParams._rpc_deadline;
1818
+ const sync = localParams._rpc_sync;
1819
+ delete localParams._rpc_sync;
1820
+ const syncGuard = localParams._rpc_sync_guard;
1821
+ delete localParams._rpc_sync_guard;
1729
1822
  const requestContext = trafficLogContext('outbound', sendParams);
1730
1823
  const requestLog = withLogContext(this._logger, requestContext);
1731
1824
  const responseLog = withLogContext(requestLog, {
@@ -1746,6 +1839,7 @@ export class RPCTransport {
1746
1839
  id: rpcId,
1747
1840
  method,
1748
1841
  params: sendParams,
1842
+ ...(sync && typeof sync === 'object' ? { _meta: { sync } } : {}),
1749
1843
  });
1750
1844
  const payloadSize = new TextEncoder().encode(payload).length;
1751
1845
  if (payloadSize > MAX_WS_PAYLOAD_SIZE) {
@@ -1829,6 +1923,7 @@ export class RPCTransport {
1829
1923
  priority: this._messagePriority(localParams.message_class),
1830
1924
  logger: requestLog,
1831
1925
  onSent,
1926
+ ...(isJsonObject(syncGuard) ? { syncGuard: syncGuard } : {}),
1832
1927
  });
1833
1928
  if (backgroundRpc) {
1834
1929
  this._rpcQueue.pop();
@@ -1843,6 +1938,7 @@ export class RPCTransport {
1843
1938
  priority: this._messagePriority(localParams.message_class),
1844
1939
  logger: requestLog,
1845
1940
  onSent,
1941
+ ...(isJsonObject(syncGuard) ? { syncGuard: syncGuard } : {}),
1846
1942
  });
1847
1943
  }
1848
1944
  this._drainRpcQueue();
@@ -1852,10 +1948,13 @@ export class RPCTransport {
1852
1948
  /** 发送 JSON-RPC 2.0 Notification,不分配 id,也不等待响应。 */
1853
1949
  async notify(method, params) {
1854
1950
  const release = this._requestAdmission?.(`rpc:${String(method).replace(/^(notification|event)\//, '')}`);
1951
+ let standbyRelease;
1855
1952
  try {
1953
+ standbyRelease = await this._standbyGate?.(method, Date.now() + this._timeout);
1856
1954
  await this._notifyAdmitted(method, params);
1857
1955
  }
1858
1956
  finally {
1957
+ standbyRelease?.();
1859
1958
  release?.();
1860
1959
  }
1861
1960
  }
@@ -1874,7 +1973,7 @@ export class RPCTransport {
1874
1973
  });
1875
1974
  }
1876
1975
  const normalizedMethod = String(method ?? '').trim();
1877
- if (!normalizedMethod.startsWith('notification/') && !normalizedMethod.startsWith('event/')) {
1976
+ if (!normalizedMethod.startsWith('notification/') && !normalizedMethod.startsWith('event/') && normalizedMethod !== 'gateway.sync_demand') {
1878
1977
  throw new ValidationError('notify method must start with notification/ or event/');
1879
1978
  }
1880
1979
  if (params !== undefined && params !== null && !isJsonObject(params)) {
@@ -2071,7 +2170,7 @@ export class RPCTransport {
2071
2170
  }
2072
2171
  if (this._rpcQueue.length > 0) {
2073
2172
  this._rpcQueue = this._rpcQueue.filter((entry) => entry.rpcId !== rpcId || (pending !== undefined && entry.pending !== pending));
2074
- if (this._rpcQueue.length === 0 && !this._closed)
2173
+ if (this.foregroundWaiting === 0 && !this._closed)
2075
2174
  this._onForegroundDrained?.();
2076
2175
  }
2077
2176
  if (this._backgroundRpcQueue.length > 0) {
@@ -2150,6 +2249,7 @@ export class RPCTransport {
2150
2249
  return false;
2151
2250
  }
2152
2251
  this._requestCheck?.(`rpc:${entry.method}`);
2252
+ this._checkSyncAdmission(entry.syncGuard);
2153
2253
  entry.pending.sent = true;
2154
2254
  return true;
2155
2255
  }, this._isRiskControlMethod(entry.method) ? 3 : entry.priority).then(() => {
@@ -2178,7 +2278,7 @@ export class RPCTransport {
2178
2278
  if (!this._closed && this._backgroundRpcQueue.length && remaining > 0) {
2179
2279
  this._rateLimitTimer = setTimeout(() => { this._rateLimitTimer = null; this._drainRpcQueue(); }, Math.min(remaining, 2_147_483_647));
2180
2280
  }
2181
- if (foregroundDrained)
2281
+ if (foregroundDrained && !this.rpcBudget.foregroundWaiting)
2182
2282
  this._onForegroundDrained?.();
2183
2283
  }
2184
2284
  }
@@ -2229,6 +2329,9 @@ export class RPCTransport {
2229
2329
  this._stopWebSocketHeartbeat(ws);
2230
2330
  const wasClosed = this._closed;
2231
2331
  this._closed = true;
2332
+ for (const request of this._budgetWaiters)
2333
+ request.cancel?.();
2334
+ this._budgetWaiters.clear();
2232
2335
  for (const wake of this._rateLimitWaiters)
2233
2336
  wake();
2234
2337
  if (this._rateLimitTimer !== null)
@@ -2272,7 +2375,8 @@ export class RPCTransport {
2272
2375
  this._dispatcher.enqueueProtocol('connection.error', { error: err });
2273
2376
  }
2274
2377
  });
2275
- this._startWebSocketHeartbeat(ws);
2378
+ if (!this._syncAuxiliary)
2379
+ this._startWebSocketHeartbeat(ws);
2276
2380
  }
2277
2381
  /** 使用 WebSocket 控制帧检测半开连接,不占用 JSON-RPC 并发额度。 */
2278
2382
  _startWebSocketHeartbeat(ws) {
@@ -2365,6 +2469,19 @@ export class RPCTransport {
2365
2469
  }
2366
2470
  /** 路由消息:RPC 响应 / challenge / 事件 / 通知 */
2367
2471
  _routeMessage(message) {
2472
+ if (typeof message.method === 'string' && !['meta.ping', 'system.ping', 'ping'].includes(message.method))
2473
+ this._businessActivity?.();
2474
+ const syncMethod = String(message.method ?? '');
2475
+ const syncMeta = isJsonObject(message._meta) ? message._meta : {};
2476
+ if (syncMeta.sync_policy !== undefined || syncMethod.startsWith('event/gateway.sync_')) {
2477
+ const policy = syncMeta.sync_policy;
2478
+ if (isJsonObject(policy) && this._syncAdmission?.parent_connection_id === policy.parent_connection_id
2479
+ && Number.isSafeInteger(policy.version) && Number(policy.version) > Number(this._syncAdmission?.version))
2480
+ this._syncAdmission = { ...policy };
2481
+ this._syncControlObserver?.(syncMeta, syncMethod, message.params ?? {});
2482
+ }
2483
+ if (syncMethod === 'event/gateway.sync_policy_changed' || syncMethod === 'event/gateway.sync_channel_close')
2484
+ return;
2368
2485
  // 入口 debug: 识别消息类型
2369
2486
  const hasId = 'id' in message;
2370
2487
  const methodStr = String(message.method ?? '');
@@ -2550,6 +2667,7 @@ if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
2550
2667
  eventDispatcher: workerDispatcher,
2551
2668
  timeout: Number(workerData.timeout ?? 35_000),
2552
2669
  verifySsl: Boolean(workerData.verifySsl ?? true),
2670
+ syncAuxiliary: Boolean(workerData.syncAuxiliary),
2553
2671
  // Worker 内只让 close handler 经 workerDispatcher 转发一次,主线程负责执行真实回调。
2554
2672
  onDisconnect: () => { },
2555
2673
  });
@@ -2562,6 +2680,7 @@ if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
2562
2680
  actor._onRpcResponse = () => parentPort.postMessage({
2563
2681
  type: 'rpc_response', generation: bridgeGeneration(),
2564
2682
  });
2683
+ actor.setSyncControlObserver((meta, method, params) => parentPort.postMessage({ type: 'event', generation: actor._connectionGeneration, event: '_transport.sync_control', payload: { meta, method, params } }));
2565
2684
  actor.setProtocolMetaObserver((meta) => workerDispatcher.enqueueProtocol('_transport.observer', {
2566
2685
  kind: 'meta_observer', payload: meta,
2567
2686
  }));
@@ -2596,6 +2715,9 @@ if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
2596
2715
  }
2597
2716
  let result;
2598
2717
  switch (command.type) {
2718
+ case 'sync_admission':
2719
+ actor.setSyncAdmission(command.syncAdmission ?? null);
2720
+ return;
2599
2721
  case 'risk_snapshot': {
2600
2722
  const state = command.riskState;
2601
2723
  const target = state.target;