@agentunion/fastaun 0.5.34 → 0.5.36
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 +56 -1
- package/_packed_docs/CHANGELOG.md +56 -1
- package/_packed_docs/INDEX.md +18 -11
- package/_packed_docs/KITE_DOCS_GUIDE.md +9 -9
- package/_packed_docs/agent.md/SCHEMA.md +1 -1
- 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
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +17 -17
- package/_packed_docs/protocol/echo-probe-gateway.md +99 -0
- package/_packed_docs/protocol/echo-probe-sdk.md +91 -0
- 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
- 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
- package/_packed_docs/sdk/0.5.36-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +130 -0
- package/_packed_docs/sdk/0.5.36-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +176 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +2 -2
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +32 -6
- package/_packed_docs/sdk/09-group-rpc-manual.md +7 -7
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +13 -13
- 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
- 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
- package/_packed_docs/sdk/INDEX.md +23 -18
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +1 -1
- 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
- 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
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +9 -9
- 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
- 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
- package/dist/agent-md.d.ts +2 -1
- package/dist/agent-md.js +33 -6
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.js +5 -1
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.js +36 -45
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +8 -1
- package/dist/client/delivery.js +203 -50
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/lifecycle.js +10 -1
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +4 -0
- package/dist/client/rpc-pipeline.js +93 -10
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/sync-channels.d.ts +2 -1
- package/dist/client/sync-channels.js +33 -14
- package/dist/client/sync-channels.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -0
- package/dist/client/v2-e2ee.js +24 -6
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +15 -0
- package/dist/client.js +329 -56
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +1 -0
- package/dist/events.js +5 -0
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mail-client.d.ts +101 -0
- package/dist/mail-client.js +369 -0
- package/dist/mail-client.js.map +1 -0
- package/dist/ownership-v21.d.ts +2 -1
- package/dist/ownership-v21.js +19 -9
- package/dist/ownership-v21.js.map +1 -1
- package/dist/pubsub/binding.js +9 -2
- package/dist/pubsub/binding.js.map +1 -1
- package/dist/pubsub/channel.d.ts +11 -3
- package/dist/pubsub/channel.js +91 -10
- package/dist/pubsub/channel.js.map +1 -1
- package/dist/pubsub/client.d.ts +8 -2
- package/dist/pubsub/client.js +62 -21
- package/dist/pubsub/client.js.map +1 -1
- package/dist/pubsub/index.d.ts +2 -2
- package/dist/pubsub/index.js +1 -1
- package/dist/pubsub/index.js.map +1 -1
- package/dist/pubsub/service.d.ts +6 -0
- package/dist/pubsub/service.js +101 -10
- package/dist/pubsub/service.js.map +1 -1
- package/dist/pubsub/types.d.ts +11 -1
- package/dist/tools/cross-sdk-agent.d.ts +1 -1
- package/dist/transport.d.ts +4 -0
- package/dist/transport.js +39 -2
- package/dist/transport.js.map +1 -1
- package/dist/udp-standby.d.ts +88 -0
- package/dist/udp-standby.js +483 -0
- package/dist/udp-standby.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
- package/scripts/patch-imapflow-external.mjs +69 -0
package/dist/client/delivery.js
CHANGED
|
@@ -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();
|
|
@@ -116,6 +180,7 @@ export class MessageDeliveryEngine {
|
|
|
116
180
|
backgroundPullTimerAt = 0;
|
|
117
181
|
pendingP2PInlineAcks = null;
|
|
118
182
|
pendingGroupInlineAcks = null;
|
|
183
|
+
pendingGroupInlineAckCount = 0;
|
|
119
184
|
pendingGroupInlineAckNamespaces = null;
|
|
120
185
|
inlineAckGeneration = 0;
|
|
121
186
|
pendingDeliveryChanges = null;
|
|
@@ -574,6 +639,7 @@ export class MessageDeliveryEngine {
|
|
|
574
639
|
if (!namespace.startsWith('p2p.peer.v1/') || !Number.isSafeInteger(sequence) || sequence < 0)
|
|
575
640
|
return;
|
|
576
641
|
this.peerServerConfirmedAcks.set(namespace, Math.max(this.peerServerConfirmedAcks.get(namespace) ?? 0, sequence));
|
|
642
|
+
this.runtime.client._rpcPipeline?.confirmBackgroundAck?.(namespace, sequence);
|
|
577
643
|
}
|
|
578
644
|
rememberCommittedSeqState(namespace) {
|
|
579
645
|
this.ensurePeerContext();
|
|
@@ -935,6 +1001,8 @@ export class MessageDeliveryEngine {
|
|
|
935
1001
|
if (this.peerRecoveryTasks.has(sender))
|
|
936
1002
|
return;
|
|
937
1003
|
const generation = this.captureInlineAckGeneration();
|
|
1004
|
+
const recoveryVersion = this.capturePeerTailVersion(sender);
|
|
1005
|
+
const recoveryAck = this.peerCommittedAck(namespace);
|
|
938
1006
|
const task = (async () => {
|
|
939
1007
|
await this.runAutomaticPull(`peer-init:${sender}`, () => this.initializePeer(sender));
|
|
940
1008
|
if (!this.hasP2pApplicationSubscription())
|
|
@@ -996,7 +1064,9 @@ export class MessageDeliveryEngine {
|
|
|
996
1064
|
const beforeAck = this.peerCommittedAck(namespace);
|
|
997
1065
|
const beforeVolatile = this.peerVolatilePullCursor(sender);
|
|
998
1066
|
const beforeWindow = this.syncState(namespace);
|
|
999
|
-
const result = await client._v2E2EE.pullPeerV2(sender, { background: true, retainMessages: false, budget: { remaining: 100 }
|
|
1067
|
+
const result = await client._v2E2EE.pullPeerV2(sender, { background: true, retainMessages: false, budget: { remaining: 100 },
|
|
1068
|
+
...(!need.volatile && need.head > 0 && pushVersion === recoveryVersion.push && catalogVersion === recoveryVersion.catalog
|
|
1069
|
+
? { autoPeerHead: need.head, autoPeerAckFloor: recoveryAck } : {}) });
|
|
1000
1070
|
need.volatile ||= result.volatile_has_more === true;
|
|
1001
1071
|
const afterWindow = this.syncState(namespace);
|
|
1002
1072
|
if ((!result.complete || result.ack_seq < need.head) && this.peerCommittedAck(namespace) <= beforeAck && this.peerVolatilePullCursor(sender) === beforeVolatile
|
|
@@ -1106,7 +1176,7 @@ export class MessageDeliveryEngine {
|
|
|
1106
1176
|
this.onGroupV2AckSucceeded(groupId, actualAckSeq, generation);
|
|
1107
1177
|
}
|
|
1108
1178
|
}
|
|
1109
|
-
async commitPlainForwardPage(ns, afterSeq, method, result, groupId = '') {
|
|
1179
|
+
async commitPlainForwardPage(ns, afterSeq, method, result, groupId = '', background = false) {
|
|
1110
1180
|
if (!isJsonObject(result)) {
|
|
1111
1181
|
throw new Error(`${method} response must be an object`);
|
|
1112
1182
|
}
|
|
@@ -1250,7 +1320,10 @@ export class MessageDeliveryEngine {
|
|
|
1250
1320
|
throw new Error(`${ackMethod} cannot confirm pending Forward watermark ${pendingAckSeq}`);
|
|
1251
1321
|
}
|
|
1252
1322
|
this.ensurePullOperationCurrent(ns);
|
|
1253
|
-
|
|
1323
|
+
if (background)
|
|
1324
|
+
this.scheduleForwardAck(ns, pendingAckSeq, seq => this.confirmPlainForwardAck(ns, ackMethod, seq, groupId));
|
|
1325
|
+
else
|
|
1326
|
+
await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
|
|
1254
1327
|
}
|
|
1255
1328
|
this.syncProgress(ns, {
|
|
1256
1329
|
rawCount: messages.length,
|
|
@@ -1455,9 +1528,11 @@ export class MessageDeliveryEngine {
|
|
|
1455
1528
|
void this.runtime.client._rpcPipeline?.invalidatePulls?.();
|
|
1456
1529
|
this.pendingP2PInlineAcks = null;
|
|
1457
1530
|
this.pendingGroupInlineAcks = null;
|
|
1531
|
+
this.pendingGroupInlineAckCount = 0;
|
|
1458
1532
|
this.pendingGroupInlineAckNamespaces = null;
|
|
1459
1533
|
this.realtimeSyncing = null;
|
|
1460
1534
|
this.pendingGroupPullUpper = null;
|
|
1535
|
+
this.pendingV2GroupPulls.clear();
|
|
1461
1536
|
this.onlineUnreadHintTargets = null;
|
|
1462
1537
|
this.onlineUnreadHintTasks = null;
|
|
1463
1538
|
this.realtimeTailHeads = null;
|
|
@@ -1715,7 +1790,7 @@ export class MessageDeliveryEngine {
|
|
|
1715
1790
|
await processing;
|
|
1716
1791
|
}
|
|
1717
1792
|
pendingInlineAckNamespaceCount() {
|
|
1718
|
-
return (this.pendingP2PInlineAcks?.size ?? 0) +
|
|
1793
|
+
return (this.pendingP2PInlineAcks?.size ?? 0) + this.pendingGroupInlineAckCount;
|
|
1719
1794
|
}
|
|
1720
1795
|
markRealtimeTailCompleted(result, tailHead) {
|
|
1721
1796
|
const heads = this.realtimeTailHeads ?? new WeakMap();
|
|
@@ -1937,6 +2012,11 @@ export class MessageDeliveryEngine {
|
|
|
1937
2012
|
this.backgroundPullNeeds.delete(ns);
|
|
1938
2013
|
continue;
|
|
1939
2014
|
}
|
|
2015
|
+
if (this.pendingV2GroupPulls.has(ns)) {
|
|
2016
|
+
if (!client._v2Session)
|
|
2017
|
+
continue;
|
|
2018
|
+
this.pendingV2GroupPulls.delete(ns);
|
|
2019
|
+
}
|
|
1940
2020
|
if (ns.startsWith('p2p:') && !this.hasP2pApplicationSubscription())
|
|
1941
2021
|
continue;
|
|
1942
2022
|
if (need.messageClassRequest && need.messageClassRequest.message_class !== 'sdk_control') {
|
|
@@ -2362,6 +2442,8 @@ export class MessageDeliveryEngine {
|
|
|
2362
2442
|
return applicationResult({ ...result, message_class: 'sdk_control' });
|
|
2363
2443
|
if (!APP_SEND_ENVELOPE_METHODS.has(method) || !isJsonObject(result))
|
|
2364
2444
|
return result;
|
|
2445
|
+
if (result.status === 'echo_return')
|
|
2446
|
+
return result;
|
|
2365
2447
|
let out = { ...result };
|
|
2366
2448
|
const serverEnvelope = method === 'group.send' && isJsonObject(out.envelope)
|
|
2367
2449
|
? { ...out.envelope }
|
|
@@ -2686,8 +2768,10 @@ export class MessageDeliveryEngine {
|
|
|
2686
2768
|
return this.runApplicationPage(namespace, source, async () => { await this.publishAppEvent(event, payload, source, deliveryContext); });
|
|
2687
2769
|
}
|
|
2688
2770
|
}
|
|
2689
|
-
if ((event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
|
|
2690
|
-
client._maybeAppendEchoTraceReceive(payload)
|
|
2771
|
+
if (source !== 'echo_return' && (event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
|
|
2772
|
+
if (client._maybeAppendEchoTraceReceive(payload)) {
|
|
2773
|
+
return client._returnReceivedEcho(payload);
|
|
2774
|
+
}
|
|
2691
2775
|
}
|
|
2692
2776
|
this.logAppMessagePublish(event, payload, source);
|
|
2693
2777
|
if (isJsonObject(payload)) {
|
|
@@ -2929,7 +3013,14 @@ export class MessageDeliveryEngine {
|
|
|
2929
3013
|
}
|
|
2930
3014
|
async onRawMessageReceived(data) {
|
|
2931
3015
|
const client = this.runtime.client;
|
|
2932
|
-
if (client.
|
|
3016
|
+
if (isJsonObject(data) && !client._echoStarts.has(data))
|
|
3017
|
+
client._echoStarts.set(data, performance.now());
|
|
3018
|
+
const message = isJsonObject(data) ? data : undefined;
|
|
3019
|
+
const payload = message?.payload;
|
|
3020
|
+
const plainEcho = message && !message.encrypted && !message.encrypt && isJsonObject(payload)
|
|
3021
|
+
&& !String(payload.type ?? '').trim().toLowerCase().startsWith('e2ee') && !payload.ciphertext
|
|
3022
|
+
&& !client._isEncryptedPushMessage(message) && client._isEchoPayload(payload);
|
|
3023
|
+
if (client._p2pPeerPullEnabled && !plainEcho) {
|
|
2933
3024
|
await this.onPeerPush(data);
|
|
2934
3025
|
return;
|
|
2935
3026
|
}
|
|
@@ -2998,6 +3089,7 @@ export class MessageDeliveryEngine {
|
|
|
2998
3089
|
return;
|
|
2999
3090
|
}
|
|
3000
3091
|
const msg = { ...data };
|
|
3092
|
+
client._echoStarts.set(msg, client._echoStarts.get(data) ?? performance.now());
|
|
3001
3093
|
if (!this.messageTargetsCurrentInstance(msg)) {
|
|
3002
3094
|
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
3095
|
return;
|
|
@@ -3054,6 +3146,8 @@ export class MessageDeliveryEngine {
|
|
|
3054
3146
|
}
|
|
3055
3147
|
async onRawGroupMessageCreated(data) {
|
|
3056
3148
|
const client = this.runtime.client;
|
|
3149
|
+
if (isJsonObject(data) && !client._echoStarts.has(data))
|
|
3150
|
+
client._echoStarts.set(data, performance.now());
|
|
3057
3151
|
const tStart = Date.now();
|
|
3058
3152
|
if (isJsonObject(data)) {
|
|
3059
3153
|
client._logMessageDebug('server-push', '_raw.group.message_created', 'group.message_created', data);
|
|
@@ -3094,6 +3188,7 @@ export class MessageDeliveryEngine {
|
|
|
3094
3188
|
}
|
|
3095
3189
|
const msg = { ...data };
|
|
3096
3190
|
const groupId = String(msg.group_id ?? '');
|
|
3191
|
+
client._echoStarts.set(msg, client._echoStarts.get(data) ?? performance.now());
|
|
3097
3192
|
const seq = msg.seq;
|
|
3098
3193
|
const payload = msg.payload;
|
|
3099
3194
|
if (groupId) {
|
|
@@ -3210,7 +3305,7 @@ export class MessageDeliveryEngine {
|
|
|
3210
3305
|
try {
|
|
3211
3306
|
// Gap Fill 本身就是 Forward Pull,必须沿用协调器的完整事务:
|
|
3212
3307
|
// 原始页提交成功后由协调器负责 Piggyback/终端 ACK。
|
|
3213
|
-
const operation = () => client._pullV2(afterSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, { gateLocked: true });
|
|
3308
|
+
const operation = () => client._pullV2(afterSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, { gateLocked: true, background: true });
|
|
3214
3309
|
const messages = await this.runAutomaticPull(ns, operation, (attempt) => client._rpcPipeline
|
|
3215
3310
|
? client._rpcPipeline.runPullSerialized(client._rpcPipeline.pullGateKeyForCall('message.pull', { after_seq: afterSeq, limit: _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize }), attempt, true)
|
|
3216
3311
|
: client._withBackgroundRpc(attempt));
|
|
@@ -3606,7 +3701,7 @@ export class MessageDeliveryEngine {
|
|
|
3606
3701
|
return result;
|
|
3607
3702
|
}
|
|
3608
3703
|
reservePendingGroupInlineAck(ns, seq, row, groupAid) {
|
|
3609
|
-
if (!ns || !Number.isSafeInteger(seq) || seq <= 0 || this.pendingGroupInlineAcks?.
|
|
3704
|
+
if (!ns || !Number.isSafeInteger(seq) || seq <= 0 || this.pendingGroupInlineAcks?.get(ns)?.has(seq)
|
|
3610
3705
|
|| this.pendingInlineAckNamespaceCount() >= MAX_INLINE_PENDING_ACK_NAMESPACES)
|
|
3611
3706
|
return false;
|
|
3612
3707
|
const normalizedGroupAid = typeof groupAid === 'string' ? groupAid.trim() : '';
|
|
@@ -3616,7 +3711,9 @@ export class MessageDeliveryEngine {
|
|
|
3616
3711
|
const namespaceMap = this.pendingGroupInlineAckNamespaces ?? new Map();
|
|
3617
3712
|
this.pendingGroupInlineAcks = pendingMap;
|
|
3618
3713
|
this.pendingGroupInlineAckNamespaces = namespaceMap;
|
|
3619
|
-
pendingMap.
|
|
3714
|
+
const entries = pendingMap.get(ns) ?? new Map();
|
|
3715
|
+
pendingMap.set(ns, entries);
|
|
3716
|
+
entries.set(seq, {
|
|
3620
3717
|
seq,
|
|
3621
3718
|
row: this.inlinePostAckRow(row),
|
|
3622
3719
|
groupAid: normalizedGroupAid,
|
|
@@ -3625,6 +3722,7 @@ export class MessageDeliveryEngine {
|
|
|
3625
3722
|
committed: false,
|
|
3626
3723
|
observedAckSeq: 0,
|
|
3627
3724
|
});
|
|
3725
|
+
this.pendingGroupInlineAckCount++;
|
|
3628
3726
|
for (const namespace of namespaces) {
|
|
3629
3727
|
let candidates = namespaceMap.get(namespace);
|
|
3630
3728
|
if (!candidates) {
|
|
@@ -3637,10 +3735,23 @@ export class MessageDeliveryEngine {
|
|
|
3637
3735
|
}
|
|
3638
3736
|
removePendingGroupInlineAck(ns, pending) {
|
|
3639
3737
|
const pendingMap = this.pendingGroupInlineAcks;
|
|
3640
|
-
|
|
3738
|
+
const entries = pendingMap?.get(ns);
|
|
3739
|
+
if (entries?.get(pending.seq) !== pending)
|
|
3641
3740
|
return false;
|
|
3642
|
-
|
|
3741
|
+
entries.delete(pending.seq);
|
|
3742
|
+
this.pendingGroupInlineAckCount--;
|
|
3743
|
+
if (entries.size === 0)
|
|
3744
|
+
pendingMap?.delete(ns);
|
|
3643
3745
|
for (const namespace of pending.namespaces) {
|
|
3746
|
+
let retained = false;
|
|
3747
|
+
for (const other of entries.values()) {
|
|
3748
|
+
if (other.namespaces.includes(namespace)) {
|
|
3749
|
+
retained = true;
|
|
3750
|
+
break;
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
if (retained)
|
|
3754
|
+
continue;
|
|
3644
3755
|
const aliases = this.pendingGroupInlineAckNamespaces?.get(namespace);
|
|
3645
3756
|
if (!aliases)
|
|
3646
3757
|
continue;
|
|
@@ -3651,8 +3762,8 @@ export class MessageDeliveryEngine {
|
|
|
3651
3762
|
return true;
|
|
3652
3763
|
}
|
|
3653
3764
|
dropPendingGroupInlineAck(ns, seq) {
|
|
3654
|
-
const pending = this.pendingGroupInlineAcks?.get(ns);
|
|
3655
|
-
if (pending
|
|
3765
|
+
const pending = this.pendingGroupInlineAcks?.get(ns)?.get(seq);
|
|
3766
|
+
if (pending)
|
|
3656
3767
|
this.removePendingGroupInlineAck(ns, pending);
|
|
3657
3768
|
}
|
|
3658
3769
|
resolvePendingGroupInlineAckNamespace(ns) {
|
|
@@ -3673,19 +3784,23 @@ export class MessageDeliveryEngine {
|
|
|
3673
3784
|
const canonicalNs = candidates.values().next().value;
|
|
3674
3785
|
if (typeof canonicalNs !== 'string')
|
|
3675
3786
|
return;
|
|
3676
|
-
const
|
|
3677
|
-
if (!
|
|
3678
|
-
return;
|
|
3679
|
-
if (!pending.committed) {
|
|
3680
|
-
pending.observedAckSeq = Math.max(pending.observedAckSeq, upToSeq);
|
|
3787
|
+
const entries = this.pendingGroupInlineAcks?.get(canonicalNs);
|
|
3788
|
+
if (!entries)
|
|
3681
3789
|
return;
|
|
3790
|
+
for (const pending of entries.values()) {
|
|
3791
|
+
if (upToSeq < pending.seq)
|
|
3792
|
+
continue;
|
|
3793
|
+
if (!pending.committed) {
|
|
3794
|
+
pending.observedAckSeq = Math.max(pending.observedAckSeq, upToSeq);
|
|
3795
|
+
continue;
|
|
3796
|
+
}
|
|
3797
|
+
this.removePendingGroupInlineAck(canonicalNs, pending);
|
|
3798
|
+
this.runPostInlineCommit(pending.row);
|
|
3682
3799
|
}
|
|
3683
|
-
this.removePendingGroupInlineAck(canonicalNs, pending);
|
|
3684
|
-
this.runPostInlineCommit(pending.row);
|
|
3685
3800
|
}
|
|
3686
3801
|
markPendingGroupInlineAckCommitted(ns, seq) {
|
|
3687
|
-
const pending = this.pendingGroupInlineAcks?.get(ns);
|
|
3688
|
-
if (!pending
|
|
3802
|
+
const pending = this.pendingGroupInlineAcks?.get(ns)?.get(seq);
|
|
3803
|
+
if (!pending)
|
|
3689
3804
|
return false;
|
|
3690
3805
|
pending.committed = true;
|
|
3691
3806
|
if (pending.observedAckSeq < seq)
|
|
@@ -3695,8 +3810,8 @@ export class MessageDeliveryEngine {
|
|
|
3695
3810
|
return true;
|
|
3696
3811
|
}
|
|
3697
3812
|
retryPendingGroupInlineAck(ns, seq, reason, ackThrough = seq) {
|
|
3698
|
-
const pending = this.pendingGroupInlineAcks?.get(ns);
|
|
3699
|
-
if (!pending
|
|
3813
|
+
const pending = this.pendingGroupInlineAcks?.get(ns)?.get(seq);
|
|
3814
|
+
if (!pending)
|
|
3700
3815
|
return false;
|
|
3701
3816
|
if (pending.acking || !pending.committed)
|
|
3702
3817
|
return true;
|
|
@@ -3715,12 +3830,12 @@ export class MessageDeliveryEngine {
|
|
|
3715
3830
|
})).then((result) => {
|
|
3716
3831
|
this.onGroupV2AckResult(groupId, result, requestedSeq, generation);
|
|
3717
3832
|
}).catch((error) => {
|
|
3718
|
-
const current = this.pendingGroupInlineAcks?.get(ns);
|
|
3833
|
+
const current = this.pendingGroupInlineAcks?.get(ns)?.get(seq);
|
|
3719
3834
|
if (current === pending)
|
|
3720
3835
|
current.acking = false;
|
|
3721
3836
|
this.runtime.client._clientLog.debug(`group.v2 ${reason} ack failed: group=${groupId} ${formatDeliveryError(error)}`);
|
|
3722
3837
|
}).finally(() => {
|
|
3723
|
-
const current = this.pendingGroupInlineAcks?.get(ns);
|
|
3838
|
+
const current = this.pendingGroupInlineAcks?.get(ns)?.get(seq);
|
|
3724
3839
|
if (current === pending)
|
|
3725
3840
|
current.acking = false;
|
|
3726
3841
|
});
|
|
@@ -3743,6 +3858,7 @@ export class MessageDeliveryEngine {
|
|
|
3743
3858
|
const gid = String(groupId ?? '').trim();
|
|
3744
3859
|
if (!gid || !Number.isSafeInteger(upToSeq) || upToSeq <= 0)
|
|
3745
3860
|
return;
|
|
3861
|
+
this.runtime.client._rpcPipeline?.confirmBackgroundAck?.(this.resolvePendingGroupInlineAckNamespace(`group:${gid}`), upToSeq);
|
|
3746
3862
|
this.completePendingGroupInlineAck(`group:${gid}`, upToSeq);
|
|
3747
3863
|
}
|
|
3748
3864
|
onGroupV2AckResult(groupId, result, requestedSeq, generation = this.inlineAckGeneration) {
|
|
@@ -3859,7 +3975,7 @@ export class MessageDeliveryEngine {
|
|
|
3859
3975
|
tailHead = this.syncState(ns).head;
|
|
3860
3976
|
return tailResult;
|
|
3861
3977
|
}
|
|
3862
|
-
const opts = { gateLocked: true };
|
|
3978
|
+
const opts = { gateLocked: true, background };
|
|
3863
3979
|
if (request.max_pages !== undefined)
|
|
3864
3980
|
opts.maxPages = request.max_pages;
|
|
3865
3981
|
const messages = await client._pullV2(after, pageLimit, opts);
|
|
@@ -3985,7 +4101,7 @@ export class MessageDeliveryEngine {
|
|
|
3985
4101
|
const client = this.runtime.client;
|
|
3986
4102
|
const request = { after_seq: this.syncState(ns).ack, limit: pageLimit, max_pages: 1 };
|
|
3987
4103
|
const invoke = async () => {
|
|
3988
|
-
const messages = await client._pullV2(Number(request.after_seq), pageLimit, { gateLocked: true, maxPages: 1 });
|
|
4104
|
+
const messages = await client._pullV2(Number(request.after_seq), pageLimit, { gateLocked: true, maxPages: 1, background });
|
|
3989
4105
|
return { messages, raw_count: messages.length };
|
|
3990
4106
|
};
|
|
3991
4107
|
if (!client._rpcPipeline)
|
|
@@ -4709,15 +4825,20 @@ export class MessageDeliveryEngine {
|
|
|
4709
4825
|
client._seqTracker._restoreNamespaceSnapshotPreservingPush(ns, snapshot);
|
|
4710
4826
|
throw error;
|
|
4711
4827
|
}
|
|
4712
|
-
await client._v2E2EE.ackPeerV2(sender, this.syncState(ns).ack);
|
|
4713
4828
|
return true;
|
|
4714
4829
|
})).catch((error) => {
|
|
4715
4830
|
if (generation === this.captureInlineAckGeneration())
|
|
4716
4831
|
this.schedulePeerRecovery(sender, seq);
|
|
4717
4832
|
throw error;
|
|
4718
4833
|
});
|
|
4719
|
-
if (consumed?.acquired && consumed.value &&
|
|
4720
|
-
|
|
4834
|
+
if (consumed?.acquired && consumed.value && generation === this.captureInlineAckGeneration()) {
|
|
4835
|
+
this.scheduleForwardAck(ns, this.peerCommittedAck(ns), async (ack) => {
|
|
4836
|
+
if (!this.isPeerHeadCovered(ns, ack))
|
|
4837
|
+
await client._v2E2EE.ackPeerV2(sender, ack);
|
|
4838
|
+
});
|
|
4839
|
+
if (!unbounded)
|
|
4840
|
+
return;
|
|
4841
|
+
}
|
|
4721
4842
|
}
|
|
4722
4843
|
if ((!unbounded && this.isPeerHeadCovered(ns, seq)) || !this.hasP2pApplicationSubscription())
|
|
4723
4844
|
return;
|
|
@@ -4729,7 +4850,7 @@ export class MessageDeliveryEngine {
|
|
|
4729
4850
|
}
|
|
4730
4851
|
else {
|
|
4731
4852
|
await this.runAutomaticPull(ns, () => client._v2E2EE.pullPeerV2(sender, { limit: _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, budget: { remaining: 1 },
|
|
4732
|
-
...(!unbounded ? { autoPeerHead: seq, peerPullVersion } : {}),
|
|
4853
|
+
...(!unbounded ? { autoPeerHead: seq, autoPeerAckFloor: committedAck, peerPullVersion } : {}),
|
|
4733
4854
|
...(this.shouldTailPeer(ns, seq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize) ? { window_mode: 'tail', autoTail: { head: seq, forward: false } } : {}) }));
|
|
4734
4855
|
}
|
|
4735
4856
|
}
|
|
@@ -4843,11 +4964,11 @@ export class MessageDeliveryEngine {
|
|
|
4843
4964
|
const coordinator = client._v2E2EE;
|
|
4844
4965
|
const pendingAckSeq = Number(coordinator.pendingForwardAck?.(ns, committedAck) ?? 0);
|
|
4845
4966
|
if (pendingAckSeq > 0) {
|
|
4846
|
-
|
|
4967
|
+
this.scheduleForwardAck(ns, pendingAckSeq, seq => coordinator.confirmForwardGroupAck(groupId, seq, String(data.group_aid ?? '').trim() || undefined, true));
|
|
4847
4968
|
}
|
|
4848
4969
|
else {
|
|
4849
4970
|
const pendingNs = this.resolvePendingGroupInlineAckNamespace(ns);
|
|
4850
|
-
const pending = this.pendingGroupInlineAcks?.get(pendingNs);
|
|
4971
|
+
const pending = this.pendingGroupInlineAcks?.get(pendingNs)?.values().next().value;
|
|
4851
4972
|
if (pending)
|
|
4852
4973
|
this.retryPendingGroupInlineAck(pendingNs, pending.seq, 'covered online hint', committedAck);
|
|
4853
4974
|
}
|
|
@@ -4904,8 +5025,6 @@ export class MessageDeliveryEngine {
|
|
|
4904
5025
|
const groupId = typeof d.group_id === 'string' ? d.group_id.trim() : '';
|
|
4905
5026
|
const rawSeq = d.seq;
|
|
4906
5027
|
const inlinePresent = hasNonEmptyInlineMessage(d.inline_message);
|
|
4907
|
-
if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent))
|
|
4908
|
-
return;
|
|
4909
5028
|
const seq = this.realtimeHeadSeq(rawSeq, inlinePresent);
|
|
4910
5029
|
if (!groupId) {
|
|
4911
5030
|
client._clientLog.debug(`_onRawGroupV2MessageCreated skipped: group=${groupId || '<empty>'}, seq=${String(d.seq ?? '')}`);
|
|
@@ -4918,6 +5037,15 @@ export class MessageDeliveryEngine {
|
|
|
4918
5037
|
return;
|
|
4919
5038
|
}
|
|
4920
5039
|
const eventKind = String(d.kind ?? '').trim();
|
|
5040
|
+
if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent)) {
|
|
5041
|
+
if (client._sessionOptions?.background_sync !== false) {
|
|
5042
|
+
const ns = `group:${groupId}`;
|
|
5043
|
+
this.recordBackgroundPullNeed(ns, seq, eventKind === 'group.online_unread_hint', true);
|
|
5044
|
+
if (this.backgroundPullNeeds.has(ns))
|
|
5045
|
+
this.pendingV2GroupPulls.add(ns);
|
|
5046
|
+
}
|
|
5047
|
+
return;
|
|
5048
|
+
}
|
|
4921
5049
|
if (eventKind === 'group.online_unread_hint') {
|
|
4922
5050
|
if (client._sessionOptions.background_sync === false)
|
|
4923
5051
|
return;
|
|
@@ -4928,9 +5056,7 @@ export class MessageDeliveryEngine {
|
|
|
4928
5056
|
if (this.automaticGroupPullStopped(ns))
|
|
4929
5057
|
return;
|
|
4930
5058
|
let inlineConsumed = false;
|
|
4931
|
-
|
|
4932
|
-
const inlineBlockedByPendingAck = Boolean(pendingInlineAck && pendingInlineAck.seq !== seq);
|
|
4933
|
-
if (inlinePresent && !inlineBlockedByPendingAck && isJsonObject(d.inline_message)) {
|
|
5059
|
+
if (inlinePresent && isJsonObject(d.inline_message)) {
|
|
4934
5060
|
try {
|
|
4935
5061
|
inlineConsumed = await this.tryConsumeInlineGroup(d, groupId, ns, seq, expectedVersion, inlineGeneration);
|
|
4936
5062
|
if (inlineGeneration !== undefined && !this.inlineGenerationIsCurrent(inlineGeneration))
|
|
@@ -4951,8 +5077,8 @@ export class MessageDeliveryEngine {
|
|
|
4951
5077
|
client._seqTracker.updateMaxSeen(ns, seq);
|
|
4952
5078
|
if (seq <= before.ack && before.ack >= before.tail - 1) {
|
|
4953
5079
|
client._clientLog.debug(`V2 group duplicate push ignored: group=${groupId} seq=${seq} A/T/H=${JSON.stringify(before)}`);
|
|
4954
|
-
const pending = this.pendingGroupInlineAcks?.get(ns);
|
|
4955
|
-
if (inlinePresent && pending
|
|
5080
|
+
const pending = this.pendingGroupInlineAcks?.get(ns)?.get(seq);
|
|
5081
|
+
if (inlinePresent && pending) {
|
|
4956
5082
|
this.retryPendingGroupInlineAck(ns, seq, 'covered inline push');
|
|
4957
5083
|
}
|
|
4958
5084
|
return;
|
|
@@ -5052,18 +5178,44 @@ export class MessageDeliveryEngine {
|
|
|
5052
5178
|
this.refreshPendingPeers();
|
|
5053
5179
|
return;
|
|
5054
5180
|
}
|
|
5055
|
-
if (!client._aid || !client._v2Session)
|
|
5181
|
+
if (!client._aid || !client._v2Session || client._sessionOptions?.background_sync === false)
|
|
5056
5182
|
return;
|
|
5057
5183
|
const ns = `p2p:${client._aid}`;
|
|
5058
5184
|
const generation = this.captureInlineAckGeneration();
|
|
5059
|
-
const
|
|
5060
|
-
|
|
5185
|
+
const state = this.syncState(ns);
|
|
5186
|
+
const afterSeq = state.ack;
|
|
5187
|
+
const hintSeq = positiveSafeSequenceHint(data.seq);
|
|
5188
|
+
if (hintSeq > 0 && afterSeq >= Math.max(hintSeq, state.head, Number(client._seqTracker.getMaxSeenSeq?.(ns) ?? 0), Number(client._pendingP2pPullUpper?.get?.(ns) ?? 0))
|
|
5189
|
+
&& afterSeq >= state.tail - 1 && !client._pendingOrderedMsgs.get(ns)?.size) {
|
|
5190
|
+
const coordinator = client._v2E2EE;
|
|
5191
|
+
const pendingAckSeq = Number(coordinator.pendingForwardAck?.(ns, afterSeq) ?? 0);
|
|
5192
|
+
if (pendingAckSeq > 0) {
|
|
5193
|
+
this.scheduleForwardAck(ns, pendingAckSeq, seq => coordinator.confirmForwardP2PAck(seq));
|
|
5194
|
+
}
|
|
5195
|
+
else {
|
|
5196
|
+
const pending = this.pendingP2PInlineAcks?.get(ns);
|
|
5197
|
+
if (pending)
|
|
5198
|
+
this.retryPendingP2PInlineAck(ns, pending.seq, 'covered online hint', afterSeq);
|
|
5199
|
+
}
|
|
5200
|
+
return;
|
|
5201
|
+
}
|
|
5202
|
+
this.recordBackgroundPullNeed(ns, hintSeq, true, true);
|
|
5061
5203
|
const pullTrigger = this.backgroundPullNeeds.get(ns)?.trigger;
|
|
5204
|
+
const tasks = this.onlineUnreadHintTasks ?? new Map();
|
|
5205
|
+
this.onlineUnreadHintTasks = tasks;
|
|
5206
|
+
if (tasks.has(ns))
|
|
5207
|
+
return;
|
|
5062
5208
|
let failed = false;
|
|
5063
|
-
|
|
5209
|
+
const task = this.runP2PForwardRecovery(ns, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, true).then(() => undefined).catch((exc) => {
|
|
5064
5210
|
failed = true;
|
|
5065
5211
|
client._clientLog.debug(`P2P online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
5066
|
-
}).finally(() =>
|
|
5212
|
+
}).finally(() => {
|
|
5213
|
+
if (tasks.get(ns) === task)
|
|
5214
|
+
tasks.delete(ns);
|
|
5215
|
+
this.finishBackgroundPull(ns, generation, afterSeq, failed, pullTrigger);
|
|
5216
|
+
});
|
|
5217
|
+
tasks.set(ns, task);
|
|
5218
|
+
client._safeAsync(task);
|
|
5067
5219
|
}
|
|
5068
5220
|
async saveSeqTrackerState() {
|
|
5069
5221
|
const client = this.runtime.client;
|
|
@@ -5413,9 +5565,10 @@ export class MessageDeliveryEngine {
|
|
|
5413
5565
|
}
|
|
5414
5566
|
else if (method === 'group.v2.ack' || method === 'group.ack_messages') {
|
|
5415
5567
|
const canonicalNs = this.resolvePendingGroupInlineAckNamespace(ns);
|
|
5416
|
-
const pending
|
|
5417
|
-
|
|
5418
|
-
|
|
5568
|
+
for (const pending of this.pendingGroupInlineAcks?.get(canonicalNs)?.values() ?? []) {
|
|
5569
|
+
if (!pending.committed && next >= pending.seq)
|
|
5570
|
+
next = pending.seq - 1;
|
|
5571
|
+
}
|
|
5419
5572
|
}
|
|
5420
5573
|
}
|
|
5421
5574
|
return next;
|