@agentunion/fastaun 0.5.34 → 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 (78) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/_packed_docs/CHANGELOG.md +30 -1
  3. package/_packed_docs/INDEX.md +11 -11
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +9 -9
  5. package/_packed_docs/agent.md/SCHEMA.md +1 -1
  6. 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
  7. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +17 -17
  8. package/_packed_docs/protocol/echo-probe-gateway.md +99 -0
  9. package/_packed_docs/protocol/echo-probe-sdk.md +91 -0
  10. 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
  11. 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
  12. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +2 -2
  13. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +32 -6
  14. package/_packed_docs/sdk/09-group-rpc-manual.md +7 -7
  15. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +13 -13
  16. 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 +73 -3
  17. 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 +50 -8
  18. package/_packed_docs/sdk/INDEX.md +18 -18
  19. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +1 -1
  20. 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
  21. 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
  22. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +9 -9
  23. 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
  24. 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
  25. package/dist/auth.js +31 -43
  26. package/dist/auth.js.map +1 -1
  27. package/dist/client/delivery.d.ts +7 -1
  28. package/dist/client/delivery.js +137 -16
  29. package/dist/client/delivery.js.map +1 -1
  30. package/dist/client/lifecycle.js +10 -1
  31. package/dist/client/lifecycle.js.map +1 -1
  32. package/dist/client/rpc-pipeline.d.ts +2 -0
  33. package/dist/client/rpc-pipeline.js +65 -7
  34. package/dist/client/rpc-pipeline.js.map +1 -1
  35. package/dist/client/sync-channels.d.ts +2 -1
  36. package/dist/client/sync-channels.js +33 -14
  37. package/dist/client/sync-channels.js.map +1 -1
  38. package/dist/client/v2-e2ee.d.ts +1 -0
  39. package/dist/client/v2-e2ee.js +19 -5
  40. package/dist/client/v2-e2ee.js.map +1 -1
  41. package/dist/client.d.ts +15 -0
  42. package/dist/client.js +310 -49
  43. package/dist/client.js.map +1 -1
  44. package/dist/events.d.ts +1 -0
  45. package/dist/events.js +5 -0
  46. package/dist/events.js.map +1 -1
  47. package/dist/index.d.ts +2 -0
  48. package/dist/index.js +1 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/mail-client.d.ts +101 -0
  51. package/dist/mail-client.js +369 -0
  52. package/dist/mail-client.js.map +1 -0
  53. package/dist/pubsub/binding.js +9 -2
  54. package/dist/pubsub/binding.js.map +1 -1
  55. package/dist/pubsub/channel.d.ts +11 -3
  56. package/dist/pubsub/channel.js +88 -7
  57. package/dist/pubsub/channel.js.map +1 -1
  58. package/dist/pubsub/client.d.ts +8 -2
  59. package/dist/pubsub/client.js +59 -17
  60. package/dist/pubsub/client.js.map +1 -1
  61. package/dist/pubsub/index.d.ts +2 -2
  62. package/dist/pubsub/index.js +1 -1
  63. package/dist/pubsub/index.js.map +1 -1
  64. package/dist/pubsub/service.d.ts +6 -0
  65. package/dist/pubsub/service.js +100 -9
  66. package/dist/pubsub/service.js.map +1 -1
  67. package/dist/pubsub/types.d.ts +11 -1
  68. package/dist/tools/cross-sdk-agent.d.ts +1 -1
  69. package/dist/transport.d.ts +4 -0
  70. package/dist/transport.js +39 -2
  71. package/dist/transport.js.map +1 -1
  72. package/dist/udp-standby.d.ts +89 -0
  73. package/dist/udp-standby.js +487 -0
  74. package/dist/udp-standby.js.map +1 -0
  75. package/dist/version.d.ts +1 -1
  76. package/dist/version.js +1 -1
  77. package/package.json +5 -1
  78. package/scripts/patch-imapflow-external.mjs +69 -0
@@ -104,9 +104,73 @@ function deduplicatePlainForwardPageMessages(value, afterSeq) {
104
104
  }
