@agentunion/fastaun 0.5.10 → 0.5.11
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 +32 -0
- package/_packed_docs/CHANGELOG.md +32 -0
- package/_packed_docs/INDEX.md +3 -3
- package/_packed_docs/KITE_DOCS_GUIDE.md +1 -1
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +59 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +3 -2
- package/_packed_docs/sdk/INDEX.md +2 -1
- package/dist/client/delivery.d.ts +18 -4
- package/dist/client/delivery.js +179 -29
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.js +18 -4
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +2 -0
- package/dist/client/v2-e2ee.js +193 -42
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.js +63 -3
- package/dist/client.js.map +1 -1
- package/dist/transport.d.ts +4 -0
- package/dist/transport.js +141 -44
- 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
|
@@ -734,7 +734,7 @@ export class V2E2EECoordinator {
|
|
|
734
734
|
let plaintext = null;
|
|
735
735
|
const retryStatus = {};
|
|
736
736
|
try {
|
|
737
|
-
plaintext = await client._decryptV2Message(entry.msg, false, true, true, true, retryStatus);
|
|
737
|
+
plaintext = await client._decryptV2Message(entry.msg, false, true, true, true, retryStatus, false, 'pending_retry');
|
|
738
738
|
}
|
|
739
739
|
catch (exc) {
|
|
740
740
|
client._clientLog.warn(`V2 sender IK pending retry raised: key=${key} err=${formatE2EEError(exc)}`);
|
|
@@ -769,10 +769,10 @@ export class V2E2EECoordinator {
|
|
|
769
769
|
if (entry.groupId) {
|
|
770
770
|
plaintext = normalizeGroupMentionMode(plaintext, entry.msg, entry.msg.envelope_json);
|
|
771
771
|
plaintext.group_id = entry.groupId;
|
|
772
|
-
await client._publishPulledMessage('group.message_created', `group:${entry.groupId}`, seq, plaintext);
|
|
772
|
+
await client._publishPulledMessage('group.message_created', `group:${entry.groupId}`, seq, plaintext, false, 'pending_retry');
|
|
773
773
|
}
|
|
774
774
|
else {
|
|
775
|
-
await client._publishPulledMessage('message.received', `p2p:${client._aid ?? ''}`, seq, plaintext);
|
|
775
|
+
await client._publishPulledMessage('message.received', `p2p:${client._aid ?? ''}`, seq, plaintext, false, 'pending_retry');
|
|
776
776
|
}
|
|
777
777
|
client._clientLog.debug(`V2 sender IK pending retry delivered: key=${key}`);
|
|
778
778
|
}
|
|
@@ -1018,10 +1018,10 @@ export class V2E2EECoordinator {
|
|
|
1018
1018
|
if (String(msg.version ?? '') === 'v1') {
|
|
1019
1019
|
const legacy = isJsonObject(msg.legacy_v1)
|
|
1020
1020
|
? msg.legacy_v1 : {};
|
|
1021
|
-
const payload = legacy.payload;
|
|
1021
|
+
const payload = legacy.payload !== undefined ? legacy.payload : msg.payload;
|
|
1022
1022
|
const payloadType = isJsonObject(payload)
|
|
1023
1023
|
? String(payload.type ?? '').trim() : '';
|
|
1024
|
-
if (payload !== undefined && payload !== null && !['e2ee.encrypted', 'e2ee.group_encrypted'].includes(payloadType)) {
|
|
1024
|
+
if (payload !== undefined && payload !== null && !['e2ee.encrypted', 'e2ee.group_encrypted', 'e2ee.p2p_encrypted'].includes(payloadType)) {
|
|
1025
1025
|
plaintext = {
|
|
1026
1026
|
message_id: String(msg.message_id ?? ''),
|
|
1027
1027
|
from: String(msg.from_aid ?? ''),
|
|
@@ -1034,9 +1034,14 @@ export class V2E2EECoordinator {
|
|
|
1034
1034
|
};
|
|
1035
1035
|
attachGatewayProximity(plaintext, msg);
|
|
1036
1036
|
}
|
|
1037
|
+
else if (isJsonObject(payload)
|
|
1038
|
+
&& ['e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(payloadType)) {
|
|
1039
|
+
msg = { ...msg, envelope_json: JSON.stringify(payload) };
|
|
1040
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, undefined, false, source);
|
|
1041
|
+
}
|
|
1037
1042
|
}
|
|
1038
1043
|
else {
|
|
1039
|
-
plaintext = await client._decryptV2Message(msg, false, !history);
|
|
1044
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, undefined, false, source);
|
|
1040
1045
|
}
|
|
1041
1046
|
if (!plaintext) {
|
|
1042
1047
|
if (history)
|
|
@@ -1061,35 +1066,57 @@ export class V2E2EECoordinator {
|
|
|
1061
1066
|
let plaintext = null;
|
|
1062
1067
|
if (String(msg.version ?? '') === 'v1') {
|
|
1063
1068
|
const payload = msg.payload;
|
|
1069
|
+
const recall = typeof client._delivery?.recallEventFromGroupMessage === 'function'
|
|
1070
|
+
? client._delivery.recallEventFromGroupMessage(msg)
|
|
1071
|
+
: null;
|
|
1072
|
+
if (recall) {
|
|
1073
|
+
const recallPayload = {
|
|
1074
|
+
...recall,
|
|
1075
|
+
group_id: groupId,
|
|
1076
|
+
group_aid: groupAid,
|
|
1077
|
+
seq,
|
|
1078
|
+
};
|
|
1079
|
+
if (publish) {
|
|
1080
|
+
if (orderedPublish) {
|
|
1081
|
+
await client._delivery.publishOrderedMessage('group.message_recalled', `group:${groupId}`, seq, recallPayload, source);
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
await client._publishAppEvent('group.message_recalled', recallPayload, source);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
return recallPayload;
|
|
1088
|
+
}
|
|
1064
1089
|
if (payload === undefined || payload === null) {
|
|
1065
1090
|
if (history)
|
|
1066
1091
|
return this.historyDecryptFailure(msg, 'legacy payload is missing');
|
|
1067
1092
|
client._clientLog.warn(`Group Tail 缺少 payload 的 V1 行已跳过,连续性证明仍保留: group=${groupId}, seq=${seq}`);
|
|
1068
1093
|
return null;
|
|
1069
1094
|
}
|
|
1095
|
+
const payloadType = isJsonObject(payload)
|
|
1096
|
+
? String(payload.type ?? '').trim() : '';
|
|
1070
1097
|
if (isJsonObject(payload)
|
|
1071
|
-
&& ['e2ee.
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1098
|
+
&& ['e2ee.group_encrypted', 'e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(payloadType)) {
|
|
1099
|
+
msg = { ...msg, envelope_json: JSON.stringify(payload) };
|
|
1100
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, undefined, false, source);
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
plaintext = {
|
|
1104
|
+
message_id: String(msg.message_id ?? ''),
|
|
1105
|
+
from: String(msg.from_aid ?? ''),
|
|
1106
|
+
group_id: groupId,
|
|
1107
|
+
group_aid: groupAid,
|
|
1108
|
+
seq,
|
|
1109
|
+
type: String(msg.type ?? ''),
|
|
1110
|
+
timestamp: msg.t_server,
|
|
1111
|
+
payload: payload,
|
|
1112
|
+
encrypted: false,
|
|
1113
|
+
};
|
|
1114
|
+
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
1115
|
+
attachGatewayProximity(plaintext, msg);
|
|
1076
1116
|
}
|
|
1077
|
-
plaintext = {
|
|
1078
|
-
message_id: String(msg.message_id ?? ''),
|
|
1079
|
-
from: String(msg.from_aid ?? ''),
|
|
1080
|
-
group_id: groupId,
|
|
1081
|
-
group_aid: groupAid,
|
|
1082
|
-
seq,
|
|
1083
|
-
type: String(msg.type ?? ''),
|
|
1084
|
-
timestamp: msg.t_server,
|
|
1085
|
-
payload: payload,
|
|
1086
|
-
encrypted: false,
|
|
1087
|
-
};
|
|
1088
|
-
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
1089
|
-
attachGatewayProximity(plaintext, msg);
|
|
1090
1117
|
}
|
|
1091
1118
|
else {
|
|
1092
|
-
plaintext = await client._decryptV2Message(msg, false, !history);
|
|
1119
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, undefined, false, source);
|
|
1093
1120
|
if (plaintext) {
|
|
1094
1121
|
plaintext.group_id = groupId;
|
|
1095
1122
|
plaintext.group_aid = groupAid;
|
|
@@ -1129,6 +1156,8 @@ export class V2E2EECoordinator {
|
|
|
1129
1156
|
const afterSeq = strictWindowSeq(params.after_seq ?? 0, 'after_seq');
|
|
1130
1157
|
const limit = strictWindowLimit(params.limit ?? V2_PULL_DEFAULT_PAGE_LIMIT);
|
|
1131
1158
|
const ns = client._aid ? `p2p:${client._aid}` : '';
|
|
1159
|
+
if (ns)
|
|
1160
|
+
client._delivery.syncStarted(ns);
|
|
1132
1161
|
const result = await client._callRawV2Rpc('message.v2.pull', { window_mode: 'tail', after_seq: afterSeq, limit, _rpc_foreground: true });
|
|
1133
1162
|
const floor = Number(result.retention_floor_seq ?? 0);
|
|
1134
1163
|
const previous = ns ? client._seqTracker.getSyncState(ns) : null;
|
|
@@ -1153,6 +1182,15 @@ export class V2E2EECoordinator {
|
|
|
1153
1182
|
const ack = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
|
|
1154
1183
|
if (previous && ack > previous.ack)
|
|
1155
1184
|
await this.ackV2(ack);
|
|
1185
|
+
if (ns)
|
|
1186
|
+
client._delivery.syncProgress(ns, {
|
|
1187
|
+
rawCount: page.messages.length,
|
|
1188
|
+
pulledCount: decoded.length,
|
|
1189
|
+
remaining: result.remaining,
|
|
1190
|
+
hasMore: typeof result.has_more === 'boolean' ? result.has_more : undefined,
|
|
1191
|
+
currentSeq: ack,
|
|
1192
|
+
targetSeq: page.head,
|
|
1193
|
+
});
|
|
1156
1194
|
return { ...result, messages: decoded, raw_count: page.messages.length };
|
|
1157
1195
|
}
|
|
1158
1196
|
async historyV2Internal(params) {
|
|
@@ -1169,21 +1207,23 @@ export class V2E2EECoordinator {
|
|
|
1169
1207
|
}
|
|
1170
1208
|
return { ...result, messages: decoded };
|
|
1171
1209
|
}
|
|
1172
|
-
async
|
|
1210
|
+
async pullV2Impl(afterSeq = 0, limit = 50, opts) {
|
|
1173
1211
|
const client = this.client;
|
|
1174
1212
|
await client._ensureV2SessionReady('message.pull');
|
|
1175
1213
|
const ns = client._aid ? `p2p:${client._aid}` : '';
|
|
1214
|
+
if (ns)
|
|
1215
|
+
client._delivery.syncStarted(ns);
|
|
1176
1216
|
if (opts?.windowMode === 'tail') {
|
|
1177
1217
|
if (!opts.gateLocked) {
|
|
1178
1218
|
const key = `${ns}|tail|after=${afterSeq}|limit=${limit}`;
|
|
1179
|
-
return (await client._runPullSerialized(key, () => this.
|
|
1219
|
+
return (await client._runPullSerialized(key, () => this.pullV2Impl(afterSeq, limit, { ...opts, gateLocked: true }), false));
|
|
1180
1220
|
}
|
|
1181
1221
|
const result = await this.pullV2TailInternal({ window_mode: 'tail', after_seq: afterSeq, limit });
|
|
1182
1222
|
return (Array.isArray(result.messages) ? result.messages : []);
|
|
1183
1223
|
}
|
|
1184
1224
|
if (ns && !opts?.gateLocked) {
|
|
1185
1225
|
const key = `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`;
|
|
1186
|
-
return await client._runPullSerialized(key, async () => this.
|
|
1226
|
+
return await client._runPullSerialized(key, async () => this.pullV2Impl(afterSeq, limit, {
|
|
1187
1227
|
...(opts ?? {}),
|
|
1188
1228
|
gateLocked: true,
|
|
1189
1229
|
scheduleFollowup: true,
|
|
@@ -1253,6 +1293,7 @@ export class V2E2EECoordinator {
|
|
|
1253
1293
|
}
|
|
1254
1294
|
const deferredKeyFetches = new Map();
|
|
1255
1295
|
let blockedSeq = 0;
|
|
1296
|
+
const pageDecryptedBefore = decrypted.length;
|
|
1256
1297
|
for (const msg of messages) {
|
|
1257
1298
|
const seq = Number(msg.seq ?? 0);
|
|
1258
1299
|
if (!Number.isFinite(seq) || seq <= 0)
|
|
@@ -1260,11 +1301,12 @@ export class V2E2EECoordinator {
|
|
|
1260
1301
|
const version = String(msg.version ?? 'v2');
|
|
1261
1302
|
if (version === 'v1') {
|
|
1262
1303
|
const legacy = isJsonObject(msg.legacy_v1) ? msg.legacy_v1 : {};
|
|
1263
|
-
const legacyPayload = legacy.payload;
|
|
1304
|
+
const legacyPayload = legacy.payload !== undefined ? legacy.payload : msg.payload;
|
|
1264
1305
|
const payloadType = isJsonObject(legacyPayload)
|
|
1265
1306
|
? String(legacyPayload.type ?? '').trim()
|
|
1266
1307
|
: '';
|
|
1267
|
-
if (legacyPayload !== undefined && legacyPayload !== null
|
|
1308
|
+
if (legacyPayload !== undefined && legacyPayload !== null
|
|
1309
|
+
&& !['e2ee.encrypted', 'e2ee.group_encrypted', 'e2ee.p2p_encrypted'].includes(payloadType)) {
|
|
1268
1310
|
const v1Msg = {
|
|
1269
1311
|
message_id: String(msg.message_id ?? ''),
|
|
1270
1312
|
from: String(msg.from_aid ?? ''),
|
|
@@ -1286,6 +1328,25 @@ export class V2E2EECoordinator {
|
|
|
1286
1328
|
decrypted.push(v1Msg);
|
|
1287
1329
|
client._clientLog.debug(`message.v2.pull plaintext V1 delivered: seq=${seq}, ns=${ns || '<none>'}`);
|
|
1288
1330
|
}
|
|
1331
|
+
else if (isJsonObject(legacyPayload)
|
|
1332
|
+
&& ['e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(payloadType)) {
|
|
1333
|
+
const deferStatus = {};
|
|
1334
|
+
const plaintext = await client._decryptV2Message({ ...msg, envelope_json: JSON.stringify(legacyPayload) }, true, true, true, true, deferStatus, true, 'pull');
|
|
1335
|
+
if (deferStatus.deferred) {
|
|
1336
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
1337
|
+
if (deferStatus.fromAid) {
|
|
1338
|
+
const key = `${deferStatus.fromAid}\u0000${deferStatus.senderDeviceId ?? ''}\u0000${deferStatus.groupId ?? ''}`;
|
|
1339
|
+
deferredKeyFetches.set(key, { fromAid: deferStatus.fromAid, senderDeviceId: deferStatus.senderDeviceId ?? '', groupId: deferStatus.groupId ?? '' });
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
if (plaintext) {
|
|
1343
|
+
if (ns)
|
|
1344
|
+
await client._publishPulledMessage('message.received', ns, seq, plaintext, false);
|
|
1345
|
+
else
|
|
1346
|
+
await client._publishAppEvent('message.received', plaintext, 'pull');
|
|
1347
|
+
decrypted.push(plaintext);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1289
1350
|
else {
|
|
1290
1351
|
client._clientLog.debug(`message.v2.pull skipping V1 envelope seq=${seq} payload_type=${payloadType || '<none>'} (V1 E2EE removed)`);
|
|
1291
1352
|
}
|
|
@@ -1300,7 +1361,7 @@ export class V2E2EECoordinator {
|
|
|
1300
1361
|
client._v2Session.trackOldSPKMaxSeq(spkId, seq);
|
|
1301
1362
|
}
|
|
1302
1363
|
const deferStatus = {};
|
|
1303
|
-
const plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
1364
|
+
const plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true, 'pull');
|
|
1304
1365
|
if (deferStatus.deferred) {
|
|
1305
1366
|
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
1306
1367
|
}
|
|
@@ -1399,8 +1460,19 @@ export class V2E2EECoordinator {
|
|
|
1399
1460
|
this.scheduleSenderIKFetch(fetch.fromAid, fetch.senderDeviceId, fetch.groupId);
|
|
1400
1461
|
}
|
|
1401
1462
|
}
|
|
1463
|
+
if (ns)
|
|
1464
|
+
client._delivery.syncProgress(ns, {
|
|
1465
|
+
rawCount: messages.length,
|
|
1466
|
+
pulledCount: decrypted.length - pageDecryptedBefore,
|
|
1467
|
+
remaining: result.remaining,
|
|
1468
|
+
hasMore: hasMoreField ? hasMore : undefined,
|
|
1469
|
+
currentSeq: client._seqTracker.getContiguousSeq(ns),
|
|
1470
|
+
targetSeq: serverHead,
|
|
1471
|
+
});
|
|
1402
1472
|
const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
|
|
1403
1473
|
const rawCount = messages.length;
|
|
1474
|
+
if (blockedSeq > 0)
|
|
1475
|
+
break;
|
|
1404
1476
|
const shouldContinue = shouldContinueForwardPage({
|
|
1405
1477
|
rawCount,
|
|
1406
1478
|
nextAfterSeq,
|
|
@@ -1434,6 +1506,19 @@ export class V2E2EECoordinator {
|
|
|
1434
1506
|
client._clientLog.debug(`message.v2.pull done: requested_after_seq=${afterSeq}, pages=${pageCount}, decrypted=${decrypted.length}, ns=${ns || '<none>'}`);
|
|
1435
1507
|
return decrypted;
|
|
1436
1508
|
}
|
|
1509
|
+
async pullV2(afterSeq = 0, limit = 50, opts) {
|
|
1510
|
+
const ns = this.client._aid ? `p2p:${this.client._aid}` : '';
|
|
1511
|
+
if (!ns)
|
|
1512
|
+
return await this.pullV2Impl(afterSeq, limit, opts);
|
|
1513
|
+
this.client._delivery.syncStarted(ns);
|
|
1514
|
+
try {
|
|
1515
|
+
return await this.pullV2Impl(afterSeq, limit, opts);
|
|
1516
|
+
}
|
|
1517
|
+
catch (error) {
|
|
1518
|
+
this.client._delivery.onPullAborted?.();
|
|
1519
|
+
throw error;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1437
1522
|
async confirmForwardP2PAck(upToSeq) {
|
|
1438
1523
|
const ns = this.client._aid ? `p2p:${this.client._aid}` : '';
|
|
1439
1524
|
try {
|
|
@@ -1739,6 +1824,14 @@ export class V2E2EECoordinator {
|
|
|
1739
1824
|
const afterSeq = strictWindowSeq(params.after_seq ?? 0, 'after_seq');
|
|
1740
1825
|
const limit = strictWindowLimit(params.limit ?? V2_PULL_DEFAULT_PAGE_LIMIT);
|
|
1741
1826
|
const ns = `group:${groupId}`;
|
|
1827
|
+
const cursorParams = isJsonObject(params._group_cursor_params)
|
|
1828
|
+
? params._group_cursor_params : params;
|
|
1829
|
+
const requestDeviceId = String(cursorParams.device_id ?? '').trim();
|
|
1830
|
+
const requestSlotId = String(cursorParams.slot_id ?? '').trim();
|
|
1831
|
+
const ownsCursor = (!requestDeviceId || requestDeviceId === String(client._deviceId ?? ''))
|
|
1832
|
+
&& (!requestSlotId || requestSlotId === String(client._slotId ?? ''));
|
|
1833
|
+
if (ownsCursor)
|
|
1834
|
+
client._delivery.syncStarted(ns);
|
|
1742
1835
|
const result = await client._callRawV2Rpc('group.v2.pull', withExplicitGroupAid({
|
|
1743
1836
|
group_id: groupId,
|
|
1744
1837
|
window_mode: 'tail',
|
|
@@ -1771,6 +1864,15 @@ export class V2E2EECoordinator {
|
|
|
1771
1864
|
const ack = client._seqTracker.getContiguousSeq(ns);
|
|
1772
1865
|
if (ack > previous.ack)
|
|
1773
1866
|
await this.ackGroupV2(groupId, ack, groupAid);
|
|
1867
|
+
if (ownsCursor)
|
|
1868
|
+
client._delivery.syncProgress(ns, {
|
|
1869
|
+
rawCount: page.messages.length,
|
|
1870
|
+
pulledCount: decoded.length,
|
|
1871
|
+
remaining: result.remaining,
|
|
1872
|
+
hasMore: typeof result.has_more === 'boolean' ? result.has_more : undefined,
|
|
1873
|
+
currentSeq: ack,
|
|
1874
|
+
targetSeq: page.head,
|
|
1875
|
+
});
|
|
1774
1876
|
return { ...result, messages: decoded, raw_count: page.messages.length };
|
|
1775
1877
|
}
|
|
1776
1878
|
async historyGroupV2Internal(params) {
|
|
@@ -1806,7 +1908,7 @@ export class V2E2EECoordinator {
|
|
|
1806
1908
|
force: params.force === true,
|
|
1807
1909
|
});
|
|
1808
1910
|
}
|
|
1809
|
-
async
|
|
1911
|
+
async pullGroupV2Impl(groupId, afterSeq = 0, limit = 50, opts) {
|
|
1810
1912
|
const client = this.client;
|
|
1811
1913
|
await client._ensureV2SessionReady('group.pull');
|
|
1812
1914
|
const gid = String(groupId ?? '').trim();
|
|
@@ -1814,15 +1916,18 @@ export class V2E2EECoordinator {
|
|
|
1814
1916
|
throw new ValidationError('group.pull requires group_id');
|
|
1815
1917
|
let groupAid = String(opts?.groupAid ?? '').trim();
|
|
1816
1918
|
const ns = `group:${gid}`;
|
|
1919
|
+
if (opts?.ownsCursor !== false)
|
|
1920
|
+
client._delivery.syncStarted(ns);
|
|
1817
1921
|
if (opts?.windowMode === 'tail') {
|
|
1818
1922
|
if (!opts.gateLocked) {
|
|
1819
1923
|
const key = `${ns}|tail|after=${afterSeq}|limit=${limit}`;
|
|
1820
|
-
return (await client._runPullSerialized(key, () => this.
|
|
1924
|
+
return (await client._runPullSerialized(key, () => this.pullGroupV2Impl(gid, afterSeq, limit, {
|
|
1821
1925
|
...opts,
|
|
1822
1926
|
gateLocked: true,
|
|
1823
1927
|
}), false));
|
|
1824
1928
|
}
|
|
1825
1929
|
const result = await this.pullGroupV2TailInternal({
|
|
1930
|
+
...(opts?.cursorParams ?? {}),
|
|
1826
1931
|
group_id: String(opts.wireGroupId ?? gid),
|
|
1827
1932
|
group_aid: groupAid || undefined,
|
|
1828
1933
|
window_mode: 'tail',
|
|
@@ -1833,7 +1938,7 @@ export class V2E2EECoordinator {
|
|
|
1833
1938
|
}
|
|
1834
1939
|
if (!opts?.gateLocked) {
|
|
1835
1940
|
const key = `${ns}|forward|after=${afterSeq}|force=${opts?.force === true}|limit=${limit}`;
|
|
1836
|
-
return await client._runPullSerialized(key, async () => this.
|
|
1941
|
+
return await client._runPullSerialized(key, async () => this.pullGroupV2Impl(gid, afterSeq, limit, {
|
|
1837
1942
|
...(opts ?? {}),
|
|
1838
1943
|
gateLocked: true,
|
|
1839
1944
|
scheduleFollowup: true,
|
|
@@ -1916,28 +2021,31 @@ export class V2E2EECoordinator {
|
|
|
1916
2021
|
}
|
|
1917
2022
|
const deferredKeyFetches = new Map();
|
|
1918
2023
|
let blockedSeq = 0;
|
|
2024
|
+
const pageDecryptedBefore = decrypted.length;
|
|
1919
2025
|
for (const msg of messages) {
|
|
1920
2026
|
const seq = Number(msg.seq ?? 0);
|
|
1921
2027
|
if (!Number.isFinite(seq) || seq <= 0)
|
|
1922
2028
|
continue;
|
|
1923
2029
|
const version = String(msg.version ?? 'v2');
|
|
1924
2030
|
if (version === 'v1') {
|
|
1925
|
-
const
|
|
2031
|
+
const legacy = isJsonObject(msg.legacy_v1) ? msg.legacy_v1 : {};
|
|
2032
|
+
const payload = msg.payload !== undefined ? msg.payload : legacy.payload;
|
|
1926
2033
|
const payloadObj = isJsonObject(payload) ? payload : null;
|
|
2034
|
+
const payloadType = payloadObj ? String(payloadObj.type ?? '').trim() : '';
|
|
1927
2035
|
// 群撤回 tombstone(占位 / 通知):归一化为 group.message_recalled 事件,仍占 seq。
|
|
1928
|
-
if (client._delivery
|
|
2036
|
+
if (typeof client._delivery?.recallEventFromGroupMessage === 'function'
|
|
2037
|
+
&& client._delivery.recallEventFromGroupMessage(msg)) {
|
|
1929
2038
|
await client._delivery.publishGroupRecallTombstone(gid, seq, {
|
|
1930
2039
|
...msg,
|
|
1931
2040
|
group_id: gid,
|
|
1932
2041
|
group_aid: eventGroupAid,
|
|
1933
|
-
});
|
|
2042
|
+
}, 'pull');
|
|
1934
2043
|
client._markPublishedSeq(ns, seq);
|
|
1935
2044
|
client._clientLog.debug(`group.v2.pull recall tombstone delivered: group=${gid}, seq=${seq}`);
|
|
1936
2045
|
continue;
|
|
1937
2046
|
}
|
|
1938
2047
|
if (payloadObj) {
|
|
1939
|
-
|
|
1940
|
-
if (payloadType !== 'e2ee.encrypted' && payloadType !== 'e2ee.group_encrypted') {
|
|
2048
|
+
if (!['e2ee.encrypted', 'e2ee.group_encrypted', 'e2ee.p2p_encrypted'].includes(payloadType)) {
|
|
1941
2049
|
let v1Msg = {
|
|
1942
2050
|
message_id: String(msg.message_id ?? ''),
|
|
1943
2051
|
from: String(msg.from_aid ?? ''),
|
|
@@ -1976,7 +2084,26 @@ export class V2E2EECoordinator {
|
|
|
1976
2084
|
client._clientLog.debug(`group.v2.pull plaintext V1 delivered: group=${gid}, seq=${seq}`);
|
|
1977
2085
|
continue;
|
|
1978
2086
|
}
|
|
1979
|
-
|
|
2087
|
+
if (payloadObj && ['e2ee.group_encrypted', 'e2ee.p2p_encrypted', 'e2ee.encrypted'].includes(payloadType)) {
|
|
2088
|
+
const deferStatus = {};
|
|
2089
|
+
const plaintext = await client._decryptV2Message({ ...msg, envelope_json: JSON.stringify(payloadObj) }, true, true, true, true, deferStatus, true, 'pull');
|
|
2090
|
+
if (deferStatus.deferred) {
|
|
2091
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
2092
|
+
if (deferStatus.fromAid) {
|
|
2093
|
+
const key = `${deferStatus.fromAid}\u0000${deferStatus.senderDeviceId ?? ''}\u0000${deferStatus.groupId ?? ''}`;
|
|
2094
|
+
deferredKeyFetches.set(key, { fromAid: deferStatus.fromAid, senderDeviceId: deferStatus.senderDeviceId ?? '', groupId: deferStatus.groupId ?? '' });
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
if (plaintext) {
|
|
2098
|
+
plaintext.group_id = gid;
|
|
2099
|
+
plaintext.group_aid = eventGroupAid;
|
|
2100
|
+
await client._publishPulledMessage('group.message_created', ns, seq, plaintext, false);
|
|
2101
|
+
decrypted.push(plaintext);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
else {
|
|
2105
|
+
client._clientLog.debug(`group.v2.pull skipping V1 envelope group=${gid} seq=${seq} payload_type=${payloadObj ? String(payloadObj.type ?? '') : '<none>'} (V1 E2EE removed)`);
|
|
2106
|
+
}
|
|
1980
2107
|
continue;
|
|
1981
2108
|
}
|
|
1982
2109
|
if (version !== 'v2') {
|
|
@@ -1984,7 +2111,7 @@ export class V2E2EECoordinator {
|
|
|
1984
2111
|
continue;
|
|
1985
2112
|
}
|
|
1986
2113
|
const deferStatus = {};
|
|
1987
|
-
let plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
2114
|
+
let plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true, 'pull');
|
|
1988
2115
|
if (deferStatus.deferred) {
|
|
1989
2116
|
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq) : seq;
|
|
1990
2117
|
}
|
|
@@ -2079,10 +2206,20 @@ export class V2E2EECoordinator {
|
|
|
2079
2206
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
2080
2207
|
}
|
|
2081
2208
|
}
|
|
2209
|
+
client._delivery.syncProgress(ns, {
|
|
2210
|
+
rawCount: messages.length,
|
|
2211
|
+
pulledCount: decrypted.length - pageDecryptedBefore,
|
|
2212
|
+
remaining: result.remaining,
|
|
2213
|
+
hasMore: hasMoreField ? hasMore : undefined,
|
|
2214
|
+
currentSeq: client._seqTracker.getContiguousSeq(ns),
|
|
2215
|
+
targetSeq: serverHead,
|
|
2216
|
+
});
|
|
2082
2217
|
const nextAfter = Math.max(pageMaxSeq, nextAfterSeq);
|
|
2083
2218
|
if (!ownsCursor)
|
|
2084
2219
|
break;
|
|
2085
2220
|
const rawCount = messages.length;
|
|
2221
|
+
if (blockedSeq > 0)
|
|
2222
|
+
break;
|
|
2086
2223
|
const shouldContinue = shouldContinueForwardPage({
|
|
2087
2224
|
rawCount,
|
|
2088
2225
|
nextAfterSeq,
|
|
@@ -2116,6 +2253,20 @@ export class V2E2EECoordinator {
|
|
|
2116
2253
|
client._clientLog.debug(`group.v2.pull done: group=${gid}, requested_after_seq=${afterSeq}, pages=${pageCount}, decrypted=${decrypted.length}, ns=${ns}`);
|
|
2117
2254
|
return decrypted;
|
|
2118
2255
|
}
|
|
2256
|
+
async pullGroupV2(groupId, afterSeq = 0, limit = 50, opts) {
|
|
2257
|
+
if (opts?.ownsCursor === false) {
|
|
2258
|
+
return await this.pullGroupV2Impl(groupId, afterSeq, limit, opts);
|
|
2259
|
+
}
|
|
2260
|
+
const ns = `group:${String(groupId ?? '').trim()}`;
|
|
2261
|
+
this.client._delivery.syncStarted(ns);
|
|
2262
|
+
try {
|
|
2263
|
+
return await this.pullGroupV2Impl(groupId, afterSeq, limit, opts);
|
|
2264
|
+
}
|
|
2265
|
+
catch (error) {
|
|
2266
|
+
this.client._delivery.onPullAborted?.();
|
|
2267
|
+
throw error;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2119
2270
|
async confirmForwardGroupAck(groupId, upToSeq, groupAid) {
|
|
2120
2271
|
const ns = `group:${String(groupId ?? '').trim()}`;
|
|
2121
2272
|
try {
|
|
@@ -2675,7 +2826,7 @@ export class V2E2EECoordinator {
|
|
|
2675
2826
|
async decryptV2PushMessage(data) {
|
|
2676
2827
|
if (!isJsonObject(data))
|
|
2677
2828
|
return null;
|
|
2678
|
-
return await this.client._decryptV2Message(data, false, false, false, false);
|
|
2829
|
+
return await this.client._decryptV2Message(data, false, false, false, false, undefined, false, 'inline_push');
|
|
2679
2830
|
}
|
|
2680
2831
|
handleGroupChangedSpk(data, groupId, action) {
|
|
2681
2832
|
if (!this.client._v2Session || !groupId || !MEMBERSHIP_ACTIONS.has(action))
|