@agentunion/fastaun-browser 0.5.17 → 0.5.19
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 +83 -0
- package/_packed_docs/CHANGELOG.md +83 -0
- package/_packed_docs/INDEX.md +163 -16
- package/_packed_docs/KITE_DOCS_GUIDE.md +52 -20
- package/_packed_docs/agent.md/SCHEMA.md +266 -207
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +64 -31
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +8 -6
- package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +39 -39
- package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +1 -1
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +28 -9
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +20 -2
- package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +5 -2
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +246 -241
- package/_packed_docs/sdk/09-group-rpc-manual.md +46 -14
- package/_packed_docs/sdk/09-message-rpc-manual.md +40 -2
- package/_packed_docs/sdk/09-storage-rpc-manual.md +69 -38
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +25 -5
- package/_packed_docs/sdk/INDEX.md +78 -18
- package/dist/agent-md-schema.d.ts +3 -0
- package/dist/agent-md-schema.d.ts.map +1 -1
- package/dist/agent-md-schema.js +46 -10
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +44 -1
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +518 -26
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +12 -1
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +113 -18
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.d.ts +17 -1
- package/dist/aid.d.ts.map +1 -1
- package/dist/aid.js +69 -9
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts +4 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +343 -23
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +37513 -31501
- package/dist/cert-utils.d.ts +1 -1
- package/dist/cert-utils.d.ts.map +1 -1
- package/dist/cert-utils.js +24 -10
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +16 -1
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +198 -58
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +28 -6
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -0
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +858 -484
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +100 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1216 -24
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -2
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +4 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +41 -1
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts +84 -2
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +104 -4
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/keystore/index.d.ts +17 -0
- package/dist/keystore/index.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.d.ts +10 -1
- package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.js +111 -0
- package/dist/keystore/indexeddb-shared.js.map +1 -1
- package/dist/keystore/indexeddb-token-store.d.ts +7 -1
- package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-token-store.js +30 -1
- package/dist/keystore/indexeddb-token-store.js.map +1 -1
- package/dist/org-protocol.d.ts +98 -0
- package/dist/org-protocol.d.ts.map +1 -0
- package/dist/org-protocol.js +1742 -0
- package/dist/org-protocol.js.map +1 -0
- package/dist/ownership-proof.d.ts +118 -0
- package/dist/ownership-proof.d.ts.map +1 -0
- package/dist/ownership-proof.js +283 -0
- package/dist/ownership-proof.js.map +1 -0
- package/dist/ownership-v21.d.ts +177 -0
- package/dist/ownership-v21.d.ts.map +1 -0
- package/dist/ownership-v21.js +609 -0
- package/dist/ownership-v21.js.map +1 -0
- package/dist/ownership-workflow.d.ts +146 -0
- package/dist/ownership-workflow.d.ts.map +1 -0
- package/dist/ownership-workflow.js +1066 -0
- package/dist/ownership-workflow.js.map +1 -0
- package/dist/seq-tracker.d.ts +1 -0
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +10 -2
- package/dist/seq-tracker.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +82 -0
- package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
- package/dist/tools/cross-sdk-agent.js +332 -7
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +6 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +88 -2
- package/dist/transport.js.map +1 -1
- package/dist/v2/e2ee/decrypt.d.ts +1 -0
- package/dist/v2/e2ee/decrypt.d.ts.map +1 -1
- package/dist/v2/e2ee/decrypt.js +9 -1
- package/dist/v2/e2ee/decrypt.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -5
package/dist/client/delivery.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { slotIsolationKey } from '../config.js';
|
|
2
2
|
import { normalizeGroupAid } from '../group-id.js';
|
|
3
|
+
import { SeqTracker } from '../seq-tracker.js';
|
|
3
4
|
import { ConnectionState, isJsonObject } from '../types.js';
|
|
4
5
|
import { hasGroupMentionModeField, normalizeGroupMentionMode } from './mention-mode.js';
|
|
5
6
|
const PUSHED_SEQS_LIMIT = 50_000;
|
|
@@ -136,6 +137,7 @@ export class MessageDeliveryEngine {
|
|
|
136
137
|
pendingP2PInlineAcks = null;
|
|
137
138
|
pendingGroupInlineAcks = null;
|
|
138
139
|
pendingGroupInlineAckNamespaces = null;
|
|
140
|
+
pendingTailWindows = new Map();
|
|
139
141
|
volatileContext = '';
|
|
140
142
|
volatilePullCursorValue = '';
|
|
141
143
|
volatileSeenMessages = new Map();
|
|
@@ -164,6 +166,7 @@ export class MessageDeliveryEngine {
|
|
|
164
166
|
this.pendingP2PInlineAcks = null;
|
|
165
167
|
this.pendingGroupInlineAcks = null;
|
|
166
168
|
this.pendingGroupInlineAckNamespaces = null;
|
|
169
|
+
this.pendingTailWindows.clear();
|
|
167
170
|
this.syncingNamespaces.clear();
|
|
168
171
|
this.syncSessions.clear();
|
|
169
172
|
}
|
|
@@ -186,6 +189,35 @@ export class MessageDeliveryEngine {
|
|
|
186
189
|
captureInlineGeneration() {
|
|
187
190
|
return this.inlineGeneration;
|
|
188
191
|
}
|
|
192
|
+
deferTailWindow(ns, proof) {
|
|
193
|
+
const tracker = new SeqTracker();
|
|
194
|
+
tracker.restoreNamespaceSnapshot(ns, this.runtime.client._seqTracker.snapshotNamespace(ns));
|
|
195
|
+
tracker.commitTailWindow(ns, proof);
|
|
196
|
+
this.pendingTailWindows.set(ns, proof);
|
|
197
|
+
}
|
|
198
|
+
prospectiveTailState(ns) {
|
|
199
|
+
const proof = this.pendingTailWindows.get(ns);
|
|
200
|
+
if (!proof)
|
|
201
|
+
return this.syncState(ns);
|
|
202
|
+
const tracker = new SeqTracker();
|
|
203
|
+
tracker.restoreNamespaceSnapshot(ns, this.runtime.client._seqTracker.snapshotNamespace(ns));
|
|
204
|
+
tracker.commitTailWindow(ns, proof);
|
|
205
|
+
return tracker.getSyncState(ns);
|
|
206
|
+
}
|
|
207
|
+
pendingTailDeliveryThrough(ns, scanThrough) {
|
|
208
|
+
const proof = this.pendingTailWindows.get(ns);
|
|
209
|
+
return proof && scanThrough >= proof.windowStartSeq - 1 ? Math.max(scanThrough, proof.headSeq) : scanThrough;
|
|
210
|
+
}
|
|
211
|
+
commitPendingTailWindow(ns, scanThrough) {
|
|
212
|
+
const proof = this.pendingTailWindows.get(ns);
|
|
213
|
+
if (proof && scanThrough >= proof.windowStartSeq - 1)
|
|
214
|
+
this.runtime.client._seqTracker.commitTailWindow(ns, proof);
|
|
215
|
+
}
|
|
216
|
+
completePendingTailWindow(ns) {
|
|
217
|
+
const proof = this.pendingTailWindows.get(ns);
|
|
218
|
+
if (proof && this.runtime.client._seqTracker.getContiguousSeq(ns) >= proof.headSeq)
|
|
219
|
+
this.pendingTailWindows.delete(ns);
|
|
220
|
+
}
|
|
189
221
|
beginRealtimeSync(ns) {
|
|
190
222
|
if (!ns || this.realtimeSyncing?.has(ns))
|
|
191
223
|
return false;
|
|
@@ -295,6 +327,18 @@ export class MessageDeliveryEngine {
|
|
|
295
327
|
return;
|
|
296
328
|
this.schedulePendingPullIfNeeded(ns, 'pull-gate-idle');
|
|
297
329
|
}
|
|
330
|
+
onForegroundPullsDrained() {
|
|
331
|
+
const client = this.runtime.client;
|
|
332
|
+
if (!client._aid || client._sessionOptions?.background_sync === false
|
|
333
|
+
|| client.state !== ConnectionState.READY || client._closing)
|
|
334
|
+
return;
|
|
335
|
+
const ns = `p2p:${client._aid}`;
|
|
336
|
+
const state = this.syncState(ns);
|
|
337
|
+
const maxSeen = client._seqTracker.getMaxSeenSeq(ns);
|
|
338
|
+
if (maxSeen <= state.ack && state.ack >= state.tail - 1)
|
|
339
|
+
return;
|
|
340
|
+
client._safeAsync(this.fillP2pGap());
|
|
341
|
+
}
|
|
298
342
|
onPullWorkSettled() {
|
|
299
343
|
const pipeline = this.runtime.client._rpcPipeline;
|
|
300
344
|
if (pipeline?.hasAnyPullActivity?.() === true)
|
|
@@ -952,9 +996,7 @@ export class MessageDeliveryEngine {
|
|
|
952
996
|
const pageInlineGeneration = this.captureInlineGeneration();
|
|
953
997
|
const deferredServerCursor = Number(coordinator.pendingForwardCursor(ns, pageContigBefore) ?? 0);
|
|
954
998
|
const deferredForwardAck = Number(coordinator.pendingForwardAck(ns, pageContigBefore) ?? 0);
|
|
955
|
-
|
|
956
|
-
? client._seqTracker.snapshotNamespace(ns)
|
|
957
|
-
: null;
|
|
999
|
+
let pageTrackerSnapshot;
|
|
958
1000
|
response._contig_before = pageContigBefore;
|
|
959
1001
|
const cursor = isJsonObject(response.cursor)
|
|
960
1002
|
? response.cursor
|
|
@@ -1005,6 +1047,15 @@ export class MessageDeliveryEngine {
|
|
|
1005
1047
|
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq)
|
|
1006
1048
|
? result.contiguous_seq
|
|
1007
1049
|
: undefined;
|
|
1050
|
+
const scanThrough = Math.max(pageContigBefore, contiguousSeq ?? 0, retentionFloor, visibilityFloor, deferredServerCursor, ...messages.map((message) => positiveSafeSequenceHint(message.seq)));
|
|
1051
|
+
const state = this.syncState(ns);
|
|
1052
|
+
const deliveryThrough = this.pendingTailDeliveryThrough(ns, scanThrough >= state.tail - 1 ? Math.max(scanThrough, state.head) : scanThrough);
|
|
1053
|
+
await this.drainOrderedMessages(ns, undefined, false, false, undefined, 'pull', deliveryThrough);
|
|
1054
|
+
this.ensurePullOperationCurrent(ns);
|
|
1055
|
+
if (!this.isInlineGenerationCurrent(pageInlineGeneration))
|
|
1056
|
+
throw new Error('pull invalidated');
|
|
1057
|
+
pageTrackerSnapshot = client._seqTracker.snapshotNamespace(ns);
|
|
1058
|
+
this.commitPendingTailWindow(ns, scanThrough);
|
|
1008
1059
|
if (contiguousSeq === undefined)
|
|
1009
1060
|
client._seqTracker.onPullResult(ns, messages, afterSeq);
|
|
1010
1061
|
else
|
|
@@ -1014,16 +1065,19 @@ export class MessageDeliveryEngine {
|
|
|
1014
1065
|
client._seqTracker.forceContiguousSeq(ns, commitTarget);
|
|
1015
1066
|
}
|
|
1016
1067
|
if (client._seqTracker.getContiguousSeq(ns) !== pageContigBefore) {
|
|
1017
|
-
this.ensurePullOperationCurrent(ns);
|
|
1018
|
-
await this.drainOrderedMessages(ns, undefined, false, false);
|
|
1019
1068
|
this.ensurePullOperationCurrent(ns);
|
|
1020
1069
|
await client._commitSeqTrackerState(ns);
|
|
1070
|
+
this.ensurePullOperationCurrent(ns);
|
|
1071
|
+
if (!this.isInlineGenerationCurrent(pageInlineGeneration))
|
|
1072
|
+
throw new Error('pull invalidated');
|
|
1021
1073
|
}
|
|
1074
|
+
this.completePendingTailWindow(ns);
|
|
1022
1075
|
committed = true;
|
|
1023
1076
|
}
|
|
1024
1077
|
catch (exc) {
|
|
1025
|
-
if (this.isPullOperationCurrent(ns) &&
|
|
1026
|
-
client._seqTracker.restoreNamespaceSnapshot
|
|
1078
|
+
if (this.isPullOperationCurrent(ns) && this.isInlineGenerationCurrent(pageInlineGeneration)
|
|
1079
|
+
&& pageTrackerSnapshot !== undefined && !committed && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
|
|
1080
|
+
client._seqTracker._restoreNamespaceSnapshotPreservingPush(ns, pageTrackerSnapshot);
|
|
1027
1081
|
this.dropSeqTrackerPending(ns);
|
|
1028
1082
|
}
|
|
1029
1083
|
throw exc;
|
|
@@ -1103,6 +1157,8 @@ export class MessageDeliveryEngine {
|
|
|
1103
1157
|
}
|
|
1104
1158
|
if (pullResponse) {
|
|
1105
1159
|
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
1160
|
+
if (pullScoped)
|
|
1161
|
+
this.ensurePullOperationCurrent(ns);
|
|
1106
1162
|
return;
|
|
1107
1163
|
}
|
|
1108
1164
|
await client._publishAppEvent(event, payload, source, ns, batch);
|
|
@@ -1111,6 +1167,10 @@ export class MessageDeliveryEngine {
|
|
|
1111
1167
|
}
|
|
1112
1168
|
async publishOrderedGroupChanged(payload, source = 'ordered') {
|
|
1113
1169
|
const client = this.runtime.client;
|
|
1170
|
+
const generation = this.captureInlineGeneration();
|
|
1171
|
+
await client._publishAppEvent('group.changed', payload, source);
|
|
1172
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
1173
|
+
throw new Error('pull invalidated');
|
|
1114
1174
|
if (isJsonObject(payload)) {
|
|
1115
1175
|
const eventPayload = payload;
|
|
1116
1176
|
client._groupState?.handleGroupChangedV2Membership?.(eventPayload);
|
|
@@ -1121,7 +1181,6 @@ export class MessageDeliveryEngine {
|
|
|
1121
1181
|
client._cleanupDissolvedGroup?.(groupId);
|
|
1122
1182
|
}
|
|
1123
1183
|
}
|
|
1124
|
-
await client._publishAppEvent('group.changed', payload, source);
|
|
1125
1184
|
}
|
|
1126
1185
|
isInstanceScopedMessageEvent(event) {
|
|
1127
1186
|
return event === 'message.received'
|
|
@@ -1559,6 +1618,7 @@ export class MessageDeliveryEngine {
|
|
|
1559
1618
|
}
|
|
1560
1619
|
async publishMessageRecallTombstone(seq, message, source = 'push') {
|
|
1561
1620
|
const client = this.runtime.client;
|
|
1621
|
+
const generation = this.captureInlineGeneration();
|
|
1562
1622
|
const eventPayload = this.recallEventFromMessage(message);
|
|
1563
1623
|
if (!eventPayload)
|
|
1564
1624
|
return false;
|
|
@@ -1572,13 +1632,15 @@ export class MessageDeliveryEngine {
|
|
|
1572
1632
|
client._clientLog.debug(`message.recalled dedup suppressed: seq=${String(seq)} key=${dedupKey}`);
|
|
1573
1633
|
return false;
|
|
1574
1634
|
}
|
|
1635
|
+
await client._publishAppEvent('message.recalled', eventPayload, source);
|
|
1636
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
1637
|
+
throw new Error('pull invalidated');
|
|
1575
1638
|
seen.set(dedupKey, Date.now());
|
|
1576
1639
|
if (seen.size > MESSAGE_RECALL_SEEN_LIMIT) {
|
|
1577
1640
|
const drop = [...seen.entries()].sort((a, b) => a[1] - b[1]).slice(0, seen.size - MESSAGE_RECALL_SEEN_LIMIT);
|
|
1578
1641
|
for (const [oldKey] of drop)
|
|
1579
1642
|
seen.delete(oldKey);
|
|
1580
1643
|
}
|
|
1581
|
-
await client._publishAppEvent('message.recalled', eventPayload, source);
|
|
1582
1644
|
client._clientLog.debug(`message.recalled published: seq=${String(seq)} ids=${JSON.stringify(eventPayload.message_ids)}`);
|
|
1583
1645
|
return true;
|
|
1584
1646
|
}
|
|
@@ -1663,6 +1725,7 @@ export class MessageDeliveryEngine {
|
|
|
1663
1725
|
}
|
|
1664
1726
|
async publishGroupRecallTombstone(groupId, seq, message, source = 'push') {
|
|
1665
1727
|
const client = this.runtime.client;
|
|
1728
|
+
const generation = this.captureInlineGeneration();
|
|
1666
1729
|
const eventPayload = this.recallEventFromGroupMessage(message);
|
|
1667
1730
|
if (!eventPayload)
|
|
1668
1731
|
return false;
|
|
@@ -1678,13 +1741,15 @@ export class MessageDeliveryEngine {
|
|
|
1678
1741
|
client._clientLog.debug(`group.message_recalled dedup suppressed: group=${groupId} seq=${String(seq)} key=${dedupKey}`);
|
|
1679
1742
|
return false;
|
|
1680
1743
|
}
|
|
1744
|
+
await client._publishAppEvent('group.message_recalled', eventPayload, source);
|
|
1745
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
1746
|
+
throw new Error('pull invalidated');
|
|
1681
1747
|
seen.set(dedupKey, Date.now());
|
|
1682
1748
|
if (seen.size > GROUP_RECALL_SEEN_LIMIT) {
|
|
1683
1749
|
const drop = [...seen.entries()].sort((a, b) => a[1] - b[1]).slice(0, seen.size - GROUP_RECALL_SEEN_LIMIT);
|
|
1684
1750
|
for (const [oldKey] of drop)
|
|
1685
1751
|
seen.delete(oldKey);
|
|
1686
1752
|
}
|
|
1687
|
-
await client._publishAppEvent('group.message_recalled', eventPayload, source);
|
|
1688
1753
|
client._clientLog.debug(`group.message_recalled published: group=${groupId} seq=${String(seq)} ids=${JSON.stringify(eventPayload.message_ids)}`);
|
|
1689
1754
|
return true;
|
|
1690
1755
|
}
|
|
@@ -1755,7 +1820,13 @@ export class MessageDeliveryEngine {
|
|
|
1755
1820
|
&& canonicalSource !== 'direct') {
|
|
1756
1821
|
normalized = { ...normalized, source: canonicalSource };
|
|
1757
1822
|
}
|
|
1758
|
-
|
|
1823
|
+
if (['message.received', 'group.message_created', 'message.recalled', 'group.message_recalled', 'group.changed'].includes(event)
|
|
1824
|
+
&& typeof client._dispatcher._publishAndWait === 'function') {
|
|
1825
|
+
await client._dispatcher._publishAndWait(event, normalized);
|
|
1826
|
+
}
|
|
1827
|
+
else {
|
|
1828
|
+
client._dispatcher.enqueue(event, normalized);
|
|
1829
|
+
}
|
|
1759
1830
|
if (generation !== this.deliveryGeneration)
|
|
1760
1831
|
return;
|
|
1761
1832
|
if (canonicalSource !== 'pull' && canonicalSource !== 'pending_retry'
|
|
@@ -1820,6 +1891,24 @@ export class MessageDeliveryEngine {
|
|
|
1820
1891
|
return false;
|
|
1821
1892
|
return senderDevice.trim() === String(client._deviceId).trim();
|
|
1822
1893
|
}
|
|
1894
|
+
isSelfSentP2PMessage(message) {
|
|
1895
|
+
if (!isJsonObject(message))
|
|
1896
|
+
return false;
|
|
1897
|
+
const client = this.runtime.client;
|
|
1898
|
+
if (String(message.direction ?? '').trim() !== 'outbound_sync')
|
|
1899
|
+
return false;
|
|
1900
|
+
const selfAid = String(client._aid ?? '').trim().toLowerCase();
|
|
1901
|
+
const senderAid = String(message.sender_aid ?? message.from_aid ?? message.from ?? '').trim().toLowerCase();
|
|
1902
|
+
if (!selfAid || senderAid !== selfAid)
|
|
1903
|
+
return false;
|
|
1904
|
+
const senderDevice = Object.prototype.hasOwnProperty.call(message, 'sender_device_id')
|
|
1905
|
+
? message.sender_device_id
|
|
1906
|
+
: message.from_device_id;
|
|
1907
|
+
return typeof senderDevice === 'string'
|
|
1908
|
+
&& Boolean(senderDevice.trim())
|
|
1909
|
+
&& Boolean(String(client._deviceId ?? '').trim())
|
|
1910
|
+
&& senderDevice.trim() === String(client._deviceId).trim();
|
|
1911
|
+
}
|
|
1823
1912
|
strictTargetString(source, key) {
|
|
1824
1913
|
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1825
1914
|
return { present: false, valid: false, value: '' };
|
|
@@ -1946,15 +2035,19 @@ export class MessageDeliveryEngine {
|
|
|
1946
2035
|
await this.processV2P2PNotification(msg, 'v1', inlineGeneration);
|
|
1947
2036
|
return;
|
|
1948
2037
|
}
|
|
2038
|
+
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
1949
2039
|
if (client._aid && legacyPushSeq > 0) {
|
|
1950
2040
|
const ns = `p2p:${client._aid}`;
|
|
1951
2041
|
client._seqTracker.updateMaxSeen(ns, legacyPushSeq);
|
|
1952
|
-
if (
|
|
1953
|
-
client.
|
|
2042
|
+
if (encryptedPush) {
|
|
2043
|
+
if (client._sessionOptions?.background_sync !== false)
|
|
2044
|
+
client._safeAsync(this.fillP2pGap());
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
await this.publishPulledMessage('message.received', ns, legacyPushSeq, msg, true, 'push');
|
|
1954
2048
|
return;
|
|
1955
2049
|
}
|
|
1956
2050
|
const seq = msg.seq;
|
|
1957
|
-
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
1958
2051
|
const ns = client._aid ? `p2p:${client._aid}` : '';
|
|
1959
2052
|
const seqNum = positiveSafeSequenceHint(seq);
|
|
1960
2053
|
if (ns && seqNum > 0) {
|
|
@@ -1970,11 +2063,13 @@ export class MessageDeliveryEngine {
|
|
|
1970
2063
|
if (ns && seq !== undefined && seq !== null) {
|
|
1971
2064
|
await this.publishOrderedMessage('message.received', ns, seq, msg);
|
|
1972
2065
|
}
|
|
1973
|
-
else {
|
|
2066
|
+
else if (!this.isSelfSentP2PMessage(msg)) {
|
|
1974
2067
|
await client._publishAppEvent('message.received', msg, 'push');
|
|
1975
2068
|
}
|
|
1976
2069
|
}
|
|
1977
2070
|
catch (exc) {
|
|
2071
|
+
if (exc?.stringCode === 'persistence_unavailable')
|
|
2072
|
+
throw exc;
|
|
1978
2073
|
client._clientLog.warn(`P2P push processing failed:${String(exc)}`);
|
|
1979
2074
|
if (isJsonObject(data)) {
|
|
1980
2075
|
const src = data;
|
|
@@ -2035,10 +2130,19 @@ export class MessageDeliveryEngine {
|
|
|
2035
2130
|
if (groupId && legacyPushSeq > 0) {
|
|
2036
2131
|
const ns = `group:${groupId}`;
|
|
2037
2132
|
client._seqTracker.updateMaxSeen(ns, legacyPushSeq);
|
|
2038
|
-
if (client._sessionOptions?.background_sync
|
|
2133
|
+
if (client._sessionOptions?.background_sync === false)
|
|
2134
|
+
return;
|
|
2135
|
+
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
2136
|
+
if (encryptedPush) {
|
|
2039
2137
|
client._safeAsync(this.fillGroupGap(groupId));
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
if (!this.isSelfSentGroupMessage(msg)) {
|
|
2141
|
+
await this.publishPulledMessage('group.message_created', ns, legacyPushSeq, msg, true, 'push');
|
|
2142
|
+
}
|
|
2040
2143
|
return;
|
|
2041
2144
|
}
|
|
2145
|
+
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
2042
2146
|
if (payload === undefined || payload === null
|
|
2043
2147
|
|| (typeof payload === 'object' && Object.keys(payload).length === 0)) {
|
|
2044
2148
|
if (client._v2Session)
|
|
@@ -2058,7 +2162,6 @@ export class MessageDeliveryEngine {
|
|
|
2058
2162
|
await client._publishAppEvent('group.message_created', msg, 'push');
|
|
2059
2163
|
return;
|
|
2060
2164
|
}
|
|
2061
|
-
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
2062
2165
|
const ns = groupId ? `group:${groupId}` : '';
|
|
2063
2166
|
const seqNum = positiveSafeSequenceHint(seq);
|
|
2064
2167
|
if (ns && seqNum > 0) {
|
|
@@ -2270,6 +2373,7 @@ export class MessageDeliveryEngine {
|
|
|
2270
2373
|
}
|
|
2271
2374
|
async fillGroupEventGap(groupId, options) {
|
|
2272
2375
|
const client = this.runtime.client;
|
|
2376
|
+
const generation = this.captureInlineGeneration();
|
|
2273
2377
|
if (client._sessionOptions?.background_sync === false)
|
|
2274
2378
|
return;
|
|
2275
2379
|
if (client.state !== ConnectionState.READY || client._closing)
|
|
@@ -2313,23 +2417,12 @@ export class MessageDeliveryEngine {
|
|
|
2313
2417
|
const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
2314
2418
|
const eventObjects = events.filter((evt) => isJsonObject(evt));
|
|
2315
2419
|
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq) ? result.contiguous_seq : undefined;
|
|
2316
|
-
if (contiguousSeq === undefined)
|
|
2317
|
-
client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq);
|
|
2318
|
-
else
|
|
2319
|
-
client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq, contiguousSeq);
|
|
2320
2420
|
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
2321
2421
|
const retentionFloor = Math.max(0, Number(result.retention_floor_event_seq ?? 0), Number(cursor?.retention_floor_seq ?? 0));
|
|
2322
2422
|
const serverAckFloor = Math.max(0, Number(cursor?.current_seq ?? 0));
|
|
2323
2423
|
const earliestAvailable = Number(result.earliest_available_event_seq ?? 0);
|
|
2324
2424
|
const visibilityFloor = Math.max(0, Number(cursor?.join_seq ?? 0), Number.isFinite(earliestAvailable) && earliestAvailable > 0 ? earliestAvailable - 1 : 0);
|
|
2325
2425
|
const effectiveFloor = Math.max(...[retentionFloor, serverAckFloor, visibilityFloor].filter((value) => Number.isFinite(value)));
|
|
2326
|
-
if (effectiveFloor > 0) {
|
|
2327
|
-
const contigBeforeFloor = client._seqTracker.getContiguousSeq(ns);
|
|
2328
|
-
if (contigBeforeFloor < effectiveFloor) {
|
|
2329
|
-
client._clientLog.info('group.pull_events floor advance: ns=' + ns + ' contiguous=' + contigBeforeFloor + ' -> effective_floor=' + effectiveFloor + ' retention_floor=' + retentionFloor + ' server_ack=' + serverAckFloor + ' visibility_floor=' + visibilityFloor);
|
|
2330
|
-
client._seqTracker.forceContiguousSeq(ns, effectiveFloor);
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
2426
|
const eventSeqs = [];
|
|
2334
2427
|
let hasDissolvedEvent = false;
|
|
2335
2428
|
let publishedEventCount = 0;
|
|
@@ -2358,8 +2451,20 @@ export class MessageDeliveryEngine {
|
|
|
2358
2451
|
publishedEventCount += 1;
|
|
2359
2452
|
}
|
|
2360
2453
|
}
|
|
2454
|
+
const deliveryThrough = Math.max(pageContigBefore, contiguousSeq ?? 0, effectiveFloor, ...eventSeqs);
|
|
2455
|
+
await this.drainOrderedMessages(ns, undefined, false, false, undefined, 'pull', deliveryThrough);
|
|
2456
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
2457
|
+
throw new Error('pull invalidated');
|
|
2458
|
+
if (hasDissolvedEvent)
|
|
2459
|
+
break;
|
|
2460
|
+
if (contiguousSeq === undefined)
|
|
2461
|
+
client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq);
|
|
2462
|
+
else
|
|
2463
|
+
client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq, contiguousSeq);
|
|
2464
|
+
if (effectiveFloor > client._seqTracker.getContiguousSeq(ns)) {
|
|
2465
|
+
client._seqTracker.forceContiguousSeq(ns, effectiveFloor);
|
|
2466
|
+
}
|
|
2361
2467
|
const ackContig = client._seqTracker.getContiguousSeq(ns);
|
|
2362
|
-
await this.drainOrderedMessages(ns);
|
|
2363
2468
|
if (ackContig !== pageContigBefore && !hasDissolvedEvent) {
|
|
2364
2469
|
this.persistSeq(ns);
|
|
2365
2470
|
}
|
|
@@ -2849,15 +2954,20 @@ export class MessageDeliveryEngine {
|
|
|
2849
2954
|
async commitInlineMessage(ns, seq, event, payload, generation) {
|
|
2850
2955
|
const client = this.runtime.client;
|
|
2851
2956
|
const tracker = client._seqTracker;
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
: null;
|
|
2957
|
+
let snapshot = null;
|
|
2958
|
+
let trackerChanged = false;
|
|
2855
2959
|
try {
|
|
2856
|
-
const
|
|
2960
|
+
const selfSync = (event === 'message.received' && this.isSelfSentP2PMessage(payload))
|
|
2961
|
+
|| (event === 'group.message_created' && this.isSelfSentGroupMessage(payload));
|
|
2962
|
+
const published = selfSync
|
|
2963
|
+
? (this.markPublishedSeq(ns, seq), true)
|
|
2964
|
+
: await this.publishPulledMessage(event, ns, seq, payload, true, 'inline_push');
|
|
2857
2965
|
if (!this.isInlineGenerationCurrent(generation))
|
|
2858
2966
|
return false;
|
|
2859
2967
|
if (!published)
|
|
2860
2968
|
return false;
|
|
2969
|
+
snapshot = typeof tracker.snapshotNamespace === 'function' ? tracker.snapshotNamespace(ns) : null;
|
|
2970
|
+
trackerChanged = true;
|
|
2861
2971
|
const needsPull = Boolean(tracker.onMessageSeq(ns, seq));
|
|
2862
2972
|
const committed = this.syncState(ns);
|
|
2863
2973
|
if (needsPull || committed.ack !== seq || committed.tail !== seq || committed.head !== seq) {
|
|
@@ -2871,8 +2981,8 @@ export class MessageDeliveryEngine {
|
|
|
2871
2981
|
return true;
|
|
2872
2982
|
}
|
|
2873
2983
|
catch (exc) {
|
|
2874
|
-
if (this.isInlineGenerationCurrent(generation) && typeof tracker.restoreNamespaceSnapshot === 'function') {
|
|
2875
|
-
tracker.
|
|
2984
|
+
if (trackerChanged && this.isInlineGenerationCurrent(generation) && typeof tracker.restoreNamespaceSnapshot === 'function') {
|
|
2985
|
+
tracker._restoreNamespaceSnapshotPreservingPush(ns, snapshot);
|
|
2876
2986
|
}
|
|
2877
2987
|
client._clientLog.debug(`inline realtime consume rolled back: ns=${ns} seq=${seq} err=${formatDeliveryError(exc)}`);
|
|
2878
2988
|
return false;
|
|
@@ -2961,7 +3071,7 @@ export class MessageDeliveryEngine {
|
|
|
2961
3071
|
}
|
|
2962
3072
|
}
|
|
2963
3073
|
hasOutstandingRealtimeGap(ns) {
|
|
2964
|
-
const state = this.
|
|
3074
|
+
const state = this.prospectiveTailState(ns);
|
|
2965
3075
|
// Tail 已建立可靠后缀窗口;后台续拉只针对尚未接上窗口的真实缺口。
|
|
2966
3076
|
// maxSeen 可能只是 Tail 期间到达的通知,不能单独据此启动全量补洞。
|
|
2967
3077
|
return state.ack < state.tail - 1;
|
|
@@ -3017,8 +3127,8 @@ export class MessageDeliveryEngine {
|
|
|
3017
3127
|
}
|
|
3018
3128
|
async runP2PRealtimeSync(ns, pushSeq, pageLimit = 50, forceTail = false) {
|
|
3019
3129
|
const client = this.runtime.client;
|
|
3020
|
-
const before = this.
|
|
3021
|
-
const order = forceTail ? ['tail'] : typeof client._seqTracker.planRealtimeSync === 'function'
|
|
3130
|
+
const before = this.prospectiveTailState(ns);
|
|
3131
|
+
const order = forceTail ? ['tail'] : this.pendingTailWindows.has(ns) ? ['forward'] : typeof client._seqTracker.planRealtimeSync === 'function'
|
|
3022
3132
|
? client._seqTracker.planRealtimeSync(ns, pushSeq, pageLimit)
|
|
3023
3133
|
: (() => {
|
|
3024
3134
|
const gap = pushSeq - before.ack;
|
|
@@ -3031,7 +3141,7 @@ export class MessageDeliveryEngine {
|
|
|
3031
3141
|
let result = { messages: [], raw_count: 0 };
|
|
3032
3142
|
let tailCompleted = false;
|
|
3033
3143
|
const run = async (tail, background, maxPages, forceForward = false, bypassCoveredHead = false) => {
|
|
3034
|
-
const live = this.
|
|
3144
|
+
const live = this.prospectiveTailState(ns);
|
|
3035
3145
|
if (tail && !bypassCoveredHead && pushSeq <= live.head)
|
|
3036
3146
|
return { messages: [], raw_count: 0 };
|
|
3037
3147
|
if (!tail && !forceForward && live.ack >= live.tail - 1)
|
|
@@ -3055,7 +3165,7 @@ export class MessageDeliveryEngine {
|
|
|
3055
3165
|
};
|
|
3056
3166
|
if (forceTail || order[0] === 'tail')
|
|
3057
3167
|
result = await run(true, false, undefined, false, forceTail);
|
|
3058
|
-
const state = this.
|
|
3168
|
+
const state = this.prospectiveTailState(ns);
|
|
3059
3169
|
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
3060
3170
|
// Tail 期间到达的新 Push 只记录在 pending Pull 上界,不写入 SeqTracker。
|
|
3061
3171
|
const pendingUpper = Number(this.pendingP2pPullUpper?.get(ns) ?? 0);
|
|
@@ -3070,16 +3180,16 @@ export class MessageDeliveryEngine {
|
|
|
3070
3180
|
|| (client._sessionOptions?.background_sync !== false && backgroundWindowForward)) {
|
|
3071
3181
|
const forwardTarget = Math.max(headForward ? Math.max(pushSeq, maxSeen) : 0, (tailForward || backgroundWindowForward) ? state.tail - 1 : 0, tailMissedDuringPull ? observedUpper : 0);
|
|
3072
3182
|
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
3073
|
-
result = await run(false, !(headForward || tailForward), forwardMaxPages, headForward || tailMissedDuringPull);
|
|
3183
|
+
result = await run(false, !(headForward || tailForward), forwardMaxPages, headForward || tailForward || tailMissedDuringPull);
|
|
3074
3184
|
if (pendingThroughSeq > 0) {
|
|
3075
|
-
const committedAck = this.
|
|
3185
|
+
const committedAck = this.prospectiveTailState(ns).ack;
|
|
3076
3186
|
if (committedAck >= pendingThroughSeq)
|
|
3077
3187
|
this.consumePendingPull(ns, pendingThroughSeq);
|
|
3078
3188
|
else if (committedAck <= state.ack)
|
|
3079
3189
|
this.markPendingPullNoProgress(ns, committedAck);
|
|
3080
3190
|
}
|
|
3081
3191
|
}
|
|
3082
|
-
const finalState = this.
|
|
3192
|
+
const finalState = this.prospectiveTailState(ns);
|
|
3083
3193
|
if (tailCompleted && finalState.ack < finalState.tail - 1) {
|
|
3084
3194
|
this.scheduleP2PRealtimeFullGapFill(ns);
|
|
3085
3195
|
}
|
|
@@ -3089,8 +3199,8 @@ export class MessageDeliveryEngine {
|
|
|
3089
3199
|
}
|
|
3090
3200
|
async runGroupRealtimeSync(groupId, ns, pushSeq, pageLimit = 50, forceTail = false) {
|
|
3091
3201
|
const client = this.runtime.client;
|
|
3092
|
-
const before = this.
|
|
3093
|
-
const order = forceTail ? ['tail'] : typeof client._seqTracker.planRealtimeSync === 'function'
|
|
3202
|
+
const before = this.prospectiveTailState(ns);
|
|
3203
|
+
const order = forceTail ? ['tail'] : this.pendingTailWindows.has(ns) ? ['forward'] : typeof client._seqTracker.planRealtimeSync === 'function'
|
|
3094
3204
|
? client._seqTracker.planRealtimeSync(ns, pushSeq, pageLimit)
|
|
3095
3205
|
: (() => {
|
|
3096
3206
|
const gap = pushSeq - before.ack;
|
|
@@ -3103,7 +3213,7 @@ export class MessageDeliveryEngine {
|
|
|
3103
3213
|
let result = { messages: [], raw_count: 0 };
|
|
3104
3214
|
let tailCompleted = false;
|
|
3105
3215
|
const run = async (tail, background, maxPages, forceForward = false, bypassCoveredHead = false) => {
|
|
3106
|
-
const live = this.
|
|
3216
|
+
const live = this.prospectiveTailState(ns);
|
|
3107
3217
|
if (tail && !bypassCoveredHead && pushSeq <= live.head)
|
|
3108
3218
|
return { messages: [], raw_count: 0 };
|
|
3109
3219
|
if (!tail && !forceForward && live.ack >= live.tail - 1)
|
|
@@ -3127,7 +3237,7 @@ export class MessageDeliveryEngine {
|
|
|
3127
3237
|
};
|
|
3128
3238
|
if (forceTail || order[0] === 'tail')
|
|
3129
3239
|
result = await run(true, false, undefined, false, forceTail);
|
|
3130
|
-
const state = this.
|
|
3240
|
+
const state = this.prospectiveTailState(ns);
|
|
3131
3241
|
// 与 P2P 相同:真实完成 Tail 后,至多用一页 Forward 收敛 Tail
|
|
3132
3242
|
// 期间新到达的序号;绝不重新规划或再执行 Tail。
|
|
3133
3243
|
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
@@ -3143,16 +3253,16 @@ export class MessageDeliveryEngine {
|
|
|
3143
3253
|
|| (client._sessionOptions?.background_sync !== false && backgroundWindowForward)) {
|
|
3144
3254
|
const forwardTarget = Math.max(headForward ? Math.max(pushSeq, maxSeen) : 0, (tailForward || backgroundWindowForward) ? state.tail - 1 : 0, tailMissedDuringPull ? observedUpper : 0);
|
|
3145
3255
|
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
3146
|
-
result = await run(false, !(headForward || tailForward), forwardMaxPages, headForward || tailMissedDuringPull);
|
|
3256
|
+
result = await run(false, !(headForward || tailForward), forwardMaxPages, headForward || tailForward || tailMissedDuringPull);
|
|
3147
3257
|
if (pendingThroughSeq > 0) {
|
|
3148
|
-
const committedAck = this.
|
|
3258
|
+
const committedAck = this.prospectiveTailState(ns).ack;
|
|
3149
3259
|
if (committedAck >= pendingThroughSeq)
|
|
3150
3260
|
this.consumePendingPull(ns, pendingThroughSeq);
|
|
3151
3261
|
else if (committedAck <= state.ack)
|
|
3152
3262
|
this.markPendingPullNoProgress(ns, committedAck);
|
|
3153
3263
|
}
|
|
3154
3264
|
}
|
|
3155
|
-
const finalState = this.
|
|
3265
|
+
const finalState = this.prospectiveTailState(ns);
|
|
3156
3266
|
if (tailCompleted && finalState.ack < finalState.tail - 1) {
|
|
3157
3267
|
this.scheduleGroupRealtimeFullGapFill(groupId, ns);
|
|
3158
3268
|
}
|
|
@@ -3769,7 +3879,7 @@ export class MessageDeliveryEngine {
|
|
|
3769
3879
|
}
|
|
3770
3880
|
return params;
|
|
3771
3881
|
}
|
|
3772
|
-
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, batch, source = 'pull') {
|
|
3882
|
+
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, batch, source = 'pull', throughSeq) {
|
|
3773
3883
|
const client = this.runtime.client;
|
|
3774
3884
|
const pullScoped = this.isPullScopedSource(source);
|
|
3775
3885
|
if (pullScoped)
|
|
@@ -3777,7 +3887,8 @@ export class MessageDeliveryEngine {
|
|
|
3777
3887
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3778
3888
|
if (!queue || queue.size === 0)
|
|
3779
3889
|
return;
|
|
3780
|
-
const
|
|
3890
|
+
const generation = this.captureInlineGeneration();
|
|
3891
|
+
const contig = throughSeq ?? client._seqTracker.getContiguousSeq(ns);
|
|
3781
3892
|
const ready = [...queue.keys()]
|
|
3782
3893
|
.filter((seq) => seq <= contig && (beforeSeq === undefined || seq < beforeSeq))
|
|
3783
3894
|
.sort((a, b) => a - b);
|
|
@@ -3788,9 +3899,12 @@ export class MessageDeliveryEngine {
|
|
|
3788
3899
|
if (pullScoped)
|
|
3789
3900
|
this.ensurePullOperationCurrent(ns);
|
|
3790
3901
|
const item = queue.get(seq);
|
|
3791
|
-
|
|
3792
|
-
if (!item || client._pushedSeqs.get(ns)?.has(seq))
|
|
3902
|
+
if (!item)
|
|
3793
3903
|
continue;
|
|
3904
|
+
if (client._pushedSeqs.get(ns)?.has(seq)) {
|
|
3905
|
+
queue.delete(seq);
|
|
3906
|
+
continue;
|
|
3907
|
+
}
|
|
3794
3908
|
const itemSource = item.source ?? source;
|
|
3795
3909
|
let itemBatch = batch;
|
|
3796
3910
|
if ((itemSource === 'push' || itemSource === 'inline_push')
|
|
@@ -3802,8 +3916,13 @@ export class MessageDeliveryEngine {
|
|
|
3802
3916
|
}
|
|
3803
3917
|
}
|
|
3804
3918
|
await this.publishOrderedQueueItem(ns, item.event, seq, item.payload, pullResponse, itemSource, itemBatch);
|
|
3919
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
3920
|
+
throw new Error('pull invalidated');
|
|
3805
3921
|
if (pullScoped)
|
|
3806
3922
|
this.ensurePullOperationCurrent(ns);
|
|
3923
|
+
queue.delete(seq);
|
|
3924
|
+
if (item.event === 'group.changed' && isJsonObject(item.payload) && item.payload.action === 'dissolved')
|
|
3925
|
+
continue;
|
|
3807
3926
|
this.markPublishedSeq(ns, seq);
|
|
3808
3927
|
delivered = true;
|
|
3809
3928
|
}
|
|
@@ -3824,6 +3943,7 @@ export class MessageDeliveryEngine {
|
|
|
3824
3943
|
}
|
|
3825
3944
|
async publishOrderedMessage(event, ns, seq, payload, source = 'push', operationBatch) {
|
|
3826
3945
|
const client = this.runtime.client;
|
|
3946
|
+
const generation = this.captureInlineGeneration();
|
|
3827
3947
|
const ownsBatch = !operationBatch && (source === 'push' || source === 'inline_push');
|
|
3828
3948
|
const batch = operationBatch ?? (ownsBatch ? this.createDeliveryChangeBatch(source) : undefined);
|
|
3829
3949
|
try {
|
|
@@ -3839,6 +3959,11 @@ export class MessageDeliveryEngine {
|
|
|
3839
3959
|
client._pendingOrderedMsgs.delete(ns);
|
|
3840
3960
|
return false;
|
|
3841
3961
|
}
|
|
3962
|
+
if (event === 'message.received' && this.isSelfSentP2PMessage(payload)) {
|
|
3963
|
+
this.markPublishedSeq(ns, seqNum);
|
|
3964
|
+
client._clientLog.debug(`publish ordered skipped current-device self-sync: ns=${ns}, seq=${seqNum}`);
|
|
3965
|
+
return false;
|
|
3966
|
+
}
|
|
3842
3967
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
3843
3968
|
if (seqNum > contig) {
|
|
3844
3969
|
this.enqueueOrderedMessage(ns, event, seqNum, payload, source);
|
|
@@ -3848,10 +3973,12 @@ export class MessageDeliveryEngine {
|
|
|
3848
3973
|
if (client._pushedSeqs.get(ns)?.has(seqNum))
|
|
3849
3974
|
return false;
|
|
3850
3975
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3976
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, false, source, batch);
|
|
3977
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
3978
|
+
throw new Error('pull invalidated');
|
|
3851
3979
|
queue?.delete(seqNum);
|
|
3852
3980
|
if (queue && queue.size === 0)
|
|
3853
3981
|
client._pendingOrderedMsgs.delete(ns);
|
|
3854
|
-
await this.publishOrderedQueueItem(ns, event, seqNum, payload, false, source, batch);
|
|
3855
3982
|
this.markPublishedSeq(ns, seqNum);
|
|
3856
3983
|
await this.drainOrderedMessages(ns, undefined, false, true, batch, source);
|
|
3857
3984
|
if (!client._pendingOrderedMsgs.get(ns))
|
|
@@ -3865,6 +3992,7 @@ export class MessageDeliveryEngine {
|
|
|
3865
3992
|
}
|
|
3866
3993
|
async publishPulledMessage(event, ns, seq, payload, persist = true, source = 'pull', operationBatch) {
|
|
3867
3994
|
const client = this.runtime.client;
|
|
3995
|
+
const generation = this.captureInlineGeneration();
|
|
3868
3996
|
const ownsBatch = !operationBatch && (source === 'push' || source === 'inline_push');
|
|
3869
3997
|
const batch = operationBatch ?? (ownsBatch ? this.createDeliveryChangeBatch(source) : undefined);
|
|
3870
3998
|
const pullScoped = this.isPullScopedSource(source);
|
|
@@ -3891,22 +4019,34 @@ export class MessageDeliveryEngine {
|
|
|
3891
4019
|
client._pendingOrderedMsgs.delete(ns);
|
|
3892
4020
|
return false;
|
|
3893
4021
|
}
|
|
4022
|
+
if (event === 'message.received' && this.isSelfSentP2PMessage(payload)) {
|
|
4023
|
+
this.markPublishedSeq(ns, seqNum);
|
|
4024
|
+
client._clientLog.debug(`publish pulled skipped current-device self-sync: ns=${ns}, seq=${seqNum}`);
|
|
4025
|
+
return source === 'inline_push';
|
|
4026
|
+
}
|
|
3894
4027
|
await this.drainOrderedMessages(ns, seqNum, false, persist, batch, source);
|
|
3895
4028
|
if (pullScoped)
|
|
3896
4029
|
this.ensurePullOperationCurrent(ns);
|
|
3897
|
-
queue?.delete(seqNum);
|
|
3898
|
-
if (queue && queue.size === 0)
|
|
3899
|
-
client._pendingOrderedMsgs.delete(ns);
|
|
3900
4030
|
if (event === 'message.recalled') {
|
|
3901
4031
|
const published = await client._withPullResponseProcessing(ns, () => this.publishMessageRecallTombstone(seqNum, payload, source));
|
|
4032
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
4033
|
+
throw new Error('pull invalidated');
|
|
3902
4034
|
if (pullScoped)
|
|
3903
4035
|
this.ensurePullOperationCurrent(ns);
|
|
4036
|
+
queue?.delete(seqNum);
|
|
4037
|
+
if (queue && queue.size === 0)
|
|
4038
|
+
client._pendingOrderedMsgs.delete(ns);
|
|
3904
4039
|
this.markPublishedSeq(ns, seqNum);
|
|
3905
4040
|
return published;
|
|
3906
4041
|
}
|
|
3907
4042
|
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
4043
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
4044
|
+
throw new Error('pull invalidated');
|
|
3908
4045
|
if (pullScoped)
|
|
3909
4046
|
this.ensurePullOperationCurrent(ns);
|
|
4047
|
+
queue?.delete(seqNum);
|
|
4048
|
+
if (queue && queue.size === 0)
|
|
4049
|
+
client._pendingOrderedMsgs.delete(ns);
|
|
3910
4050
|
this.markPublishedSeq(ns, seqNum);
|
|
3911
4051
|
return true;
|
|
3912
4052
|
}
|