105
105
  export class MessageDeliveryEngine {
106
106
  runtime;
107
+ forwardAckJobs = new Map();
108
+ forwardAckTasks = new Set();
109
+ scheduleForwardAck(ns, seq, send) {
110
+ const client = this.runtime.client;
111
+ if (client._closing || seq <= 0)
112
+ return;
113
+ const scope = () => [client._aid, client._deviceId, client._slotId, this.captureInlineAckGeneration(),
114
+ client._v2RuntimeGeneration, client._transport, client._transport?._connectionGeneration,
115
+ client._transport?._workerGeneration, this.captureSeqNamespaceGeneration(ns)];
116
+ const current = scope();
117
+ const previous = this.forwardAckJobs.get(ns);
118
+ if (previous && previous.scope.every((value, i) => value === current[i])) {
119
+ if (seq > previous.seq) {
120
+ previous.seq = seq;
121
+ previous.send = send;
122
+ }
123
+ return;
124
+ }
125
+ const job = { seq, scope: current, send };
126
+ this.forwardAckJobs.set(ns, job);
127
+ const isCurrent = () => this.forwardAckJobs.get(ns) === job && job.scope.every((value, i) => value === scope()[i]);
128
+ const task = (async () => {
129
+ let failures = 0;
130
+ while (isCurrent()) {
131
+ const pending = job.seq;
132
+ try {
133
+ await job.send(pending);
134
+ failures = 0;
135
+ if (job.seq <= pending) {
136
+ if (this.forwardAckJobs.get(ns) === job)
137
+ this.forwardAckJobs.delete(ns);
138
+ return;
139
+ }
140
+ }
141
+ catch {
142
+ if (!isCurrent() || client._closing || client.state !== ConnectionState.READY)
143
+ return;
144
+ if (job.seq <= pending)
145
+ await new Promise(resolve => setTimeout(resolve, Math.min(100 * 2 ** Math.min(failures++, 5), 3000)));
146
+ }
147
+ }
148
+ })().finally(() => {
149
+ if (this.forwardAckJobs.get(ns) === job)
150
+ this.forwardAckJobs.delete(ns);
151
+ this.forwardAckTasks.delete(task);
152
+ });
153
+ this.forwardAckTasks.add(task);
154
+ }
155
+ drainForwardAcks() {
156
+ if (!this.forwardAckTasks.size)
157
+ return;
158
+ return this.waitForwardAcks();
159
+ }
160
+ async waitForwardAcks() {
161
+ let timer;
162
+ try {
163
+ await Promise.race([Promise.allSettled([...this.forwardAckTasks]), new Promise(resolve => { timer = setTimeout(resolve, 1000); })]);
164
+ }
165
+ finally {
166
+ if (timer)
167
+ clearTimeout(timer);
168
+ }
169
+ }
107
170
  realtimeTailHeads = null;
108
171
  realtimeSyncing = null;
109
172
  pendingGroupPullUpper = null;
173
+ pendingV2GroupPulls = new Set();
110
174
  onlineUnreadHintTargets = null;
111
175
  onlineUnreadHintTasks = null;
112
176
  backgroundPullNeeds = new Map();
@@ -1106,7 +1170,7 @@ export class MessageDeliveryEngine {
1106
1170
  this.onGroupV2AckSucceeded(groupId, actualAckSeq, generation);
1107
1171
  }
1108
1172
  }
