@agentunion/fastaun 0.5.19 → 0.5.20
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 +129 -78
- package/_packed_docs/CHANGELOG.md +129 -78
- package/_packed_docs/INDEX.md +201 -195
- package/_packed_docs/KITE_DOCS_GUIDE.md +93 -90
- package/_packed_docs/agent.md/SCHEMA.md +7 -7
- package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +11 -11
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1072 -1072
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +676 -676
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +8 -12
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +443 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +658 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
- package/_packed_docs/protocol/agent.md/SCHEMA.md +1 -1
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +1 -1
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +67 -63
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +35 -8
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
- package/_packed_docs/sdk/09-group-rpc-manual.md +258 -254
- package/_packed_docs/sdk/09-message-rpc-manual.md +7 -4
- package/_packed_docs/sdk/09-storage-rpc-manual.md +18 -26
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +61 -52
- package/_packed_docs/sdk/INDEX.md +92 -80
- package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +922 -0
- package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
- 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 +300 -0
- 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 +382 -0
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +476 -0
- package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
- package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +173 -0
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +211 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
- package/dist/agent-md-schema.d.ts +13 -1
- package/dist/agent-md-schema.js +61 -33
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +8 -1
- package/dist/agent-md.js +243 -119
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +29 -0
- package/dist/aid-store.js +179 -34
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.js +18 -13
- package/dist/aid.js.map +1 -1
- package/dist/auth.js +74 -2
- package/dist/auth.js.map +1 -1
- package/dist/cert-utils.d.ts +43 -1
- package/dist/cert-utils.js +144 -56
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +9 -0
- package/dist/client/delivery.js +179 -11
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +1 -0
- package/dist/client/rpc-pipeline.js +125 -82
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.js +95 -89
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.js +48 -19
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +5 -3
- package/dist/events.js +25 -8
- package/dist/events.js.map +1 -1
- package/dist/facades.js +5 -5
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js.map +1 -1
- package/dist/keystore/aid-db.d.ts +1 -1
- package/dist/keystore/aid-db.js +11 -2
- package/dist/keystore/aid-db.js.map +1 -1
- package/dist/keystore/index.d.ts +1 -1
- package/dist/keystore/local-token-store.d.ts +1 -1
- package/dist/keystore/local-token-store.js +2 -2
- package/dist/keystore/local-token-store.js.map +1 -1
- package/dist/org-protocol.js +77 -13
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +26 -8
- package/dist/ownership-v21.js +147 -70
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +5 -0
- package/dist/ownership-workflow.js +366 -56
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +2 -1
- package/dist/tools/cross-sdk-agent.js +109 -6
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +1 -0
- package/dist/transport.js +10 -0
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/client/delivery.js
CHANGED
|
@@ -9,6 +9,7 @@ const MESSAGE_RECALL_SEEN_LIMIT = 10_000;
|
|
|
9
9
|
const GROUP_RECALL_SEEN_LIMIT = 10_000;
|
|
10
10
|
const VOLATILE_SEEN_LIMIT = 10_000;
|
|
11
11
|
const SEQ_TRACKER_PERSIST_FLUSH_DELAY_MS = 200;
|
|
12
|
+
const BACKGROUND_PULL_RETRY_DELAY_MS = 250;
|
|
12
13
|
const DELIVERY_CHANGED_MESSAGE_EVENTS = new Set([
|
|
13
14
|
'message.received',
|
|
14
15
|
'group.message_created',
|
|
@@ -80,6 +81,11 @@ export class MessageDeliveryEngine {
|
|
|
80
81
|
pendingGroupPullUpper = null;
|
|
81
82
|
onlineUnreadHintTargets = null;
|
|
82
83
|
onlineUnreadHintTasks = null;
|
|
84
|
+
backgroundPullNeeds = new Map();
|
|
85
|
+
backgroundPullTasks = new Set();
|
|
86
|
+
backgroundPullCheckQueued = false;
|
|
87
|
+
backgroundPullTimer = null;
|
|
88
|
+
backgroundPullTimerAt = 0;
|
|
83
89
|
pendingP2PInlineAcks = null;
|
|
84
90
|
pendingGroupInlineAcks = null;
|
|
85
91
|
pendingGroupInlineAckNamespaces = null;
|
|
@@ -422,6 +428,13 @@ export class MessageDeliveryEngine {
|
|
|
422
428
|
this.deliveryChangedGeneration += 1;
|
|
423
429
|
this.pendingDeliveryChanges = null;
|
|
424
430
|
this.inlineAckGeneration += 1;
|
|
431
|
+
if (this.backgroundPullTimer)
|
|
432
|
+
clearTimeout(this.backgroundPullTimer);
|
|
433
|
+
this.backgroundPullTimer = null;
|
|
434
|
+
this.backgroundPullTimerAt = 0;
|
|
435
|
+
this.backgroundPullNeeds.clear();
|
|
436
|
+
this.backgroundPullTasks.clear();
|
|
437
|
+
this.backgroundPullCheckQueued = false;
|
|
425
438
|
void this.runtime.client._rpcPipeline?.invalidatePulls?.();
|
|
426
439
|
this.pendingP2PInlineAcks = null;
|
|
427
440
|
this.pendingGroupInlineAcks = null;
|
|
@@ -693,6 +706,7 @@ export class MessageDeliveryEngine {
|
|
|
693
706
|
}
|
|
694
707
|
endRealtimeSync(ns) {
|
|
695
708
|
this.realtimeSyncing?.delete(ns);
|
|
709
|
+
this.requestBackgroundPullRecovery();
|
|
696
710
|
this.runtime.client._rpcPipeline?.requestPullDrainedCheck?.();
|
|
697
711
|
}
|
|
698
712
|
hasPendingPull(ns) {
|
|
@@ -703,6 +717,7 @@ export class MessageDeliveryEngine {
|
|
|
703
717
|
}
|
|
704
718
|
hasAnyPendingPull() {
|
|
705
719
|
return [...(this.pendingGroupPullUpper?.values() ?? [])].some((seq) => seq > 0)
|
|
720
|
+
|| this.backgroundPullNeeds.size > 0
|
|
706
721
|
|| Boolean(this.onlineUnreadHintTasks?.size)
|
|
707
722
|
|| Boolean(this.realtimeSyncing?.size)
|
|
708
723
|
|| Boolean(this.runtime.client._v2E2EE?.hasPendingSenderIKWork?.());
|
|
@@ -710,12 +725,124 @@ export class MessageDeliveryEngine {
|
|
|
710
725
|
onPullGateIdle(ns) {
|
|
711
726
|
if (!ns)
|
|
712
727
|
return;
|
|
728
|
+
this.requestBackgroundPullRecovery();
|
|
713
729
|
if (ns.startsWith('p2p:')) {
|
|
714
730
|
this.runtime.client._schedulePendingP2pPullIfNeeded?.(ns, 'pull-gate-idle');
|
|
715
731
|
return;
|
|
716
732
|
}
|
|
717
733
|
this.schedulePendingGroupPullIfNeeded(ns, 'pull-gate-idle');
|
|
718
734
|
}
|
|
735
|
+
recordBackgroundPullNeed(ns, throughSeq = 0, probe = false) {
|
|
736
|
+
const client = this.runtime.client;
|
|
737
|
+
if (client._sessionOptions?.background_sync === false || !client._aid
|
|
738
|
+
|| !(ns === `p2p:${client._aid}` || ns.startsWith('group:') || ns.startsWith('group_event:')))
|
|
739
|
+
return;
|
|
740
|
+
const need = this.backgroundPullNeeds.get(ns) ?? {
|
|
741
|
+
throughSeq: 0, hasMore: false, probe, lastAfter: -1, retryAt: 0,
|
|
742
|
+
};
|
|
743
|
+
need.throughSeq = Math.max(need.throughSeq, throughSeq);
|
|
744
|
+
need.probe ||= probe;
|
|
745
|
+
this.backgroundPullNeeds.set(ns, need);
|
|
746
|
+
}
|
|
747
|
+
observeBackgroundPullResponse(ns, afterSeq, result, limit = 50) {
|
|
748
|
+
if (!isJsonObject(result))
|
|
749
|
+
return;
|
|
750
|
+
const response = result;
|
|
751
|
+
const rows = ns.startsWith('group_event:') ? response.events : response.messages;
|
|
752
|
+
if (!Array.isArray(rows))
|
|
753
|
+
return;
|
|
754
|
+
const cursor = isJsonObject(response.cursor)
|
|
755
|
+
? response.cursor : null;
|
|
756
|
+
const throughSeq = Math.max(positiveSafeSequenceHint(cursor?.latest_seq), positiveSafeSequenceHint(response.latest_seq), positiveSafeSequenceHint(response.latest_message_seq), positiveSafeSequenceHint(response.latest_event_seq), ...rows.map((row) => row && typeof row === 'object' && row.storage !== 'volatile'
|
|
757
|
+
? positiveSafeSequenceHint(row.seq ?? row.event_seq) : 0));
|
|
758
|
+
this.recordBackgroundPullNeed(ns, throughSeq);
|
|
759
|
+
const need = this.backgroundPullNeeds.get(ns);
|
|
760
|
+
if (!need || afterSeq < need.lastAfter)
|
|
761
|
+
return;
|
|
762
|
+
need.lastAfter = afterSeq;
|
|
763
|
+
need.hasMore = response.has_more === true || positiveSafeSequenceHint(response.remaining) > 0
|
|
764
|
+
|| (!('has_more' in response) && limit > 0 && rows.length >= limit);
|
|
765
|
+
need.probe = false;
|
|
766
|
+
}
|
|
767
|
+
finishBackgroundPull(ns, generation, afterSeq, failed) {
|
|
768
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
769
|
+
return;
|
|
770
|
+
const need = this.backgroundPullNeeds.get(ns);
|
|
771
|
+
if (need) {
|
|
772
|
+
if (failed)
|
|
773
|
+
need.probe = true;
|
|
774
|
+
else
|
|
775
|
+
need.probe = false;
|
|
776
|
+
need.retryAt = failed || this.syncState(ns).ack <= afterSeq
|
|
777
|
+
? Date.now() + BACKGROUND_PULL_RETRY_DELAY_MS : 0;
|
|
778
|
+
}
|
|
779
|
+
this.requestBackgroundPullRecovery();
|
|
780
|
+
}
|
|
781
|
+
requestBackgroundPullRecovery() {
|
|
782
|
+
if (this.backgroundPullCheckQueued || this.backgroundPullNeeds.size === 0)
|
|
783
|
+
return;
|
|
784
|
+
this.backgroundPullCheckQueued = true;
|
|
785
|
+
const generation = this.captureInlineAckGeneration();
|
|
786
|
+
queueMicrotask(() => {
|
|
787
|
+
this.backgroundPullCheckQueued = false;
|
|
788
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
789
|
+
return;
|
|
790
|
+
const client = this.runtime.client;
|
|
791
|
+
if (client._sessionOptions?.background_sync === false || client.state !== ConnectionState.READY || client._closing)
|
|
792
|
+
return;
|
|
793
|
+
let retryAt = Infinity;
|
|
794
|
+
for (const [ns, need] of this.backgroundPullNeeds) {
|
|
795
|
+
if (this.backgroundPullTasks.has(ns) || this.realtimeSyncing?.has(ns) || this.onlineUnreadHintTasks?.has(ns))
|
|
796
|
+
continue;
|
|
797
|
+
const eventScope = ns.startsWith('group_event:');
|
|
798
|
+
const filling = [...(client._gapFillDone?.keys?.() ?? [])].some((key) => eventScope
|
|
799
|
+
? String(key) === `group_event_pull:${ns}`
|
|
800
|
+
: ns.startsWith('p2p:') ? String(key).startsWith('p2p:') : String(key).startsWith(`group_msg:${ns.slice(6)}:`));
|
|
801
|
+
if (filling || (!eventScope && client._rpcPipeline?.hasPullActivity?.(ns, false))
|
|
802
|
+
|| (eventScope && ['pulling', 'processing', 'pulled'].includes(client._rpcPipeline?.getPullLifecycle?.(ns))))
|
|
803
|
+
continue;
|
|
804
|
+
if (this.syncState(ns).ack >= need.throughSeq && !need.hasMore && !need.probe) {
|
|
805
|
+
this.backgroundPullNeeds.delete(ns);
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
if (need.retryAt > Date.now()) {
|
|
809
|
+
retryAt = Math.min(retryAt, need.retryAt);
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
this.backgroundPullTasks.add(ns);
|
|
813
|
+
const task = Promise.resolve().then(() => {
|
|
814
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
815
|
+
return;
|
|
816
|
+
return eventScope ? this.fillGroupEventGap(ns.slice('group_event:'.length))
|
|
817
|
+
: ns.startsWith('group:') ? this.fillGroupGap(ns.slice(6)) : this.fillP2pGap();
|
|
818
|
+
}).finally(() => {
|
|
819
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
820
|
+
return;
|
|
821
|
+
this.backgroundPullTasks.delete(ns);
|
|
822
|
+
this.requestBackgroundPullRecovery();
|
|
823
|
+
});
|
|
824
|
+
client._safeAsync(task);
|
|
825
|
+
}
|
|
826
|
+
if (this.backgroundPullNeeds.size === 0) {
|
|
827
|
+
if (this.backgroundPullTimer)
|
|
828
|
+
clearTimeout(this.backgroundPullTimer);
|
|
829
|
+
this.backgroundPullTimer = null;
|
|
830
|
+
this.backgroundPullTimerAt = 0;
|
|
831
|
+
client._rpcPipeline?.requestPullDrainedCheck?.();
|
|
832
|
+
}
|
|
833
|
+
if (Number.isFinite(retryAt) && (!this.backgroundPullTimer || retryAt < this.backgroundPullTimerAt)) {
|
|
834
|
+
if (this.backgroundPullTimer)
|
|
835
|
+
clearTimeout(this.backgroundPullTimer);
|
|
836
|
+
this.backgroundPullTimerAt = retryAt;
|
|
837
|
+
this.backgroundPullTimer = setTimeout(() => {
|
|
838
|
+
this.backgroundPullTimer = null;
|
|
839
|
+
this.backgroundPullTimerAt = 0;
|
|
840
|
+
this.requestBackgroundPullRecovery();
|
|
841
|
+
}, Math.max(0, retryAt - Date.now()));
|
|
842
|
+
this.backgroundPullTimer.unref?.();
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
}
|
|
719
846
|
onForegroundPullsDrained() {
|
|
720
847
|
const client = this.runtime.client;
|
|
721
848
|
if (!client._aid || client._sessionOptions?.background_sync === false
|
|
@@ -1340,6 +1467,7 @@ export class MessageDeliveryEngine {
|
|
|
1340
1467
|
if (seqNum > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) {
|
|
1341
1468
|
this.fillGroupGap(groupId).catch((exc) => client._clientLog.warn(`background recall gap fill failed: ${formatDeliveryError(exc)}`));
|
|
1342
1469
|
}
|
|
1470
|
+
await this.publishGroupRecallTombstone(groupId, seq, wrapped);
|
|
1343
1471
|
}
|
|
1344
1472
|
publishAppEvent(event, payload, source = 'direct', deliveryContext) {
|
|
1345
1473
|
const client = this.runtime.client;
|
|
@@ -1625,7 +1753,6 @@ export class MessageDeliveryEngine {
|
|
|
1625
1753
|
if (Number(seq) > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) {
|
|
1626
1754
|
this.fillP2pGap().catch((exc) => client._clientLog.warn(`background recall gap fill failed: ${formatDeliveryError(exc)}`));
|
|
1627
1755
|
}
|
|
1628
|
-
return;
|
|
1629
1756
|
}
|
|
1630
1757
|
await this.publishMessageRecallTombstone(seq, msg);
|
|
1631
1758
|
}
|
|
@@ -1826,12 +1953,15 @@ export class MessageDeliveryEngine {
|
|
|
1826
1953
|
return;
|
|
1827
1954
|
const ns = `p2p:${client._aid}`;
|
|
1828
1955
|
const afterSeq = client._seqTracker.getContiguousSeq(ns);
|
|
1956
|
+
const generation = this.captureInlineAckGeneration();
|
|
1829
1957
|
const dedupKey = `p2p:${afterSeq}`;
|
|
1830
1958
|
if (client._gapFillDone.has(dedupKey))
|
|
1831
1959
|
return;
|
|
1832
1960
|
client._gapFillDone.set(dedupKey, Date.now());
|
|
1961
|
+
this.recordBackgroundPullNeed(ns, 0, true);
|
|
1833
1962
|
client._clientLog.debug(`P2P message gap fill start: after_seq=${afterSeq}`);
|
|
1834
1963
|
let filled = 0;
|
|
1964
|
+
let failed = false;
|
|
1835
1965
|
try {
|
|
1836
1966
|
// Gap Fill 本身就是 Forward Pull,必须沿用协调器的完整事务:
|
|
1837
1967
|
// 原始页提交成功后由协调器负责 Piggyback/终端 ACK。
|
|
@@ -1844,11 +1974,15 @@ export class MessageDeliveryEngine {
|
|
|
1844
1974
|
client._clientLog.debug(`P2P message gap fill done: after_seq=${afterSeq}, filled=${filled}`);
|
|
1845
1975
|
}
|
|
1846
1976
|
catch (exc) {
|
|
1977
|
+
failed = true;
|
|
1847
1978
|
client._clientLog.warn(`P2P message gap fill failed: ${formatDeliveryError(exc)}`);
|
|
1848
1979
|
}
|
|
1849
1980
|
finally {
|
|
1981
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
1982
|
+
return;
|
|
1850
1983
|
client._gapFillDone.delete(dedupKey);
|
|
1851
1984
|
client._schedulePendingP2pPullIfNeeded?.(ns, 'gap-fill-complete');
|
|
1985
|
+
this.finishBackgroundPull(ns, generation, afterSeq, failed);
|
|
1852
1986
|
}
|
|
1853
1987
|
}
|
|
1854
1988
|
async fillGroupGap(groupId) {
|
|
@@ -1860,12 +1994,15 @@ export class MessageDeliveryEngine {
|
|
|
1860
1994
|
return;
|
|
1861
1995
|
const ns = `group:${groupId}`;
|
|
1862
1996
|
const afterSeq = client._seqTracker.getContiguousSeq(ns);
|
|
1997
|
+
const generation = this.captureInlineAckGeneration();
|
|
1863
1998
|
const dedupKey = `group_msg:${groupId}:${afterSeq}`;
|
|
1864
1999
|
if (client._gapFillDone.has(dedupKey))
|
|
1865
2000
|
return;
|
|
1866
2001
|
client._gapFillDone.set(dedupKey, Date.now());
|
|
2002
|
+
this.recordBackgroundPullNeed(ns, 0, true);
|
|
1867
2003
|
client._clientLog.debug(`group message gap fill start: group=${groupId}, after_seq=${afterSeq}`);
|
|
1868
2004
|
let filled = 0;
|
|
2005
|
+
let failed = false;
|
|
1869
2006
|
try {
|
|
1870
2007
|
const operation = () => client._pullGroupV2(groupId, afterSeq, 50, { gateLocked: true });
|
|
1871
2008
|
const messages = client._rpcPipeline
|
|
@@ -1876,14 +2013,15 @@ export class MessageDeliveryEngine {
|
|
|
1876
2013
|
client._clientLog.debug(`group message gap fill done: group=${groupId}, after_seq=${afterSeq}, filled=${filled}`);
|
|
1877
2014
|
}
|
|
1878
2015
|
catch (exc) {
|
|
2016
|
+
failed = true;
|
|
1879
2017
|
client._clientLog.warn(`group message gap fill failed: ${formatDeliveryError(exc)}`);
|
|
1880
2018
|
}
|
|
1881
2019
|
finally {
|
|
2020
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
2021
|
+
return;
|
|
1882
2022
|
client._gapFillDone.delete(dedupKey);
|
|
1883
|
-
if (filled > 0 && client._seqTracker.getContiguousSeq(ns) > afterSeq) {
|
|
1884
|
-
void this.fillGroupGap(groupId);
|
|
1885
|
-
}
|
|
1886
2023
|
this.schedulePendingGroupPullIfNeeded(ns, 'gap-fill-complete');
|
|
2024
|
+
this.finishBackgroundPull(ns, generation, afterSeq, failed);
|
|
1887
2025
|
}
|
|
1888
2026
|
}
|
|
1889
2027
|
scheduleRealtimeWindowForward(ns, groupId = '') {
|
|
@@ -1944,6 +2082,7 @@ export class MessageDeliveryEngine {
|
|
|
1944
2082
|
}
|
|
1945
2083
|
}
|
|
1946
2084
|
client._gapFillDone.set(dedupKey, Date.now());
|
|
2085
|
+
this.recordBackgroundPullNeed(ns, client._seqTracker.getMaxSeenSeq(ns), true);
|
|
1947
2086
|
this.syncStarted(ns);
|
|
1948
2087
|
let filled = 0;
|
|
1949
2088
|
let continuationAfterSeq = 0;
|
|
@@ -1974,6 +2113,9 @@ export class MessageDeliveryEngine {
|
|
|
1974
2113
|
}
|
|
1975
2114
|
if (!isJsonObject(result))
|
|
1976
2115
|
return;
|
|
2116
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
2117
|
+
return;
|
|
2118
|
+
this.observeBackgroundPullResponse(ns, nextAfterSeq, result);
|
|
1977
2119
|
const events = result.events;
|
|
1978
2120
|
if (!Array.isArray(events))
|
|
1979
2121
|
return;
|
|
@@ -2085,6 +2227,7 @@ export class MessageDeliveryEngine {
|
|
|
2085
2227
|
const nextAfter = Math.max(eventSeqs.length > 0 ? Math.max(...eventSeqs) : nextAfterSeq, nextAfterSeq);
|
|
2086
2228
|
const pageAdvanced = eventObjects.length > 0 && nextAfter > nextAfterSeq;
|
|
2087
2229
|
const needsMore = result.has_more === true
|
|
2230
|
+
|| positiveSafeSequenceHint(result.remaining) > 0
|
|
2088
2231
|
|| client._seqTracker.getMaxSeenSeq(ns) > nextAfter;
|
|
2089
2232
|
if (singlePage && pageAdvanced && needsMore) {
|
|
2090
2233
|
continuationAfterSeq = nextAfter;
|
|
@@ -2103,19 +2246,22 @@ export class MessageDeliveryEngine {
|
|
|
2103
2246
|
client._clientLog.warn(`group event gap fill failed: ${formatDeliveryError(exc)}`);
|
|
2104
2247
|
}
|
|
2105
2248
|
finally {
|
|
2106
|
-
|
|
2249
|
+
if (generation === this.captureInlineAckGeneration())
|
|
2250
|
+
client._gapFillDone.delete(dedupKey);
|
|
2107
2251
|
if (legacyGateToken !== null && typeof client._releasePullGate === 'function') {
|
|
2108
2252
|
client._releasePullGate(ns, legacyGateToken);
|
|
2109
2253
|
}
|
|
2254
|
+
if (generation !== this.captureInlineAckGeneration())
|
|
2255
|
+
return;
|
|
2256
|
+
if (dissolved)
|
|
2257
|
+
this.backgroundPullNeeds.delete(ns);
|
|
2110
2258
|
if (!dissolved && singlePage && continuationAfterSeq > afterSeq) {
|
|
2111
2259
|
this.enqueueOnlineUnreadEventHint({
|
|
2112
2260
|
group_id: groupId,
|
|
2113
2261
|
_online_hint_after_event_seq: continuationAfterSeq,
|
|
2114
2262
|
});
|
|
2115
2263
|
}
|
|
2116
|
-
|
|
2117
|
-
void this.fillGroupEventGap(groupId);
|
|
2118
|
-
}
|
|
2264
|
+
this.finishBackgroundPull(ns, generation, afterSeq, failed);
|
|
2119
2265
|
if (!client._rpcPipeline)
|
|
2120
2266
|
this.syncStopped(failed ? 'aborted' : 'pull_drained');
|
|
2121
2267
|
}
|
|
@@ -2125,6 +2271,7 @@ export class MessageDeliveryEngine {
|
|
|
2125
2271
|
const groupId = String(data.group_id ?? '').trim();
|
|
2126
2272
|
if (!groupId || client._sessionOptions?.background_sync === false)
|
|
2127
2273
|
return;
|
|
2274
|
+
this.recordBackgroundPullNeed(`group_event:${groupId}`, positiveSafeSequenceHint(data.event_seq), true);
|
|
2128
2275
|
const rawAfter = Number(data._online_hint_after_event_seq ?? 0);
|
|
2129
2276
|
const afterSeq = Number.isSafeInteger(rawAfter) && rawAfter > 0 ? rawAfter : 0;
|
|
2130
2277
|
client._safeAsync(this.fillGroupEventGap(groupId, {
|
|
@@ -3197,6 +3344,7 @@ export class MessageDeliveryEngine {
|
|
|
3197
3344
|
}
|
|
3198
3345
|
async onV2PushNotification(data, expectedVersion, inlineGeneration) {
|
|
3199
3346
|
const client = this.runtime.client;
|
|
3347
|
+
const syncGeneration = this.captureInlineAckGeneration();
|
|
3200
3348
|
if (inlineGeneration !== undefined && !this.inlineGenerationIsCurrent(inlineGeneration))
|
|
3201
3349
|
return;
|
|
3202
3350
|
const pushData = isJsonObject(data) ? data : null;
|
|
@@ -3251,6 +3399,7 @@ export class MessageDeliveryEngine {
|
|
|
3251
3399
|
this.retryPendingP2PInlineAck(ns, pushSeq, 'covered inline push');
|
|
3252
3400
|
return;
|
|
3253
3401
|
}
|
|
3402
|
+
this.recordBackgroundPullNeed(ns, pushSeq);
|
|
3254
3403
|
const pullActive = client._rpcPipeline?.hasPullActivity?.(ns) === true;
|
|
3255
3404
|
if (pullActive || !this.beginRealtimeSync(ns)) {
|
|
3256
3405
|
client._recordPendingP2pPull(ns, pushSeq);
|
|
@@ -3267,7 +3416,9 @@ export class MessageDeliveryEngine {
|
|
|
3267
3416
|
client._clientLog.warn(`V2 P2P push auto-sync failed: ${formatDeliveryError(exc)}`);
|
|
3268
3417
|
}
|
|
3269
3418
|
finally {
|
|
3270
|
-
if (
|
|
3419
|
+
if (syncGeneration === this.captureInlineAckGeneration()
|
|
3420
|
+
&& (inlineGeneration === undefined || this.inlineGenerationIsCurrent(inlineGeneration))) {
|
|
3421
|
+
this.finishBackgroundPull(ns, syncGeneration, this.syncState(ns).ack, false);
|
|
3271
3422
|
this.endRealtimeSync(ns);
|
|
3272
3423
|
client._schedulePendingP2pPullIfNeeded?.(ns, 'push-auto-pull-complete');
|
|
3273
3424
|
}
|
|
@@ -3279,6 +3430,9 @@ export class MessageDeliveryEngine {
|
|
|
3279
3430
|
if (!groupId)
|
|
3280
3431
|
return;
|
|
3281
3432
|
const ns = `group:${groupId}`;
|
|
3433
|
+
const generation = this.captureInlineAckGeneration();
|
|
3434
|
+
const afterSeq = this.syncState(ns).ack;
|
|
3435
|
+
this.recordBackgroundPullNeed(ns, positiveSafeSequenceHint(data.seq));
|
|
3282
3436
|
const targets = this.onlineUnreadHintTargets ?? new Map();
|
|
3283
3437
|
const tasks = this.onlineUnreadHintTasks ?? new Map();
|
|
3284
3438
|
this.onlineUnreadHintTargets = targets;
|
|
@@ -3286,10 +3440,13 @@ export class MessageDeliveryEngine {
|
|
|
3286
3440
|
targets.set(ns, Math.max(targets.get(ns) ?? 0, positiveSafeSequenceHint(data.seq)));
|
|
3287
3441
|
if (tasks.has(ns))
|
|
3288
3442
|
return;
|
|
3443
|
+
let attemptAfterSeq = afterSeq;
|
|
3289
3444
|
const task = Promise.resolve().then(async () => {
|
|
3445
|
+
let failed = false;
|
|
3290
3446
|
try {
|
|
3291
3447
|
while (true) {
|
|
3292
3448
|
const ackBefore = this.syncState(ns).ack;
|
|
3449
|
+
attemptAfterSeq = ackBefore;
|
|
3293
3450
|
await this.runGroupForwardRecovery(groupId, ns, 50, true, targets.get(ns) ?? 0);
|
|
3294
3451
|
const ackAfter = this.syncState(ns).ack;
|
|
3295
3452
|
if (ackAfter >= (targets.get(ns) ?? 0) || ackAfter <= ackBefore)
|
|
@@ -3297,12 +3454,14 @@ export class MessageDeliveryEngine {
|
|
|
3297
3454
|
}
|
|
3298
3455
|
}
|
|
3299
3456
|
catch (exc) {
|
|
3457
|
+
failed = true;
|
|
3300
3458
|
client._clientLog.debug(`online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
3301
3459
|
}
|
|
3302
3460
|
finally {
|
|
3303
3461
|
targets.delete(ns);
|
|
3304
3462
|
if (tasks.get(ns) === task)
|
|
3305
3463
|
tasks.delete(ns);
|
|
3464
|
+
this.finishBackgroundPull(ns, generation, attemptAfterSeq, failed);
|
|
3306
3465
|
client._rpcPipeline?.requestPullDrainedCheck?.();
|
|
3307
3466
|
}
|
|
3308
3467
|
});
|
|
@@ -3311,6 +3470,7 @@ export class MessageDeliveryEngine {
|
|
|
3311
3470
|
}
|
|
3312
3471
|
async onRawGroupV2MessageCreated(data, expectedVersion, inlineGeneration) {
|
|
3313
3472
|
const client = this.runtime.client;
|
|
3473
|
+
const syncGeneration = this.captureInlineAckGeneration();
|
|
3314
3474
|
if (inlineGeneration !== undefined && !this.inlineGenerationIsCurrent(inlineGeneration))
|
|
3315
3475
|
return;
|
|
3316
3476
|
if (!isJsonObject(data)) {
|
|
@@ -3373,6 +3533,7 @@ export class MessageDeliveryEngine {
|
|
|
3373
3533
|
}
|
|
3374
3534
|
return;
|
|
3375
3535
|
}
|
|
3536
|
+
this.recordBackgroundPullNeed(ns, seq);
|
|
3376
3537
|
const pullActive = client._rpcPipeline?.hasPullActivity?.(ns) === true;
|
|
3377
3538
|
if (pullActive || !this.beginRealtimeSync(ns)) {
|
|
3378
3539
|
this.recordPendingGroupPull(ns, seq);
|
|
@@ -3388,7 +3549,9 @@ export class MessageDeliveryEngine {
|
|
|
3388
3549
|
return;
|
|
3389
3550
|
client._clientLog.warn(`V2 group push auto-sync failed: group=${groupId} err=${formatDeliveryError(exc)}`);
|
|
3390
3551
|
}).finally(() => {
|
|
3391
|
-
if (
|
|
3552
|
+
if (syncGeneration === this.captureInlineAckGeneration()
|
|
3553
|
+
&& (inlineGeneration === undefined || this.inlineGenerationIsCurrent(inlineGeneration))) {
|
|
3554
|
+
this.finishBackgroundPull(ns, syncGeneration, this.syncState(ns).ack, false);
|
|
3392
3555
|
this.endRealtimeSync(ns);
|
|
3393
3556
|
this.schedulePendingGroupPullIfNeeded(ns, 'push-auto-pull-complete');
|
|
3394
3557
|
}
|
|
@@ -3450,9 +3613,14 @@ export class MessageDeliveryEngine {
|
|
|
3450
3613
|
if (!client._aid || !client._v2Session)
|
|
3451
3614
|
return;
|
|
3452
3615
|
const ns = `p2p:${client._aid}`;
|
|
3616
|
+
const generation = this.captureInlineAckGeneration();
|
|
3617
|
+
const afterSeq = this.syncState(ns).ack;
|
|
3618
|
+
this.recordBackgroundPullNeed(ns, positiveSafeSequenceHint(data.seq), true);
|
|
3619
|
+
let failed = false;
|
|
3453
3620
|
client._safeAsync(this.runP2PForwardRecovery(ns, 50, true).catch((exc) => {
|
|
3621
|
+
failed = true;
|
|
3454
3622
|
client._clientLog.debug(`P2P online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
3455
|
-
}));
|
|
3623
|
+
}).finally(() => this.finishBackgroundPull(ns, generation, afterSeq, failed)));
|
|
3456
3624
|
}
|
|
3457
3625
|
async saveSeqTrackerState() {
|
|
3458
3626
|
const client = this.runtime.client;
|