@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/bundle.js
CHANGED
|
@@ -460,7 +460,7 @@ var init_indexeddb_store = __esm({
|
|
|
460
460
|
});
|
|
461
461
|
|
|
462
462
|
// src/version.ts
|
|
463
|
-
var VERSION = "0.5.
|
|
463
|
+
var VERSION = "0.5.12";
|
|
464
464
|
|
|
465
465
|
// src/types.ts
|
|
466
466
|
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
@@ -1296,6 +1296,8 @@ var GatewayDiscovery = class {
|
|
|
1296
1296
|
var MAX_WS_PAYLOAD_SIZE = 1e6;
|
|
1297
1297
|
var MAX_RPC_INFLIGHT = 16;
|
|
1298
1298
|
var MAX_BACKGROUND_RPC_INFLIGHT = 8;
|
|
1299
|
+
var WORKER_START_TIMEOUT_MS = 2e3;
|
|
1300
|
+
var WORKER_OPEN_TIMEOUT_MS = 2e3;
|
|
1299
1301
|
var _noopLog3 = { error: () => {
|
|
1300
1302
|
}, warn: () => {
|
|
1301
1303
|
}, info: () => {
|
|
@@ -1304,6 +1306,7 @@ var _noopLog3 = { error: () => {
|
|
|
1304
1306
|
var _rpcIdCounter = 0;
|
|
1305
1307
|
var WORKER_WEBSOCKET_SOURCE = `
|
|
1306
1308
|
let socket = null;
|
|
1309
|
+
self.postMessage({ type: 'ready' });
|
|
1307
1310
|
self.onmessage = (event) => {
|
|
1308
1311
|
const command = event.data || {};
|
|
1309
1312
|
if (command.type === 'connect') {
|
|
@@ -1343,11 +1346,19 @@ var _WorkerWebSocketProxy = class _WorkerWebSocketProxy {
|
|
|
1343
1346
|
__publicField(this, "onmessage", null);
|
|
1344
1347
|
__publicField(this, "onerror", null);
|
|
1345
1348
|
__publicField(this, "onclose", null);
|
|
1349
|
+
__publicField(this, "_url");
|
|
1346
1350
|
__publicField(this, "_worker");
|
|
1347
1351
|
__publicField(this, "_workerUrl");
|
|
1352
|
+
__publicField(this, "_nativeSocket", null);
|
|
1353
|
+
__publicField(this, "_workerReady", false);
|
|
1354
|
+
__publicField(this, "_opened", false);
|
|
1355
|
+
__publicField(this, "_closedEventEmitted", false);
|
|
1356
|
+
__publicField(this, "_workerStartTimer", null);
|
|
1357
|
+
__publicField(this, "_workerOpenTimer", null);
|
|
1348
1358
|
__publicField(this, "_listeners", /* @__PURE__ */ new Map());
|
|
1349
1359
|
__publicField(this, "_pendingSends", /* @__PURE__ */ new Map());
|
|
1350
1360
|
__publicField(this, "_sendSeq", 0);
|
|
1361
|
+
this._url = url;
|
|
1351
1362
|
this._workerUrl = URL.createObjectURL(new Blob([WORKER_WEBSOCKET_SOURCE], { type: "text/javascript" }));
|
|
1352
1363
|
try {
|
|
1353
1364
|
this._worker = new Worker(this._workerUrl);
|
|
@@ -1355,17 +1366,35 @@ var _WorkerWebSocketProxy = class _WorkerWebSocketProxy {
|
|
|
1355
1366
|
URL.revokeObjectURL(this._workerUrl);
|
|
1356
1367
|
throw error;
|
|
1357
1368
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1369
|
+
const worker = this._worker;
|
|
1370
|
+
worker.onmessage = (event) => this._handleWorkerMessage(event.data);
|
|
1371
|
+
worker.onerror = (event) => {
|
|
1372
|
+
event.preventDefault?.();
|
|
1373
|
+
if (!this._opened) {
|
|
1374
|
+
this._fallbackToNative();
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
this._fallbackToNative(true);
|
|
1378
|
+
};
|
|
1379
|
+
this._workerStartTimer = globalThis.setTimeout(() => this._fallbackToNative(), WORKER_START_TIMEOUT_MS);
|
|
1361
1380
|
}
|
|
1362
1381
|
send(data) {
|
|
1363
1382
|
if (this.readyState !== _WorkerWebSocketProxy.OPEN) return Promise.reject(new Error("websocket is not open"));
|
|
1383
|
+
if (this._nativeSocket) {
|
|
1384
|
+
try {
|
|
1385
|
+
this._nativeSocket.send(data);
|
|
1386
|
+
return Promise.resolve();
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
return Promise.reject(error instanceof Error ? error : new Error(String(error)));
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
const worker = this._worker;
|
|
1392
|
+
if (!worker) return Promise.reject(new Error("websocket worker is not available"));
|
|
1364
1393
|
const id = ++this._sendSeq;
|
|
1365
1394
|
return new Promise((resolve, reject) => {
|
|
1366
1395
|
this._pendingSends.set(id, { resolve, reject });
|
|
1367
1396
|
try {
|
|
1368
|
-
|
|
1397
|
+
worker.postMessage({ type: "send", id, data });
|
|
1369
1398
|
} catch (error) {
|
|
1370
1399
|
this._pendingSends.delete(id);
|
|
1371
1400
|
reject(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -1375,7 +1404,24 @@ var _WorkerWebSocketProxy = class _WorkerWebSocketProxy {
|
|
|
1375
1404
|
close(code, reason) {
|
|
1376
1405
|
if (this.readyState === _WorkerWebSocketProxy.CLOSED) return;
|
|
1377
1406
|
this.readyState = _WorkerWebSocketProxy.CLOSING;
|
|
1378
|
-
this.
|
|
1407
|
+
if (this._nativeSocket) {
|
|
1408
|
+
try {
|
|
1409
|
+
this._nativeSocket.close(code, reason);
|
|
1410
|
+
} catch {
|
|
1411
|
+
this._emitClose(new CloseEvent("close", { code: code ?? 1e3, reason: reason ?? "", wasClean: true }));
|
|
1412
|
+
}
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
if (!this._workerReady || !this._worker) {
|
|
1416
|
+
this._disposeWorker();
|
|
1417
|
+
this._emitClose(new CloseEvent("close", { code: code ?? 1e3, reason: reason ?? "", wasClean: true }));
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
1420
|
+
try {
|
|
1421
|
+
this._worker.postMessage({ type: "close", code, reason });
|
|
1422
|
+
} catch {
|
|
1423
|
+
this._fallbackToNative();
|
|
1424
|
+
}
|
|
1379
1425
|
}
|
|
1380
1426
|
addEventListener(type, listener) {
|
|
1381
1427
|
const callback = typeof listener === "function" ? listener : (event) => listener.handleEvent(event);
|
|
@@ -1387,6 +1433,21 @@ var _WorkerWebSocketProxy = class _WorkerWebSocketProxy {
|
|
|
1387
1433
|
if (typeof listener === "function") this._listeners.get(type)?.delete(listener);
|
|
1388
1434
|
}
|
|
1389
1435
|
_handleWorkerMessage(reply) {
|
|
1436
|
+
if (reply.type === "ready") {
|
|
1437
|
+
if (this._workerReady || !this._worker) return;
|
|
1438
|
+
this._workerReady = true;
|
|
1439
|
+
this._clearWorkerStartTimer();
|
|
1440
|
+
try {
|
|
1441
|
+
this._worker.postMessage({ type: "connect", url: this._url });
|
|
1442
|
+
this._workerOpenTimer = globalThis.setTimeout(
|
|
1443
|
+
() => this._fallbackToNative(),
|
|
1444
|
+
WORKER_OPEN_TIMEOUT_MS
|
|
1445
|
+
);
|
|
1446
|
+
} catch {
|
|
1447
|
+
this._fallbackToNative();
|
|
1448
|
+
}
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1390
1451
|
if (reply.type === "send_result" && reply.id !== void 0) {
|
|
1391
1452
|
const pending = this._pendingSends.get(reply.id);
|
|
1392
1453
|
if (!pending) return;
|
|
@@ -1396,6 +1457,8 @@ var _WorkerWebSocketProxy = class _WorkerWebSocketProxy {
|
|
|
1396
1457
|
return;
|
|
1397
1458
|
}
|
|
1398
1459
|
if (reply.type === "open") {
|
|
1460
|
+
this._clearWorkerOpenTimer();
|
|
1461
|
+
this._opened = true;
|
|
1399
1462
|
this.readyState = _WorkerWebSocketProxy.OPEN;
|
|
1400
1463
|
const event = new Event("open");
|
|
1401
1464
|
this.onopen?.(event);
|
|
@@ -1409,24 +1472,94 @@ var _WorkerWebSocketProxy = class _WorkerWebSocketProxy {
|
|
|
1409
1472
|
return;
|
|
1410
1473
|
}
|
|
1411
1474
|
if (reply.type === "error") {
|
|
1475
|
+
if (!this._opened && this.readyState === _WorkerWebSocketProxy.CONNECTING) {
|
|
1476
|
+
this._fallbackToNative();
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1412
1479
|
this._emitError(reply.message || "websocket worker error");
|
|
1413
1480
|
return;
|
|
1414
1481
|
}
|
|
1415
1482
|
if (reply.type === "close") {
|
|
1416
|
-
this.readyState
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1483
|
+
if (!this._opened && this.readyState === _WorkerWebSocketProxy.CONNECTING) {
|
|
1484
|
+
this._fallbackToNative();
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
this._emitClose(new CloseEvent("close", {
|
|
1420
1488
|
code: reply.code ?? 1006,
|
|
1421
1489
|
reason: reply.reason ?? "",
|
|
1422
1490
|
wasClean: reply.wasClean === true
|
|
1423
|
-
});
|
|
1424
|
-
this.onclose?.(event);
|
|
1425
|
-
this._emit("close", event);
|
|
1426
|
-
this._worker.terminate();
|
|
1427
|
-
URL.revokeObjectURL(this._workerUrl);
|
|
1491
|
+
}));
|
|
1428
1492
|
}
|
|
1429
1493
|
}
|
|
1494
|
+
_fallbackToNative(force = false) {
|
|
1495
|
+
if (this._nativeSocket || this.readyState === _WorkerWebSocketProxy.CLOSED) return;
|
|
1496
|
+
if (!force && (this.readyState !== _WorkerWebSocketProxy.CONNECTING || this._opened)) return;
|
|
1497
|
+
const wasOpened = this._opened;
|
|
1498
|
+
this._opened = false;
|
|
1499
|
+
this.readyState = _WorkerWebSocketProxy.CONNECTING;
|
|
1500
|
+
this._disposeWorker();
|
|
1501
|
+
try {
|
|
1502
|
+
const socket = new WebSocket(this._url);
|
|
1503
|
+
this._nativeSocket = socket;
|
|
1504
|
+
socket.onopen = (event) => {
|
|
1505
|
+
this._opened = true;
|
|
1506
|
+
this.readyState = _WorkerWebSocketProxy.OPEN;
|
|
1507
|
+
if (!wasOpened) {
|
|
1508
|
+
this.onopen?.(event);
|
|
1509
|
+
this._emit("open", event);
|
|
1510
|
+
}
|
|
1511
|
+
};
|
|
1512
|
+
socket.onmessage = (event) => {
|
|
1513
|
+
this.onmessage?.(event);
|
|
1514
|
+
this._emit("message", event);
|
|
1515
|
+
};
|
|
1516
|
+
socket.onerror = (event) => {
|
|
1517
|
+
this.onerror?.(event);
|
|
1518
|
+
this._emit("error", event);
|
|
1519
|
+
};
|
|
1520
|
+
socket.onclose = (event) => this._emitClose(event);
|
|
1521
|
+
} catch (error) {
|
|
1522
|
+
this.readyState = _WorkerWebSocketProxy.CLOSED;
|
|
1523
|
+
this._emitError(error instanceof Error ? error.message : String(error));
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
_emitClose(event) {
|
|
1527
|
+
if (this._closedEventEmitted) return;
|
|
1528
|
+
this._closedEventEmitted = true;
|
|
1529
|
+
this.readyState = _WorkerWebSocketProxy.CLOSED;
|
|
1530
|
+
for (const pending of this._pendingSends.values()) pending.reject(new Error("websocket closed"));
|
|
1531
|
+
this._pendingSends.clear();
|
|
1532
|
+
this.onclose?.(event);
|
|
1533
|
+
this._emit("close", event);
|
|
1534
|
+
this._disposeWorker();
|
|
1535
|
+
this._nativeSocket = null;
|
|
1536
|
+
}
|
|
1537
|
+
_clearWorkerStartTimer() {
|
|
1538
|
+
if (this._workerStartTimer === null) return;
|
|
1539
|
+
globalThis.clearTimeout(this._workerStartTimer);
|
|
1540
|
+
this._workerStartTimer = null;
|
|
1541
|
+
}
|
|
1542
|
+
_clearWorkerOpenTimer() {
|
|
1543
|
+
if (this._workerOpenTimer === null) return;
|
|
1544
|
+
globalThis.clearTimeout(this._workerOpenTimer);
|
|
1545
|
+
this._workerOpenTimer = null;
|
|
1546
|
+
}
|
|
1547
|
+
_disposeWorker() {
|
|
1548
|
+
this._clearWorkerStartTimer();
|
|
1549
|
+
this._clearWorkerOpenTimer();
|
|
1550
|
+
for (const pending of this._pendingSends.values()) pending.reject(new Error("websocket worker unavailable"));
|
|
1551
|
+
this._pendingSends.clear();
|
|
1552
|
+
const worker = this._worker;
|
|
1553
|
+
this._worker = null;
|
|
1554
|
+
if (worker) {
|
|
1555
|
+
worker.onmessage = null;
|
|
1556
|
+
worker.onerror = null;
|
|
1557
|
+
worker.terminate();
|
|
1558
|
+
}
|
|
1559
|
+
const workerUrl = this._workerUrl;
|
|
1560
|
+
this._workerUrl = null;
|
|
1561
|
+
if (workerUrl && typeof URL.revokeObjectURL === "function") URL.revokeObjectURL(workerUrl);
|
|
1562
|
+
}
|
|
1430
1563
|
_emitError(message) {
|
|
1431
1564
|
const event = new ErrorEvent("error", { message });
|
|
1432
1565
|
this.onerror?.(event);
|
|
@@ -1614,6 +1747,9 @@ var EVENT_NAME_MAP = {
|
|
|
1614
1747
|
"message.recalled": "message.recalled",
|
|
1615
1748
|
"message.ack": "message.ack",
|
|
1616
1749
|
"group.changed": "group.changed",
|
|
1750
|
+
"group.invite_created": "group.invite_created",
|
|
1751
|
+
"group.invite_received": "group.invite_received",
|
|
1752
|
+
"group.invite_finalized": "group.invite_finalized",
|
|
1617
1753
|
"group.message_created": "group.message_created",
|
|
1618
1754
|
"group.message_recalled": "group.message_recalled",
|
|
1619
1755
|
"group.state_committed": "group.state_committed",
|
|
@@ -4070,7 +4206,6 @@ var SeqTracker = class {
|
|
|
4070
4206
|
if (headSeq === t.headSeq) {
|
|
4071
4207
|
if (windowStartSeq <= t.tailSeq) return false;
|
|
4072
4208
|
t.tailSeq = windowStartSeq;
|
|
4073
|
-
this._normalizeWindow(t);
|
|
4074
4209
|
return true;
|
|
4075
4210
|
}
|
|
4076
4211
|
if (t.headSeq + pageLimit < headSeq && windowStartSeq <= t.headSeq + 1) {
|
|
@@ -4079,7 +4214,6 @@ var SeqTracker = class {
|
|
|
4079
4214
|
if (windowStartSeq > t.headSeq + 1) t.tailSeq = windowStartSeq;
|
|
4080
4215
|
t.headSeq = headSeq;
|
|
4081
4216
|
t.maxSeenSeq = Math.max(t.maxSeenSeq, headSeq);
|
|
4082
|
-
this._normalizeWindow(t);
|
|
4083
4217
|
return true;
|
|
4084
4218
|
}
|
|
4085
4219
|
/** Push 专用:只扩展上界 maxSeenSeq,不动 contiguousSeq。 */
|
|
@@ -4154,8 +4288,8 @@ var SeqTracker = class {
|
|
|
4154
4288
|
}
|
|
4155
4289
|
return true;
|
|
4156
4290
|
}
|
|
4157
|
-
/** 提交已校验的 Forward
|
|
4158
|
-
onPullResult(ns, messages, afterSeq) {
|
|
4291
|
+
/** 提交已校验的 Forward 原始页;缺号只有服务端明确证明时才能跳过。 */
|
|
4292
|
+
onPullResult(ns, messages, afterSeq, contiguousSeq) {
|
|
4159
4293
|
const t = this._get(ns);
|
|
4160
4294
|
const pulledSeqs = /* @__PURE__ */ new Set();
|
|
4161
4295
|
for (const m of messages) {
|
|
@@ -4185,6 +4319,7 @@ var SeqTracker = class {
|
|
|
4185
4319
|
if (maxPulled > 0) {
|
|
4186
4320
|
t.maxSeenSeq = Math.max(t.maxSeenSeq, maxPulled);
|
|
4187
4321
|
}
|
|
4322
|
+
this._tryAdvance(t);
|
|
4188
4323
|
if (maxPulled > t.contiguousSeq) {
|
|
4189
4324
|
for (const [key, probe] of t.pendingGaps) {
|
|
4190
4325
|
if (probe.gapEnd <= maxPulled) t.pendingGaps.delete(key);
|
|
@@ -4194,7 +4329,11 @@ var SeqTracker = class {
|
|
|
4194
4329
|
}
|
|
4195
4330
|
t.contiguousSeq = maxPulled;
|
|
4196
4331
|
}
|
|
4197
|
-
|
|
4332
|
+
let proof = Number.isSafeInteger(contiguousSeq) && contiguousSeq > 0 ? contiguousSeq : 0;
|
|
4333
|
+
if (proof > 0) {
|
|
4334
|
+
if (proof > t.contiguousSeq) this.forceContiguousSeq(ns, proof);
|
|
4335
|
+
}
|
|
4336
|
+
this._normalizeWindow(t);
|
|
4198
4337
|
const remaining = [...t.receivedSeqs].filter((seq2) => seq2 > t.contiguousSeq);
|
|
4199
4338
|
if (remaining.length > 0) {
|
|
4200
4339
|
const firstPending = Math.min(...remaining);
|
|
@@ -4373,7 +4512,6 @@ var SeqTracker = class {
|
|
|
4373
4512
|
restored.tailSeq = Number(tailRaw);
|
|
4374
4513
|
restored.headSeq = Number(headRaw);
|
|
4375
4514
|
restored.maxSeenSeq = Math.max(ack, restored.headSeq);
|
|
4376
|
-
this._normalizeWindow(restored);
|
|
4377
4515
|
this._trackers.set(ns, restored);
|
|
4378
4516
|
}
|
|
4379
4517
|
return issues;
|
|
@@ -4873,10 +5011,33 @@ function positiveSafeSequenceHint(value) {
|
|
|
4873
5011
|
const parsed = Number(value);
|
|
4874
5012
|
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 0;
|
|
4875
5013
|
}
|
|
5014
|
+
function hasNonEmptyInlineMessage(value) {
|
|
5015
|
+
return isJsonObject(value) && Object.keys(value).length > 0;
|
|
5016
|
+
}
|
|
4876
5017
|
function nonNegativeSafeSequenceHint(value) {
|
|
4877
5018
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return null;
|
|
4878
5019
|
return value;
|
|
4879
5020
|
}
|
|
5021
|
+
function canonicalDeliverySource(source) {
|
|
5022
|
+
switch (String(source ?? "").trim()) {
|
|
5023
|
+
case "group-push":
|
|
5024
|
+
case "ordered":
|
|
5025
|
+
case "legacy":
|
|
5026
|
+
return "push";
|
|
5027
|
+
case "tail":
|
|
5028
|
+
case "pull-drained":
|
|
5029
|
+
case "pull_drained":
|
|
5030
|
+
return "pull";
|
|
5031
|
+
case "inline-push":
|
|
5032
|
+
return "inline_push";
|
|
5033
|
+
case "pending-retry":
|
|
5034
|
+
return "pending_retry";
|
|
5035
|
+
case "":
|
|
5036
|
+
return "direct";
|
|
5037
|
+
default:
|
|
5038
|
+
return String(source).trim();
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
4880
5041
|
function deduplicatePlainForwardPageMessages(value, afterSeq) {
|
|
4881
5042
|
if (!Array.isArray(value)) return [];
|
|
4882
5043
|
const bySeq = /* @__PURE__ */ new Map();
|
|
@@ -4905,6 +5066,9 @@ function p2pAppEventFromPlainPullMessage(message) {
|
|
|
4905
5066
|
var MessageDeliveryEngine = class {
|
|
4906
5067
|
constructor(runtime) {
|
|
4907
5068
|
__publicField(this, "runtime");
|
|
5069
|
+
__publicField(this, "syncRun", 0);
|
|
5070
|
+
__publicField(this, "syncingNamespaces", /* @__PURE__ */ new Set());
|
|
5071
|
+
__publicField(this, "syncSessions", /* @__PURE__ */ new Map());
|
|
4908
5072
|
__publicField(this, "pendingPullDeliveryChanges", null);
|
|
4909
5073
|
__publicField(this, "deliveryGeneration", 0);
|
|
4910
5074
|
__publicField(this, "realtimeTailResults", null);
|
|
@@ -4925,6 +5089,7 @@ var MessageDeliveryEngine = class {
|
|
|
4925
5089
|
this.runtime = runtime;
|
|
4926
5090
|
}
|
|
4927
5091
|
resetInlineAckState() {
|
|
5092
|
+
this.syncStopped("aborted");
|
|
4928
5093
|
this.inlineGeneration += 1;
|
|
4929
5094
|
this.deliveryGeneration += 1;
|
|
4930
5095
|
this.pendingPullDeliveryChanges = null;
|
|
@@ -4940,6 +5105,8 @@ var MessageDeliveryEngine = class {
|
|
|
4940
5105
|
this.pendingP2PInlineAcks = null;
|
|
4941
5106
|
this.pendingGroupInlineAcks = null;
|
|
4942
5107
|
this.pendingGroupInlineAckNamespaces = null;
|
|
5108
|
+
this.syncingNamespaces.clear();
|
|
5109
|
+
this.syncSessions.clear();
|
|
4943
5110
|
}
|
|
4944
5111
|
isInlineGenerationCurrent(generation) {
|
|
4945
5112
|
return generation === this.inlineGeneration;
|
|
@@ -4967,6 +5134,91 @@ var MessageDeliveryEngine = class {
|
|
|
4967
5134
|
endRealtimeSync(ns) {
|
|
4968
5135
|
this.realtimeSyncing?.delete(ns);
|
|
4969
5136
|
}
|
|
5137
|
+
onPullStarted(ns) {
|
|
5138
|
+
if (!ns || this.syncingNamespaces.has(ns)) return;
|
|
5139
|
+
if (this.syncingNamespaces.size === 0) {
|
|
5140
|
+
this.syncRun += 1;
|
|
5141
|
+
this.syncSessions.clear();
|
|
5142
|
+
this.runtime.client._dispatcher?.enqueue?.("sync.started", {
|
|
5143
|
+
run_id: this.syncRun,
|
|
5144
|
+
source: "pull",
|
|
5145
|
+
syncing: true,
|
|
5146
|
+
namespaces_pending: 1,
|
|
5147
|
+
received_total: 0,
|
|
5148
|
+
namespace: ns,
|
|
5149
|
+
started_at: Date.now()
|
|
5150
|
+
});
|
|
5151
|
+
}
|
|
5152
|
+
this.syncingNamespaces.add(ns);
|
|
5153
|
+
this.syncSessions.set(ns, { pages: 0, raw: 0, pulled: 0 });
|
|
5154
|
+
}
|
|
5155
|
+
onPullPage(ns, pulledCount, hasMore, maxSeen, remaining, rawCount = pulledCount, currentSeq, targetSeq) {
|
|
5156
|
+
this.onPullStarted(ns);
|
|
5157
|
+
if (!ns) return;
|
|
5158
|
+
const session = this.syncSessions.get(ns) ?? { pages: 0, raw: 0, pulled: 0 };
|
|
5159
|
+
session.pages += 1;
|
|
5160
|
+
session.raw += Math.max(0, rawCount);
|
|
5161
|
+
session.pulled += Math.max(0, pulledCount);
|
|
5162
|
+
this.syncSessions.set(ns, session);
|
|
5163
|
+
const received = session.pulled;
|
|
5164
|
+
const progress = {
|
|
5165
|
+
run_id: this.syncRun,
|
|
5166
|
+
source: "pull",
|
|
5167
|
+
namespace: ns,
|
|
5168
|
+
page: session.pages,
|
|
5169
|
+
page_raw_count: Math.max(0, rawCount),
|
|
5170
|
+
page_pulled_count: Math.max(0, pulledCount),
|
|
5171
|
+
pulled_count: received,
|
|
5172
|
+
received_total: received,
|
|
5173
|
+
batch_size: Math.max(0, pulledCount),
|
|
5174
|
+
estimated_remaining: hasMore ? void 0 : 0,
|
|
5175
|
+
max_seen: maxSeen,
|
|
5176
|
+
has_more: hasMore
|
|
5177
|
+
};
|
|
5178
|
+
if (typeof currentSeq === "number" && Number.isSafeInteger(currentSeq) && currentSeq >= 0) {
|
|
5179
|
+
progress.current_seq = currentSeq;
|
|
5180
|
+
}
|
|
5181
|
+
if (typeof targetSeq === "number" && Number.isSafeInteger(targetSeq) && targetSeq >= 0) {
|
|
5182
|
+
progress.target_seq = targetSeq;
|
|
5183
|
+
}
|
|
5184
|
+
if (typeof remaining === "number" && Number.isSafeInteger(remaining) && remaining >= 0) {
|
|
5185
|
+
progress.remaining = remaining;
|
|
5186
|
+
progress.estimated_remaining = progress.remaining;
|
|
5187
|
+
}
|
|
5188
|
+
this.runtime.client._dispatcher?.enqueue?.("sync.progress", progress);
|
|
5189
|
+
}
|
|
5190
|
+
onPullAborted() {
|
|
5191
|
+
this.syncStopped("aborted");
|
|
5192
|
+
}
|
|
5193
|
+
syncStopped(reason = "pull_drained") {
|
|
5194
|
+
if (this.syncingNamespaces.size === 0) return;
|
|
5195
|
+
const sessions = [...this.syncSessions.entries()];
|
|
5196
|
+
const receivedTotal = sessions.reduce((total, [, session]) => total + session.pulled, 0);
|
|
5197
|
+
this.syncingNamespaces.clear();
|
|
5198
|
+
this.syncSessions.clear();
|
|
5199
|
+
const payload = {
|
|
5200
|
+
run_id: this.syncRun,
|
|
5201
|
+
source: "pull",
|
|
5202
|
+
syncing: false,
|
|
5203
|
+
namespaces_pending: 0,
|
|
5204
|
+
received_total: receivedTotal,
|
|
5205
|
+
reason,
|
|
5206
|
+
stopped_at: Date.now()
|
|
5207
|
+
};
|
|
5208
|
+
if (sessions.length === 1) {
|
|
5209
|
+
const [namespace, session] = sessions[0];
|
|
5210
|
+
payload.namespace = namespace;
|
|
5211
|
+
payload.pages = session.pages;
|
|
5212
|
+
payload.pulled_count = session.pulled;
|
|
5213
|
+
} else if (sessions.length > 1) {
|
|
5214
|
+
payload.namespaces = sessions.map(([namespace]) => namespace);
|
|
5215
|
+
payload.pages = sessions.reduce((total, [, session]) => total + session.pages, 0);
|
|
5216
|
+
payload.pulled_count = receivedTotal;
|
|
5217
|
+
}
|
|
5218
|
+
this.runtime.client._dispatcher?.enqueue?.("sync.stopped", {
|
|
5219
|
+
...payload
|
|
5220
|
+
});
|
|
5221
|
+
}
|
|
4970
5222
|
hasPendingPull(ns) {
|
|
4971
5223
|
const pending = ns.startsWith("p2p:") ? this.pendingP2pPullUpper : this.pendingGroupPullUpper;
|
|
4972
5224
|
return (pending?.get(ns) ?? 0) > 0;
|
|
@@ -4978,7 +5230,7 @@ var MessageDeliveryEngine = class {
|
|
|
4978
5230
|
onPullWorkSettled() {
|
|
4979
5231
|
const pipeline = this.runtime.client._rpcPipeline;
|
|
4980
5232
|
if (pipeline?.hasAnyPullActivity?.() === true) return;
|
|
4981
|
-
void this.flushPullDeliveryChanges();
|
|
5233
|
+
void this.flushPullDeliveryChanges().finally(() => this.syncStopped("pull_drained"));
|
|
4982
5234
|
}
|
|
4983
5235
|
deliveryChangeNamespace(event, payload, ns = "") {
|
|
4984
5236
|
if (event === "message.received") return "p2p";
|
|
@@ -5024,7 +5276,11 @@ var MessageDeliveryEngine = class {
|
|
|
5024
5276
|
if (batch.generation !== this.deliveryGeneration) return;
|
|
5025
5277
|
const changes = this.deliveryChangesPayload(batch.changes);
|
|
5026
5278
|
if (changes.length === 0) return;
|
|
5027
|
-
this.runtime.client._dispatcher.enqueue("delivery.changed", {
|
|
5279
|
+
this.runtime.client._dispatcher.enqueue("delivery.changed", {
|
|
5280
|
+
trigger: batch.trigger,
|
|
5281
|
+
source: batch.trigger,
|
|
5282
|
+
changes
|
|
5283
|
+
});
|
|
5028
5284
|
}
|
|
5029
5285
|
async flushPullDeliveryChanges() {
|
|
5030
5286
|
const generation = this.deliveryGeneration;
|
|
@@ -5034,7 +5290,11 @@ var MessageDeliveryEngine = class {
|
|
|
5034
5290
|
if (generation !== this.deliveryGeneration) return;
|
|
5035
5291
|
const changes = this.deliveryChangesPayload(pending);
|
|
5036
5292
|
if (changes.length === 0) return;
|
|
5037
|
-
this.runtime.client._dispatcher.enqueue("delivery.changed", {
|
|
5293
|
+
this.runtime.client._dispatcher.enqueue("delivery.changed", {
|
|
5294
|
+
trigger: "pull_drained",
|
|
5295
|
+
source: "pull",
|
|
5296
|
+
changes
|
|
5297
|
+
});
|
|
5038
5298
|
}
|
|
5039
5299
|
recordPendingPull(ns, seq2) {
|
|
5040
5300
|
if (!ns || !Number.isSafeInteger(seq2) || seq2 <= 0) return;
|
|
@@ -5537,18 +5797,22 @@ var MessageDeliveryEngine = class {
|
|
|
5537
5797
|
}
|
|
5538
5798
|
const message = normalizeGroupMentionMode(rawMessage);
|
|
5539
5799
|
if (this.recallEventFromGroupMessage(message)) {
|
|
5540
|
-
if (await this.publishGroupRecallTombstone(groupId, seq2, message)) {
|
|
5800
|
+
if (await this.publishGroupRecallTombstone(groupId, seq2, message, "pull")) {
|
|
5541
5801
|
this.ensurePullOperationCurrent();
|
|
5542
5802
|
this.markPublishedSeq(ns, seq2);
|
|
5543
5803
|
publishedCount += 1;
|
|
5544
5804
|
}
|
|
5805
|
+
} else if (this.isSelfSentGroupMessage(message)) {
|
|
5806
|
+
this.markPublishedSeq(ns, seq2);
|
|
5545
5807
|
} else if (await this.publishPulledMessage("group.message_created", ns, seq2, message, false)) {
|
|
5546
5808
|
this.ensurePullOperationCurrent();
|
|
5547
5809
|
publishedCount += 1;
|
|
5548
5810
|
}
|
|
5549
5811
|
}
|
|
5550
5812
|
this.ensurePullOperationCurrent();
|
|
5551
|
-
|
|
5813
|
+
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq) ? result.contiguous_seq : void 0;
|
|
5814
|
+
if (contiguousSeq === void 0) client._seqTracker.onPullResult(ns, messages, afterSeq);
|
|
5815
|
+
else client._seqTracker.onPullResult(ns, messages, afterSeq, contiguousSeq);
|
|
5552
5816
|
const commitTarget = Math.max(
|
|
5553
5817
|
client._seqTracker.getContiguousSeq(ns),
|
|
5554
5818
|
retentionFloor,
|
|
@@ -5608,6 +5872,17 @@ var MessageDeliveryEngine = class {
|
|
|
5608
5872
|
this.ensurePullOperationCurrent();
|
|
5609
5873
|
await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
|
|
5610
5874
|
}
|
|
5875
|
+
const remaining = typeof response.remaining === "number" && Number.isSafeInteger(response.remaining) && response.remaining >= 0 ? response.remaining : null;
|
|
5876
|
+
this.onPullPage(
|
|
5877
|
+
ns,
|
|
5878
|
+
publishedCount,
|
|
5879
|
+
response.has_more === true,
|
|
5880
|
+
messages.length > 0 ? Number(messages[messages.length - 1].seq ?? 0) : void 0,
|
|
5881
|
+
remaining,
|
|
5882
|
+
messages.length,
|
|
5883
|
+
client._seqTracker.getContiguousSeq(ns),
|
|
5884
|
+
messages.length > 0 ? Number(messages[messages.length - 1].seq ?? 0) : void 0
|
|
5885
|
+
);
|
|
5611
5886
|
return { rawCount: messages.length, publishedCount };
|
|
5612
5887
|
}
|
|
5613
5888
|
enqueueOrderedMessage(ns, event, seq2, payload, source = "push") {
|
|
@@ -5629,11 +5904,11 @@ var MessageDeliveryEngine = class {
|
|
|
5629
5904
|
async publishOrderedQueueItem(ns, event, seq2, payload, pullResponse = false, source = "push", batch) {
|
|
5630
5905
|
const client = this.runtime.client;
|
|
5631
5906
|
if (event === "group.changed" && this.isGroupEventNamespace(ns)) {
|
|
5632
|
-
await this.publishOrderedGroupChanged(payload);
|
|
5907
|
+
await this.publishOrderedGroupChanged(payload, source);
|
|
5633
5908
|
return;
|
|
5634
5909
|
}
|
|
5635
5910
|
if (event === "message.recalled") {
|
|
5636
|
-
await this.publishMessageRecallTombstone(seq2, payload);
|
|
5911
|
+
await this.publishMessageRecallTombstone(seq2, payload, source);
|
|
5637
5912
|
return;
|
|
5638
5913
|
}
|
|
5639
5914
|
if (pullResponse) {
|
|
@@ -5642,7 +5917,7 @@ var MessageDeliveryEngine = class {
|
|
|
5642
5917
|
}
|
|
5643
5918
|
await client._publishAppEvent(event, payload, source, ns, batch);
|
|
5644
5919
|
}
|
|
5645
|
-
async publishOrderedGroupChanged(payload) {
|
|
5920
|
+
async publishOrderedGroupChanged(payload, source = "ordered") {
|
|
5646
5921
|
const client = this.runtime.client;
|
|
5647
5922
|
if (isJsonObject(payload)) {
|
|
5648
5923
|
const eventPayload = payload;
|
|
@@ -5653,7 +5928,7 @@ var MessageDeliveryEngine = class {
|
|
|
5653
5928
|
if (groupId) client._cleanupDissolvedGroup?.(groupId);
|
|
5654
5929
|
}
|
|
5655
5930
|
}
|
|
5656
|
-
await client._publishAppEvent("group.changed", payload);
|
|
5931
|
+
await client._publishAppEvent("group.changed", payload, source);
|
|
5657
5932
|
}
|
|
5658
5933
|
isInstanceScopedMessageEvent(event) {
|
|
5659
5934
|
return event === "message.received" || event === "message.recalled" || event === "message.undecryptable" || event === "group.message_created" || event === "group.message_recalled" || event === "group.message_undecryptable";
|
|
@@ -5670,17 +5945,22 @@ var MessageDeliveryEngine = class {
|
|
|
5670
5945
|
}
|
|
5671
5946
|
return result;
|
|
5672
5947
|
}
|
|
5673
|
-
normalizePublishedMessagePayload(event, payload) {
|
|
5948
|
+
normalizePublishedMessagePayload(event, payload, source = "direct") {
|
|
5949
|
+
let normalized;
|
|
5674
5950
|
if (this.isInstanceScopedMessageEvent(event)) {
|
|
5675
5951
|
payload = this.stripInlineInternalFields(payload);
|
|
5676
5952
|
if (event === "group.message_created") payload = normalizeGroupMentionMode(payload);
|
|
5677
|
-
|
|
5678
|
-
}
|
|
5679
|
-
if (this.isGroupScopedEvent(event)) {
|
|
5953
|
+
normalized = this.attachAppMessageEnvelope(this.stripInternalSenderDeviceFields(this.attachCurrentInstanceContext(payload)));
|
|
5954
|
+
} else if (this.isGroupScopedEvent(event)) {
|
|
5680
5955
|
payload = this.stripInlineInternalFields(payload);
|
|
5681
|
-
|
|
5956
|
+
normalized = this.attachAppGroupEventEnvelope(this.attachCurrentInstanceContext(payload));
|
|
5957
|
+
} else {
|
|
5958
|
+
normalized = payload;
|
|
5682
5959
|
}
|
|
5683
|
-
|
|
5960
|
+
const canonicalSource = canonicalDeliverySource(source);
|
|
5961
|
+
if (canonicalSource === "direct" || !isJsonObject(normalized)) return normalized;
|
|
5962
|
+
if (!this.isInstanceScopedMessageEvent(event) && !this.isGroupScopedEvent(event)) return normalized;
|
|
5963
|
+
return { ...normalized, source: canonicalSource };
|
|
5684
5964
|
}
|
|
5685
5965
|
stripInlineInternalFields(payload) {
|
|
5686
5966
|
if (!isJsonObject(payload)) return payload;
|
|
@@ -5896,7 +6176,7 @@ var MessageDeliveryEngine = class {
|
|
|
5896
6176
|
if (tombstoneId) return `p2p|tombstone:${tombstoneId}`;
|
|
5897
6177
|
return `p2p|unknown:${Date.now()}:${Math.random()}`;
|
|
5898
6178
|
}
|
|
5899
|
-
async publishMessageRecallTombstone(seq2, message) {
|
|
6179
|
+
async publishMessageRecallTombstone(seq2, message, source = "push") {
|
|
5900
6180
|
const client = this.runtime.client;
|
|
5901
6181
|
const eventPayload = this.recallEventFromMessage(message);
|
|
5902
6182
|
if (!eventPayload) return false;
|
|
@@ -5915,7 +6195,7 @@ var MessageDeliveryEngine = class {
|
|
|
5915
6195
|
const drop = [...seen.entries()].sort((a, b) => a[1] - b[1]).slice(0, seen.size - MESSAGE_RECALL_SEEN_LIMIT);
|
|
5916
6196
|
for (const [oldKey] of drop) seen.delete(oldKey);
|
|
5917
6197
|
}
|
|
5918
|
-
await client._publishAppEvent("message.recalled", eventPayload);
|
|
6198
|
+
await client._publishAppEvent("message.recalled", eventPayload, source);
|
|
5919
6199
|
client._clientLog.debug(`message.recalled published: seq=${String(seq2)} ids=${JSON.stringify(eventPayload.message_ids)}`);
|
|
5920
6200
|
return true;
|
|
5921
6201
|
}
|
|
@@ -5977,7 +6257,7 @@ var MessageDeliveryEngine = class {
|
|
|
5977
6257
|
if (tombstoneId) return `${normalizedGroupId}|tombstone:${tombstoneId}`;
|
|
5978
6258
|
return `${normalizedGroupId}|unknown:${Date.now()}:${Math.random()}`;
|
|
5979
6259
|
}
|
|
5980
|
-
async publishGroupRecallTombstone(groupId, seq2, message) {
|
|
6260
|
+
async publishGroupRecallTombstone(groupId, seq2, message, source = "push") {
|
|
5981
6261
|
const client = this.runtime.client;
|
|
5982
6262
|
const eventPayload = this.recallEventFromGroupMessage(message);
|
|
5983
6263
|
if (!eventPayload) return false;
|
|
@@ -5998,7 +6278,7 @@ var MessageDeliveryEngine = class {
|
|
|
5998
6278
|
const drop = [...seen.entries()].sort((a, b) => a[1] - b[1]).slice(0, seen.size - GROUP_RECALL_SEEN_LIMIT);
|
|
5999
6279
|
for (const [oldKey] of drop) seen.delete(oldKey);
|
|
6000
6280
|
}
|
|
6001
|
-
await client._publishAppEvent("group.message_recalled", eventPayload);
|
|
6281
|
+
await client._publishAppEvent("group.message_recalled", eventPayload, source);
|
|
6002
6282
|
client._clientLog.debug(`group.message_recalled published: group=${groupId} seq=${String(seq2)} ids=${JSON.stringify(eventPayload.message_ids)}`);
|
|
6003
6283
|
return true;
|
|
6004
6284
|
}
|
|
@@ -6028,40 +6308,11 @@ var MessageDeliveryEngine = class {
|
|
|
6028
6308
|
return;
|
|
6029
6309
|
}
|
|
6030
6310
|
const ns = `group:${groupId}`;
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
if (client._seqTracker.getContiguousSeq(ns) === seqNum) {
|
|
6034
|
-
await this.publishGroupRecallTombstone(groupId, seq2, wrapped);
|
|
6035
|
-
return;
|
|
6036
|
-
}
|
|
6037
|
-
client._repairPushContiguousBound(ns, seqNum, true, "_raw.group.message_recalled");
|
|
6038
|
-
}
|
|
6039
|
-
const pushed = client._pushedSeqs.get(ns);
|
|
6040
|
-
const pending = client._pendingOrderedMsgs.get(ns);
|
|
6041
|
-
if (pushed?.has(seqNum) || pending?.has(seqNum)) {
|
|
6042
|
-
await this.publishGroupRecallTombstone(groupId, seq2, wrapped);
|
|
6043
|
-
return;
|
|
6044
|
-
}
|
|
6045
|
-
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
6046
|
-
client._seqTracker.onMessageSeq(ns, seqNum);
|
|
6311
|
+
client._seqTracker.updateMaxSeen(ns, seqNum);
|
|
6312
|
+
if (seqNum > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillGroupGap(groupId));
|
|
6047
6313
|
await this.publishGroupRecallTombstone(groupId, seq2, wrapped);
|
|
6048
|
-
this.markPublishedSeq(ns, seqNum);
|
|
6049
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
6050
|
-
if (contig > 0) {
|
|
6051
|
-
const ackSeq = this.clampAckSeq("group.ack_messages", "msg_seq", ns, contig);
|
|
6052
|
-
client._transport.call("group.ack_messages", {
|
|
6053
|
-
group_id: groupId,
|
|
6054
|
-
msg_seq: ackSeq,
|
|
6055
|
-
device_id: client._deviceId,
|
|
6056
|
-
slot_id: client._slotId,
|
|
6057
|
-
_rpc_background: true
|
|
6058
|
-
}).catch((e) => {
|
|
6059
|
-
client._clientLog.warn("group recall auto-ack failed: group=" + groupId, e);
|
|
6060
|
-
});
|
|
6061
|
-
}
|
|
6062
|
-
if (contig !== contigBefore) this.persistSeq(ns);
|
|
6063
6314
|
}
|
|
6064
|
-
async publishAppEvent(event, payload, source = "", ns = "", batch) {
|
|
6315
|
+
async publishAppEvent(event, payload, source = "direct", ns = "", batch) {
|
|
6065
6316
|
const client = this.runtime.client;
|
|
6066
6317
|
const generation = this.deliveryGeneration;
|
|
6067
6318
|
if ((event === "message.received" || event === "group.message_created") && isJsonObject(payload)) {
|
|
@@ -6082,11 +6333,16 @@ var MessageDeliveryEngine = class {
|
|
|
6082
6333
|
client._clientLog.debug(`agent_md etag inject skipped: ${String(exc)}`);
|
|
6083
6334
|
}
|
|
6084
6335
|
}
|
|
6085
|
-
|
|
6336
|
+
const canonicalSource = canonicalDeliverySource(source);
|
|
6337
|
+
let normalized = this.normalizePublishedMessagePayload(event, payload, source);
|
|
6338
|
+
if (isJsonObject(normalized) && (this.isInstanceScopedMessageEvent(event) || this.isGroupScopedEvent(event)) && canonicalSource !== "direct") {
|
|
6339
|
+
normalized = { ...normalized, source: canonicalSource };
|
|
6340
|
+
}
|
|
6341
|
+
client._dispatcher.enqueue(event, normalized);
|
|
6086
6342
|
if (generation !== this.deliveryGeneration) return;
|
|
6087
|
-
if (
|
|
6088
|
-
if (
|
|
6089
|
-
const localBatch = batch ?? this.createDeliveryChangeBatch(
|
|
6343
|
+
if (canonicalSource !== "pull" && canonicalSource !== "pending_retry" && canonicalSource !== "push" && canonicalSource !== "inline_push") return;
|
|
6344
|
+
if (canonicalSource === "push" || canonicalSource === "inline_push") {
|
|
6345
|
+
const localBatch = batch ?? this.createDeliveryChangeBatch(canonicalSource);
|
|
6090
6346
|
this.recordDeliveryChange(localBatch.changes, event, payload, ns, generation);
|
|
6091
6347
|
if (!batch) await this.flushRealtimeDeliveryChanges(localBatch);
|
|
6092
6348
|
} else {
|
|
@@ -6119,6 +6375,16 @@ var MessageDeliveryEngine = class {
|
|
|
6119
6375
|
}
|
|
6120
6376
|
return true;
|
|
6121
6377
|
}
|
|
6378
|
+
isSelfSentGroupMessage(message) {
|
|
6379
|
+
if (!isJsonObject(message)) return false;
|
|
6380
|
+
const client = this.runtime.client;
|
|
6381
|
+
const selfAid = String(client._aid ?? "").trim().toLowerCase();
|
|
6382
|
+
const senderAid = String(message.sender_aid ?? message.from_aid ?? message.from ?? "").trim().toLowerCase();
|
|
6383
|
+
if (!selfAid || senderAid !== selfAid) return false;
|
|
6384
|
+
const senderDevice = Object.prototype.hasOwnProperty.call(message, "sender_device_id") ? message.sender_device_id : message.from_device_id;
|
|
6385
|
+
if (typeof senderDevice !== "string" || !senderDevice.trim() || !String(client._deviceId ?? "").trim()) return false;
|
|
6386
|
+
return senderDevice.trim() === String(client._deviceId).trim();
|
|
6387
|
+
}
|
|
6122
6388
|
strictTargetString(source, key) {
|
|
6123
6389
|
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
6124
6390
|
return { present: false, valid: false, value: "" };
|
|
@@ -6179,11 +6445,11 @@ var MessageDeliveryEngine = class {
|
|
|
6179
6445
|
const client = this.runtime.client;
|
|
6180
6446
|
client._clientLog.debug(`_onRawMessageReceived enter: from=${data?.from ?? "-"} mid=${data?.message_id ?? "-"} seq=${data?.seq ?? "-"}`);
|
|
6181
6447
|
const ns = isJsonObject(data) && client._aid && data.seq !== void 0 ? `p2p:${client._aid}` : "";
|
|
6182
|
-
const seq2 = isJsonObject(data)
|
|
6183
|
-
if (client._v2Session && ns &&
|
|
6448
|
+
const seq2 = isJsonObject(data) ? positiveSafeSequenceHint(data.seq) : 0;
|
|
6449
|
+
if (client._v2Session && ns && seq2 > 0 && this.messageTargetsCurrentInstance(data)) {
|
|
6184
6450
|
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
6185
6451
|
}
|
|
6186
|
-
const hasInlineObject = isJsonObject(data) &&
|
|
6452
|
+
const hasInlineObject = isJsonObject(data) && hasNonEmptyInlineMessage(data.inline_message);
|
|
6187
6453
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
6188
6454
|
const operation = () => this.processAndPublishMessage(data, inlineGeneration);
|
|
6189
6455
|
client._safeAsync(client._v2Session && ns && !hasInlineObject ? operation() : this.runPushProcessSerialized(ns, operation, inlineGeneration));
|
|
@@ -6195,33 +6461,13 @@ var MessageDeliveryEngine = class {
|
|
|
6195
6461
|
const msg = { ...data };
|
|
6196
6462
|
if (!("type" in msg)) msg.type = "message.recalled";
|
|
6197
6463
|
if (!this.messageTargetsCurrentInstance(msg)) return;
|
|
6198
|
-
const seq2 = msg.seq;
|
|
6199
|
-
if (
|
|
6464
|
+
const seq2 = positiveSafeSequenceHint(msg.seq);
|
|
6465
|
+
if (client._aid && seq2 > 0) {
|
|
6200
6466
|
const ns = `p2p:${client._aid}`;
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
const seqNeedsPull = client._seqTracker.onMessageSeq(ns, seq2);
|
|
6204
|
-
const published = await this.publishOrderedMessage("message.recalled", ns, seq2, msg);
|
|
6205
|
-
const contigAfter = client._seqTracker.getContiguousSeq(ns);
|
|
6206
|
-
if (seqNeedsPull && !published && client._sessionOptions?.background_sync !== false) {
|
|
6207
|
-
client._safeAsync(this.fillP2pGap());
|
|
6208
|
-
}
|
|
6209
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
6210
|
-
if (contig > 0) {
|
|
6211
|
-
const ackSeq = this.clampAckSeq("message.ack", "seq", ns, contig);
|
|
6212
|
-
client._transport.call("message.ack", {
|
|
6213
|
-
seq: ackSeq,
|
|
6214
|
-
device_id: client._deviceId,
|
|
6215
|
-
slot_id: client._slotId,
|
|
6216
|
-
_rpc_background: true
|
|
6217
|
-
}).catch((e) => {
|
|
6218
|
-
client._clientLog.warn(`P2P recall auto-ack failed:${String(e)}`);
|
|
6219
|
-
});
|
|
6220
|
-
}
|
|
6221
|
-
if (contigAfter !== contigBefore) this.persistSeq(ns);
|
|
6222
|
-
return;
|
|
6467
|
+
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
6468
|
+
if (seq2 > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillP2pGap());
|
|
6223
6469
|
}
|
|
6224
|
-
await this.publishMessageRecallTombstone(
|
|
6470
|
+
await this.publishMessageRecallTombstone(msg.seq, msg);
|
|
6225
6471
|
}
|
|
6226
6472
|
async processAndPublishMessage(data, inlineGeneration) {
|
|
6227
6473
|
const client = this.runtime.client;
|
|
@@ -6235,43 +6481,32 @@ var MessageDeliveryEngine = class {
|
|
|
6235
6481
|
return;
|
|
6236
6482
|
}
|
|
6237
6483
|
const legacyPushSeq = positiveSafeSequenceHint(msg.seq);
|
|
6238
|
-
const hasInlineField =
|
|
6484
|
+
const hasInlineField = hasNonEmptyInlineMessage(msg.inline_message);
|
|
6239
6485
|
if (client._v2Session && client._aid && (legacyPushSeq > 0 || hasInlineField)) {
|
|
6240
6486
|
await this.processV2P2PNotification(msg, "v1", inlineGeneration);
|
|
6241
6487
|
return;
|
|
6242
6488
|
}
|
|
6489
|
+
if (client._aid && legacyPushSeq > 0) {
|
|
6490
|
+
const ns2 = `p2p:${client._aid}`;
|
|
6491
|
+
client._seqTracker.updateMaxSeen(ns2, legacyPushSeq);
|
|
6492
|
+
if (client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillP2pGap());
|
|
6493
|
+
return;
|
|
6494
|
+
}
|
|
6243
6495
|
const seq2 = msg.seq;
|
|
6244
6496
|
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
if (contig > 0) {
|
|
6258
|
-
const ackSeq = this.clampAckSeq("message.ack", "seq", ns, contig);
|
|
6259
|
-
client._transport.call("message.ack", {
|
|
6260
|
-
seq: ackSeq,
|
|
6261
|
-
device_id: client._deviceId,
|
|
6262
|
-
slot_id: client._slotId,
|
|
6263
|
-
_rpc_background: true
|
|
6264
|
-
}).catch((e) => {
|
|
6265
|
-
client._clientLog.warn(`P2P auto-ack failed:${String(e)}`);
|
|
6266
|
-
});
|
|
6267
|
-
}
|
|
6268
|
-
if (contigAfter !== contigBefore) this.persistSeq(ns);
|
|
6269
|
-
if (encryptedPush) return;
|
|
6497
|
+
const ns = client._aid ? `p2p:${client._aid}` : "";
|
|
6498
|
+
const seqNum = positiveSafeSequenceHint(seq2);
|
|
6499
|
+
if (ns && seqNum > 0) {
|
|
6500
|
+
client._seqTracker.updateMaxSeen(ns, seqNum);
|
|
6501
|
+
if (seqNum > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillP2pGap());
|
|
6502
|
+
}
|
|
6503
|
+
if (encryptedPush) {
|
|
6504
|
+
await client._publishEncryptedPushMessage("message.received", "message.undecryptable", ns, seq2 ?? 0, msg, false);
|
|
6505
|
+
return;
|
|
6506
|
+
}
|
|
6507
|
+
if (ns && seq2 !== void 0 && seq2 !== null) {
|
|
6508
|
+
await this.publishOrderedMessage("message.received", ns, seq2, msg);
|
|
6270
6509
|
} else {
|
|
6271
|
-
if (encryptedPush) {
|
|
6272
|
-
await client._publishEncryptedPushMessage("message.received", "message.undecryptable", "", seq2 ?? 0, msg, false);
|
|
6273
|
-
return;
|
|
6274
|
-
}
|
|
6275
6510
|
await client._publishAppEvent("message.received", msg, "push");
|
|
6276
6511
|
}
|
|
6277
6512
|
} catch (exc) {
|
|
@@ -6287,7 +6522,7 @@ var MessageDeliveryEngine = class {
|
|
|
6287
6522
|
_decrypt_error: String(exc)
|
|
6288
6523
|
};
|
|
6289
6524
|
client._attachV2EnvelopeMetadataFromSource(safeEvent, data);
|
|
6290
|
-
await client._publishAppEvent("message.undecryptable", safeEvent);
|
|
6525
|
+
await client._publishAppEvent("message.undecryptable", safeEvent, "push");
|
|
6291
6526
|
}
|
|
6292
6527
|
}
|
|
6293
6528
|
}
|
|
@@ -6295,13 +6530,13 @@ var MessageDeliveryEngine = class {
|
|
|
6295
6530
|
const client = this.runtime.client;
|
|
6296
6531
|
client._clientLog.debug(`_onRawGroupMessageCreated enter: group_id=${data?.group_id ?? "-"} from=${data?.from ?? "-"} seq=${data?.seq ?? "-"}`);
|
|
6297
6532
|
const groupId = isJsonObject(data) && typeof data.group_id === "string" ? data.group_id.trim() : "";
|
|
6298
|
-
const seq2 = isJsonObject(data) && typeof data.seq === "number" ? data.seq : 0;
|
|
6299
6533
|
const kind = isJsonObject(data) ? String(data.kind ?? "").trim() : "";
|
|
6300
|
-
if (client._v2Session && groupId && kind !== "group.online_unread_hint" && Number.isSafeInteger(seq2) && seq2 > 0) {
|
|
6301
|
-
client._seqTracker.updateMaxSeen(`group:${groupId}`, seq2);
|
|
6302
|
-
}
|
|
6303
6534
|
const ns = groupId ? `group:${groupId}` : "";
|
|
6304
|
-
const
|
|
6535
|
+
const seq2 = isJsonObject(data) ? positiveSafeSequenceHint(data.seq) : 0;
|
|
6536
|
+
if (client._v2Session && ns && kind !== "group.online_unread_hint" && seq2 > 0) {
|
|
6537
|
+
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
6538
|
+
}
|
|
6539
|
+
const hasInlineObject = isJsonObject(data) && hasNonEmptyInlineMessage(data.inline_message);
|
|
6305
6540
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
6306
6541
|
const operation = () => this.processAndPublishGroupMessage(data, inlineGeneration);
|
|
6307
6542
|
client._safeAsync(client._v2Session && ns && !hasInlineObject ? operation() : this.runPushProcessSerialized(ns, operation, inlineGeneration));
|
|
@@ -6322,69 +6557,56 @@ var MessageDeliveryEngine = class {
|
|
|
6322
6557
|
client._groupSynced.add(groupId);
|
|
6323
6558
|
}
|
|
6324
6559
|
const legacyPushSeq = positiveSafeSequenceHint(seq2);
|
|
6325
|
-
const hasInlineField =
|
|
6560
|
+
const hasInlineField = hasNonEmptyInlineMessage(msg.inline_message);
|
|
6326
6561
|
if (client._v2Session && groupId && (legacyPushSeq > 0 || hasInlineField)) {
|
|
6327
6562
|
await this.processGroupV2MessageCreated(msg, "v1", inlineGeneration);
|
|
6328
6563
|
return;
|
|
6329
6564
|
}
|
|
6565
|
+
if (groupId && legacyPushSeq > 0) {
|
|
6566
|
+
const ns2 = `group:${groupId}`;
|
|
6567
|
+
client._seqTracker.updateMaxSeen(ns2, legacyPushSeq);
|
|
6568
|
+
if (client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillGroupGap(groupId));
|
|
6569
|
+
return;
|
|
6570
|
+
}
|
|
6330
6571
|
if (payload === void 0 || payload === null || typeof payload === "object" && Object.keys(payload).length === 0) {
|
|
6331
|
-
await this.autoPullGroupMessages(msg);
|
|
6572
|
+
if (client._v2Session) await this.autoPullGroupMessages(msg);
|
|
6573
|
+
else if (groupId && seq2 !== void 0 && seq2 !== null) {
|
|
6574
|
+
const ns2 = `group:${groupId}`;
|
|
6575
|
+
const seqNum2 = positiveSafeSequenceHint(seq2);
|
|
6576
|
+
if (seqNum2 > 0) {
|
|
6577
|
+
client._seqTracker.updateMaxSeen(ns2, seqNum2);
|
|
6578
|
+
if (seqNum2 > client._seqTracker.getContiguousSeq(ns2) && client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillGroupGap(groupId));
|
|
6579
|
+
}
|
|
6580
|
+
await this.publishOrderedMessage("group.message_created", ns2, seq2, msg);
|
|
6581
|
+
} else await client._publishAppEvent("group.message_created", msg, "push");
|
|
6332
6582
|
return;
|
|
6333
6583
|
}
|
|
6334
6584
|
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
if (contig2 > 0) {
|
|
6346
|
-
const ackSeq = this.clampAckSeq("group.ack_messages", "msg_seq", ns, contig2);
|
|
6347
|
-
client._transport.call("group.ack_messages", {
|
|
6348
|
-
group_id: groupId,
|
|
6349
|
-
msg_seq: ackSeq,
|
|
6350
|
-
device_id: client._deviceId,
|
|
6351
|
-
slot_id: client._slotId,
|
|
6352
|
-
_rpc_background: true
|
|
6353
|
-
}).catch((e) => {
|
|
6354
|
-
client._clientLog.warn("group recall auto-ack failed: group=" + groupId, e);
|
|
6355
|
-
});
|
|
6356
|
-
}
|
|
6357
|
-
if (contigAfter2 !== contigBefore) this.persistSeq(ns);
|
|
6358
|
-
return;
|
|
6359
|
-
}
|
|
6360
|
-
const published = encryptedPush ? await client._publishEncryptedPushMessage("group.message_created", "group.message_undecryptable", ns, seq2, msg, true) : await this.publishOrderedMessage("group.message_created", ns, seq2, msg);
|
|
6361
|
-
const contigAfter = client._seqTracker.getContiguousSeq(ns);
|
|
6362
|
-
const needPull = seqNeedsPull && !published;
|
|
6363
|
-
if (needPull && client._sessionOptions?.background_sync !== false) {
|
|
6364
|
-
client._safeAsync(this.fillGroupGap(groupId));
|
|
6365
|
-
}
|
|
6366
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
6367
|
-
if (contig > 0) {
|
|
6368
|
-
const ackSeq = this.clampAckSeq("group.ack_messages", "msg_seq", ns, contig);
|
|
6369
|
-
client._transport.call("group.ack_messages", {
|
|
6370
|
-
group_id: groupId,
|
|
6371
|
-
msg_seq: ackSeq,
|
|
6372
|
-
device_id: client._deviceId,
|
|
6373
|
-
slot_id: client._slotId,
|
|
6374
|
-
_rpc_background: true
|
|
6375
|
-
}).catch((e) => {
|
|
6376
|
-
client._clientLog.warn("group message auto-ack failed: group=" + groupId, e);
|
|
6377
|
-
});
|
|
6378
|
-
}
|
|
6379
|
-
if (contigAfter !== contigBefore) this.persistSeq(ns);
|
|
6380
|
-
if (encryptedPush) return;
|
|
6381
|
-
} else {
|
|
6382
|
-
if (encryptedPush) {
|
|
6383
|
-
await client._publishEncryptedPushMessage("group.message_created", "group.message_undecryptable", "", seq2 ?? 0, msg, true);
|
|
6384
|
-
return;
|
|
6385
|
-
}
|
|
6386
|
-
await client._publishAppEvent("group.message_created", msg, "push");
|
|
6585
|
+
const ns = groupId ? `group:${groupId}` : "";
|
|
6586
|
+
const seqNum = positiveSafeSequenceHint(seq2);
|
|
6587
|
+
if (ns && seqNum > 0) {
|
|
6588
|
+
client._seqTracker.updateMaxSeen(ns, seqNum);
|
|
6589
|
+
if (seqNum > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillGroupGap(groupId));
|
|
6590
|
+
}
|
|
6591
|
+
if (this.isSelfSentGroupMessage(msg)) return;
|
|
6592
|
+
if (!encryptedPush && this.recallEventFromGroupMessage(msg)) {
|
|
6593
|
+
await this.publishGroupRecallTombstone(groupId, seq2, msg);
|
|
6594
|
+
return;
|
|
6387
6595
|
}
|
|
6596
|
+
if (encryptedPush) {
|
|
6597
|
+
await client._publishEncryptedPushMessage(
|
|
6598
|
+
"group.message_created",
|
|
6599
|
+
"group.message_undecryptable",
|
|
6600
|
+
ns,
|
|
6601
|
+
seq2 ?? 0,
|
|
6602
|
+
msg,
|
|
6603
|
+
true
|
|
6604
|
+
);
|
|
6605
|
+
return;
|
|
6606
|
+
}
|
|
6607
|
+
if (ns && seq2 !== void 0 && seq2 !== null) {
|
|
6608
|
+
await this.publishOrderedMessage("group.message_created", ns, seq2, msg);
|
|
6609
|
+
} else await client._publishAppEvent("group.message_created", msg, "push");
|
|
6388
6610
|
} catch (exc) {
|
|
6389
6611
|
client._clientLog.warn(`group push processing failed:${String(exc)}`);
|
|
6390
6612
|
if (isJsonObject(data)) {
|
|
@@ -6398,7 +6620,7 @@ var MessageDeliveryEngine = class {
|
|
|
6398
6620
|
_decrypt_error: String(exc)
|
|
6399
6621
|
};
|
|
6400
6622
|
client._attachV2EnvelopeMetadataFromSource(safeEvent, data);
|
|
6401
|
-
await client._publishAppEvent("group.message_undecryptable", safeEvent);
|
|
6623
|
+
await client._publishAppEvent("group.message_undecryptable", safeEvent, "push");
|
|
6402
6624
|
}
|
|
6403
6625
|
}
|
|
6404
6626
|
}
|
|
@@ -6406,7 +6628,7 @@ var MessageDeliveryEngine = class {
|
|
|
6406
6628
|
const client = this.runtime.client;
|
|
6407
6629
|
const groupId = notification.group_id ?? "";
|
|
6408
6630
|
if (!groupId) {
|
|
6409
|
-
await client._publishAppEvent("group.message_created", notification);
|
|
6631
|
+
await client._publishAppEvent("group.message_created", notification, "push");
|
|
6410
6632
|
return;
|
|
6411
6633
|
}
|
|
6412
6634
|
if (client._sessionOptions?.background_sync === false) {
|
|
@@ -6426,7 +6648,7 @@ var MessageDeliveryEngine = class {
|
|
|
6426
6648
|
return;
|
|
6427
6649
|
} catch (exc) {
|
|
6428
6650
|
client._clientLog.warn(`auto pull group message failed:${String(exc)}`);
|
|
6429
|
-
await client._publishAppEvent("group.message_created", notification);
|
|
6651
|
+
await client._publishAppEvent("group.message_created", notification, "push");
|
|
6430
6652
|
return;
|
|
6431
6653
|
}
|
|
6432
6654
|
}
|
|
@@ -6453,7 +6675,7 @@ var MessageDeliveryEngine = class {
|
|
|
6453
6675
|
} catch (exc) {
|
|
6454
6676
|
client._clientLog.warn(`auto pull group message commit/ack failed:${String(exc)}`);
|
|
6455
6677
|
if (!rawCompleted) {
|
|
6456
|
-
await client._publishAppEvent("group.message_created", notification);
|
|
6678
|
+
await client._publishAppEvent("group.message_created", notification, "push");
|
|
6457
6679
|
}
|
|
6458
6680
|
}
|
|
6459
6681
|
}
|
|
@@ -6581,6 +6803,8 @@ var MessageDeliveryEngine = class {
|
|
|
6581
6803
|
client._gapFillDone.add(dedupKey);
|
|
6582
6804
|
this.runtime.delivery.setGapFillActive(true);
|
|
6583
6805
|
let continuationAfterSeq = 0;
|
|
6806
|
+
let pendingAckSeq = 0;
|
|
6807
|
+
let failed = false;
|
|
6584
6808
|
try {
|
|
6585
6809
|
let nextAfterSeq = afterSeq;
|
|
6586
6810
|
const maxPages = singlePage ? 1 : 100;
|
|
@@ -6600,9 +6824,9 @@ var MessageDeliveryEngine = class {
|
|
|
6600
6824
|
if (!Array.isArray(events)) return;
|
|
6601
6825
|
const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
6602
6826
|
const eventObjects = events.filter((evt) => isJsonObject(evt));
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6827
|
+
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq) ? result.contiguous_seq : void 0;
|
|
6828
|
+
if (contiguousSeq === void 0) client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq);
|
|
6829
|
+
else client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq, contiguousSeq);
|
|
6606
6830
|
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
6607
6831
|
const retentionFloor = Math.max(
|
|
6608
6832
|
0,
|
|
@@ -6628,6 +6852,7 @@ var MessageDeliveryEngine = class {
|
|
|
6628
6852
|
}
|
|
6629
6853
|
const eventSeqs = [];
|
|
6630
6854
|
let hasDissolvedEvent = false;
|
|
6855
|
+
let publishedEventCount = 0;
|
|
6631
6856
|
for (const evt of eventObjects) {
|
|
6632
6857
|
const eventSeq = Number(evt.event_seq ?? 0);
|
|
6633
6858
|
if (Number.isFinite(eventSeq) && eventSeq > 0) eventSeqs.push(eventSeq);
|
|
@@ -6645,7 +6870,8 @@ var MessageDeliveryEngine = class {
|
|
|
6645
6870
|
}
|
|
6646
6871
|
}
|
|
6647
6872
|
if (Number.isFinite(eventSeq) && eventSeq > 0 && !client._pushedSeqs.get(ns)?.has(eventSeq)) {
|
|
6648
|
-
this.enqueueOrderedMessage(ns, "group.changed", eventSeq, evt);
|
|
6873
|
+
this.enqueueOrderedMessage(ns, "group.changed", eventSeq, evt, "pull");
|
|
6874
|
+
publishedEventCount += 1;
|
|
6649
6875
|
}
|
|
6650
6876
|
}
|
|
6651
6877
|
const ackContig = client._seqTracker.getContiguousSeq(ns);
|
|
@@ -6654,37 +6880,49 @@ var MessageDeliveryEngine = class {
|
|
|
6654
6880
|
this.persistSeq(ns);
|
|
6655
6881
|
}
|
|
6656
6882
|
if (eventObjects.length > 0 && ackContig > 0 && ackContig !== pageContigBefore) {
|
|
6657
|
-
|
|
6658
|
-
const ackPromise = client._transport.call("group.ack_events", {
|
|
6659
|
-
group_id: groupId,
|
|
6660
|
-
event_seq: ackContig,
|
|
6661
|
-
device_id: client._deviceId,
|
|
6662
|
-
slot_id: client._slotId,
|
|
6663
|
-
_rpc_background: true
|
|
6664
|
-
});
|
|
6665
|
-
if (singlePage) await ackPromise;
|
|
6666
|
-
else ackPromise.catch((e) => {
|
|
6667
|
-
client._clientLog.warn("group event auto-ack failed: group=" + groupId, e);
|
|
6668
|
-
});
|
|
6669
|
-
} catch (e) {
|
|
6670
|
-
client._clientLog.warn("group event auto-ack failed: group=" + groupId, e);
|
|
6671
|
-
}
|
|
6883
|
+
pendingAckSeq = Math.max(pendingAckSeq, ackContig);
|
|
6672
6884
|
}
|
|
6885
|
+
this.onPullPage(
|
|
6886
|
+
ns,
|
|
6887
|
+
publishedEventCount,
|
|
6888
|
+
result.has_more === true,
|
|
6889
|
+
eventObjects.length > 0 ? Number(eventObjects[eventObjects.length - 1].event_seq ?? 0) : void 0,
|
|
6890
|
+
typeof result.remaining === "number" && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null,
|
|
6891
|
+
eventObjects.length,
|
|
6892
|
+
ackContig,
|
|
6893
|
+
eventObjects.length > 0 ? Number(eventObjects[eventObjects.length - 1].event_seq ?? 0) : void 0
|
|
6894
|
+
);
|
|
6673
6895
|
const nextAfter = Math.max(eventSeqs.length > 0 ? Math.max(...eventSeqs) : nextAfterSeq, nextAfterSeq);
|
|
6674
|
-
|
|
6896
|
+
const needsMore = result.has_more === true || client._seqTracker.getMaxSeenSeq(ns) > nextAfter;
|
|
6897
|
+
if (singlePage && needsMore && nextAfter > nextAfterSeq) {
|
|
6675
6898
|
continuationAfterSeq = nextAfter;
|
|
6676
6899
|
}
|
|
6677
|
-
if (eventObjects.length === 0 || nextAfter <= nextAfterSeq ||
|
|
6900
|
+
if (eventObjects.length === 0 || nextAfter <= nextAfterSeq || !needsMore) break;
|
|
6678
6901
|
nextAfterSeq = nextAfter;
|
|
6679
6902
|
}
|
|
6680
6903
|
if (pageCount >= maxPages) {
|
|
6681
6904
|
client._clientLog.warn(`group event gap fill reached max_pages=${maxPages} group=${groupId} after_seq=${nextAfterSeq}`);
|
|
6682
6905
|
}
|
|
6906
|
+
if (pendingAckSeq > 0) {
|
|
6907
|
+
try {
|
|
6908
|
+
await client._transport.call("group.ack_events", {
|
|
6909
|
+
group_id: groupId,
|
|
6910
|
+
event_seq: pendingAckSeq,
|
|
6911
|
+
device_id: client._deviceId,
|
|
6912
|
+
slot_id: client._slotId,
|
|
6913
|
+
_rpc_background: true
|
|
6914
|
+
});
|
|
6915
|
+
} catch (e) {
|
|
6916
|
+
client._clientLog.warn("group event auto-ack failed: group=" + groupId, e);
|
|
6917
|
+
}
|
|
6918
|
+
}
|
|
6683
6919
|
} catch (exc) {
|
|
6920
|
+
failed = true;
|
|
6684
6921
|
client._clientLog.warn(`group event gap-fill failed:${String(exc)}`);
|
|
6685
6922
|
} finally {
|
|
6686
6923
|
client._gapFillDone.delete(dedupKey);
|
|
6687
6924
|
this.runtime.delivery.setGapFillActive(false);
|
|
6925
|
+
if (!client._rpcPipeline) this.syncStopped(failed ? "aborted" : "pull_drained");
|
|
6688
6926
|
if (singlePage && continuationAfterSeq > afterSeq) {
|
|
6689
6927
|
this.enqueueOnlineUnreadEventHint({
|
|
6690
6928
|
group_id: groupId,
|
|
@@ -6713,41 +6951,15 @@ var MessageDeliveryEngine = class {
|
|
|
6713
6951
|
this.enqueueOnlineUnreadEventHint(data);
|
|
6714
6952
|
return;
|
|
6715
6953
|
}
|
|
6716
|
-
if (this.isSelfJoinGroupChanged(data)) {
|
|
6717
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
6718
|
-
const maxSeen = client._seqTracker.getMaxSeenSeq(ns);
|
|
6719
|
-
if (contig === 0 && maxSeen === 0 && eventSeq > 1) {
|
|
6720
|
-
client._clientLog.debug(`group.changed self-join baseline: group=${groupId}, event_seq=${eventSeq}, baseline=${eventSeq - 1}`);
|
|
6721
|
-
client._seqTracker.forceContiguousSeq(ns, eventSeq - 1);
|
|
6722
|
-
}
|
|
6723
|
-
}
|
|
6724
6954
|
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
6955
|
+
client._seqTracker.updateMaxSeen(ns, eventSeq);
|
|
6725
6956
|
const publishedDuplicate = client._pushedSeqs.get(ns)?.has(eventSeq) === true;
|
|
6726
6957
|
if (eventSeq <= contigBefore || publishedDuplicate) {
|
|
6727
6958
|
client._clientLog.debug(`group.changed skipped duplicate/stale: group=${groupId}, event_seq=${eventSeq}, contiguous=${contigBefore}`);
|
|
6728
|
-
if (eventSeq <= contigBefore) {
|
|
6729
|
-
this.fireGroupEventAck(groupId, ns, eventSeq, "group event covered push ack");
|
|
6730
|
-
} else if (contigBefore > 0) {
|
|
6731
|
-
this.fireGroupEventAck(groupId, ns, contigBefore, "group event covered push ack");
|
|
6732
|
-
}
|
|
6733
6959
|
return;
|
|
6734
6960
|
}
|
|
6735
6961
|
this.enqueueOrderedMessage(ns, "group.changed", eventSeq, data);
|
|
6736
|
-
needPull =
|
|
6737
|
-
const ackContig = client._seqTracker.getContiguousSeq(ns);
|
|
6738
|
-
await this.drainOrderedMessages(ns);
|
|
6739
|
-
if (ackContig > 0 && ackContig !== contigBefore) {
|
|
6740
|
-
if (data.action !== "dissolved") this.persistSeq(ns);
|
|
6741
|
-
client._transport.call("group.ack_events", {
|
|
6742
|
-
group_id: groupId,
|
|
6743
|
-
event_seq: ackContig,
|
|
6744
|
-
device_id: client._deviceId,
|
|
6745
|
-
slot_id: client._slotId,
|
|
6746
|
-
_rpc_background: true
|
|
6747
|
-
}).catch((e) => {
|
|
6748
|
-
client._clientLog.warn("group event push auto-ack failed: group=" + groupId, e);
|
|
6749
|
-
});
|
|
6750
|
-
}
|
|
6962
|
+
needPull = eventSeq > contigBefore;
|
|
6751
6963
|
if (needPull && groupId && !data._from_gap_fill && client._sessionOptions?.background_sync !== false) {
|
|
6752
6964
|
client._safeAsync(this.fillGroupEventGap(groupId));
|
|
6753
6965
|
}
|
|
@@ -7180,16 +7392,18 @@ var MessageDeliveryEngine = class {
|
|
|
7180
7392
|
};
|
|
7181
7393
|
if (forceTail || order[0] === "tail") result = await run(true, false, void 0, false, forceTail);
|
|
7182
7394
|
const state = this.syncState(ns);
|
|
7183
|
-
const tailMissedDuringPull = tailCompleted && Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
7184
7395
|
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
7185
|
-
const
|
|
7186
|
-
const
|
|
7396
|
+
const pendingUpper = Number(this.pendingP2pPullUpper?.get(ns) ?? 0);
|
|
7397
|
+
const observedUpper = Math.max(maxSeen, pendingUpper);
|
|
7398
|
+
const tailMissedDuringPull = tailCompleted && observedUpper > state.head;
|
|
7399
|
+
const pendingThroughSeq = tailMissedDuringPull ? observedUpper : 0;
|
|
7400
|
+
const tailForward = tailCompleted && (state.ack < state.head || tailMissedDuringPull);
|
|
7187
7401
|
const backgroundWindowForward = order[0] === "forward" && !headForward;
|
|
7188
7402
|
if (headForward || tailForward || client._sessionOptions?.background_sync !== false && backgroundWindowForward) {
|
|
7189
7403
|
const forwardTarget = Math.max(
|
|
7190
7404
|
headForward ? Math.max(pushSeq, maxSeen) : 0,
|
|
7191
7405
|
tailForward || backgroundWindowForward ? state.tail - 1 : 0,
|
|
7192
|
-
tailMissedDuringPull ?
|
|
7406
|
+
tailMissedDuringPull ? observedUpper : 0
|
|
7193
7407
|
);
|
|
7194
7408
|
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
7195
7409
|
result = await run(
|
|
@@ -7248,16 +7462,18 @@ var MessageDeliveryEngine = class {
|
|
|
7248
7462
|
};
|
|
7249
7463
|
if (forceTail || order[0] === "tail") result = await run(true, false, void 0, false, forceTail);
|
|
7250
7464
|
const state = this.syncState(ns);
|
|
7251
|
-
const tailMissedDuringPull = tailCompleted && Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
7252
7465
|
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
7253
|
-
const
|
|
7254
|
-
const
|
|
7466
|
+
const pendingUpper = Number(this.pendingGroupPullUpper?.get(ns) ?? 0);
|
|
7467
|
+
const observedUpper = Math.max(maxSeen, pendingUpper);
|
|
7468
|
+
const tailMissedDuringPull = tailCompleted && observedUpper > state.head;
|
|
7469
|
+
const pendingThroughSeq = tailMissedDuringPull ? observedUpper : 0;
|
|
7470
|
+
const tailForward = tailCompleted && (state.ack < state.head || tailMissedDuringPull);
|
|
7255
7471
|
const backgroundWindowForward = order[0] === "forward" && !headForward;
|
|
7256
7472
|
if (headForward || tailForward || client._sessionOptions?.background_sync !== false && backgroundWindowForward) {
|
|
7257
7473
|
const forwardTarget = Math.max(
|
|
7258
7474
|
headForward ? Math.max(pushSeq, maxSeen) : 0,
|
|
7259
7475
|
tailForward || backgroundWindowForward ? state.tail - 1 : 0,
|
|
7260
|
-
tailMissedDuringPull ?
|
|
7476
|
+
tailMissedDuringPull ? observedUpper : 0
|
|
7261
7477
|
);
|
|
7262
7478
|
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
7263
7479
|
result = await run(
|
|
@@ -7309,13 +7525,13 @@ var MessageDeliveryEngine = class {
|
|
|
7309
7525
|
if (!row) return;
|
|
7310
7526
|
const groupId = typeof row.group_id === "string" ? row.group_id.trim() : "";
|
|
7311
7527
|
if (!groupId) return;
|
|
7312
|
-
const seq2 = typeof row.seq === "number" ? row.seq : 0;
|
|
7313
7528
|
const eventKind = String(row.kind ?? "").trim();
|
|
7314
7529
|
const ns = this.resolvePendingGroupInlineAckNamespace(`group:${groupId}`);
|
|
7315
|
-
|
|
7530
|
+
const seq2 = positiveSafeSequenceHint(row.seq);
|
|
7531
|
+
if (client._v2Session && eventKind !== "group.online_unread_hint" && seq2 > 0) {
|
|
7316
7532
|
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
7317
7533
|
}
|
|
7318
|
-
const hasInlineObject =
|
|
7534
|
+
const hasInlineObject = hasNonEmptyInlineMessage(row.inline_message) && eventKind !== "group.online_unread_hint";
|
|
7319
7535
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
7320
7536
|
const operation = () => this.processGroupV2MessageCreated(data, "v2", inlineGeneration);
|
|
7321
7537
|
if (hasInlineObject) await this.runPushProcessSerialized(ns, operation, inlineGeneration);
|
|
@@ -7327,7 +7543,6 @@ var MessageDeliveryEngine = class {
|
|
|
7327
7543
|
if (!isJsonObject(data) || !client._v2Session) return;
|
|
7328
7544
|
const groupId = typeof data.group_id === "string" ? data.group_id.trim() : "";
|
|
7329
7545
|
const seq2 = positiveSafeSequenceHint(data.seq);
|
|
7330
|
-
const strictSeq = typeof data.seq === "number" && Number.isSafeInteger(data.seq) && data.seq > 0;
|
|
7331
7546
|
if (!groupId) return;
|
|
7332
7547
|
const eventKind = String(data.kind ?? "").trim();
|
|
7333
7548
|
if (eventKind === "group.online_unread_hint") {
|
|
@@ -7336,11 +7551,12 @@ var MessageDeliveryEngine = class {
|
|
|
7336
7551
|
return;
|
|
7337
7552
|
}
|
|
7338
7553
|
const ns = this.resolvePendingGroupInlineAckNamespace(`group:${groupId}`);
|
|
7339
|
-
const inlinePresent =
|
|
7554
|
+
const inlinePresent = hasNonEmptyInlineMessage(data.inline_message);
|
|
7340
7555
|
if (seq2 <= 0) {
|
|
7341
7556
|
if (inlinePresent) await this.recoverInvalidGroupRealtimeHead(groupId, ns, data.seq);
|
|
7342
7557
|
return;
|
|
7343
7558
|
}
|
|
7559
|
+
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
7344
7560
|
const inline = this.inlineMessage(data);
|
|
7345
7561
|
const inlineMatches = inline !== null && this.inlineGroupBindingMatches(data, inline, groupId, seq2, expectedInlineVersion);
|
|
7346
7562
|
const pendingInline = this.pendingGroupInlineAcks?.get(ns);
|
|
@@ -7361,13 +7577,12 @@ var MessageDeliveryEngine = class {
|
|
|
7361
7577
|
}
|
|
7362
7578
|
if (inlineMatches && !this.isInlineGenerationCurrent(inlineGeneration)) return;
|
|
7363
7579
|
const before = this.syncState(ns);
|
|
7364
|
-
if (strictSeq || !inlinePresent) client._seqTracker.updateMaxSeen(ns, seq2);
|
|
7365
7580
|
if (seq2 <= before.ack && before.ack >= before.tail - 1) {
|
|
7366
7581
|
const canonicalNs = this.resolvePendingGroupInlineAckNamespace(ns);
|
|
7367
7582
|
const pending = this.pendingGroupInlineAcks?.get(canonicalNs);
|
|
7368
|
-
if (pending && seq2 >= pending.seq) {
|
|
7583
|
+
if (inlinePresent && pending && seq2 >= pending.seq) {
|
|
7369
7584
|
this.retryPendingGroupInlineAck(canonicalNs, pending.seq, "covered inline Group ack", seq2);
|
|
7370
|
-
} else if (
|
|
7585
|
+
} else if (inlineMatches) {
|
|
7371
7586
|
this.fireGroupV2Ack(
|
|
7372
7587
|
groupId,
|
|
7373
7588
|
ns,
|
|
@@ -7406,7 +7621,7 @@ var MessageDeliveryEngine = class {
|
|
|
7406
7621
|
if (client._v2Session && Number.isSafeInteger(pushSeq) && pushSeq > 0) {
|
|
7407
7622
|
client._seqTracker.updateMaxSeen(ns, pushSeq);
|
|
7408
7623
|
}
|
|
7409
|
-
const hasInlineObject = isJsonObject(data) &&
|
|
7624
|
+
const hasInlineObject = isJsonObject(data) && hasNonEmptyInlineMessage(data.inline_message);
|
|
7410
7625
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
7411
7626
|
const operation = () => this.processV2P2PNotification(data, "v2", inlineGeneration);
|
|
7412
7627
|
if (hasInlineObject) await this.runPushProcessSerialized(ns, operation, inlineGeneration);
|
|
@@ -7417,10 +7632,10 @@ var MessageDeliveryEngine = class {
|
|
|
7417
7632
|
const client = this.runtime.client;
|
|
7418
7633
|
if (!client._v2Session) return;
|
|
7419
7634
|
const pushSeq = isJsonObject(data) ? positiveSafeSequenceHint(data.seq) : 0;
|
|
7420
|
-
const strictSeq = isJsonObject(data) && typeof data.seq === "number" && Number.isSafeInteger(data.seq) && data.seq > 0;
|
|
7421
7635
|
const ns = client._aid ? `p2p:${client._aid}` : "";
|
|
7422
7636
|
if (!ns) return;
|
|
7423
|
-
|
|
7637
|
+
if (pushSeq > 0) client._seqTracker.updateMaxSeen(ns, pushSeq);
|
|
7638
|
+
const inlinePresent = isJsonObject(data) && hasNonEmptyInlineMessage(data.inline_message);
|
|
7424
7639
|
if (pushSeq <= 0) {
|
|
7425
7640
|
if (inlinePresent) await this.recoverInvalidP2PRealtimeHead(ns, isJsonObject(data) ? data.seq : void 0);
|
|
7426
7641
|
return;
|
|
@@ -7443,10 +7658,9 @@ var MessageDeliveryEngine = class {
|
|
|
7443
7658
|
}
|
|
7444
7659
|
if (inlineMatches && !this.isInlineGenerationCurrent(inlineGeneration)) return;
|
|
7445
7660
|
const before = this.syncState(ns);
|
|
7446
|
-
if (strictSeq || !inlinePresent) client._seqTracker.updateMaxSeen(ns, pushSeq);
|
|
7447
7661
|
if (pushSeq <= before.ack && before.ack >= before.tail - 1) {
|
|
7448
7662
|
const pending = this.pendingP2PInlineAcks?.get(ns);
|
|
7449
|
-
if (pending && pushSeq >= pending.seq) {
|
|
7663
|
+
if (inlinePresent && pending && pushSeq >= pending.seq) {
|
|
7450
7664
|
this.retryPendingP2PInlineAck(ns, pending.seq, "covered inline P2P ack", pushSeq);
|
|
7451
7665
|
} else if (inlineMatches) {
|
|
7452
7666
|
this.fireP2PV2Ack(pushSeq, "P2P inline covered push ack", inlineGeneration);
|
|
@@ -7919,7 +8133,7 @@ var MessageDeliveryEngine = class {
|
|
|
7919
8133
|
if (event === "message.recalled") {
|
|
7920
8134
|
const published = await client._withPullResponseProcessing(
|
|
7921
8135
|
ns,
|
|
7922
|
-
() => this.publishMessageRecallTombstone(seq2, payload)
|
|
8136
|
+
() => this.publishMessageRecallTombstone(seq2, payload, source)
|
|
7923
8137
|
);
|
|
7924
8138
|
this.ensurePullOperationCurrent();
|
|
7925
8139
|
return published;
|
|
@@ -7941,7 +8155,7 @@ var MessageDeliveryEngine = class {
|
|
|
7941
8155
|
if (event === "message.recalled") {
|
|
7942
8156
|
const published = await client._withPullResponseProcessing(
|
|
7943
8157
|
ns,
|
|
7944
|
-
() => this.publishMessageRecallTombstone(seqNum, payload)
|
|
8158
|
+
() => this.publishMessageRecallTombstone(seqNum, payload, source)
|
|
7945
8159
|
);
|
|
7946
8160
|
this.ensurePullOperationCurrent();
|
|
7947
8161
|
this.markPublishedSeq(ns, seqNum);
|
|
@@ -15389,6 +15603,11 @@ var SIGNED_METHODS = /* @__PURE__ */ new Set([
|
|
|
15389
15603
|
"group.v2.get_proposal",
|
|
15390
15604
|
"group.kick",
|
|
15391
15605
|
"group.add_member",
|
|
15606
|
+
"group.invite_member",
|
|
15607
|
+
"group.list_my_invites",
|
|
15608
|
+
"group.accept_invite",
|
|
15609
|
+
"group.reject_invite",
|
|
15610
|
+
"group.revoke_invite",
|
|
15392
15611
|
"group.leave",
|
|
15393
15612
|
"group.remove_member",
|
|
15394
15613
|
"group.update",
|
|
@@ -15541,7 +15760,9 @@ var NON_IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
|
|
|
15541
15760
|
"mail.send",
|
|
15542
15761
|
"group.send",
|
|
15543
15762
|
"group.create",
|
|
15544
|
-
"group.
|
|
15763
|
+
"group.accept_invite",
|
|
15764
|
+
"group.reject_invite",
|
|
15765
|
+
"group.revoke_invite",
|
|
15545
15766
|
"group.kick",
|
|
15546
15767
|
"group.remove_member",
|
|
15547
15768
|
"group.leave",
|
|
@@ -16301,9 +16522,13 @@ var RpcPipeline = class {
|
|
|
16301
16522
|
throw new Error("pull invalidated");
|
|
16302
16523
|
}
|
|
16303
16524
|
if (!key) {
|
|
16525
|
+
this.runtime.client._delivery?.onPullStarted?.("");
|
|
16304
16526
|
const releasePullWork = this.reservePullWork();
|
|
16305
16527
|
try {
|
|
16306
16528
|
return await this.executePullOperation(operation, background);
|
|
16529
|
+
} catch (error) {
|
|
16530
|
+
this.runtime.client._delivery?.onPullAborted?.();
|
|
16531
|
+
throw error;
|
|
16307
16532
|
} finally {
|
|
16308
16533
|
releasePullWork();
|
|
16309
16534
|
}
|
|
@@ -16428,6 +16653,7 @@ var RpcPipeline = class {
|
|
|
16428
16653
|
const job = takeRunnable(state.foreground) ?? takeRunnable(state.background);
|
|
16429
16654
|
if (!job) return;
|
|
16430
16655
|
state.active = job;
|
|
16656
|
+
this.runtime.client._delivery?.onPullStarted?.(job.namespace);
|
|
16431
16657
|
if (job.timer) clearTimeout(job.timer);
|
|
16432
16658
|
job.pullingStartedAt = Date.now();
|
|
16433
16659
|
job.timedOut = false;
|
|
@@ -16441,11 +16667,13 @@ var RpcPipeline = class {
|
|
|
16441
16667
|
return;
|
|
16442
16668
|
}
|
|
16443
16669
|
job.running = true;
|
|
16670
|
+
let failed = false;
|
|
16444
16671
|
void this.executePullOperation(job.operation, job.background).then(
|
|
16445
16672
|
(value) => {
|
|
16446
16673
|
if (!job.timedOut && !job.invalidated) job.resolve(value);
|
|
16447
16674
|
},
|
|
16448
16675
|
(error) => {
|
|
16676
|
+
failed = true;
|
|
16449
16677
|
if (!job.timedOut && !job.invalidated) job.reject(error);
|
|
16450
16678
|
}
|
|
16451
16679
|
).finally(() => {
|
|
@@ -16457,6 +16685,7 @@ var RpcPipeline = class {
|
|
|
16457
16685
|
job.settledResolve?.();
|
|
16458
16686
|
job.settledResolve = null;
|
|
16459
16687
|
if (!job.invalidated) this.runtime.client._delivery?.onPullGateIdle?.(job.namespace);
|
|
16688
|
+
if (failed || job.invalidated) this.runtime.client._delivery?.onPullAborted?.();
|
|
16460
16689
|
this.runtime.client._delivery?.onPullWorkSettled?.();
|
|
16461
16690
|
});
|
|
16462
16691
|
}
|
|
@@ -16559,6 +16788,8 @@ var RpcPipeline = class {
|
|
|
16559
16788
|
}
|
|
16560
16789
|
postprocessMessagePull(params2, result) {
|
|
16561
16790
|
const client = this.runtime.client;
|
|
16791
|
+
const isTail = String(result.window_mode ?? params2.window_mode ?? "").trim().toLowerCase() === "tail";
|
|
16792
|
+
if (isTail) return;
|
|
16562
16793
|
const messages = result.messages;
|
|
16563
16794
|
const rawMessages = (Array.isArray(messages) ? messages : []).filter(isJsonObject);
|
|
16564
16795
|
if (!client._aid || !client._seqTracker) {
|
|
@@ -16566,9 +16797,9 @@ var RpcPipeline = class {
|
|
|
16566
16797
|
}
|
|
16567
16798
|
const ns = `p2p:${client._aid}`;
|
|
16568
16799
|
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
16800
|
+
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq) ? result.contiguous_seq : void 0;
|
|
16801
|
+
if (contiguousSeq === void 0) client._seqTracker.onPullResult(ns, rawMessages, Number(params2.after_seq ?? 0) || 0);
|
|
16802
|
+
else client._seqTracker.onPullResult(ns, rawMessages, Number(params2.after_seq ?? 0) || 0, contiguousSeq);
|
|
16572
16803
|
const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
|
|
16573
16804
|
if (retentionFloor > 0) {
|
|
16574
16805
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
@@ -16587,6 +16818,8 @@ var RpcPipeline = class {
|
|
|
16587
16818
|
if (Array.isArray(result.messages)) {
|
|
16588
16819
|
result.messages = result.messages.map((message) => normalizeGroupMentionMode(message));
|
|
16589
16820
|
}
|
|
16821
|
+
const isTail = String(result.window_mode ?? params2.window_mode ?? "").trim().toLowerCase() === "tail";
|
|
16822
|
+
if (isTail) return;
|
|
16590
16823
|
const gid = String(params2.group_id ?? params2.group_aid ?? "").trim();
|
|
16591
16824
|
if (!gid || !client._seqTracker) {
|
|
16592
16825
|
return;
|
|
@@ -16595,17 +16828,17 @@ var RpcPipeline = class {
|
|
|
16595
16828
|
const rawMessages = (Array.isArray(messages) ? messages : []).filter(isJsonObject);
|
|
16596
16829
|
const ns = `group:${gid}`;
|
|
16597
16830
|
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16831
|
+
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq) ? result.contiguous_seq : void 0;
|
|
16832
|
+
const afterSeq = Number(params2.after_message_seq ?? params2.after_seq ?? 0) || 0;
|
|
16833
|
+
if (contiguousSeq === void 0) client._seqTracker.onPullResult(ns, rawMessages, afterSeq);
|
|
16834
|
+
else client._seqTracker.onPullResult(ns, rawMessages, afterSeq, contiguousSeq);
|
|
16601
16835
|
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
16602
16836
|
const retentionFloor = Math.max(
|
|
16603
16837
|
0,
|
|
16604
16838
|
Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0),
|
|
16605
16839
|
Number(cursor?.retention_floor_seq ?? 0)
|
|
16606
16840
|
);
|
|
16607
|
-
const
|
|
16608
|
-
const visibilityFloor = isTail ? 0 : Math.max(
|
|
16841
|
+
const visibilityFloor = Math.max(
|
|
16609
16842
|
0,
|
|
16610
16843
|
Math.max(0, Number(result.earliest_available_message_seq ?? 1) - 1),
|
|
16611
16844
|
Number(cursor?.join_seq ?? 0)
|
|
@@ -16614,7 +16847,7 @@ var RpcPipeline = class {
|
|
|
16614
16847
|
if (effectiveFloor > 0) {
|
|
16615
16848
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
16616
16849
|
if (contig < effectiveFloor) {
|
|
16617
|
-
client._clientLog?.info?.(`group.pull floor advance: ns=${ns} contiguous=${contig} -> effective_floor=${effectiveFloor} retention_floor=${retentionFloor} visibility_floor=${visibilityFloor} mode
|
|
16850
|
+
client._clientLog?.info?.(`group.pull floor advance: ns=${ns} contiguous=${contig} -> effective_floor=${effectiveFloor} retention_floor=${retentionFloor} visibility_floor=${visibilityFloor} mode=forward`);
|
|
16618
16851
|
client._seqTracker.forceContiguousSeq(ns, effectiveFloor);
|
|
16619
16852
|
}
|
|
16620
16853
|
}
|
|
@@ -18147,6 +18380,21 @@ var MessageFacade = class extends RpcFacade {
|
|
|
18147
18380
|
return this.call("message.query_online", params2);
|
|
18148
18381
|
}
|
|
18149
18382
|
};
|
|
18383
|
+
function normalizeInviteParams(params2) {
|
|
18384
|
+
const out = stripNil2(params2);
|
|
18385
|
+
const rawGroupId = out.group_id ?? out.groupId ?? out.group_aid ?? out.groupAid;
|
|
18386
|
+
if (rawGroupId !== void 0) {
|
|
18387
|
+
out.group_id = normalizeGroupId(rawGroupId);
|
|
18388
|
+
delete out.groupId;
|
|
18389
|
+
delete out.group_aid;
|
|
18390
|
+
delete out.groupAid;
|
|
18391
|
+
}
|
|
18392
|
+
for (const [alias, canonical] of [["inviteId", "invite_id"], ["inviteeAid", "invitee_aid"]]) {
|
|
18393
|
+
if (out[canonical] === void 0 && out[alias] !== void 0) out[canonical] = out[alias];
|
|
18394
|
+
delete out[alias];
|
|
18395
|
+
}
|
|
18396
|
+
return out;
|
|
18397
|
+
}
|
|
18150
18398
|
var MailFacade = class extends RpcFacade {
|
|
18151
18399
|
send(params2) {
|
|
18152
18400
|
return this.call("mail.send", params2);
|
|
@@ -18259,6 +18507,32 @@ var GroupFacade = class extends RpcFacade {
|
|
|
18259
18507
|
addMember(params2) {
|
|
18260
18508
|
return this.call("group.add_member", params2);
|
|
18261
18509
|
}
|
|
18510
|
+
async inviteCall(method, params2) {
|
|
18511
|
+
const normalized = normalizeInviteParams(params2);
|
|
18512
|
+
try {
|
|
18513
|
+
const result = await this.call(method, normalized);
|
|
18514
|
+
await this.client._onGroupInviteActionResult?.(method, normalized, result);
|
|
18515
|
+
return result;
|
|
18516
|
+
} catch (error) {
|
|
18517
|
+
await this.client._onGroupInviteActionResult?.(method, normalized, void 0, error);
|
|
18518
|
+
throw error;
|
|
18519
|
+
}
|
|
18520
|
+
}
|
|
18521
|
+
inviteMember(params2) {
|
|
18522
|
+
return this.inviteCall("group.invite_member", params2);
|
|
18523
|
+
}
|
|
18524
|
+
listMyInvites(params2) {
|
|
18525
|
+
return this.inviteCall("group.list_my_invites", params2);
|
|
18526
|
+
}
|
|
18527
|
+
acceptInvite(params2) {
|
|
18528
|
+
return this.inviteCall("group.accept_invite", params2);
|
|
18529
|
+
}
|
|
18530
|
+
rejectInvite(params2) {
|
|
18531
|
+
return this.inviteCall("group.reject_invite", params2);
|
|
18532
|
+
}
|
|
18533
|
+
revokeInvite(params2) {
|
|
18534
|
+
return this.inviteCall("group.revoke_invite", params2);
|
|
18535
|
+
}
|
|
18262
18536
|
getMembers(params2) {
|
|
18263
18537
|
return this.call("group.get_members", params2);
|
|
18264
18538
|
}
|
|
@@ -23646,6 +23920,22 @@ function deduplicateForwardPageMessages(value, afterSeq) {
|
|
|
23646
23920
|
}
|
|
23647
23921
|
return [...bySeq.entries()].sort(([a], [b]) => a - b).map(([, row]) => row);
|
|
23648
23922
|
}
|
|
23923
|
+
function contiguousPullSeq(afterSeq, seqs, proof) {
|
|
23924
|
+
let contiguous = seqs.length > 0 ? Math.max(afterSeq, ...seqs) : afterSeq;
|
|
23925
|
+
const serverProof = safeNonNegativeSeq(proof);
|
|
23926
|
+
return serverProof !== null ? Math.max(contiguous, serverProof) : contiguous;
|
|
23927
|
+
}
|
|
23928
|
+
function deduplicatePulledResults(messages) {
|
|
23929
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23930
|
+
return messages.filter((message) => {
|
|
23931
|
+
if (!isJsonObject(message)) return true;
|
|
23932
|
+
const seq2 = safeNonNegativeSeq(message.seq);
|
|
23933
|
+
if (seq2 === null || seq2 <= 0) return true;
|
|
23934
|
+
if (seen.has(seq2)) return false;
|
|
23935
|
+
seen.add(seq2);
|
|
23936
|
+
return true;
|
|
23937
|
+
});
|
|
23938
|
+
}
|
|
23649
23939
|
function shouldContinueForwardPage({
|
|
23650
23940
|
rawCount,
|
|
23651
23941
|
nextAfterSeq,
|
|
@@ -23654,10 +23944,11 @@ function shouldContinueForwardPage({
|
|
|
23654
23944
|
hasMoreField,
|
|
23655
23945
|
hasMore,
|
|
23656
23946
|
serverHead,
|
|
23657
|
-
pendingAckSeq
|
|
23947
|
+
pendingAckSeq,
|
|
23948
|
+
observedUpper
|
|
23658
23949
|
}) {
|
|
23659
23950
|
if (rawCount <= 0 || nextAfter <= nextAfterSeq) return false;
|
|
23660
|
-
if (hasMore || serverHead > nextAfter || pendingAckSeq > 0) return true;
|
|
23951
|
+
if (hasMore || serverHead > nextAfter || pendingAckSeq > 0 || observedUpper > nextAfter) return true;
|
|
23661
23952
|
return !hasMoreField && limit > 0 && rawCount >= limit;
|
|
23662
23953
|
}
|
|
23663
23954
|
function validateTailPage(result, afterSeq, pageLimit) {
|
|
@@ -24396,7 +24687,7 @@ var V2E2EECoordinator = class {
|
|
|
24396
24687
|
client._clientLog.warn(`V2 sender IK pending group bootstrap failed group=${groupId}: ${String(formatE2EEError(exc))}`);
|
|
24397
24688
|
}
|
|
24398
24689
|
}
|
|
24399
|
-
if (!session.getPeerIK(fromAid, senderDeviceId)) {
|
|
24690
|
+
if (typeof session.getPeerIK === "function" && !session.getPeerIK(fromAid, senderDeviceId)) {
|
|
24400
24691
|
await this.getV2SenderPubDer(fromAid, senderDeviceId);
|
|
24401
24692
|
}
|
|
24402
24693
|
}
|
|
@@ -24407,7 +24698,7 @@ var V2E2EECoordinator = class {
|
|
|
24407
24698
|
let plaintext = null;
|
|
24408
24699
|
const retryStatus = {};
|
|
24409
24700
|
try {
|
|
24410
|
-
plaintext = await client._decryptV2Message(entry.msg, false, true, true, true, retryStatus);
|
|
24701
|
+
plaintext = await client._decryptV2Message(entry.msg, false, true, true, true, retryStatus, false, "pending_retry");
|
|
24411
24702
|
} catch (exc) {
|
|
24412
24703
|
if (!generationCurrent()) return;
|
|
24413
24704
|
client._clientLog.warn(`V2 sender IK pending retry raised: key=${key} err=${String(formatE2EEError(exc))}`);
|
|
@@ -24432,11 +24723,12 @@ var V2E2EECoordinator = class {
|
|
|
24432
24723
|
client._v2SenderIKPending.delete(key);
|
|
24433
24724
|
const seq2 = Number(entry.msg.seq ?? 0);
|
|
24434
24725
|
if (entry.groupId) {
|
|
24726
|
+
if (client._delivery.isSelfSentGroupMessage?.(entry.msg)) continue;
|
|
24435
24727
|
plaintext = normalizeGroupMentionMode(plaintext, entry.msg, entry.msg.envelope_json);
|
|
24436
24728
|
plaintext.group_id = entry.groupId;
|
|
24437
|
-
await client._publishPulledMessage("group.message_created", `group:${entry.groupId}`, seq2, plaintext);
|
|
24729
|
+
await client._publishPulledMessage("group.message_created", `group:${entry.groupId}`, seq2, plaintext, false, "pending_retry");
|
|
24438
24730
|
} else {
|
|
24439
|
-
await client._publishPulledMessage("message.received", `p2p:${client._aid ?? ""}`, seq2, plaintext);
|
|
24731
|
+
await client._publishPulledMessage("message.received", `p2p:${client._aid ?? ""}`, seq2, plaintext, false, "pending_retry");
|
|
24440
24732
|
}
|
|
24441
24733
|
client._clientLog.debug(`V2 sender IK pending retry delivered: key=${key}`);
|
|
24442
24734
|
}
|
|
@@ -24513,9 +24805,9 @@ var V2E2EECoordinator = class {
|
|
|
24513
24805
|
let plaintext = null;
|
|
24514
24806
|
if (String(msg.version ?? "") === "v1") {
|
|
24515
24807
|
const legacy = isJsonObject(msg.legacy_v1) ? msg.legacy_v1 : {};
|
|
24516
|
-
const payload = legacy.payload;
|
|
24808
|
+
const payload = legacy.payload !== void 0 ? legacy.payload : msg.payload;
|
|
24517
24809
|
const payloadType = isJsonObject(payload) ? String(payload.type ?? "").trim() : "";
|
|
24518
|
-
if (payload !== void 0 && payload !== null && !["e2ee.encrypted", "e2ee.group_encrypted"].includes(payloadType)) {
|
|
24810
|
+
if (payload !== void 0 && payload !== null && !["e2ee.encrypted", "e2ee.group_encrypted", "e2ee.p2p_encrypted"].includes(payloadType)) {
|
|
24519
24811
|
plaintext = {
|
|
24520
24812
|
message_id: String(msg.message_id ?? ""),
|
|
24521
24813
|
from: String(msg.from_aid ?? ""),
|
|
@@ -24527,6 +24819,9 @@ var V2E2EECoordinator = class {
|
|
|
24527
24819
|
encrypted: false
|
|
24528
24820
|
};
|
|
24529
24821
|
attachGatewayProximity(plaintext, msg);
|
|
24822
|
+
} else if (isJsonObject(payload) && ["e2ee.p2p_encrypted", "e2ee.encrypted"].includes(payloadType)) {
|
|
24823
|
+
msg = { ...msg, envelope_json: JSON.stringify(payload) };
|
|
24824
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, void 0, false, source);
|
|
24530
24825
|
}
|
|
24531
24826
|
} else {
|
|
24532
24827
|
plaintext = source === "inline_push" ? await client._decryptV2Message(msg, false, false, false, false) : await client._decryptV2Message(msg, false);
|
|
@@ -24558,29 +24853,53 @@ var V2E2EECoordinator = class {
|
|
|
24558
24853
|
let plaintext = null;
|
|
24559
24854
|
if (String(msg.version ?? "") === "v1") {
|
|
24560
24855
|
const payload = msg.payload;
|
|
24856
|
+
const recall = typeof client._delivery?.recallEventFromGroupMessage === "function" ? client._delivery.recallEventFromGroupMessage(msg) : null;
|
|
24857
|
+
if (recall) {
|
|
24858
|
+
const recallPayload = {
|
|
24859
|
+
...recall,
|
|
24860
|
+
group_id: groupId,
|
|
24861
|
+
group_aid: groupAid,
|
|
24862
|
+
seq: seq2
|
|
24863
|
+
};
|
|
24864
|
+
if (publish) {
|
|
24865
|
+
if (orderedPublish) {
|
|
24866
|
+
await client._delivery.publishOrderedMessage(
|
|
24867
|
+
"group.message_recalled",
|
|
24868
|
+
`group:${groupId}`,
|
|
24869
|
+
seq2,
|
|
24870
|
+
recallPayload,
|
|
24871
|
+
source
|
|
24872
|
+
);
|
|
24873
|
+
} else {
|
|
24874
|
+
await client._publishAppEvent("group.message_recalled", recallPayload, source);
|
|
24875
|
+
}
|
|
24876
|
+
}
|
|
24877
|
+
return recallPayload;
|
|
24878
|
+
}
|
|
24561
24879
|
if (payload === void 0 || payload === null) {
|
|
24562
24880
|
if (history) return this.historyDecryptFailure(msg, "legacy payload is missing");
|
|
24563
24881
|
client._clientLog.warn(`Group Tail \u7F3A\u5C11 payload \u7684 V1 \u884C\u5DF2\u8DF3\u8FC7\uFF0C\u8FDE\u7EED\u6027\u8BC1\u660E\u4ECD\u4FDD\u7559: group=${groupId}, seq=${seq2}`);
|
|
24564
24882
|
return null;
|
|
24565
24883
|
}
|
|
24566
|
-
|
|
24567
|
-
|
|
24568
|
-
|
|
24569
|
-
|
|
24884
|
+
const payloadType = isJsonObject(payload) ? String(payload.type ?? "").trim() : "";
|
|
24885
|
+
if (isJsonObject(payload) && ["e2ee.group_encrypted", "e2ee.p2p_encrypted", "e2ee.encrypted"].includes(payloadType)) {
|
|
24886
|
+
msg = { ...msg, envelope_json: JSON.stringify(payload) };
|
|
24887
|
+
plaintext = await client._decryptV2Message(msg, false, !history, true, true, void 0, false, source);
|
|
24888
|
+
} else {
|
|
24889
|
+
plaintext = {
|
|
24890
|
+
message_id: String(msg.message_id ?? ""),
|
|
24891
|
+
from: String(msg.from_aid ?? ""),
|
|
24892
|
+
group_id: groupId,
|
|
24893
|
+
group_aid: groupAid,
|
|
24894
|
+
seq: seq2,
|
|
24895
|
+
type: String(msg.type ?? ""),
|
|
24896
|
+
timestamp: msg.t_server,
|
|
24897
|
+
payload,
|
|
24898
|
+
encrypted: false
|
|
24899
|
+
};
|
|
24900
|
+
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
24901
|
+
attachGatewayProximity(plaintext, msg);
|
|
24570
24902
|
}
|
|
24571
|
-
plaintext = {
|
|
24572
|
-
message_id: String(msg.message_id ?? ""),
|
|
24573
|
-
from: String(msg.from_aid ?? ""),
|
|
24574
|
-
group_id: groupId,
|
|
24575
|
-
group_aid: groupAid,
|
|
24576
|
-
seq: seq2,
|
|
24577
|
-
type: String(msg.type ?? ""),
|
|
24578
|
-
timestamp: msg.t_server,
|
|
24579
|
-
payload,
|
|
24580
|
-
encrypted: false
|
|
24581
|
-
};
|
|
24582
|
-
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
24583
|
-
attachGatewayProximity(plaintext, msg);
|
|
24584
24903
|
} else {
|
|
24585
24904
|
plaintext = source === "inline_push" ? await client._decryptV2Message(msg, false, false, false, false) : await client._decryptV2Message(msg, false);
|
|
24586
24905
|
if (plaintext) {
|
|
@@ -24597,6 +24916,9 @@ var V2E2EECoordinator = class {
|
|
|
24597
24916
|
client._clientLog.warn(`Group Tail \u5355\u6761\u6D88\u606F\u89E3\u5BC6\u5931\u8D25\uFF0C\u8FDE\u7EED\u6027\u8BC1\u660E\u4ECD\u4FDD\u7559: group=${groupId}, seq=${seq2}`);
|
|
24598
24917
|
return null;
|
|
24599
24918
|
}
|
|
24919
|
+
if (publish && !history && client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
24920
|
+
return plaintext;
|
|
24921
|
+
}
|
|
24600
24922
|
if (publish) {
|
|
24601
24923
|
if (orderedPublish) {
|
|
24602
24924
|
await client._delivery.publishOrderedMessage(
|
|
@@ -24618,13 +24940,6 @@ var V2E2EECoordinator = class {
|
|
|
24618
24940
|
async decodeInlineGroupMessage(msg, groupId, groupAid) {
|
|
24619
24941
|
return await this.decodeGroupWindowMessage(msg, groupId, groupAid, false, false, "inline_push");
|
|
24620
24942
|
}
|
|
24621
|
-
async applyTailFloor(ns, floor) {
|
|
24622
|
-
const client = this.client;
|
|
24623
|
-
if (!ns || floor <= 0 || client._seqTracker.getContiguousSeq(ns) >= floor) return;
|
|
24624
|
-
client._seqTracker.forceContiguousSeq(ns, floor);
|
|
24625
|
-
client._persistSeq(ns);
|
|
24626
|
-
await client._saveSeqTrackerState?.();
|
|
24627
|
-
}
|
|
24628
24943
|
async pullV2TailInternal(params2, deferPublish = false) {
|
|
24629
24944
|
const client = this.client;
|
|
24630
24945
|
if (params2.window_mode !== "tail") throw new ValidationError("window_mode must equal tail");
|
|
@@ -24632,10 +24947,8 @@ var V2E2EECoordinator = class {
|
|
|
24632
24947
|
const afterSeq = strictWindowSeq(params2.after_seq ?? 0, "after_seq");
|
|
24633
24948
|
const limit = strictWindowLimit(params2.limit ?? V2_PULL_DEFAULT_PAGE_LIMIT);
|
|
24634
24949
|
const ns = client._aid ? `p2p:${client._aid}` : "";
|
|
24950
|
+
if (ns) client._delivery.onPullStarted?.(ns);
|
|
24635
24951
|
const result = await client._callRawV2Rpc("message.v2.pull", { window_mode: "tail", after_seq: afterSeq, limit, _rpc_foreground: true });
|
|
24636
|
-
const floor = Number(result.retention_floor_seq ?? 0);
|
|
24637
|
-
const previous = ns ? client._seqTracker.getSyncState(ns) : null;
|
|
24638
|
-
await this.applyTailFloor(ns, Number.isSafeInteger(floor) ? floor : 0);
|
|
24639
24952
|
const page = validateTailPage(result, afterSeq, limit);
|
|
24640
24953
|
if (ns) {
|
|
24641
24954
|
client._seqTracker.commitTailWindow(ns, {
|
|
@@ -24653,7 +24966,17 @@ var V2E2EECoordinator = class {
|
|
|
24653
24966
|
if (plaintext) decoded.push(plaintext);
|
|
24654
24967
|
}
|
|
24655
24968
|
const ack = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
|
|
24656
|
-
if (
|
|
24969
|
+
if (ns) client._delivery.onPullPage?.(
|
|
24970
|
+
ns,
|
|
24971
|
+
decoded.length,
|
|
24972
|
+
result.has_more === true,
|
|
24973
|
+
page.head,
|
|
24974
|
+
typeof result.remaining === "number" && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null,
|
|
24975
|
+
page.messages.length,
|
|
24976
|
+
ack,
|
|
24977
|
+
page.head
|
|
24978
|
+
);
|
|
24979
|
+
client._delivery.onPullWorkSettled?.();
|
|
24657
24980
|
return { ...result, messages: decoded, raw_count: page.messages.length };
|
|
24658
24981
|
}
|
|
24659
24982
|
async historyV2Internal(params2) {
|
|
@@ -24668,10 +24991,24 @@ var V2E2EECoordinator = class {
|
|
|
24668
24991
|
}
|
|
24669
24992
|
return { ...result, messages: decoded };
|
|
24670
24993
|
}
|
|
24994
|
+
async runPullWithLifecycle(ns, operation) {
|
|
24995
|
+
if (ns) this.client._delivery.onPullStarted?.(ns);
|
|
24996
|
+
try {
|
|
24997
|
+
return await operation();
|
|
24998
|
+
} catch (error) {
|
|
24999
|
+
this.client._delivery.onPullAborted?.();
|
|
25000
|
+
throw error;
|
|
25001
|
+
}
|
|
25002
|
+
}
|
|
24671
25003
|
async pullV2(afterSeq = 0, limit = 50, opts) {
|
|
25004
|
+
const ns = this.client._aid ? `p2p:${this.client._aid}` : "";
|
|
25005
|
+
return await this.runPullWithLifecycle(ns, () => this.pullV2Impl(afterSeq, limit, opts));
|
|
25006
|
+
}
|
|
25007
|
+
async pullV2Impl(afterSeq = 0, limit = 50, opts) {
|
|
24672
25008
|
const client = this.client;
|
|
24673
25009
|
await client._ensureV2SessionReady("message.pull");
|
|
24674
25010
|
const ns = client._aid ? `p2p:${client._aid}` : "";
|
|
25011
|
+
if (ns) client._delivery.onPullStarted?.(ns);
|
|
24675
25012
|
if (opts?.windowMode === "tail") {
|
|
24676
25013
|
if (!opts.gateLocked) {
|
|
24677
25014
|
const key = pullGateKeyForClient(client, "message.v2.pull", {
|
|
@@ -24679,7 +25016,7 @@ var V2E2EECoordinator = class {
|
|
|
24679
25016
|
after_seq: afterSeq,
|
|
24680
25017
|
limit
|
|
24681
25018
|
}, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
|
|
24682
|
-
return await client._runPullSerialized(key, () => this.
|
|
25019
|
+
return await client._runPullSerialized(key, () => this.pullV2Impl(afterSeq, limit, {
|
|
24683
25020
|
...opts ?? {},
|
|
24684
25021
|
gateLocked: true
|
|
24685
25022
|
}), false);
|
|
@@ -24693,7 +25030,7 @@ var V2E2EECoordinator = class {
|
|
|
24693
25030
|
force: opts?.force === true,
|
|
24694
25031
|
limit
|
|
24695
25032
|
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
24696
|
-
return await client._runPullSerialized(key, () => this.
|
|
25033
|
+
return await client._runPullSerialized(key, () => this.pullV2Impl(afterSeq, limit, {
|
|
24697
25034
|
...opts ?? {},
|
|
24698
25035
|
gateLocked: true
|
|
24699
25036
|
}), true);
|
|
@@ -24748,17 +25085,23 @@ var V2E2EECoordinator = class {
|
|
|
24748
25085
|
const pageContigBefore = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
|
|
24749
25086
|
const pageTrackerSnapshot = ns && typeof client._seqTracker.snapshotNamespace === "function" ? client._seqTracker.snapshotNamespace(ns) : null;
|
|
24750
25087
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
25088
|
+
const pageContiguousSeq = contiguousPullSeq(
|
|
25089
|
+
pageContigBefore,
|
|
25090
|
+
seqs,
|
|
25091
|
+
result.contiguous_seq
|
|
25092
|
+
);
|
|
24751
25093
|
const deferredKeyFetches = /* @__PURE__ */ new Map();
|
|
24752
25094
|
let blockedSeq = 0;
|
|
25095
|
+
const pageDecryptedBefore = decrypted.length;
|
|
24753
25096
|
for (const msg of messages) {
|
|
24754
25097
|
const seq2 = Number(msg.seq ?? 0);
|
|
24755
25098
|
if (!Number.isFinite(seq2) || seq2 <= 0) continue;
|
|
24756
25099
|
const version = String(msg.version ?? "v2");
|
|
24757
25100
|
if (version === "v1") {
|
|
24758
25101
|
const legacy = isJsonObject(msg.legacy_v1) ? msg.legacy_v1 : {};
|
|
24759
|
-
const legacyPayload = legacy.payload;
|
|
25102
|
+
const legacyPayload = legacy.payload !== void 0 ? legacy.payload : msg.payload;
|
|
24760
25103
|
const payloadType = isJsonObject(legacyPayload) ? String(legacyPayload.type ?? "").trim() : "";
|
|
24761
|
-
if (legacyPayload !== void 0 && legacyPayload !== null &&
|
|
25104
|
+
if (legacyPayload !== void 0 && legacyPayload !== null && !["e2ee.encrypted", "e2ee.group_encrypted", "e2ee.p2p_encrypted"].includes(payloadType)) {
|
|
24762
25105
|
const v1Msg = {
|
|
24763
25106
|
message_id: String(msg.message_id ?? ""),
|
|
24764
25107
|
from: String(msg.from_aid ?? ""),
|
|
@@ -24774,6 +25117,30 @@ var V2E2EECoordinator = class {
|
|
|
24774
25117
|
if (ns) await client._publishPulledMessage(appEvent.event, ns, seq2, appEvent.payload, false);
|
|
24775
25118
|
else await client._publishAppEvent(appEvent.event, appEvent.payload, "pull");
|
|
24776
25119
|
decrypted.push(v1Msg);
|
|
25120
|
+
} else if (isJsonObject(legacyPayload) && ["e2ee.p2p_encrypted", "e2ee.encrypted"].includes(payloadType)) {
|
|
25121
|
+
const deferStatus2 = {};
|
|
25122
|
+
const plaintext2 = await client._decryptV2Message(
|
|
25123
|
+
{ ...msg, envelope_json: JSON.stringify(legacyPayload) },
|
|
25124
|
+
true,
|
|
25125
|
+
true,
|
|
25126
|
+
true,
|
|
25127
|
+
true,
|
|
25128
|
+
deferStatus2,
|
|
25129
|
+
true,
|
|
25130
|
+
"pull"
|
|
25131
|
+
);
|
|
25132
|
+
if (deferStatus2.deferred) {
|
|
25133
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq2) : seq2;
|
|
25134
|
+
if (deferStatus2.fromAid) {
|
|
25135
|
+
const key = `${deferStatus2.fromAid}\0${deferStatus2.senderDeviceId ?? ""}\0${deferStatus2.groupId ?? ""}`;
|
|
25136
|
+
deferredKeyFetches.set(key, { fromAid: deferStatus2.fromAid, senderDeviceId: deferStatus2.senderDeviceId ?? "", groupId: deferStatus2.groupId ?? "" });
|
|
25137
|
+
}
|
|
25138
|
+
}
|
|
25139
|
+
if (plaintext2) {
|
|
25140
|
+
if (ns) await client._publishPulledMessage("message.received", ns, seq2, plaintext2, false);
|
|
25141
|
+
else await client._publishAppEvent("message.received", plaintext2, "pull");
|
|
25142
|
+
decrypted.push(plaintext2);
|
|
25143
|
+
}
|
|
24777
25144
|
} else {
|
|
24778
25145
|
client._clientLog.debug(`message.v2.pull skipping V1 envelope seq=${seq2} payload_type=${payloadType || "<none>"} (V1 E2EE removed)`);
|
|
24779
25146
|
}
|
|
@@ -24788,7 +25155,7 @@ var V2E2EECoordinator = class {
|
|
|
24788
25155
|
client._v2Session.trackOldSPKMaxSeq(msgSpkId, seq2);
|
|
24789
25156
|
}
|
|
24790
25157
|
const deferStatus = {};
|
|
24791
|
-
const plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
25158
|
+
const plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true, "pull");
|
|
24792
25159
|
if (deferStatus.deferred) {
|
|
24793
25160
|
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq2) : seq2;
|
|
24794
25161
|
}
|
|
@@ -24814,11 +25181,12 @@ var V2E2EECoordinator = class {
|
|
|
24814
25181
|
const serverAckSeq = parsedServerAckSeq ?? 0;
|
|
24815
25182
|
const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
|
|
24816
25183
|
if (ns) {
|
|
24817
|
-
const commitTarget =
|
|
25184
|
+
const commitTarget = Math.max(
|
|
24818
25185
|
pageContigBefore,
|
|
24819
25186
|
Number.isFinite(retentionFloor) ? retentionFloor : 0,
|
|
24820
25187
|
pageCount === 1 ? deferredServerCursor : 0,
|
|
24821
|
-
|
|
25188
|
+
serverAckSeq,
|
|
25189
|
+
blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq
|
|
24822
25190
|
);
|
|
24823
25191
|
let ackSeq = pageContigBefore;
|
|
24824
25192
|
let contigAdvanced = false;
|
|
@@ -24856,11 +25224,11 @@ var V2E2EECoordinator = class {
|
|
|
24856
25224
|
this.recordForwardCursor(ns, serverAckSeq, ackSeq);
|
|
24857
25225
|
}
|
|
24858
25226
|
const knownServerAckSeq = hasServerAckSeq ? serverAckSeq : pageCount === 1 ? deferredServerCursor : 0;
|
|
24859
|
-
const ackNeeded =
|
|
25227
|
+
const ackNeeded = ackSeq > 0 && ackSeq > lastAutoAckSeq && (hasServerAckSeq && ackSeq > serverAckSeq || contigAdvanced && ackSeq > knownServerAckSeq);
|
|
24860
25228
|
if (ackNeeded) {
|
|
24861
25229
|
this.recordForwardAck(ns, ackSeq);
|
|
24862
|
-
const nextAfter2 = Math.max(
|
|
24863
|
-
const canContinuePage = messages.length > 0 && nextAfter2 > nextAfterSeq;
|
|
25230
|
+
const nextAfter2 = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
25231
|
+
const canContinuePage = blockedSeq <= 0 && messages.length > 0 && nextAfter2 > nextAfterSeq;
|
|
24864
25232
|
if (canContinuePage) {
|
|
24865
25233
|
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
24866
25234
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
@@ -24870,7 +25238,17 @@ var V2E2EECoordinator = class {
|
|
|
24870
25238
|
}
|
|
24871
25239
|
}
|
|
24872
25240
|
}
|
|
24873
|
-
|
|
25241
|
+
if (ns) client._delivery.onPullPage?.(
|
|
25242
|
+
ns,
|
|
25243
|
+
decrypted.length - pageDecryptedBefore,
|
|
25244
|
+
hasMore,
|
|
25245
|
+
pageMaxSeq,
|
|
25246
|
+
typeof result.remaining === "number" && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null,
|
|
25247
|
+
messages.length,
|
|
25248
|
+
client._seqTracker.getContiguousSeq(ns),
|
|
25249
|
+
pageMaxSeq
|
|
25250
|
+
);
|
|
25251
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
24874
25252
|
const rawCount = messages.length;
|
|
24875
25253
|
if (blockedSeq > 0) break;
|
|
24876
25254
|
const shouldContinue = shouldContinueForwardPage({
|
|
@@ -24881,7 +25259,8 @@ var V2E2EECoordinator = class {
|
|
|
24881
25259
|
hasMoreField,
|
|
24882
25260
|
hasMore,
|
|
24883
25261
|
serverHead,
|
|
24884
|
-
pendingAckSeq
|
|
25262
|
+
pendingAckSeq,
|
|
25263
|
+
observedUpper: typeof client._seqTracker.getMaxSeenSeq === "function" ? client._seqTracker.getMaxSeenSeq(ns) : nextAfter
|
|
24885
25264
|
});
|
|
24886
25265
|
if (!shouldContinue) break;
|
|
24887
25266
|
if (pullGateKey && opts?.gateLocked && client._rpcPipeline?.yieldPullGate) {
|
|
@@ -24904,7 +25283,8 @@ var V2E2EECoordinator = class {
|
|
|
24904
25283
|
pendingAckSeq = 0;
|
|
24905
25284
|
}
|
|
24906
25285
|
}
|
|
24907
|
-
|
|
25286
|
+
client._delivery.onPullWorkSettled?.();
|
|
25287
|
+
return deduplicatePulledResults(decrypted);
|
|
24908
25288
|
}
|
|
24909
25289
|
async confirmForwardP2PAck(upToSeq, inlineGeneration) {
|
|
24910
25290
|
const ns = this.client._aid ? `p2p:${this.client._aid}` : "";
|
|
@@ -24990,10 +25370,7 @@ var V2E2EECoordinator = class {
|
|
|
24990
25370
|
if (isJsonObject(result)) {
|
|
24991
25371
|
const seq2 = Number(result.seq ?? 0);
|
|
24992
25372
|
if (seq2 > 0) {
|
|
24993
|
-
|
|
24994
|
-
client._seqTracker.onMessageSeq(ns, seq2);
|
|
24995
|
-
client._markPublishedSeq(ns, seq2);
|
|
24996
|
-
await client._saveSeqTrackerState();
|
|
25373
|
+
client._markPublishedSeq(`group:${gid}`, seq2);
|
|
24997
25374
|
}
|
|
24998
25375
|
}
|
|
24999
25376
|
return client._delivery.attachSendResultEnvelope("group.send", withExplicitGroupAid({
|
|
@@ -25013,10 +25390,7 @@ var V2E2EECoordinator = class {
|
|
|
25013
25390
|
if (isJsonObject(result)) {
|
|
25014
25391
|
const seq2 = Number(result.seq ?? 0);
|
|
25015
25392
|
if (seq2 > 0) {
|
|
25016
|
-
|
|
25017
|
-
client._seqTracker.onMessageSeq(ns, seq2);
|
|
25018
|
-
client._markPublishedSeq(ns, seq2);
|
|
25019
|
-
await client._saveSeqTrackerState();
|
|
25393
|
+
client._markPublishedSeq(`group:${gid}`, seq2);
|
|
25020
25394
|
}
|
|
25021
25395
|
}
|
|
25022
25396
|
return client._delivery.attachSendResultEnvelope("group.send", withExplicitGroupAid({
|
|
@@ -25041,6 +25415,11 @@ var V2E2EECoordinator = class {
|
|
|
25041
25415
|
const afterSeq = strictWindowSeq(params2.after_seq ?? 0, "after_seq");
|
|
25042
25416
|
const limit = strictWindowLimit(params2.limit ?? V2_PULL_DEFAULT_PAGE_LIMIT);
|
|
25043
25417
|
const ns = `group:${groupId}`;
|
|
25418
|
+
const cursorParams = isJsonObject(params2._group_cursor_params) ? params2._group_cursor_params : params2;
|
|
25419
|
+
const requestDeviceId = String(cursorParams.device_id ?? "").trim();
|
|
25420
|
+
const requestSlotId = String(cursorParams.slot_id ?? "").trim();
|
|
25421
|
+
const ownsCursor = (!requestDeviceId || requestDeviceId === String(client._deviceId ?? "")) && (!requestSlotId || requestSlotId === String(client._slotId ?? ""));
|
|
25422
|
+
if (ownsCursor) client._delivery.onPullStarted?.(ns);
|
|
25044
25423
|
const result = await client._callRawV2Rpc("group.v2.pull", withExplicitGroupAid({
|
|
25045
25424
|
group_id: groupId,
|
|
25046
25425
|
window_mode: "tail",
|
|
@@ -25050,9 +25429,6 @@ var V2E2EECoordinator = class {
|
|
|
25050
25429
|
}, groupAid));
|
|
25051
25430
|
const resultAid = String(result.group_aid ?? result.groupAid ?? "").trim();
|
|
25052
25431
|
if (resultAid) groupAid = resultAid;
|
|
25053
|
-
const floor = Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0);
|
|
25054
|
-
const previous = client._seqTracker.getSyncState(ns);
|
|
25055
|
-
await this.applyTailFloor(ns, Number.isSafeInteger(floor) ? floor : 0);
|
|
25056
25432
|
const page = validateTailPage(result, afterSeq, limit);
|
|
25057
25433
|
client._seqTracker.commitTailWindow(ns, {
|
|
25058
25434
|
windowStartSeq: page.windowStart,
|
|
@@ -25069,7 +25445,17 @@ var V2E2EECoordinator = class {
|
|
|
25069
25445
|
if (plaintext) decoded.push(plaintext);
|
|
25070
25446
|
}
|
|
25071
25447
|
const ack = client._seqTracker.getContiguousSeq(ns);
|
|
25072
|
-
if (
|
|
25448
|
+
if (ownsCursor) client._delivery.onPullPage?.(
|
|
25449
|
+
ns,
|
|
25450
|
+
decoded.length,
|
|
25451
|
+
result.has_more === true,
|
|
25452
|
+
page.head,
|
|
25453
|
+
typeof result.remaining === "number" && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null,
|
|
25454
|
+
page.messages.length,
|
|
25455
|
+
ack,
|
|
25456
|
+
page.head
|
|
25457
|
+
);
|
|
25458
|
+
client._delivery.onPullWorkSettled?.();
|
|
25073
25459
|
return { ...result, messages: decoded, raw_count: page.messages.length };
|
|
25074
25460
|
}
|
|
25075
25461
|
async historyGroupV2Internal(params2) {
|
|
@@ -25102,6 +25488,13 @@ var V2E2EECoordinator = class {
|
|
|
25102
25488
|
});
|
|
25103
25489
|
}
|
|
25104
25490
|
async pullGroupV2(groupId, afterSeq = 0, limit = 50, opts) {
|
|
25491
|
+
const lifecycleNs = `group:${String(groupId ?? "").trim()}`;
|
|
25492
|
+
if (opts?.ownsCursor === false) {
|
|
25493
|
+
return await this.pullGroupV2Impl(groupId, afterSeq, limit, opts);
|
|
25494
|
+
}
|
|
25495
|
+
return await this.runPullWithLifecycle(lifecycleNs, () => this.pullGroupV2Impl(groupId, afterSeq, limit, opts));
|
|
25496
|
+
}
|
|
25497
|
+
async pullGroupV2Impl(groupId, afterSeq = 0, limit = 50, opts) {
|
|
25105
25498
|
const client = this.client;
|
|
25106
25499
|
await client._ensureV2SessionReady("group.pull");
|
|
25107
25500
|
const gid = String(groupId ?? "").trim();
|
|
@@ -25117,12 +25510,13 @@ var V2E2EECoordinator = class {
|
|
|
25117
25510
|
limit,
|
|
25118
25511
|
_group_cursor_params: opts?.cursorParams
|
|
25119
25512
|
}, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
|
|
25120
|
-
return await client._runPullSerialized(key, () => this.
|
|
25513
|
+
return await client._runPullSerialized(key, () => this.pullGroupV2Impl(gid, afterSeq, limit, {
|
|
25121
25514
|
...opts ?? {},
|
|
25122
25515
|
gateLocked: true
|
|
25123
25516
|
}), false);
|
|
25124
25517
|
}
|
|
25125
25518
|
const result = await this.pullGroupV2TailInternal({
|
|
25519
|
+
...opts?.cursorParams ?? {},
|
|
25126
25520
|
group_id: String(opts.wireGroupId ?? gid),
|
|
25127
25521
|
group_aid: groupAid || void 0,
|
|
25128
25522
|
window_mode: "tail",
|
|
@@ -25139,7 +25533,7 @@ var V2E2EECoordinator = class {
|
|
|
25139
25533
|
limit,
|
|
25140
25534
|
_group_cursor_params: opts?.cursorParams
|
|
25141
25535
|
}, `${ns}|forward|after=${afterSeq}|force=${String(Boolean(opts?.force))}|limit=${limit}`);
|
|
25142
|
-
return await client._runPullSerialized(key, () => this.
|
|
25536
|
+
return await client._runPullSerialized(key, () => this.pullGroupV2Impl(gid, afterSeq, limit, {
|
|
25143
25537
|
...opts ?? {},
|
|
25144
25538
|
gateLocked: true
|
|
25145
25539
|
}), true);
|
|
@@ -25148,6 +25542,7 @@ var V2E2EECoordinator = class {
|
|
|
25148
25542
|
const wireGroupId = String(opts?.wireGroupId ?? groupId ?? "").trim() || gid;
|
|
25149
25543
|
const cursorParams = opts?.cursorParams ?? {};
|
|
25150
25544
|
const ownsCursor = opts?.ownsCursor !== false;
|
|
25545
|
+
if (ownsCursor) client._delivery.onPullStarted?.(ns);
|
|
25151
25546
|
let pullGateKey = ownsCursor ? pullGateKeyForClient(client, "group.v2.pull", {
|
|
25152
25547
|
group_id: gid,
|
|
25153
25548
|
after_seq: afterSeq,
|
|
@@ -25206,28 +25601,35 @@ var V2E2EECoordinator = class {
|
|
|
25206
25601
|
const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
25207
25602
|
const pageTrackerSnapshot = typeof client._seqTracker.snapshotNamespace === "function" ? client._seqTracker.snapshotNamespace(ns) : null;
|
|
25208
25603
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
25604
|
+
const pageContiguousSeq = contiguousPullSeq(
|
|
25605
|
+
pageContigBefore,
|
|
25606
|
+
seqs,
|
|
25607
|
+
result.contiguous_seq
|
|
25608
|
+
);
|
|
25209
25609
|
const deferredKeyFetches = /* @__PURE__ */ new Map();
|
|
25210
25610
|
let blockedSeq = 0;
|
|
25611
|
+
const pageDecryptedBefore = decrypted.length;
|
|
25211
25612
|
for (const msg of messages) {
|
|
25212
25613
|
const seq2 = Number(msg.seq ?? 0);
|
|
25213
25614
|
if (!Number.isFinite(seq2) || seq2 <= 0) continue;
|
|
25214
25615
|
const version = String(msg.version ?? "v2");
|
|
25215
25616
|
if (version === "v1") {
|
|
25216
|
-
const
|
|
25617
|
+
const legacy = isJsonObject(msg.legacy_v1) ? msg.legacy_v1 : {};
|
|
25618
|
+
const payload = msg.payload !== void 0 ? msg.payload : legacy.payload;
|
|
25217
25619
|
const payloadObj = isJsonObject(payload) ? payload : null;
|
|
25218
|
-
if (client._delivery.recallEventFromGroupMessage(msg)) {
|
|
25620
|
+
if (typeof client._delivery?.recallEventFromGroupMessage === "function" && client._delivery.recallEventFromGroupMessage(msg)) {
|
|
25219
25621
|
await client._delivery.publishGroupRecallTombstone(gid, seq2, {
|
|
25220
25622
|
...msg,
|
|
25221
25623
|
group_id: gid,
|
|
25222
25624
|
group_aid: eventGroupAid
|
|
25223
|
-
});
|
|
25625
|
+
}, "pull");
|
|
25224
25626
|
client._markPublishedSeq(ns, seq2);
|
|
25225
25627
|
client._clientLog.debug(`group.v2.pull recall tombstone delivered: group=${gid}, seq=${seq2}`);
|
|
25226
25628
|
continue;
|
|
25227
25629
|
}
|
|
25228
25630
|
if (payloadObj) {
|
|
25229
25631
|
const payloadType = String(payloadObj.type ?? "").trim();
|
|
25230
|
-
if (payloadType !== "e2ee.encrypted" && payloadType !== "e2ee.group_encrypted") {
|
|
25632
|
+
if (payloadType !== "e2ee.encrypted" && payloadType !== "e2ee.group_encrypted" && payloadType !== "e2ee.p2p_encrypted") {
|
|
25231
25633
|
let v1Msg = {
|
|
25232
25634
|
message_id: String(msg.message_id ?? ""),
|
|
25233
25635
|
from: String(msg.from_aid ?? ""),
|
|
@@ -25241,7 +25643,11 @@ var V2E2EECoordinator = class {
|
|
|
25241
25643
|
};
|
|
25242
25644
|
v1Msg = normalizeGroupMentionMode(v1Msg, msg, msg.envelope_json);
|
|
25243
25645
|
attachGatewayProximity(v1Msg, msg);
|
|
25244
|
-
|
|
25646
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
25647
|
+
await client._publishPulledMessage("group.message_created", ns, seq2, v1Msg, false);
|
|
25648
|
+
} else {
|
|
25649
|
+
client._markPublishedSeq(ns, seq2);
|
|
25650
|
+
}
|
|
25245
25651
|
decrypted.push(v1Msg);
|
|
25246
25652
|
continue;
|
|
25247
25653
|
}
|
|
@@ -25263,6 +25669,36 @@ var V2E2EECoordinator = class {
|
|
|
25263
25669
|
decrypted.push(v1Msg);
|
|
25264
25670
|
continue;
|
|
25265
25671
|
}
|
|
25672
|
+
if (payloadObj && ["e2ee.group_encrypted", "e2ee.p2p_encrypted", "e2ee.encrypted"].includes(String(payloadObj.type ?? "").trim())) {
|
|
25673
|
+
const deferStatus2 = {};
|
|
25674
|
+
const plaintext2 = await client._decryptV2Message(
|
|
25675
|
+
{ ...msg, envelope_json: JSON.stringify(payloadObj) },
|
|
25676
|
+
true,
|
|
25677
|
+
true,
|
|
25678
|
+
true,
|
|
25679
|
+
true,
|
|
25680
|
+
deferStatus2,
|
|
25681
|
+
true,
|
|
25682
|
+
"pull"
|
|
25683
|
+
);
|
|
25684
|
+
if (deferStatus2.deferred) {
|
|
25685
|
+
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq2) : seq2;
|
|
25686
|
+
if (deferStatus2.fromAid) {
|
|
25687
|
+
const key = `${deferStatus2.fromAid}\0${deferStatus2.senderDeviceId ?? ""}\0${deferStatus2.groupId ?? ""}`;
|
|
25688
|
+
deferredKeyFetches.set(key, { fromAid: deferStatus2.fromAid, senderDeviceId: deferStatus2.senderDeviceId ?? "", groupId: deferStatus2.groupId ?? "" });
|
|
25689
|
+
}
|
|
25690
|
+
}
|
|
25691
|
+
if (plaintext2) {
|
|
25692
|
+
plaintext2.group_id = gid;
|
|
25693
|
+
plaintext2.group_aid = eventGroupAid;
|
|
25694
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
25695
|
+
await client._publishPulledMessage("group.message_created", ns, seq2, plaintext2, false);
|
|
25696
|
+
} else {
|
|
25697
|
+
client._markPublishedSeq(ns, seq2);
|
|
25698
|
+
}
|
|
25699
|
+
decrypted.push(plaintext2);
|
|
25700
|
+
}
|
|
25701
|
+
}
|
|
25266
25702
|
client._clientLog.debug(`group.v2.pull skipping V1 envelope group=${gid} seq=${seq2} payload_type=${payloadObj ? String(payloadObj.type ?? "") : "<none>"} (V1 E2EE removed)`);
|
|
25267
25703
|
continue;
|
|
25268
25704
|
}
|
|
@@ -25271,7 +25707,7 @@ var V2E2EECoordinator = class {
|
|
|
25271
25707
|
continue;
|
|
25272
25708
|
}
|
|
25273
25709
|
const deferStatus = {};
|
|
25274
|
-
let plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true);
|
|
25710
|
+
let plaintext = await client._decryptV2Message(msg, true, true, true, true, deferStatus, true, "pull");
|
|
25275
25711
|
if (deferStatus.deferred) {
|
|
25276
25712
|
blockedSeq = blockedSeq > 0 ? Math.min(blockedSeq, seq2) : seq2;
|
|
25277
25713
|
}
|
|
@@ -25287,7 +25723,11 @@ var V2E2EECoordinator = class {
|
|
|
25287
25723
|
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
25288
25724
|
plaintext.group_id = gid;
|
|
25289
25725
|
plaintext.group_aid = eventGroupAid;
|
|
25290
|
-
|
|
25726
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
25727
|
+
await client._publishPulledMessage("group.message_created", ns, seq2, plaintext, false);
|
|
25728
|
+
} else {
|
|
25729
|
+
client._markPublishedSeq(ns, seq2);
|
|
25730
|
+
}
|
|
25291
25731
|
decrypted.push(plaintext);
|
|
25292
25732
|
}
|
|
25293
25733
|
const hasServerCursor = cursor !== null && Object.prototype.hasOwnProperty.call(cursor, "current_seq");
|
|
@@ -25303,11 +25743,12 @@ var V2E2EECoordinator = class {
|
|
|
25303
25743
|
Number(cursor?.join_seq ?? 0)
|
|
25304
25744
|
);
|
|
25305
25745
|
const effectiveFloor = Math.max(retentionFloor, visibilityFloor);
|
|
25306
|
-
const commitTarget =
|
|
25746
|
+
const commitTarget = Math.max(
|
|
25307
25747
|
pageContigBefore,
|
|
25308
25748
|
Number.isFinite(effectiveFloor) ? effectiveFloor : 0,
|
|
25309
25749
|
ownsCursor && pageCount === 1 ? deferredServerCursor : 0,
|
|
25310
|
-
|
|
25750
|
+
cursorCurrentSeq,
|
|
25751
|
+
blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq
|
|
25311
25752
|
);
|
|
25312
25753
|
let ackSeq = pageContigBefore;
|
|
25313
25754
|
let contigAdvanced = false;
|
|
@@ -25343,15 +25784,25 @@ var V2E2EECoordinator = class {
|
|
|
25343
25784
|
for (const fetch2 of deferredKeyFetches.values()) {
|
|
25344
25785
|
this.scheduleSenderIKFetch(fetch2.fromAid, fetch2.senderDeviceId, fetch2.groupId);
|
|
25345
25786
|
}
|
|
25787
|
+
client._delivery.onPullPage?.(
|
|
25788
|
+
ns,
|
|
25789
|
+
decrypted.length - pageDecryptedBefore,
|
|
25790
|
+
hasMore,
|
|
25791
|
+
pageMaxSeq,
|
|
25792
|
+
typeof result.remaining === "number" && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null,
|
|
25793
|
+
messages.length,
|
|
25794
|
+
client._seqTracker.getContiguousSeq(ns),
|
|
25795
|
+
pageMaxSeq
|
|
25796
|
+
);
|
|
25346
25797
|
if (ownsCursor && parsedCursorCurrentSeq !== null && cursorCurrentSeq > ackSeq) {
|
|
25347
25798
|
this.recordForwardCursor(ns, cursorCurrentSeq, ackSeq);
|
|
25348
25799
|
}
|
|
25349
25800
|
const knownServerCursorSeq = hasServerCursor ? cursorCurrentSeq : ownsCursor && pageCount === 1 ? deferredServerCursor : 0;
|
|
25350
|
-
const ackNeeded =
|
|
25801
|
+
const ackNeeded = ackSeq > 0 && ackSeq > lastAutoAckSeq && ownsCursor && (hasServerCursor && ackSeq > cursorCurrentSeq || contigAdvanced && ackSeq > knownServerCursorSeq);
|
|
25351
25802
|
if (ackNeeded) {
|
|
25352
25803
|
this.recordForwardAck(ns, ackSeq);
|
|
25353
|
-
const nextAfter2 = Math.max(
|
|
25354
|
-
const canContinuePage = messages.length > 0 && nextAfter2 > nextAfterSeq && ownsCursor;
|
|
25804
|
+
const nextAfter2 = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
25805
|
+
const canContinuePage = blockedSeq <= 0 && messages.length > 0 && nextAfter2 > nextAfterSeq && ownsCursor;
|
|
25355
25806
|
if (canContinuePage) {
|
|
25356
25807
|
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
25357
25808
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
@@ -25360,7 +25811,7 @@ var V2E2EECoordinator = class {
|
|
|
25360
25811
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
25361
25812
|
}
|
|
25362
25813
|
}
|
|
25363
|
-
const nextAfter = Math.max(
|
|
25814
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
25364
25815
|
if (!ownsCursor) break;
|
|
25365
25816
|
const rawCount = messages.length;
|
|
25366
25817
|
if (blockedSeq > 0) break;
|
|
@@ -25372,7 +25823,8 @@ var V2E2EECoordinator = class {
|
|
|
25372
25823
|
hasMoreField,
|
|
25373
25824
|
hasMore,
|
|
25374
25825
|
serverHead,
|
|
25375
|
-
pendingAckSeq
|
|
25826
|
+
pendingAckSeq,
|
|
25827
|
+
observedUpper: typeof client._seqTracker.getMaxSeenSeq === "function" ? client._seqTracker.getMaxSeenSeq(ns) : nextAfter
|
|
25376
25828
|
});
|
|
25377
25829
|
if (!shouldContinue) break;
|
|
25378
25830
|
if (pullGateKey && opts?.gateLocked && client._rpcPipeline?.yieldPullGate) {
|
|
@@ -25397,7 +25849,8 @@ var V2E2EECoordinator = class {
|
|
|
25397
25849
|
pendingAckSeq = 0;
|
|
25398
25850
|
}
|
|
25399
25851
|
}
|
|
25400
|
-
|
|
25852
|
+
client._delivery.onPullWorkSettled?.();
|
|
25853
|
+
return deduplicatePulledResults(decrypted);
|
|
25401
25854
|
}
|
|
25402
25855
|
async confirmForwardGroupAck(groupId, upToSeq, groupAid) {
|
|
25403
25856
|
const ns = `group:${String(groupId ?? "").trim()}`;
|
|
@@ -25906,7 +26359,7 @@ var V2E2EECoordinator = class {
|
|
|
25906
26359
|
}
|
|
25907
26360
|
async decryptV2PushMessage(data) {
|
|
25908
26361
|
if (!isJsonObject(data)) return null;
|
|
25909
|
-
return await this.client._decryptV2Message(data);
|
|
26362
|
+
return await this.client._decryptV2Message(data, false, false, false, false, void 0, false, "inline_push");
|
|
25910
26363
|
}
|
|
25911
26364
|
async buildV2P2PEnvelope(opts) {
|
|
25912
26365
|
const client = this.client;
|
|
@@ -26234,7 +26687,8 @@ var MEMBERSHIP_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
|
26234
26687
|
"group.review_join_request",
|
|
26235
26688
|
"group.batch_review_join_request",
|
|
26236
26689
|
"group.use_invite_code",
|
|
26237
|
-
"group.request_join"
|
|
26690
|
+
"group.request_join",
|
|
26691
|
+
"group.accept_invite"
|
|
26238
26692
|
]);
|
|
26239
26693
|
var SPK_REGISTRATION_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
26240
26694
|
"group.create",
|
|
@@ -28963,6 +29417,7 @@ var RECONNECT_MIN_BASE_DELAY_SECONDS = 1;
|
|
|
28963
29417
|
var RECONNECT_MAX_BASE_DELAY_SECONDS = 64;
|
|
28964
29418
|
var TOKEN_REFRESH_CHECK_INTERVAL_MS = 3e4;
|
|
28965
29419
|
var MAX_NOTIFY_PAYLOAD_SIZE = 64 * 1024;
|
|
29420
|
+
var GROUP_INVITE_METADATA_KEY = "group_invite_pending_v1";
|
|
28966
29421
|
function clampReconnectDelaySeconds(value, fallback, upper = RECONNECT_MAX_BASE_DELAY_SECONDS) {
|
|
28967
29422
|
const parsed = Number(value);
|
|
28968
29423
|
const seconds = Number.isFinite(parsed) ? parsed : fallback;
|
|
@@ -29355,6 +29810,9 @@ var _AUNClient = class _AUNClient {
|
|
|
29355
29810
|
__publicField(this, "_mailFacade");
|
|
29356
29811
|
__publicField(this, "_groupFacade");
|
|
29357
29812
|
__publicField(this, "_streamFacade");
|
|
29813
|
+
__publicField(this, "_groupInvitePending", /* @__PURE__ */ new Map());
|
|
29814
|
+
__publicField(this, "_groupInviteStateAid", null);
|
|
29815
|
+
__publicField(this, "_groupInviteStateLoad", null);
|
|
29358
29816
|
/**
|
|
29359
29817
|
* 处理 V2 push 通知:自动 pull + decrypt + emit。
|
|
29360
29818
|
*/
|
|
@@ -29478,6 +29936,15 @@ var _AUNClient = class _AUNClient {
|
|
|
29478
29936
|
this._dispatcher.subscribe("_raw.group.changed", (data) => {
|
|
29479
29937
|
this._onRawGroupChanged(data);
|
|
29480
29938
|
});
|
|
29939
|
+
this._dispatcher.subscribe("_raw.group.invite_created", (data) => {
|
|
29940
|
+
this._safeAsync(this._onRawGroupInviteReceived(data, "push"));
|
|
29941
|
+
});
|
|
29942
|
+
this._dispatcher.subscribe("_raw.group.invite_received", (data) => {
|
|
29943
|
+
this._safeAsync(this._onRawGroupInviteReceived(data, "push"));
|
|
29944
|
+
});
|
|
29945
|
+
this._dispatcher.subscribe("_raw.group.invite_finalized", (data) => {
|
|
29946
|
+
this._safeAsync(this._onRawGroupInviteFinalized(data));
|
|
29947
|
+
});
|
|
29481
29948
|
this._dispatcher.subscribe("_raw.peer.v2.message_received", (data) => {
|
|
29482
29949
|
this._safeAsync(this._onV2PushNotification(data));
|
|
29483
29950
|
});
|
|
@@ -29952,6 +30419,53 @@ var _AUNClient = class _AUNClient {
|
|
|
29952
30419
|
await this._agentMdManager.upload(await this._agentMdManager.readContent(target) ?? buildDefaultAgentMd(target));
|
|
29953
30420
|
return true;
|
|
29954
30421
|
}
|
|
30422
|
+
async _checkIdentityAdmissionAfterConnect() {
|
|
30423
|
+
const aid = String(this._aid ?? this._currentAid?.aid ?? "").trim();
|
|
30424
|
+
if (!aid) return;
|
|
30425
|
+
try {
|
|
30426
|
+
const checked = await this._agentMdManager.check(aid);
|
|
30427
|
+
if (!checked.remote_found) {
|
|
30428
|
+
const content = await this._agentMdManager.readContent(aid) ?? buildDefaultAgentMd(aid);
|
|
30429
|
+
await this._agentMdManager.upload(content);
|
|
30430
|
+
}
|
|
30431
|
+
} catch (exc) {
|
|
30432
|
+
this._clientLog.warn(`post-connect agent.md check failed: ${String(exc)}`);
|
|
30433
|
+
}
|
|
30434
|
+
const store = this._aidStore;
|
|
30435
|
+
if (!store) return;
|
|
30436
|
+
let listed;
|
|
30437
|
+
try {
|
|
30438
|
+
listed = await this.call("group.list_my", {});
|
|
30439
|
+
} catch (exc) {
|
|
30440
|
+
this._clientLog.warn(`post-connect group identity check failed: ${String(exc)}`);
|
|
30441
|
+
return;
|
|
30442
|
+
}
|
|
30443
|
+
const result = isJsonObject(listed) ? listed : {};
|
|
30444
|
+
const groups = Array.isArray(result.groups) ? result.groups : Array.isArray(result.items) ? result.items : [];
|
|
30445
|
+
for (const raw of groups) {
|
|
30446
|
+
if (!isJsonObject(raw)) continue;
|
|
30447
|
+
const role = String(raw.role ?? raw.my_role ?? "").trim().toLowerCase();
|
|
30448
|
+
if (role !== "owner") continue;
|
|
30449
|
+
const groupId = String(raw.group_id ?? raw.groupId ?? raw.group_aid ?? raw.groupAid ?? "").trim();
|
|
30450
|
+
const groupAid = String(raw.group_aid ?? raw.groupAid ?? groupId).trim();
|
|
30451
|
+
if (!groupId || !groupAid) continue;
|
|
30452
|
+
try {
|
|
30453
|
+
await this._runGroupIdentityOperation(groupId, async () => {
|
|
30454
|
+
const loaded = await store.load(groupAid);
|
|
30455
|
+
if (!loaded.ok || !loaded.data?.aid?.isPrivateKeyValid()) {
|
|
30456
|
+
await this.bindGroupAid({ group_id: groupId, group_aid: groupAid }, { aidStore: store });
|
|
30457
|
+
return;
|
|
30458
|
+
}
|
|
30459
|
+
const checked = await this._agentMdManager.check(groupAid);
|
|
30460
|
+
if (!checked.remote_found) {
|
|
30461
|
+
await this._uploadGroupAgentMd(store, groupAid, {}, {}, aid);
|
|
30462
|
+
}
|
|
30463
|
+
});
|
|
30464
|
+
} catch (exc) {
|
|
30465
|
+
this._clientLog.warn(`post-connect group identity check failed: group=${groupId} err=${String(exc)}`);
|
|
30466
|
+
}
|
|
30467
|
+
}
|
|
30468
|
+
}
|
|
29955
30469
|
async _runGroupIdentityOperation(groupId, operation) {
|
|
29956
30470
|
const aid = String(this._aid ?? this._currentAid?.aid ?? "").trim();
|
|
29957
30471
|
const dot = aid.indexOf(".");
|
|
@@ -29978,6 +30492,8 @@ var _AUNClient = class _AUNClient {
|
|
|
29978
30492
|
}
|
|
29979
30493
|
this._aidStore = store;
|
|
29980
30494
|
const payload = { ...params2 };
|
|
30495
|
+
const initialMembers = payload.members;
|
|
30496
|
+
delete payload.members;
|
|
29981
30497
|
if (payload.group_name === void 0 && payload.groupName !== void 0) {
|
|
29982
30498
|
payload.group_name = payload.groupName;
|
|
29983
30499
|
delete payload.groupName;
|
|
@@ -30007,7 +30523,8 @@ var _AUNClient = class _AUNClient {
|
|
|
30007
30523
|
const result2 = { ...createdMap, ...boundMap, group: { ...createdGroup, ...boundGroup } };
|
|
30008
30524
|
const postprocessParams2 = { ...payload };
|
|
30009
30525
|
delete postprocessParams2._defer_group_ready_postprocess;
|
|
30010
|
-
|
|
30526
|
+
const processed2 = await this._groupState.postprocessResult("group.create", postprocessParams2, result2);
|
|
30527
|
+
return await this._inviteInitialGroupMembers(processed2, groupId, initialMembers);
|
|
30011
30528
|
}
|
|
30012
30529
|
const pendingKey = `create:${String(payload.group_name).trim().toLowerCase()}`;
|
|
30013
30530
|
const keystore = store._keystore;
|
|
@@ -30057,7 +30574,29 @@ var _AUNClient = class _AUNClient {
|
|
|
30057
30574
|
}
|
|
30058
30575
|
const postprocessParams = { ...payload };
|
|
30059
30576
|
delete postprocessParams._defer_group_ready_postprocess;
|
|
30060
|
-
|
|
30577
|
+
const processed = await this._groupState.postprocessResult("group.create", postprocessParams, result);
|
|
30578
|
+
return await this._inviteInitialGroupMembers(processed, String(group.group_id ?? groupAid).trim(), initialMembers);
|
|
30579
|
+
}
|
|
30580
|
+
async _inviteInitialGroupMembers(result, groupId, members) {
|
|
30581
|
+
const invites = [];
|
|
30582
|
+
const inviteErrors = [];
|
|
30583
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30584
|
+
if (Array.isArray(members)) {
|
|
30585
|
+
for (const item of members) {
|
|
30586
|
+
const aid = typeof item === "string" ? item.trim() : isJsonObject(item) ? String(item.aid ?? "").trim() : "";
|
|
30587
|
+
const memberType = isJsonObject(item) ? String(item.member_type ?? "").trim() : "";
|
|
30588
|
+
if (!aid || aid === String(this._aid ?? this._currentAid?.aid ?? "").trim() || seen.has(aid)) continue;
|
|
30589
|
+
seen.add(aid);
|
|
30590
|
+
const params2 = { group_id: groupId, invitee_aid: aid };
|
|
30591
|
+
if (memberType) params2.member_type = memberType;
|
|
30592
|
+
try {
|
|
30593
|
+
invites.push(await this.group.inviteMember(params2));
|
|
30594
|
+
} catch (err) {
|
|
30595
|
+
inviteErrors.push({ aid, error: err instanceof Error ? err.message : String(err) });
|
|
30596
|
+
}
|
|
30597
|
+
}
|
|
30598
|
+
}
|
|
30599
|
+
return { ...isJsonObject(result) ? result : {}, invites, invite_errors: inviteErrors };
|
|
30061
30600
|
}
|
|
30062
30601
|
_groupAgentMdContent(groupAid, params2 = {}, group = {}) {
|
|
30063
30602
|
const explicit = params2.group_agent_md ?? params2.groupAgentMd ?? params2.content;
|
|
@@ -30585,7 +31124,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30585
31124
|
_markPublishedSeq(ns, seq2) {
|
|
30586
31125
|
this._delivery.markPublishedSeq(ns, seq2);
|
|
30587
31126
|
}
|
|
30588
|
-
async _publishAppEvent(event, payload, source = "", ns = "", batch) {
|
|
31127
|
+
async _publishAppEvent(event, payload, source = "direct", ns = "", batch) {
|
|
30589
31128
|
await this._delivery.publishAppEvent(event, payload, source, ns, batch);
|
|
30590
31129
|
}
|
|
30591
31130
|
_echoTimestamp() {
|
|
@@ -30639,6 +31178,239 @@ var _AUNClient = class _AUNClient {
|
|
|
30639
31178
|
const member = isJsonObject(result.member) ? result.member : null;
|
|
30640
31179
|
return member ? String(member.group_id ?? member.groupId ?? member.group_aid ?? member.groupAid ?? "") : "";
|
|
30641
31180
|
}
|
|
31181
|
+
groupInviteKey(groupId, inviteeAid) {
|
|
31182
|
+
const group = normalizeGroupId(groupId);
|
|
31183
|
+
const invitee = String(inviteeAid ?? "").trim().toLowerCase();
|
|
31184
|
+
return group && invitee ? `${group}
|
|
31185
|
+
${invitee}` : "";
|
|
31186
|
+
}
|
|
31187
|
+
async ensureGroupInviteStateLoaded() {
|
|
31188
|
+
const aid = String(this._aid ?? "").trim();
|
|
31189
|
+
if (!aid) {
|
|
31190
|
+
this._groupInvitePending.clear();
|
|
31191
|
+
this._groupInviteStateAid = null;
|
|
31192
|
+
return;
|
|
31193
|
+
}
|
|
31194
|
+
if (this._groupInviteStateAid === aid) return;
|
|
31195
|
+
if (this._groupInviteStateLoad) {
|
|
31196
|
+
await this._groupInviteStateLoad;
|
|
31197
|
+
if (this._groupInviteStateAid === aid) return;
|
|
31198
|
+
}
|
|
31199
|
+
this._groupInviteStateLoad = (async () => {
|
|
31200
|
+
this._groupInvitePending.clear();
|
|
31201
|
+
this._groupInviteStateAid = aid;
|
|
31202
|
+
const getter = this._tokenStore?.getMetadata;
|
|
31203
|
+
if (typeof getter !== "function") return;
|
|
31204
|
+
try {
|
|
31205
|
+
const raw = await getter.call(this._tokenStore, aid, GROUP_INVITE_METADATA_KEY);
|
|
31206
|
+
const parsed = raw ? JSON.parse(String(raw)) : {};
|
|
31207
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
31208
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
31209
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
31210
|
+
this._groupInvitePending.set(key, value);
|
|
31211
|
+
}
|
|
31212
|
+
}
|
|
31213
|
+
} catch (exc) {
|
|
31214
|
+
this._clientLog.debug(`group invite state restore skipped: ${String(exc)}`);
|
|
31215
|
+
}
|
|
31216
|
+
})().finally(() => {
|
|
31217
|
+
this._groupInviteStateLoad = null;
|
|
31218
|
+
});
|
|
31219
|
+
return this._groupInviteStateLoad;
|
|
31220
|
+
}
|
|
31221
|
+
async persistGroupInviteState() {
|
|
31222
|
+
const aid = String(this._aid ?? "").trim();
|
|
31223
|
+
const setter = this._tokenStore?.setMetadata;
|
|
31224
|
+
if (!aid || typeof setter !== "function") return;
|
|
31225
|
+
const state = {};
|
|
31226
|
+
for (const [key, value] of this._groupInvitePending) state[key] = value;
|
|
31227
|
+
try {
|
|
31228
|
+
await setter.call(this._tokenStore, aid, GROUP_INVITE_METADATA_KEY, JSON.stringify(state));
|
|
31229
|
+
} catch (exc) {
|
|
31230
|
+
this._clientLog.debug(`group invite state persist skipped: ${String(exc)}`);
|
|
31231
|
+
}
|
|
31232
|
+
}
|
|
31233
|
+
inviteArray(value, singular) {
|
|
31234
|
+
const values = Array.isArray(value) ? value : singular !== void 0 ? [singular] : [];
|
|
31235
|
+
return [...new Set(values.map((item) => String(item ?? "").trim()).filter(Boolean))];
|
|
31236
|
+
}
|
|
31237
|
+
inviteBool(value) {
|
|
31238
|
+
return value === true || value === 1 || String(value ?? "").trim().toLowerCase() === "true";
|
|
31239
|
+
}
|
|
31240
|
+
async _onRawGroupInviteReceived(data, source = "push") {
|
|
31241
|
+
if (!isJsonObject(data)) return;
|
|
31242
|
+
const groupId = normalizeGroupId(data.group_id ?? data.groupId ?? data.group_aid ?? data.groupAid);
|
|
31243
|
+
const inviteeAid = String(data.invitee_aid ?? data.inviteeAid ?? this._aid ?? "").trim();
|
|
31244
|
+
if (!groupId || !inviteeAid || this._aid && inviteeAid.toLowerCase() !== this._aid.toLowerCase()) return;
|
|
31245
|
+
if (String(data.status ?? "pending").trim().toLowerCase() !== "pending") {
|
|
31246
|
+
await this._onRawGroupInviteFinalized(data);
|
|
31247
|
+
return;
|
|
31248
|
+
}
|
|
31249
|
+
await this.ensureGroupInviteStateLoaded();
|
|
31250
|
+
const key = this.groupInviteKey(groupId, inviteeAid);
|
|
31251
|
+
if (!key) return;
|
|
31252
|
+
const inviteIds = this.inviteArray(data.invite_ids, data.invite_id);
|
|
31253
|
+
const inviterAids = this.inviteArray(data.inviter_aids, data.inviter_aid);
|
|
31254
|
+
const existing = this._groupInvitePending.get(key);
|
|
31255
|
+
if (existing) {
|
|
31256
|
+
existing.invite_ids = [.../* @__PURE__ */ new Set([...this.inviteArray(existing.invite_ids), ...inviteIds])];
|
|
31257
|
+
existing.inviter_aids = [.../* @__PURE__ */ new Set([...this.inviteArray(existing.inviter_aids), ...inviterAids])];
|
|
31258
|
+
await this.persistGroupInviteState();
|
|
31259
|
+
return;
|
|
31260
|
+
}
|
|
31261
|
+
const payload = {
|
|
31262
|
+
...data,
|
|
31263
|
+
group_id: groupId,
|
|
31264
|
+
group_aid: groupId,
|
|
31265
|
+
invitee_aid: inviteeAid,
|
|
31266
|
+
invite_ids: inviteIds,
|
|
31267
|
+
inviter_aids: inviterAids,
|
|
31268
|
+
role: data.role ?? "member",
|
|
31269
|
+
member_type: data.member_type ?? data.memberType ?? "human",
|
|
31270
|
+
created_at: data.created_at ?? data.createdAt ?? 0,
|
|
31271
|
+
expires_at: data.expires_at ?? data.expiresAt ?? 0,
|
|
31272
|
+
status: "pending"
|
|
31273
|
+
};
|
|
31274
|
+
delete payload.groupId;
|
|
31275
|
+
delete payload.groupAid;
|
|
31276
|
+
delete payload.inviteeAid;
|
|
31277
|
+
delete payload.inviterAid;
|
|
31278
|
+
this._groupInvitePending.set(key, payload);
|
|
31279
|
+
await this.persistGroupInviteState();
|
|
31280
|
+
await this._publishAppEvent("group.invite_received", JSON.parse(JSON.stringify(payload)), source);
|
|
31281
|
+
}
|
|
31282
|
+
async _onRawGroupInviteFinalized(data) {
|
|
31283
|
+
if (!isJsonObject(data)) return;
|
|
31284
|
+
await this.ensureGroupInviteStateLoaded();
|
|
31285
|
+
const groupId = normalizeGroupId(data.group_id ?? data.groupId ?? data.group_aid ?? data.groupAid);
|
|
31286
|
+
const inviteeAid = String(data.invitee_aid ?? data.inviteeAid ?? this._aid ?? "").trim();
|
|
31287
|
+
if (this._aid && inviteeAid.toLowerCase() !== this._aid.toLowerCase()) return;
|
|
31288
|
+
const inviteId = String(data.invite_id ?? "").trim();
|
|
31289
|
+
const key = this.groupInviteKey(groupId, inviteeAid);
|
|
31290
|
+
const status = String(data.status ?? "").trim().toLowerCase();
|
|
31291
|
+
const aggregateStatus = String(data.aggregate_status ?? data.aggregateStatus ?? "").trim().toLowerCase();
|
|
31292
|
+
const pendingIds = this.inviteArray(data.pending_invite_ids ?? data.pendingInviteIds);
|
|
31293
|
+
const pendingInviters = this.inviteArray(data.pending_inviter_aids ?? data.pendingInviterAids);
|
|
31294
|
+
const finalizedIds = this.inviteBool(data.remaining_pending) && inviteId ? [inviteId] : this.inviteArray(data.invite_ids, data.invite_id);
|
|
31295
|
+
const finalizedInviters = this.inviteArray(data.inviter_aids, data.inviter_aid);
|
|
31296
|
+
const leavesPending = this.inviteBool(data.remaining_pending) || this.inviteBool(data.pending) || status === "pending" || aggregateStatus === "pending" || pendingIds.length > 0;
|
|
31297
|
+
let changed = false;
|
|
31298
|
+
const candidates = [];
|
|
31299
|
+
if (key) {
|
|
31300
|
+
const current = this._groupInvitePending.get(key);
|
|
31301
|
+
if (current) candidates.push([key, current]);
|
|
31302
|
+
}
|
|
31303
|
+
if (candidates.length === 0 && inviteId) {
|
|
31304
|
+
for (const [itemKey, item] of this._groupInvitePending) {
|
|
31305
|
+
if (this.inviteArray(item.invite_ids).includes(inviteId)) candidates.push([itemKey, item]);
|
|
31306
|
+
}
|
|
31307
|
+
}
|
|
31308
|
+
for (const [itemKey, item] of candidates) {
|
|
31309
|
+
if (!leavesPending) {
|
|
31310
|
+
this._groupInvitePending.delete(itemKey);
|
|
31311
|
+
changed = true;
|
|
31312
|
+
continue;
|
|
31313
|
+
}
|
|
31314
|
+
const currentIds = this.inviteArray(item.invite_ids);
|
|
31315
|
+
const currentInviters = this.inviteArray(item.inviter_aids);
|
|
31316
|
+
const finalizedIndexes = new Set(currentIds.map((id, index) => finalizedIds.includes(id) ? index : -1).filter((index) => index >= 0));
|
|
31317
|
+
const nextIds = pendingIds.length > 0 ? pendingIds : finalizedIds.length > 0 ? currentIds.filter((id) => !finalizedIds.includes(id)) : currentIds;
|
|
31318
|
+
const nextInviters = pendingInviters.length > 0 ? pendingInviters : finalizedInviters.length > 0 ? currentInviters.filter((aid) => !finalizedInviters.includes(aid)) : finalizedIndexes.size > 0 ? currentInviters.filter((_aid, index) => !finalizedIndexes.has(index)) : currentInviters;
|
|
31319
|
+
if (nextIds.length === 0) {
|
|
31320
|
+
this._groupInvitePending.delete(itemKey);
|
|
31321
|
+
} else {
|
|
31322
|
+
item.invite_ids = nextIds;
|
|
31323
|
+
item.inviter_aids = nextInviters;
|
|
31324
|
+
}
|
|
31325
|
+
changed = true;
|
|
31326
|
+
}
|
|
31327
|
+
if (changed) await this.persistGroupInviteState();
|
|
31328
|
+
}
|
|
31329
|
+
async _onGroupInviteActionResult(method, params2, result, error) {
|
|
31330
|
+
if (method === "group.list_my_invites" && !error && (isJsonObject(result) || Array.isArray(result))) {
|
|
31331
|
+
await this.restoreGroupInvitesFromResult(result, params2);
|
|
31332
|
+
return;
|
|
31333
|
+
}
|
|
31334
|
+
if (!["group.accept_invite", "group.reject_invite", "group.revoke_invite"].includes(method)) return;
|
|
31335
|
+
const text3 = String(error instanceof Error ? error.message : error ?? "").toLowerCase();
|
|
31336
|
+
const resultStatus = isJsonObject(result) ? String(result.status ?? "").toLowerCase() : "";
|
|
31337
|
+
const aggregateResultStatus = isJsonObject(result) ? String(result.aggregate_status ?? result.aggregateStatus ?? "").toLowerCase() : "";
|
|
31338
|
+
const terminalStatus = resultStatus || aggregateResultStatus;
|
|
31339
|
+
const pendingResult = resultStatus === "pending" || aggregateResultStatus === "pending" || isJsonObject(result) && (this.inviteBool(result.remaining_pending) || this.inviteBool(result.pending));
|
|
31340
|
+
if (pendingResult) {
|
|
31341
|
+
if (isJsonObject(result) && (this.inviteBool(result.remaining_pending) || this.inviteArray(result.pending_invite_ids ?? result.pendingInviteIds).length > 0)) {
|
|
31342
|
+
await this._onRawGroupInviteFinalized({ ...params2, ...result });
|
|
31343
|
+
}
|
|
31344
|
+
return;
|
|
31345
|
+
}
|
|
31346
|
+
const terminal = !pendingResult && (!error || ["accepted", "rejected", "revoked", "expired", "ended"].includes(terminalStatus) || /ended|expired|not.*pending|no longer.*pending|not found|finalized|already\s+(?:been\s+)?(?:accepted|rejected|revoked)/.test(text3));
|
|
31347
|
+
if (!terminal) return;
|
|
31348
|
+
await this._onRawGroupInviteFinalized({
|
|
31349
|
+
...params2,
|
|
31350
|
+
...isJsonObject(result) ? result : {},
|
|
31351
|
+
status: terminalStatus || "ended"
|
|
31352
|
+
});
|
|
31353
|
+
}
|
|
31354
|
+
async restoreGroupInvitesFromResult(result, requestParams = {}) {
|
|
31355
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31356
|
+
const visitedPages = /* @__PURE__ */ new Set();
|
|
31357
|
+
let current = result;
|
|
31358
|
+
let currentParams = { ...requestParams };
|
|
31359
|
+
let finalPage = false;
|
|
31360
|
+
while (!finalPage) {
|
|
31361
|
+
const root = Array.isArray(current) ? null : isJsonObject(current) ? current : null;
|
|
31362
|
+
const nestedValue = root && isJsonObject(root.data) ? root.data : root;
|
|
31363
|
+
const nested = nestedValue ?? {};
|
|
31364
|
+
const rawItems = Array.isArray(nested.items) ? nested.items : Array.isArray(nested.invites) ? nested.invites : Array.isArray(current) ? current : [];
|
|
31365
|
+
for (const item of rawItems) {
|
|
31366
|
+
if (!isJsonObject(item)) continue;
|
|
31367
|
+
const status = String(item.status ?? "pending").toLowerCase();
|
|
31368
|
+
const gid = normalizeGroupId(item.group_id ?? item.group_aid ?? item.groupId ?? item.groupAid);
|
|
31369
|
+
const aid = String(item.invitee_aid ?? item.inviteeAid ?? this._aid ?? "").trim();
|
|
31370
|
+
if (this._aid && aid.toLowerCase() !== this._aid.toLowerCase()) continue;
|
|
31371
|
+
const key = this.groupInviteKey(gid, aid);
|
|
31372
|
+
if (status === "pending" && key) {
|
|
31373
|
+
seen.add(key);
|
|
31374
|
+
await this._onRawGroupInviteReceived(item, "pull");
|
|
31375
|
+
} else if (key) {
|
|
31376
|
+
seen.add(key);
|
|
31377
|
+
await this._onRawGroupInviteFinalized(item);
|
|
31378
|
+
}
|
|
31379
|
+
}
|
|
31380
|
+
const hasMore = this.inviteBool(nested.has_more ?? nested.hasMore ?? (root ? root.has_more ?? root.hasMore : void 0));
|
|
31381
|
+
if (!hasMore) {
|
|
31382
|
+
finalPage = true;
|
|
31383
|
+
break;
|
|
31384
|
+
}
|
|
31385
|
+
const page = Number(nested.page ?? root?.page ?? currentParams.page ?? 1);
|
|
31386
|
+
const nextPageValue = nested.next_page ?? nested.nextPage ?? root?.next_page ?? root?.nextPage;
|
|
31387
|
+
const nextPage = Number(nextPageValue ?? page + 1);
|
|
31388
|
+
if (!Number.isFinite(nextPage) || nextPage <= 0 || visitedPages.has(nextPage) || nextPage === page) break;
|
|
31389
|
+
visitedPages.add(page);
|
|
31390
|
+
currentParams = { ...currentParams, page: nextPage };
|
|
31391
|
+
if (currentParams.size === void 0) {
|
|
31392
|
+
const size = nested.size ?? root?.size;
|
|
31393
|
+
if (size !== void 0) currentParams.size = size;
|
|
31394
|
+
}
|
|
31395
|
+
current = await this.call("group.list_my_invites", currentParams);
|
|
31396
|
+
}
|
|
31397
|
+
await this.ensureGroupInviteStateLoaded();
|
|
31398
|
+
let changed = false;
|
|
31399
|
+
for (const key of this._groupInvitePending.keys()) {
|
|
31400
|
+
if (!seen.has(key)) {
|
|
31401
|
+
this._groupInvitePending.delete(key);
|
|
31402
|
+
changed = true;
|
|
31403
|
+
}
|
|
31404
|
+
}
|
|
31405
|
+
if (changed) await this.persistGroupInviteState();
|
|
31406
|
+
}
|
|
31407
|
+
async restoreGroupInvitesAfterConnect() {
|
|
31408
|
+
if (!this._aid || this._state !== "connected") return;
|
|
31409
|
+
const result = await this.call("group.list_my_invites", { page: 1, size: 200, _rpc_background: true });
|
|
31410
|
+
if (isJsonObject(result) || Array.isArray(result)) {
|
|
31411
|
+
await this.restoreGroupInvitesFromResult(result, { page: 1, size: 200, _rpc_background: true });
|
|
31412
|
+
}
|
|
31413
|
+
}
|
|
30642
31414
|
async _onRawGroupChanged(data) {
|
|
30643
31415
|
const tStart = Date.now();
|
|
30644
31416
|
const action = String(data?.action ?? "");
|
|
@@ -30969,6 +31741,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30969
31741
|
}
|
|
30970
31742
|
this._lifecycle.assertConnectionAttemptOwner(connectionOwner);
|
|
30971
31743
|
this._startBackgroundTasks();
|
|
31744
|
+
this._safeAsync(this.restoreGroupInvitesAfterConnect());
|
|
30972
31745
|
const connectionKind = String(params2.connection_kind ?? "long");
|
|
30973
31746
|
const isShortConnection = connectionKind === "short";
|
|
30974
31747
|
const hasExplicitBackgroundSync = Object.prototype.hasOwnProperty.call(params2, "background_sync");
|
|
@@ -30983,6 +31756,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30983
31756
|
if (backgroundSyncEnabled) {
|
|
30984
31757
|
this._safeAsync(this._fillP2pGap());
|
|
30985
31758
|
}
|
|
31759
|
+
this._safeAsync(this._checkIdentityAdmissionAfterConnect());
|
|
30986
31760
|
this._clientLog.debug(`_connectOnce exit: elapsed=${Date.now() - tStart}ms aid=${this._aid ?? "-"}`);
|
|
30987
31761
|
} catch (err) {
|
|
30988
31762
|
this._clientLog.debug(`_connectOnce exit (error): elapsed=${Date.now() - tStart}ms err=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -31678,20 +32452,7 @@ var _AUNClient = class _AUNClient {
|
|
|
31678
32452
|
return this._delivery.clampAckParams(method, params2);
|
|
31679
32453
|
}
|
|
31680
32454
|
_repairPushContiguousBound(ns, pushSeq, hasPayload, label) {
|
|
31681
|
-
|
|
31682
|
-
return ns ? this._seqTracker.getContiguousSeq(ns) : 0;
|
|
31683
|
-
}
|
|
31684
|
-
const contig = this._seqTracker.getContiguousSeq(ns);
|
|
31685
|
-
const shouldRepair = contig > pushSeq;
|
|
31686
|
-
if (!shouldRepair) return contig;
|
|
31687
|
-
const repairedTo = Math.max(0, pushSeq - 1);
|
|
31688
|
-
this._seqTracker.repairContiguousSeq(ns, repairedTo);
|
|
31689
|
-
const repaired = this._seqTracker.getContiguousSeq(ns);
|
|
31690
|
-
this._persistRepairedSeq(ns);
|
|
31691
|
-
this._clientLog.warn(
|
|
31692
|
-
`${label} push repaired contiguous_seq: ns=${ns} payload=${hasPayload} push_seq=${pushSeq} contiguous=${contig}->${repaired}`
|
|
31693
|
-
);
|
|
31694
|
-
return repaired;
|
|
32455
|
+
return ns ? this._seqTracker.getContiguousSeq(ns) : 0;
|
|
31695
32456
|
}
|
|
31696
32457
|
async _ensureV2SessionReady(method, errorMessage3) {
|
|
31697
32458
|
if (!this._v2SessionMatchesIdentity()) {
|
|
@@ -31869,7 +32630,7 @@ var _AUNClient = class _AUNClient {
|
|
|
31869
32630
|
* undecryptable 事件、成功消费后触发 SPK 轮换。inline Push 在游标提交和
|
|
31870
32631
|
* Head/正文绑定校验前调用本入口时必须显式关闭这些副作用。
|
|
31871
32632
|
*/
|
|
31872
|
-
async _decryptV2Message(msg, allowPending = true, emitUndecryptable = true, rotateKeys = true, observeAgentMd = true, deferStatus, deferKeyFetch = false) {
|
|
32633
|
+
async _decryptV2Message(msg, allowPending = true, emitUndecryptable = true, rotateKeys = true, observeAgentMd = true, deferStatus, deferKeyFetch = false, source = "pull") {
|
|
31873
32634
|
const session = this._v2Session;
|
|
31874
32635
|
if (!session) return null;
|
|
31875
32636
|
const envJson = msg.envelope_json;
|
|
@@ -31957,7 +32718,8 @@ var _AUNClient = class _AUNClient {
|
|
|
31957
32718
|
_decrypt_stage: "spk_lookup",
|
|
31958
32719
|
_envelope_type: String(envelope.type ?? ""),
|
|
31959
32720
|
_suite: String(envelope.suite ?? ""),
|
|
31960
|
-
_spk_id: spkId
|
|
32721
|
+
_spk_id: spkId,
|
|
32722
|
+
source
|
|
31961
32723
|
};
|
|
31962
32724
|
attachV2EnvelopeMetadata2(event, e2eeMeta);
|
|
31963
32725
|
this._dispatcher.enqueue(undecryptableEvent, event);
|
|
@@ -31998,7 +32760,8 @@ var _AUNClient = class _AUNClient {
|
|
|
31998
32760
|
_decrypt_error: "sender_ik_not_found",
|
|
31999
32761
|
_decrypt_stage: "sender_ik",
|
|
32000
32762
|
_envelope_type: String(envelope.type ?? ""),
|
|
32001
|
-
_suite: String(envelope.suite ?? "")
|
|
32763
|
+
_suite: String(envelope.suite ?? ""),
|
|
32764
|
+
source
|
|
32002
32765
|
};
|
|
32003
32766
|
attachV2EnvelopeMetadata2(event, e2eeMeta);
|
|
32004
32767
|
this._dispatcher.enqueue(undecryptableEvent, event);
|
|
@@ -32034,7 +32797,8 @@ var _AUNClient = class _AUNClient {
|
|
|
32034
32797
|
_decrypt_error: String(exc),
|
|
32035
32798
|
_decrypt_stage: "decrypt",
|
|
32036
32799
|
_envelope_type: String(envelope.type ?? ""),
|
|
32037
|
-
_suite: String(envelope.suite ?? "")
|
|
32800
|
+
_suite: String(envelope.suite ?? ""),
|
|
32801
|
+
source
|
|
32038
32802
|
};
|
|
32039
32803
|
attachV2EnvelopeMetadata2(event, e2eeMeta);
|
|
32040
32804
|
this._dispatcher.enqueue(undecryptableEvent, event);
|