@agentunion/fastaun-browser 0.5.10 → 0.5.12
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 +62 -0
- package/_packed_docs/CHANGELOG.md +62 -0
- package/_packed_docs/INDEX.md +3 -3
- package/_packed_docs/KITE_DOCS_GUIDE.md +1 -1
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +21 -3
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +59 -0
- package/_packed_docs/sdk/09-group-rpc-manual.md +29 -2
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +3 -2
- package/_packed_docs/sdk/INDEX.md +2 -1
- package/dist/bundle.js +1145 -381
- package/dist/client/delivery.d.ts +12 -4
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +341 -273
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.d.ts.map +1 -1
- package/dist/client/group-state.js +1 -0
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +38 -13
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +3 -1
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +211 -75
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +15 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +402 -20
- package/dist/client.js.map +1 -1
- package/dist/facades.d.ts +7 -0
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +44 -0
- package/dist/facades.js.map +1 -1
- package/dist/seq-tracker.d.ts +2 -2
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +11 -7
- package/dist/seq-tracker.js.map +1 -1
- package/dist/tools/cross-sdk-agent.js +50 -12
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +162 -15
- 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/v2-e2ee.js
CHANGED
|
@@ -67,11 +67,32 @@ function deduplicateForwardPageMessages(value, afterSeq) {
|
|
|
67
67
|
}
|
|
68
68
|
return [...bySeq.entries()].sort(([a], [b]) => a - b).map(([, row]) => row);
|
|
69
69
|
}
|
|
70
|
-
function
|
|
70
|
+
function contiguousPullSeq(afterSeq, seqs, proof) {
|
|
71
|
+
// Forward 原始页中的缺号视为服务端永久空号;页完成后按页内最大
|
|
72
|
+
// seq 推进 A,避免单页空洞阻塞后续 pull/ACK。
|
|
73
|
+
let contiguous = seqs.length > 0 ? Math.max(afterSeq, ...seqs) : afterSeq;
|
|
74
|
+
const serverProof = safeNonNegativeSeq(proof);
|
|
75
|
+
return serverProof !== null ? Math.max(contiguous, serverProof) : contiguous;
|
|
76
|
+
}
|
|
77
|
+
function deduplicatePulledResults(messages) {
|
|
78
|
+
const seen = new Set();
|
|
79
|
+
return messages.filter((message) => {
|
|
80
|
+
if (!isJsonObject(message))
|
|
81
|
+
return true;
|
|
82
|
+
const seq = safeNonNegativeSeq(message.seq);
|
|
83
|
+
if (seq === null || seq <= 0)
|
|
84
|
+
return true;
|
|
85
|
+
if (seen.has(seq))
|
|
86
|
+
return false;
|
|
87
|
+
seen.add(seq);
|
|
88
|
+
return true;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function shouldContinueForwardPage({ rawCount, nextAfterSeq, nextAfter, limit, hasMoreField, hasMore, serverHead, pendingAckSeq, observedUpper, }) {
|
|
71
92
|
// 无新 seq 或游标未前进时必须停止,避免错误元数据造成循环。
|
|
72
93
|
if (rawCount <= 0 || nextAfter <= nextAfterSeq)
|
|
73
94
|
return false;
|
|
74
|
-
if (hasMore || serverHead > nextAfter || pendingAckSeq > 0)
|
|
95
|
+
if (hasMore || serverHead > nextAfter || pendingAckSeq > 0 || observedUpper > nextAfter)
|
|
75
96
|
return true;
|
|
76
97
|
// 仅旧服务缺失 has_more 时,以满页保留兼容续拉。
|
|
77
98
|
return !hasMoreField && limit > 0 && rawCount >= limit;
|
|
@@ -889,7 +910,7 @@ export class V2E2EECoordinator {
|
|
|
889
910
|
client._clientLog.warn(`V2 sender IK pending group bootstrap failed group=${groupId}: ${String(formatE2EEError(exc))}`);
|
|
890
911
|
}
|
|
891
912
|
}
|
|
892
|
-
if (!session.getPeerIK(fromAid, senderDeviceId)) {
|
|
913
|
+
if (typeof session.getPeerIK === 'function' && !session.getPeerIK(fromAid, senderDeviceId)) {
|
|
893
914
|
await this.getV2SenderPubDer(fromAid, senderDeviceId);
|
|
894
915
|
}
|
|
895
916
|
}
|
|
@@ -902,7 +923,7 @@ export class V2E2EECoordinator {
|
|
|
902
923
|
let plaintext = null;
|
|
903
924
|
const retryStatus = {};
|
|
904
925
|
try {
|
|
905
|
-
plaintext = await client._decryptV2Message(entry.msg, false, true, true, true, retryStatus);
|
|
926
|
+
plaintext = await client._decryptV2Message(entry.msg, false, true, true, true, retryStatus, false, 'pending_retry');
|
|
906
927
|
}
|
|
907
928
|
catch (exc) {
|
|
908
929
|
if (!generationCurrent())
|
|
@@ -930,12 +951,14 @@ export class V2E2EECoordinator {
|
|
|
930
951
|
client._v2SenderIKPending.delete(key);
|
|
931
952
|
const seq = Number(entry.msg.seq ?? 0);
|
|
932
953
|
if (entry.groupId) {
|
|
954
|
+
if (client._delivery.isSelfSentGroupMessage?.(entry.msg))
|
|
955
|
+
continue;
|
|
933
956
|
plaintext = normalizeGroupMentionMode(plaintext, entry.msg, entry.msg.envelope_json);
|
|
934
957
|
plaintext.group_id = entry.groupId;
|
|
935
|
-
await client._publishPulledMessage('group.message_created', `group:${entry.groupId}`, seq, plaintext);
|
|
958
|
+
await client._publishPulledMessage('group.message_created', `group:${entry.groupId}`, seq, plaintext, false, 'pending_retry');
|
|
936
959
|
}
|
|
937
960
|
else {
|
|
938
|
-
await client._publishPulledMessage('message.received', `p2p:${client._aid ?? ''}`, seq, plaintext);
|
|
961
|
+
await client._publishPulledMessage('message.received', `p2p:${client._aid ?? ''}`, seq, plaintext, false, 'pending_retry');
|
|
939
962
|
}
|
|
940
963
|
client._clientLog.debug(`V2 sender IK pending retry delivered: key=${key}`);
|
|
941
964
|
}
|
|
@@ -1014,10 +1037,10 @@ export class V2E2EECoordinator {
|
|
|
1014
1037
|
if (String(msg.version ?? '') === 'v1') {
|
|
1015
1038
|
const legacy = isJsonObject(msg.legacy_v1)
|
|
1016
1039
|
? msg.legacy_v1 : {};
|
|
1017
|
-
const payload = legacy.payload;
|
|
1040
|
+
const payload = legacy.payload !== undefined ? legacy.payload : msg.payload;
|
|
1018
1041
|
const payloadType = isJsonObject(payload)
|
|
1019
1042
|
? String(payload.type ?? '').trim() : '';
|
|
1020
|
-
if (payload !== undefined && payload !== null && !['e2ee.encrypted', 'e2ee.group_encrypted'].includes(payloadType)) {
|
|
1043
|
+
if (payload !== undefined && payload !== null && !['e2ee.encrypted', 'e2ee.group_encrypted', 'e2ee.p2p_encrypted'].includes(payloadType)) {
|
|
1021
1044
|
plaintext = {
|
|
1022
1045
|
message_id: String(msg.message_id ?? ''), from: String(msg.from_aid ?? ''),
|
|
1023
1046
|
to: String(legacy.to ?? client._aid ?? ''), seq, type: String(msg.type ?? ''),
|
|
@@ -1025,6 +1048,11 @@ export class V2E2EECoordinator {
|
|
|
1025
1048
|
};
|
|
1026
1049
|
attachGatewayProximity(plaintext, msg);
|
|
1027
1050
|
}
|
|
1051
|
+
else if (isJsonObject(payload)
|
|
1052
|
+
&& ['e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(payloadType)) {
|
|
1053
|
+
msg = { ...msg, envelope_json: JSON.stringify(payload) };
|
|
1054
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, undefined, false, source);
|
|
1055
|
+
}
|
|
1028
1056
|
}
|
|
1029
1057
|
else {
|
|
1030
1058
|
plaintext = source === 'inline_push'
|
|
@@ -1054,26 +1082,48 @@ export class V2E2EECoordinator {
|
|
|
1054
1082
|
let plaintext = null;
|
|
1055
1083
|
if (String(msg.version ?? '') === 'v1') {
|
|
1056
1084
|
const payload = msg.payload;
|
|
1085
|
+
const recall = typeof client._delivery?.recallEventFromGroupMessage === 'function'
|
|
1086
|
+
? client._delivery.recallEventFromGroupMessage(msg)
|
|
1087
|
+
: null;
|
|
1088
|
+
if (recall) {
|
|
1089
|
+
const recallPayload = {
|
|
1090
|
+
...recall,
|
|
1091
|
+
group_id: groupId,
|
|
1092
|
+
group_aid: groupAid,
|
|
1093
|
+
seq,
|
|
1094
|
+
};
|
|
1095
|
+
if (publish) {
|
|
1096
|
+
if (orderedPublish) {
|
|
1097
|
+
await client._delivery.publishOrderedMessage('group.message_recalled', `group:${groupId}`, seq, recallPayload, source);
|
|
1098
|
+
}
|
|
1099
|
+
else {
|
|
1100
|
+
await client._publishAppEvent('group.message_recalled', recallPayload, source);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
return recallPayload;
|
|
1104
|
+
}
|
|
1057
1105
|
if (payload === undefined || payload === null) {
|
|
1058
1106
|
if (history)
|
|
1059
1107
|
return this.historyDecryptFailure(msg, 'legacy payload is missing');
|
|
1060
1108
|
client._clientLog.warn(`Group Tail 缺少 payload 的 V1 行已跳过,连续性证明仍保留: group=${groupId}, seq=${seq}`);
|
|
1061
1109
|
return null;
|
|
1062
1110
|
}
|
|
1111
|
+
const payloadType = isJsonObject(payload)
|
|
1112
|
+
? String(payload.type ?? '').trim() : '';
|
|
1063
1113
|
if (isJsonObject(payload)
|
|
1064
|
-
&& ['e2ee.
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1114
|
+
&& ['e2ee.group_encrypted', 'e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(payloadType)) {
|
|
1115
|
+
msg = { ...msg, envelope_json: JSON.stringify(payload) };
|
|
1116
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, undefined, false, source);
|
|
1117
|
+
}
|
|
1118
|
+
else {
|
|
1119
|
+
plaintext = {
|
|
1120
|
+
message_id: String(msg.message_id ?? ''), from: String(msg.from_aid ?? ''),
|
|
1121
|
+
group_id: groupId, group_aid: groupAid, seq, type: String(msg.type ?? ''),
|
|
1122
|
+
timestamp: msg.t_server, payload: payload, encrypted: false,
|
|
1123
|
+
};
|
|
1124
|
+
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
1125
|
+
attachGatewayProximity(plaintext, msg);
|
|
1069
1126
|
}
|
|
1070
|
-
plaintext = {
|
|
1071
|
-
message_id: String(msg.message_id ?? ''), from: String(msg.from_aid ?? ''),
|
|
1072
|
-
group_id: groupId, group_aid: groupAid, seq, type: String(msg.type ?? ''),
|
|
1073
|
-
timestamp: msg.t_server, payload: payload, encrypted: false,
|
|
1074
|
-
};
|
|
1075
|
-
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
1076
|
-
attachGatewayProximity(plaintext, msg);
|
|
1077
1127
|
}
|
|
1078
1128
|
else {
|
|
1079
1129
|
plaintext = source === 'inline_push'
|
|
@@ -1096,6 +1146,9 @@ export class V2E2EECoordinator {
|
|
|
1096
1146
|
client._clientLog.warn(`Group Tail 单条消息解密失败,连续性证明仍保留: group=${groupId}, seq=${seq}`);
|
|
1097
1147
|
return null;
|
|
1098
1148
|
}
|
|
1149
|
+
if (publish && !history && client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
1150
|
+
return plaintext;
|
|
1151
|
+
}
|
|
1099
1152
|
if (publish) {
|
|
1100
1153
|
if (orderedPublish) {
|
|
1101
1154
|
await client._delivery.publishOrderedMessage('group.message_created', `group:${groupId}`, seq, plaintext, source);
|
|
@@ -1112,14 +1165,6 @@ export class V2E2EECoordinator {
|
|
|
1112
1165
|
async decodeInlineGroupMessage(msg, groupId, groupAid) {
|
|
1113
1166
|
return await this.decodeGroupWindowMessage(msg, groupId, groupAid, false, false, 'inline_push');
|
|
1114
1167
|
}
|
|
1115
|
-
async applyTailFloor(ns, floor) {
|
|
1116
|
-
const client = this.client;
|
|
1117
|
-
if (!ns || floor <= 0 || client._seqTracker.getContiguousSeq(ns) >= floor)
|
|
1118
|
-
return;
|
|
1119
|
-
client._seqTracker.forceContiguousSeq(ns, floor);
|
|
1120
|
-
client._persistSeq(ns);
|
|
1121
|
-
await client._saveSeqTrackerState?.();
|
|
1122
|
-
}
|
|
1123
1168
|
async pullV2TailInternal(params, deferPublish = false) {
|
|
1124
1169
|
const client = this.client;
|
|
1125
1170
|
if (params.window_mode !== 'tail')
|
|
@@ -1129,10 +1174,9 @@ export class V2E2EECoordinator {
|
|
|
1129
1174
|
const afterSeq = strictWindowSeq(params.after_seq ?? 0, 'after_seq');
|
|
1130
1175
|
const limit = strictWindowLimit(params.limit ?? V2_PULL_DEFAULT_PAGE_LIMIT);
|
|
1131
1176
|
const ns = client._aid ? `p2p:${client._aid}` : '';
|
|
1177
|
+
if (ns)
|
|
1178
|
+
client._delivery.onPullStarted?.(ns);
|
|
1132
1179
|
const result = await client._callRawV2Rpc('message.v2.pull', { window_mode: 'tail', after_seq: afterSeq, limit, _rpc_foreground: true });
|
|
1133
|
-
const floor = Number(result.retention_floor_seq ?? 0);
|
|
1134
|
-
const previous = ns ? client._seqTracker.getSyncState(ns) : null;
|
|
1135
|
-
await this.applyTailFloor(ns, Number.isSafeInteger(floor) ? floor : 0);
|
|
1136
1180
|
const page = validateTailPage(result, afterSeq, limit);
|
|
1137
1181
|
if (ns) {
|
|
1138
1182
|
client._seqTracker.commitTailWindow(ns, {
|
|
@@ -1148,8 +1192,9 @@ export class V2E2EECoordinator {
|
|
|
1148
1192
|
decoded.push(plaintext);
|
|
1149
1193
|
}
|
|
1150
1194
|
const ack = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
|
|
1151
|
-
if (
|
|
1152
|
-
|
|
1195
|
+
if (ns)
|
|
1196
|
+
client._delivery.onPullPage?.(ns, decoded.length, result.has_more === true, page.head, typeof result.remaining === 'number' && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null, page.messages.length, ack, page.head);
|
|
1197
|
+
client._delivery.onPullWorkSettled?.();
|
|
1153
1198
|
return { ...result, messages: decoded, raw_count: page.messages.length };
|
|
1154
1199
|
}
|
|
1155
1200
|
async historyV2Internal(params) {
|
|
@@ -1165,16 +1210,33 @@ export class V2E2EECoordinator {
|
|
|
1165
1210
|
}
|
|
1166
1211
|
return { ...result, messages: decoded };
|
|
1167
1212
|
}
|
|
1213
|
+
async runPullWithLifecycle(ns, operation) {
|
|
1214
|
+
if (ns)
|
|
1215
|
+
this.client._delivery.onPullStarted?.(ns);
|
|
1216
|
+
try {
|
|
1217
|
+
return await operation();
|
|
1218
|
+
}
|
|
1219
|
+
catch (error) {
|
|
1220
|
+
this.client._delivery.onPullAborted?.();
|
|
1221
|
+
throw error;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1168
1224
|
async pullV2(afterSeq = 0, limit = 50, opts) {
|
|
1225
|
+
const ns = this.client._aid ? `p2p:${this.client._aid}` : '';
|
|
1226
|
+
return await this.runPullWithLifecycle(ns, () => this.pullV2Impl(afterSeq, limit, opts));
|
|
1227
|
+
}
|
|
1228
|
+
async pullV2Impl(afterSeq = 0, limit = 50, opts) {
|
|
1169
1229
|
const client = this.client;
|
|
1170
1230
|
await client._ensureV2SessionReady('message.pull');
|
|
1171
1231
|
const ns = client._aid ? `p2p:${client._aid}` : '';
|
|
1232
|
+
if (ns)
|
|
1233
|
+
client._delivery.onPullStarted?.(ns);
|
|
1172
1234
|
if (opts?.windowMode === 'tail') {
|
|
1173
1235
|
if (!opts.gateLocked) {
|
|
1174
1236
|
const key = pullGateKeyForClient(client, 'message.v2.pull', {
|
|
1175
1237
|
window_mode: 'tail', after_seq: afterSeq, limit,
|
|
1176
1238
|
}, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
|
|
1177
|
-
return await client._runPullSerialized(key, () => this.
|
|
1239
|
+
return await client._runPullSerialized(key, () => this.pullV2Impl(afterSeq, limit, {
|
|
1178
1240
|
...(opts ?? {}),
|
|
1179
1241
|
gateLocked: true,
|
|
1180
1242
|
}), false);
|
|
@@ -1186,7 +1248,7 @@ export class V2E2EECoordinator {
|
|
|
1186
1248
|
const key = pullGateKeyForClient(client, 'message.v2.pull', {
|
|
1187
1249
|
after_seq: afterSeq, force: opts?.force === true, limit,
|
|
1188
1250
|
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
1189
|
-
return await client._runPullSerialized(key, () => this.
|
|
1251
|
+
return await client._runPullSerialized(key, () => this.pullV2Impl(afterSeq, limit, {
|
|
1190
1252
|
...(opts ?? {}),
|
|
1191
1253
|
gateLocked: true,
|
|
1192
1254
|
}), true);
|
|
@@ -1248,8 +1310,10 @@ export class V2E2EECoordinator {
|
|
|
1248
1310
|
? client._seqTracker.snapshotNamespace(ns)
|
|
1249
1311
|
: null;
|
|
1250
1312
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
1313
|
+
const pageContiguousSeq = contiguousPullSeq(pageContigBefore, seqs, result.contiguous_seq);
|
|
1251
1314
|
const deferredKeyFetches = new Map();
|
|
1252
1315
|
let blockedSeq = 0;
|
|
1316
|
+
const pageDecryptedBefore = decrypted.length;
|
|
1253
1317
|
for (const msg of messages) {
|
|
1254
1318
|
const seq = Number(msg.seq ?? 0);
|
|
1255
1319
|
if (!Number.isFinite(seq) || seq <= 0)
|
|
@@ -1257,12 +1321,12 @@ export class V2E2EECoordinator {
|
|
|
1257
1321
|
const version = String(msg.version ?? 'v2');
|
|
1258
1322
|
if (version === 'v1') {
|
|
1259
1323
|
const legacy = isJsonObject(msg.legacy_v1) ? msg.legacy_v1 : {};
|
|
1260
|
-
const legacyPayload = legacy.payload;
|
|
1324
|
+
const legacyPayload = legacy.payload !== undefined ? legacy.payload : msg.payload;
|
|
1261
1325
|
const payloadType = isJsonObject(legacyPayload)
|
|
1262
1326
|
? String(legacyPayload.type ?? '').trim()
|
|
1263
1327
|
: '';
|
|
1264
1328
|
if (legacyPayload !== undefined && legacyPayload !== null
|
|
1265
|
-
&&
|
|
1329
|
+
&& !['e2ee.encrypted', 'e2ee.group_encrypted', 'e2ee.p2p_encrypted'].includes(payloadType)) {
|
|
1266
1330
|
const v1Msg = {
|
|
1267
1331
|
message_id: String(msg.message_id ?? ''),
|
|
1268
1332
|
from: String(msg.from_aid ?? ''),
|
|
@@ -1281,6 +1345,25 @@ export class V2E2EECoordinator {
|
|
|
1281
1345
|
await client._publishAppEvent(appEvent.event, appEvent.payload, 'pull');
|
|
1282
1346
|
decrypted.push(v1Msg);
|
|
1283
1347
|
}
|
|
1348
|
+
else if (isJsonObject(legacyPayload)
|
|
1349
|
+
&& ['e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(payloadType)) {
|
|
1350
|
+
const deferStatus = {};
|
|
1351
|
+
const plaintext = await client._decryptV2Message({ ...msg, envelope_json: JSON.stringify(legacyPayload) }, true, true, true, true, deferStatus, true, 'pull');
|
|
1352
|
+
if (deferStatus.deferred) {
|
|
1353
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
1354
|
+
if (deferStatus.fromAid) {
|
|
1355
|
+
const key = `${deferStatus.fromAid}\u0000${deferStatus.senderDeviceId ?? ''}\u0000${deferStatus.groupId ?? ''}`;
|
|
1356
|
+
deferredKeyFetches.set(key, { fromAid: deferStatus.fromAid, senderDeviceId: deferStatus.senderDeviceId ?? '', groupId: deferStatus.groupId ?? '' });
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
if (plaintext) {
|
|
1360
|
+
if (ns)
|
|
1361
|
+
await client._publishPulledMessage('message.received', ns, seq, plaintext, false);
|
|
1362
|
+
else
|
|
1363
|
+
await client._publishAppEvent('message.received', plaintext, 'pull');
|
|
1364
|
+
decrypted.push(plaintext);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1284
1367
|
else {
|
|
1285
1368
|
client._clientLog.debug(`message.v2.pull skipping V1 envelope seq=${seq} payload_type=${payloadType || '<none>'} (V1 E2EE removed)`);
|
|
1286
1369
|
}
|
|
@@ -1295,7 +1378,7 @@ export class V2E2EECoordinator {
|
|
|
1295
1378
|
client._v2Session.trackOldSPKMaxSeq(msgSpkId, seq);
|
|
1296
1379
|
}
|
|
1297
1380
|
const deferStatus = {};
|
|
1298
|
-
const plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
1381
|
+
const plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true, 'pull');
|
|
1299
1382
|
if (deferStatus.deferred) {
|
|
1300
1383
|
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
1301
1384
|
}
|
|
@@ -1323,7 +1406,7 @@ export class V2E2EECoordinator {
|
|
|
1323
1406
|
const serverAckSeq = parsedServerAckSeq ?? 0;
|
|
1324
1407
|
const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
|
|
1325
1408
|
if (ns) {
|
|
1326
|
-
const commitTarget =
|
|
1409
|
+
const commitTarget = Math.max(pageContigBefore, Number.isFinite(retentionFloor) ? retentionFloor : 0, pageCount === 1 ? deferredServerCursor : 0, serverAckSeq, blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq);
|
|
1327
1410
|
let ackSeq = pageContigBefore;
|
|
1328
1411
|
let contigAdvanced = false;
|
|
1329
1412
|
try {
|
|
@@ -1367,15 +1450,14 @@ export class V2E2EECoordinator {
|
|
|
1367
1450
|
const knownServerAckSeq = hasServerAckSeq
|
|
1368
1451
|
? serverAckSeq
|
|
1369
1452
|
: (pageCount === 1 ? deferredServerCursor : 0);
|
|
1370
|
-
const ackNeeded =
|
|
1371
|
-
&& ackSeq > 0
|
|
1453
|
+
const ackNeeded = ackSeq > 0
|
|
1372
1454
|
&& ackSeq > lastAutoAckSeq
|
|
1373
1455
|
&& ((hasServerAckSeq && ackSeq > serverAckSeq)
|
|
1374
1456
|
|| (contigAdvanced && ackSeq > knownServerAckSeq));
|
|
1375
1457
|
if (ackNeeded) {
|
|
1376
1458
|
this.recordForwardAck(ns, ackSeq);
|
|
1377
|
-
const nextAfter = Math.max(
|
|
1378
|
-
const canContinuePage = messages.length > 0 && nextAfter > nextAfterSeq;
|
|
1459
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
1460
|
+
const canContinuePage = blockedSeq <= 0 && messages.length > 0 && nextAfter > nextAfterSeq;
|
|
1379
1461
|
if (canContinuePage) {
|
|
1380
1462
|
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
1381
1463
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
@@ -1386,7 +1468,9 @@ export class V2E2EECoordinator {
|
|
|
1386
1468
|
}
|
|
1387
1469
|
}
|
|
1388
1470
|
}
|
|
1389
|
-
|
|
1471
|
+
if (ns)
|
|
1472
|
+
client._delivery.onPullPage?.(ns, decrypted.length - pageDecryptedBefore, hasMore, pageMaxSeq, typeof result.remaining === 'number' && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null, messages.length, client._seqTracker.getContiguousSeq(ns), pageMaxSeq);
|
|
1473
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
1390
1474
|
const rawCount = messages.length;
|
|
1391
1475
|
if (blockedSeq > 0)
|
|
1392
1476
|
break;
|
|
@@ -1399,6 +1483,8 @@ export class V2E2EECoordinator {
|
|
|
1399
1483
|
hasMore,
|
|
1400
1484
|
serverHead,
|
|
1401
1485
|
pendingAckSeq,
|
|
1486
|
+
observedUpper: typeof client._seqTracker.getMaxSeenSeq === 'function'
|
|
1487
|
+
? client._seqTracker.getMaxSeenSeq(ns) : nextAfter,
|
|
1402
1488
|
});
|
|
1403
1489
|
if (!shouldContinue)
|
|
1404
1490
|
break;
|
|
@@ -1421,7 +1507,8 @@ export class V2E2EECoordinator {
|
|
|
1421
1507
|
pendingAckSeq = 0;
|
|
1422
1508
|
}
|
|
1423
1509
|
}
|
|
1424
|
-
|
|
1510
|
+
client._delivery.onPullWorkSettled?.();
|
|
1511
|
+
return deduplicatePulledResults(decrypted);
|
|
1425
1512
|
}
|
|
1426
1513
|
async confirmForwardP2PAck(upToSeq, inlineGeneration) {
|
|
1427
1514
|
const ns = this.client._aid ? `p2p:${this.client._aid}` : '';
|
|
@@ -1519,10 +1606,7 @@ export class V2E2EECoordinator {
|
|
|
1519
1606
|
if (isJsonObject(result)) {
|
|
1520
1607
|
const seq = Number(result.seq ?? 0);
|
|
1521
1608
|
if (seq > 0) {
|
|
1522
|
-
|
|
1523
|
-
client._seqTracker.onMessageSeq(ns, seq);
|
|
1524
|
-
client._markPublishedSeq(ns, seq);
|
|
1525
|
-
await client._saveSeqTrackerState();
|
|
1609
|
+
client._markPublishedSeq(`group:${gid}`, seq);
|
|
1526
1610
|
}
|
|
1527
1611
|
}
|
|
1528
1612
|
return client._delivery.attachSendResultEnvelope('group.send', withExplicitGroupAid({
|
|
@@ -1543,10 +1627,7 @@ export class V2E2EECoordinator {
|
|
|
1543
1627
|
if (isJsonObject(result)) {
|
|
1544
1628
|
const seq = Number(result.seq ?? 0);
|
|
1545
1629
|
if (seq > 0) {
|
|
1546
|
-
|
|
1547
|
-
client._seqTracker.onMessageSeq(ns, seq);
|
|
1548
|
-
client._markPublishedSeq(ns, seq);
|
|
1549
|
-
await client._saveSeqTrackerState();
|
|
1630
|
+
client._markPublishedSeq(`group:${gid}`, seq);
|
|
1550
1631
|
}
|
|
1551
1632
|
}
|
|
1552
1633
|
return client._delivery.attachSendResultEnvelope('group.send', withExplicitGroupAid({
|
|
@@ -1574,15 +1655,20 @@ export class V2E2EECoordinator {
|
|
|
1574
1655
|
const afterSeq = strictWindowSeq(params.after_seq ?? 0, 'after_seq');
|
|
1575
1656
|
const limit = strictWindowLimit(params.limit ?? V2_PULL_DEFAULT_PAGE_LIMIT);
|
|
1576
1657
|
const ns = `group:${groupId}`;
|
|
1658
|
+
const cursorParams = isJsonObject(params._group_cursor_params)
|
|
1659
|
+
? params._group_cursor_params : params;
|
|
1660
|
+
const requestDeviceId = String(cursorParams.device_id ?? '').trim();
|
|
1661
|
+
const requestSlotId = String(cursorParams.slot_id ?? '').trim();
|
|
1662
|
+
const ownsCursor = (!requestDeviceId || requestDeviceId === String(client._deviceId ?? ''))
|
|
1663
|
+
&& (!requestSlotId || requestSlotId === String(client._slotId ?? ''));
|
|
1664
|
+
if (ownsCursor)
|
|
1665
|
+
client._delivery.onPullStarted?.(ns);
|
|
1577
1666
|
const result = await client._callRawV2Rpc('group.v2.pull', withExplicitGroupAid({
|
|
1578
1667
|
group_id: groupId, window_mode: 'tail', after_seq: afterSeq, limit, _rpc_foreground: true,
|
|
1579
1668
|
}, groupAid));
|
|
1580
1669
|
const resultAid = String(result.group_aid ?? result.groupAid ?? '').trim();
|
|
1581
1670
|
if (resultAid)
|
|
1582
1671
|
groupAid = resultAid;
|
|
1583
|
-
const floor = Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0);
|
|
1584
|
-
const previous = client._seqTracker.getSyncState(ns);
|
|
1585
|
-
await this.applyTailFloor(ns, Number.isSafeInteger(floor) ? floor : 0);
|
|
1586
1672
|
const page = validateTailPage(result, afterSeq, limit);
|
|
1587
1673
|
client._seqTracker.commitTailWindow(ns, {
|
|
1588
1674
|
windowStartSeq: page.windowStart, headSeq: page.head, coveredThroughSeq: page.head, pageLimit: limit,
|
|
@@ -1597,8 +1683,9 @@ export class V2E2EECoordinator {
|
|
|
1597
1683
|
decoded.push(plaintext);
|
|
1598
1684
|
}
|
|
1599
1685
|
const ack = client._seqTracker.getContiguousSeq(ns);
|
|
1600
|
-
if (
|
|
1601
|
-
|
|
1686
|
+
if (ownsCursor)
|
|
1687
|
+
client._delivery.onPullPage?.(ns, decoded.length, result.has_more === true, page.head, typeof result.remaining === 'number' && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null, page.messages.length, ack, page.head);
|
|
1688
|
+
client._delivery.onPullWorkSettled?.();
|
|
1602
1689
|
return { ...result, messages: decoded, raw_count: page.messages.length };
|
|
1603
1690
|
}
|
|
1604
1691
|
async historyGroupV2Internal(params) {
|
|
@@ -1631,6 +1718,13 @@ export class V2E2EECoordinator {
|
|
|
1631
1718
|
});
|
|
1632
1719
|
}
|
|
1633
1720
|
async pullGroupV2(groupId, afterSeq = 0, limit = 50, opts) {
|
|
1721
|
+
const lifecycleNs = `group:${String(groupId ?? '').trim()}`;
|
|
1722
|
+
if (opts?.ownsCursor === false) {
|
|
1723
|
+
return await this.pullGroupV2Impl(groupId, afterSeq, limit, opts);
|
|
1724
|
+
}
|
|
1725
|
+
return await this.runPullWithLifecycle(lifecycleNs, () => this.pullGroupV2Impl(groupId, afterSeq, limit, opts));
|
|
1726
|
+
}
|
|
1727
|
+
async pullGroupV2Impl(groupId, afterSeq = 0, limit = 50, opts) {
|
|
1634
1728
|
const client = this.client;
|
|
1635
1729
|
await client._ensureV2SessionReady('group.pull');
|
|
1636
1730
|
const gid = String(groupId ?? '').trim();
|
|
@@ -1644,12 +1738,13 @@ export class V2E2EECoordinator {
|
|
|
1644
1738
|
group_id: gid, window_mode: 'tail', after_seq: afterSeq, limit,
|
|
1645
1739
|
_group_cursor_params: opts?.cursorParams,
|
|
1646
1740
|
}, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
|
|
1647
|
-
return await client._runPullSerialized(key, () => this.
|
|
1741
|
+
return await client._runPullSerialized(key, () => this.pullGroupV2Impl(gid, afterSeq, limit, {
|
|
1648
1742
|
...(opts ?? {}),
|
|
1649
1743
|
gateLocked: true,
|
|
1650
1744
|
}), false);
|
|
1651
1745
|
}
|
|
1652
1746
|
const result = await this.pullGroupV2TailInternal({
|
|
1747
|
+
...(opts?.cursorParams ?? {}),
|
|
1653
1748
|
group_id: String(opts.wireGroupId ?? gid), group_aid: groupAid || undefined,
|
|
1654
1749
|
window_mode: 'tail', after_seq: afterSeq, limit,
|
|
1655
1750
|
});
|
|
@@ -1660,7 +1755,7 @@ export class V2E2EECoordinator {
|
|
|
1660
1755
|
group_id: gid, after_seq: afterSeq, force: opts?.force === true, limit,
|
|
1661
1756
|
_group_cursor_params: opts?.cursorParams,
|
|
1662
1757
|
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
1663
|
-
return await client._runPullSerialized(key, () => this.
|
|
1758
|
+
return await client._runPullSerialized(key, () => this.pullGroupV2Impl(gid, afterSeq, limit, {
|
|
1664
1759
|
...(opts ?? {}),
|
|
1665
1760
|
gateLocked: true,
|
|
1666
1761
|
}), true);
|
|
@@ -1669,6 +1764,8 @@ export class V2E2EECoordinator {
|
|
|
1669
1764
|
const wireGroupId = String(opts?.wireGroupId ?? groupId ?? '').trim() || gid;
|
|
1670
1765
|
const cursorParams = opts?.cursorParams ?? {};
|
|
1671
1766
|
const ownsCursor = opts?.ownsCursor !== false;
|
|
1767
|
+
if (ownsCursor)
|
|
1768
|
+
client._delivery.onPullStarted?.(ns);
|
|
1672
1769
|
let pullGateKey = ownsCursor
|
|
1673
1770
|
? pullGateKeyForClient(client, 'group.v2.pull', {
|
|
1674
1771
|
group_id: gid, after_seq: afterSeq, force: opts?.force === true, limit,
|
|
@@ -1735,30 +1832,34 @@ export class V2E2EECoordinator {
|
|
|
1735
1832
|
? client._seqTracker.snapshotNamespace(ns)
|
|
1736
1833
|
: null;
|
|
1737
1834
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
1835
|
+
const pageContiguousSeq = contiguousPullSeq(pageContigBefore, seqs, result.contiguous_seq);
|
|
1738
1836
|
const deferredKeyFetches = new Map();
|
|
1739
1837
|
let blockedSeq = 0;
|
|
1838
|
+
const pageDecryptedBefore = decrypted.length;
|
|
1740
1839
|
for (const msg of messages) {
|
|
1741
1840
|
const seq = Number(msg.seq ?? 0);
|
|
1742
1841
|
if (!Number.isFinite(seq) || seq <= 0)
|
|
1743
1842
|
continue;
|
|
1744
1843
|
const version = String(msg.version ?? 'v2');
|
|
1745
1844
|
if (version === 'v1') {
|
|
1746
|
-
const
|
|
1845
|
+
const legacy = isJsonObject(msg.legacy_v1) ? msg.legacy_v1 : {};
|
|
1846
|
+
const payload = msg.payload !== undefined ? msg.payload : legacy.payload;
|
|
1747
1847
|
const payloadObj = isJsonObject(payload) ? payload : null;
|
|
1748
1848
|
// 群撤回 tombstone(占位 / 通知):归一化为 group.message_recalled 事件,仍占 seq。
|
|
1749
|
-
if (client._delivery
|
|
1849
|
+
if (typeof client._delivery?.recallEventFromGroupMessage === 'function'
|
|
1850
|
+
&& client._delivery.recallEventFromGroupMessage(msg)) {
|
|
1750
1851
|
await client._delivery.publishGroupRecallTombstone(gid, seq, {
|
|
1751
1852
|
...msg,
|
|
1752
1853
|
group_id: gid,
|
|
1753
1854
|
group_aid: eventGroupAid,
|
|
1754
|
-
});
|
|
1855
|
+
}, 'pull');
|
|
1755
1856
|
client._markPublishedSeq(ns, seq);
|
|
1756
1857
|
client._clientLog.debug(`group.v2.pull recall tombstone delivered: group=${gid}, seq=${seq}`);
|
|
1757
1858
|
continue;
|
|
1758
1859
|
}
|
|
1759
1860
|
if (payloadObj) {
|
|
1760
1861
|
const payloadType = String(payloadObj.type ?? '').trim();
|
|
1761
|
-
if (payloadType !== 'e2ee.encrypted' && payloadType !== 'e2ee.group_encrypted') {
|
|
1862
|
+
if (payloadType !== 'e2ee.encrypted' && payloadType !== 'e2ee.group_encrypted' && payloadType !== 'e2ee.p2p_encrypted') {
|
|
1762
1863
|
let v1Msg = {
|
|
1763
1864
|
message_id: String(msg.message_id ?? ''),
|
|
1764
1865
|
from: String(msg.from_aid ?? ''),
|
|
@@ -1772,7 +1873,12 @@ export class V2E2EECoordinator {
|
|
|
1772
1873
|
};
|
|
1773
1874
|
v1Msg = normalizeGroupMentionMode(v1Msg, msg, msg.envelope_json);
|
|
1774
1875
|
attachGatewayProximity(v1Msg, msg);
|
|
1775
|
-
|
|
1876
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
1877
|
+
await client._publishPulledMessage('group.message_created', ns, seq, v1Msg, false);
|
|
1878
|
+
}
|
|
1879
|
+
else {
|
|
1880
|
+
client._markPublishedSeq(ns, seq);
|
|
1881
|
+
}
|
|
1776
1882
|
decrypted.push(v1Msg);
|
|
1777
1883
|
continue;
|
|
1778
1884
|
}
|
|
@@ -1795,6 +1901,28 @@ export class V2E2EECoordinator {
|
|
|
1795
1901
|
decrypted.push(v1Msg);
|
|
1796
1902
|
continue;
|
|
1797
1903
|
}
|
|
1904
|
+
if (payloadObj && ['e2ee.group_encrypted', 'e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(String(payloadObj.type ?? '').trim())) {
|
|
1905
|
+
const deferStatus = {};
|
|
1906
|
+
const plaintext = await client._decryptV2Message({ ...msg, envelope_json: JSON.stringify(payloadObj) }, true, true, true, true, deferStatus, true, 'pull');
|
|
1907
|
+
if (deferStatus.deferred) {
|
|
1908
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
1909
|
+
if (deferStatus.fromAid) {
|
|
1910
|
+
const key = `${deferStatus.fromAid}\u0000${deferStatus.senderDeviceId ?? ''}\u0000${deferStatus.groupId ?? ''}`;
|
|
1911
|
+
deferredKeyFetches.set(key, { fromAid: deferStatus.fromAid, senderDeviceId: deferStatus.senderDeviceId ?? '', groupId: deferStatus.groupId ?? '' });
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
if (plaintext) {
|
|
1915
|
+
plaintext.group_id = gid;
|
|
1916
|
+
plaintext.group_aid = eventGroupAid;
|
|
1917
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
1918
|
+
await client._publishPulledMessage('group.message_created', ns, seq, plaintext, false);
|
|
1919
|
+
}
|
|
1920
|
+
else {
|
|
1921
|
+
client._markPublishedSeq(ns, seq);
|
|
1922
|
+
}
|
|
1923
|
+
decrypted.push(plaintext);
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1798
1926
|
client._clientLog.debug(`group.v2.pull skipping V1 envelope group=${gid} seq=${seq} payload_type=${payloadObj ? String(payloadObj.type ?? '') : '<none>'} (V1 E2EE removed)`);
|
|
1799
1927
|
continue;
|
|
1800
1928
|
}
|
|
@@ -1803,7 +1931,7 @@ export class V2E2EECoordinator {
|
|
|
1803
1931
|
continue;
|
|
1804
1932
|
}
|
|
1805
1933
|
const deferStatus = {};
|
|
1806
|
-
let plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
1934
|
+
let plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true, 'pull');
|
|
1807
1935
|
if (deferStatus.deferred) {
|
|
1808
1936
|
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
1809
1937
|
}
|
|
@@ -1820,7 +1948,12 @@ export class V2E2EECoordinator {
|
|
|
1820
1948
|
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
1821
1949
|
plaintext.group_id = gid;
|
|
1822
1950
|
plaintext.group_aid = eventGroupAid;
|
|
1823
|
-
|
|
1951
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
1952
|
+
await client._publishPulledMessage('group.message_created', ns, seq, plaintext, false);
|
|
1953
|
+
}
|
|
1954
|
+
else {
|
|
1955
|
+
client._markPublishedSeq(ns, seq);
|
|
1956
|
+
}
|
|
1824
1957
|
decrypted.push(plaintext);
|
|
1825
1958
|
}
|
|
1826
1959
|
const hasServerCursor = cursor !== null && Object.prototype.hasOwnProperty.call(cursor, 'current_seq');
|
|
@@ -1829,7 +1962,7 @@ export class V2E2EECoordinator {
|
|
|
1829
1962
|
const retentionFloor = Math.max(Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0), Number(cursor?.retention_floor_seq ?? 0));
|
|
1830
1963
|
const visibilityFloor = Math.max(0, Math.max(0, Number(result.earliest_available_message_seq ?? 1) - 1), Number(cursor?.join_seq ?? 0));
|
|
1831
1964
|
const effectiveFloor = Math.max(retentionFloor, visibilityFloor);
|
|
1832
|
-
const commitTarget =
|
|
1965
|
+
const commitTarget = Math.max(pageContigBefore, Number.isFinite(effectiveFloor) ? effectiveFloor : 0, ownsCursor && pageCount === 1 ? deferredServerCursor : 0, cursorCurrentSeq, blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq);
|
|
1833
1966
|
let ackSeq = pageContigBefore;
|
|
1834
1967
|
let contigAdvanced = false;
|
|
1835
1968
|
if (ownsCursor) {
|
|
@@ -1867,6 +2000,7 @@ export class V2E2EECoordinator {
|
|
|
1867
2000
|
for (const fetch of deferredKeyFetches.values()) {
|
|
1868
2001
|
this.scheduleSenderIKFetch(fetch.fromAid, fetch.senderDeviceId, fetch.groupId);
|
|
1869
2002
|
}
|
|
2003
|
+
client._delivery.onPullPage?.(ns, decrypted.length - pageDecryptedBefore, hasMore, pageMaxSeq, typeof result.remaining === 'number' && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null, messages.length, client._seqTracker.getContiguousSeq(ns), pageMaxSeq);
|
|
1870
2004
|
if (ownsCursor && parsedCursorCurrentSeq !== null && cursorCurrentSeq > ackSeq) {
|
|
1871
2005
|
this.recordForwardCursor(ns, cursorCurrentSeq, ackSeq);
|
|
1872
2006
|
}
|
|
@@ -1875,16 +2009,15 @@ export class V2E2EECoordinator {
|
|
|
1875
2009
|
const knownServerCursorSeq = hasServerCursor
|
|
1876
2010
|
? cursorCurrentSeq
|
|
1877
2011
|
: (ownsCursor && pageCount === 1 ? deferredServerCursor : 0);
|
|
1878
|
-
const ackNeeded =
|
|
1879
|
-
&& ackSeq > 0
|
|
2012
|
+
const ackNeeded = ackSeq > 0
|
|
1880
2013
|
&& ackSeq > lastAutoAckSeq
|
|
1881
2014
|
&& ownsCursor
|
|
1882
2015
|
&& ((hasServerCursor && ackSeq > cursorCurrentSeq)
|
|
1883
2016
|
|| (contigAdvanced && ackSeq > knownServerCursorSeq));
|
|
1884
2017
|
if (ackNeeded) {
|
|
1885
2018
|
this.recordForwardAck(ns, ackSeq);
|
|
1886
|
-
const nextAfter = Math.max(
|
|
1887
|
-
const canContinuePage = messages.length > 0 && nextAfter > nextAfterSeq && ownsCursor;
|
|
2019
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
2020
|
+
const canContinuePage = blockedSeq <= 0 && messages.length > 0 && nextAfter > nextAfterSeq && ownsCursor;
|
|
1888
2021
|
if (canContinuePage) {
|
|
1889
2022
|
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
1890
2023
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
@@ -1894,7 +2027,7 @@ export class V2E2EECoordinator {
|
|
|
1894
2027
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
1895
2028
|
}
|
|
1896
2029
|
}
|
|
1897
|
-
const nextAfter = Math.max(
|
|
2030
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
1898
2031
|
if (!ownsCursor)
|
|
1899
2032
|
break;
|
|
1900
2033
|
const rawCount = messages.length;
|
|
@@ -1909,6 +2042,8 @@ export class V2E2EECoordinator {
|
|
|
1909
2042
|
hasMore,
|
|
1910
2043
|
serverHead,
|
|
1911
2044
|
pendingAckSeq,
|
|
2045
|
+
observedUpper: typeof client._seqTracker.getMaxSeenSeq === 'function'
|
|
2046
|
+
? client._seqTracker.getMaxSeenSeq(ns) : nextAfter,
|
|
1912
2047
|
});
|
|
1913
2048
|
if (!shouldContinue)
|
|
1914
2049
|
break;
|
|
@@ -1932,7 +2067,8 @@ export class V2E2EECoordinator {
|
|
|
1932
2067
|
pendingAckSeq = 0;
|
|
1933
2068
|
}
|
|
1934
2069
|
}
|
|
1935
|
-
|
|
2070
|
+
client._delivery.onPullWorkSettled?.();
|
|
2071
|
+
return deduplicatePulledResults(decrypted);
|
|
1936
2072
|
}
|
|
1937
2073
|
async confirmForwardGroupAck(groupId, upToSeq, groupAid) {
|
|
1938
2074
|
const ns = `group:${String(groupId ?? '').trim()}`;
|
|
@@ -2486,7 +2622,7 @@ export class V2E2EECoordinator {
|
|
|
2486
2622
|
async decryptV2PushMessage(data) {
|
|
2487
2623
|
if (!isJsonObject(data))
|
|
2488
2624
|
return null;
|
|
2489
|
-
return await this.client._decryptV2Message(data);
|
|
2625
|
+
return await this.client._decryptV2Message(data, false, false, false, false, undefined, false, 'inline_push');
|
|
2490
2626
|
}
|
|
2491
2627
|
async buildV2P2PEnvelope(opts) {
|
|
2492
2628
|
const client = this.client;
|