1109
- async commitPlainForwardPage(ns, afterSeq, method, result, groupId = '') {
1173
+ async commitPlainForwardPage(ns, afterSeq, method, result, groupId = '', background = false) {
1110
1174
  if (!isJsonObject(result)) {
1111
1175
  throw new Error(`${method} response must be an object`);
1112
1176
  }
@@ -1250,7 +1314,10 @@ export class MessageDeliveryEngine {
1250
1314
  throw new Error(`${ackMethod} cannot confirm pending Forward watermark ${pendingAckSeq}`);
1251
1315
  }
1252
1316
  this.ensurePullOperationCurrent(ns);
1253
- await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
1317
+ if (background)
1318
+ this.scheduleForwardAck(ns, pendingAckSeq, seq => this.confirmPlainForwardAck(ns, ackMethod, seq, groupId));
1319
+ else
1320
+ await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
1254
1321
  }
1255
1322
  this.syncProgress(ns, {
1256
1323
  rawCount: messages.length,
@@ -1458,6 +1525,7 @@ export class MessageDeliveryEngine {
1458
1525
  this.pendingGroupInlineAckNamespaces = null;
1459
1526
  this.realtimeSyncing = null;
1460
1527
  this.pendingGroupPullUpper = null;
1528
+ this.pendingV2GroupPulls.clear();
1461
1529
  this.onlineUnreadHintTargets = null;
1462
1530
  this.onlineUnreadHintTasks = null;
1463
1531
  this.realtimeTailHeads = null;
@@ -1937,6 +2005,11 @@ export class MessageDeliveryEngine {
1937
2005
  this.backgroundPullNeeds.delete(ns);
1938
2006
  continue;
1939
2007
  }
2008
+ if (this.pendingV2GroupPulls.has(ns)) {
2009
+ if (!client._v2Session)
2010
+ continue;
2011
+ this.pendingV2GroupPulls.delete(ns);
2012
+ }
1940
2013
  if (ns.startsWith('p2p:') && !this.hasP2pApplicationSubscription())
1941
2014
  continue;
1942
2015
  if (need.messageClassRequest && need.messageClassRequest.message_class !== 'sdk_control') {
@@ -2362,6 +2435,8 @@ export class MessageDeliveryEngine {
2362
2435
  return applicationResult({ ...result, message_class: 'sdk_control' });
2363
2436
  if (!APP_SEND_ENVELOPE_METHODS.has(method) || !isJsonObject(result))
2364
2437
  return result;
2438
+ if (result.status === 'echo_return')
2439
+ return result;
2365
2440
  let out = { ...result };
2366
2441
  const serverEnvelope = method === 'group.send' && isJsonObject(out.envelope)
2367
2442
  ? { ...out.envelope }
@@ -2686,8 +2761,10 @@ export class MessageDeliveryEngine {
2686
2761
  return this.runApplicationPage(namespace, source, async () => { await this.publishAppEvent(event, payload, source, deliveryContext); });
2687
2762
  }
2688
2763
  }
2689
- if ((event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
2690
- client._maybeAppendEchoTraceReceive(payload);
2764
+ if (source !== 'echo_return' && (event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
2765
+ if (client._maybeAppendEchoTraceReceive(payload)) {
2766
+ return client._returnReceivedEcho(payload);
2767
+ }
2691
2768
  }
2692
2769
  this.logAppMessagePublish(event, payload, source);
2693
2770
  if (isJsonObject(payload)) {
@@ -2929,7 +3006,14 @@ export class MessageDeliveryEngine {
2929
3006
  }
2930
3007
  async onRawMessageReceived(data) {
2931
3008
  const client = this.runtime.client;
2932
- if (client._p2pPeerPullEnabled) {
3009
+ if (isJsonObject(data) && !client._echoStarts.has(data))
3010
+ client._echoStarts.set(data, performance.now());
3011
+ const message = isJsonObject(data) ? data : undefined;
3012
+ const payload = message?.payload;
3013
+ const plainEcho = message && !message.encrypted && !message.encrypt && isJsonObject(payload)
3014
+ && !String(payload.type ?? '').trim().toLowerCase().startsWith('e2ee') && !payload.ciphertext
3015
+ && !client._isEncryptedPushMessage(message) && client._isEchoPayload(payload);
3016
+ if (client._p2pPeerPullEnabled && !plainEcho) {
2933
3017
  await this.onPeerPush(data);
2934
3018
  return;
2935
3019
  }
@@ -2998,6 +3082,7 @@ export class MessageDeliveryEngine {
2998
3082
  return;
2999
3083
  }
3000
3084
  const msg = { ...data };
3085
+ client._echoStarts.set(msg, client._echoStarts.get(data) ?? performance.now());
3001
3086
  if (!this.messageTargetsCurrentInstance(msg)) {
3002
3087
  client._clientLog.debug(`P2P push filtered by instance: message_id=${String(msg.message_id ?? '')}, seq=${String(msg.seq ?? '')}, target_device=${String(msg.device_id ?? '')}, target_slot=${String(msg.slot_id ?? '')}, local_device=${client._deviceId}, local_slot=${client._slotId}`);
3003
3088
  return;
@@ -3054,6 +3139,8 @@ export class MessageDeliveryEngine {
3054
3139
  }
3055
3140
  async onRawGroupMessageCreated(data) {
3056
3141
  const client = this.runtime.client;
3142
+ if (isJsonObject(data) && !client._echoStarts.has(data))
3143
+ client._echoStarts.set(data, performance.now());
3057
3144
  const tStart = Date.now();
3058
3145
  if (isJsonObject(data)) {
3059
3146
  client._logMessageDebug('server-push', '_raw.group.message_created', 'group.message_created', data);
@@ -3094,6 +3181,7 @@ export class MessageDeliveryEngine {
3094
3181
  }
3095
3182
  const msg = { ...data };
3096
3183
  const groupId = String(msg.group_id ?? '');
3184
+ client._echoStarts.set(msg, client._echoStarts.get(data) ?? performance.now());
3097
3185
  const seq = msg.seq;
3098
3186
  const payload = msg.payload;
3099
3187
  if (groupId) {
@@ -3210,7 +3298,7 @@ export class MessageDeliveryEngine {
3210
3298
  try {
3211
3299
  // Gap Fill 本身就是 Forward Pull,必须沿用协调器的完整事务:
3212
3300
  // 原始页提交成功后由协调器负责 Piggyback/终端 ACK。
3213
- const operation = () => client._pullV2(afterSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, { gateLocked: true });
3301
+ const operation = () => client._pullV2(afterSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, { gateLocked: true, background: true });
3214
3302
  const messages = await this.runAutomaticPull(ns, operation, (attempt) => client._rpcPipeline
3215
3303
  ? client._rpcPipeline.runPullSerialized(client._rpcPipeline.pullGateKeyForCall('message.pull', { after_seq: afterSeq, limit: _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize }), attempt, true)
3216
3304
  : client._withBackgroundRpc(attempt));
@@ -3859,7 +3947,7 @@ export class MessageDeliveryEngine {
3859
3947
  tailHead = this.syncState(ns).head;
3860
3948
  return tailResult;
3861
3949
  }
3862
- const opts = { gateLocked: true };
3950
+ const opts = { gateLocked: true, background };
3863
3951
  if (request.max_pages !== undefined)
3864
3952
  opts.maxPages = request.max_pages;
3865
3953
  const messages = await client._pullV2(after, pageLimit, opts);
@@ -3985,7 +4073,7 @@ export class MessageDeliveryEngine {
3985
4073
  const client = this.runtime.client;
3986
4074
  const request = { after_seq: this.syncState(ns).ack, limit: pageLimit, max_pages: 1 };
3987
4075
  const invoke = async () => {
3988
- const messages = await client._pullV2(Number(request.after_seq), pageLimit, { gateLocked: true, maxPages: 1 });
4076
+ const messages = await client._pullV2(Number(request.after_seq), pageLimit, { gateLocked: true, maxPages: 1, background });
3989
4077
  return { messages, raw_count: messages.length };
3990
4078
  };
3991
4079
  if (!client._rpcPipeline)
@@ -4843,7 +4931,7 @@ export class MessageDeliveryEngine {
4843
4931
  const coordinator = client._v2E2EE;
4844
4932
  const pendingAckSeq = Number(coordinator.pendingForwardAck?.(ns, committedAck) ?? 0);
4845
4933
  if (pendingAckSeq > 0) {
4846
- client._safeAsync(coordinator.confirmForwardGroupAck(groupId, pendingAckSeq, String(data.group_aid ?? '').trim() || undefined, true));
4934
+ this.scheduleForwardAck(ns, pendingAckSeq, seq => coordinator.confirmForwardGroupAck(groupId, seq, String(data.group_aid ?? '').trim() || undefined, true));
4847
4935
  }
4848
4936
  else {
4849
4937
  const pendingNs = this.resolvePendingGroupInlineAckNamespace(ns);
@@ -4904,8 +4992,6 @@ export class MessageDeliveryEngine {
4904
4992
  const groupId = typeof d.group_id === 'string' ? d.group_id.trim() : '';
4905
4993
  const rawSeq = d.seq;
4906
4994
  const inlinePresent = hasNonEmptyInlineMessage(d.inline_message);
4907
- if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent))
4908
- return;
4909
4995
  const seq = this.realtimeHeadSeq(rawSeq, inlinePresent);
4910
4996
  if (!groupId) {
4911
4997
  client._clientLog.debug(`_onRawGroupV2MessageCreated skipped: group=${groupId || '<empty>'}, seq=${String(d.seq ?? '')}`);
@@ -4918,6 +5004,15 @@ export class MessageDeliveryEngine {
4918
5004
  return;
4919
5005
  }
4920
5006
  const eventKind = String(d.kind ?? '').trim();
5007
+ if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent)) {
5008
+ if (client._sessionOptions?.background_sync !== false) {
5009
+ const ns = `group:${groupId}`;
5010
+ this.recordBackgroundPullNeed(ns, seq, eventKind === 'group.online_unread_hint', true);
5011
+ if (this.backgroundPullNeeds.has(ns))
5012
+ this.pendingV2GroupPulls.add(ns);
5013
+ }
5014
+ return;
5015
+ }
4921
5016
  if (eventKind === 'group.online_unread_hint') {
4922
5017
  if (client._sessionOptions.background_sync === false)
4923
5018
  return;
@@ -5052,18 +5147,44 @@ export class MessageDeliveryEngine {
5052
5147
  this.refreshPendingPeers();
5053
5148
  return;
5054
5149
  }
5055
- if (!client._aid || !client._v2Session)
5150
+ if (!client._aid || !client._v2Session || client._sessionOptions?.background_sync === false)
5056
5151
  return;
5057
5152
  const ns = `p2p:${client._aid}`;
5058
5153
  const generation = this.captureInlineAckGeneration();
5059
- const afterSeq = this.syncState(ns).ack;
5060
- this.recordBackgroundPullNeed(ns, positiveSafeSequenceHint(data.seq), true, true);
5154
+ const state = this.syncState(ns);
5155
+ const afterSeq = state.ack;
5156
+ const hintSeq = positiveSafeSequenceHint(data.seq);
5157
+ if (hintSeq > 0 && afterSeq >= Math.max(hintSeq, state.head, Number(client._seqTracker.getMaxSeenSeq?.(ns) ?? 0), Number(client._pendingP2pPullUpper?.get?.(ns) ?? 0))
5158
+ && afterSeq >= state.tail - 1 && !client._pendingOrderedMsgs.get(ns)?.size) {
5159
+ const coordinator = client._v2E2EE;
5160
+ const pendingAckSeq = Number(coordinator.pendingForwardAck?.(ns, afterSeq) ?? 0);
5161
+ if (pendingAckSeq > 0) {
5162
+ this.scheduleForwardAck(ns, pendingAckSeq, seq => coordinator.confirmForwardP2PAck(seq));
5163
+ }
5164
+ else {
5165
+ const pending = this.pendingP2PInlineAcks?.get(ns);
5166
+ if (pending)
5167
+ this.retryPendingP2PInlineAck(ns, pending.seq, 'covered online hint', afterSeq);
5168
+ }
5169
+ return;
5170
+ }
5171
+ this.recordBackgroundPullNeed(ns, hintSeq, true, true);
5061
5172
  const pullTrigger = this.backgroundPullNeeds.get(ns)?.trigger;
5173
+ const tasks = this.onlineUnreadHintTasks ?? new Map();
5174
+ this.onlineUnreadHintTasks = tasks;
5175
+ if (tasks.has(ns))
5176
+ return;
5062
5177
  let failed = false;
5063
- client._safeAsync(this.runP2PForwardRecovery(ns, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, true).catch((exc) => {
5178
+ const task = this.runP2PForwardRecovery(ns, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, true).then(() => undefined).catch((exc) => {
5064
5179
  failed = true;
5065
5180
  client._clientLog.debug(`P2P online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
5066
- }).finally(() => this.finishBackgroundPull(ns, generation, afterSeq, failed, pullTrigger)));
5181
+ }).finally(() => {
5182
+ if (tasks.get(ns) === task)
5183
+ tasks.delete(ns);
5184
+ this.finishBackgroundPull(ns, generation, afterSeq, failed, pullTrigger);
5185
+ });
5186
+ tasks.set(ns, task);
5187
+ client._safeAsync(task);
5067
5188
  }
5068
5189
  async saveSeqTrackerState() {
5069
5190
  const client = this.runtime.client;