@agentunion/fastaun-browser 0.5.11 → 0.5.13
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 +46 -0
- package/_packed_docs/CHANGELOG.md +46 -0
- package/_packed_docs/INDEX.md +3 -3
- package/_packed_docs/KITE_DOCS_GUIDE.md +1 -1
- package/_packed_docs/agent.md/SCHEMA.md +84 -84
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +8 -6
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +29 -15
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +21 -3
- package/_packed_docs/sdk/09-group-rpc-manual.md +29 -2
- package/dist/agent-md-schema.d.ts.map +1 -1
- package/dist/agent-md-schema.js +8 -4
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/bundle.js +565 -298
- package/dist/client/delivery.d.ts +1 -0
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +161 -242
- 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 +24 -11
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +0 -1
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +65 -44
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +14 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +341 -18
- 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 +3 -0
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/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.13";
|
|
464
464
|
|
|
465
465
|
// src/types.ts
|
|
466
466
|
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
@@ -1747,6 +1747,9 @@ var EVENT_NAME_MAP = {
|
|
|
1747
1747
|
"message.recalled": "message.recalled",
|
|
1748
1748
|
"message.ack": "message.ack",
|
|
1749
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",
|
|
1750
1753
|
"group.message_created": "group.message_created",
|
|
1751
1754
|
"group.message_recalled": "group.message_recalled",
|
|
1752
1755
|
"group.state_committed": "group.state_committed",
|
|
@@ -4203,7 +4206,6 @@ var SeqTracker = class {
|
|
|
4203
4206
|
if (headSeq === t.headSeq) {
|
|
4204
4207
|
if (windowStartSeq <= t.tailSeq) return false;
|
|
4205
4208
|
t.tailSeq = windowStartSeq;
|
|
4206
|
-
this._normalizeWindow(t);
|
|
4207
4209
|
return true;
|
|
4208
4210
|
}
|
|
4209
4211
|
if (t.headSeq + pageLimit < headSeq && windowStartSeq <= t.headSeq + 1) {
|
|
@@ -4212,7 +4214,6 @@ var SeqTracker = class {
|
|
|
4212
4214
|
if (windowStartSeq > t.headSeq + 1) t.tailSeq = windowStartSeq;
|
|
4213
4215
|
t.headSeq = headSeq;
|
|
4214
4216
|
t.maxSeenSeq = Math.max(t.maxSeenSeq, headSeq);
|
|
4215
|
-
this._normalizeWindow(t);
|
|
4216
4217
|
return true;
|
|
4217
4218
|
}
|
|
4218
4219
|
/** Push 专用:只扩展上界 maxSeenSeq,不动 contiguousSeq。 */
|
|
@@ -4287,8 +4288,8 @@ var SeqTracker = class {
|
|
|
4287
4288
|
}
|
|
4288
4289
|
return true;
|
|
4289
4290
|
}
|
|
4290
|
-
/** 提交已校验的 Forward
|
|
4291
|
-
onPullResult(ns, messages, afterSeq) {
|
|
4291
|
+
/** 提交已校验的 Forward 原始页;缺号只有服务端明确证明时才能跳过。 */
|
|
4292
|
+
onPullResult(ns, messages, afterSeq, contiguousSeq) {
|
|
4292
4293
|
const t = this._get(ns);
|
|
4293
4294
|
const pulledSeqs = /* @__PURE__ */ new Set();
|
|
4294
4295
|
for (const m of messages) {
|
|
@@ -4318,6 +4319,7 @@ var SeqTracker = class {
|
|
|
4318
4319
|
if (maxPulled > 0) {
|
|
4319
4320
|
t.maxSeenSeq = Math.max(t.maxSeenSeq, maxPulled);
|
|
4320
4321
|
}
|
|
4322
|
+
this._tryAdvance(t);
|
|
4321
4323
|
if (maxPulled > t.contiguousSeq) {
|
|
4322
4324
|
for (const [key, probe] of t.pendingGaps) {
|
|
4323
4325
|
if (probe.gapEnd <= maxPulled) t.pendingGaps.delete(key);
|
|
@@ -4327,7 +4329,11 @@ var SeqTracker = class {
|
|
|
4327
4329
|
}
|
|
4328
4330
|
t.contiguousSeq = maxPulled;
|
|
4329
4331
|
}
|
|
4330
|
-
|
|
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);
|
|
4331
4337
|
const remaining = [...t.receivedSeqs].filter((seq2) => seq2 > t.contiguousSeq);
|
|
4332
4338
|
if (remaining.length > 0) {
|
|
4333
4339
|
const firstPending = Math.min(...remaining);
|
|
@@ -4506,7 +4512,6 @@ var SeqTracker = class {
|
|
|
4506
4512
|
restored.tailSeq = Number(tailRaw);
|
|
4507
4513
|
restored.headSeq = Number(headRaw);
|
|
4508
4514
|
restored.maxSeenSeq = Math.max(ack, restored.headSeq);
|
|
4509
|
-
this._normalizeWindow(restored);
|
|
4510
4515
|
this._trackers.set(ns, restored);
|
|
4511
4516
|
}
|
|
4512
4517
|
return issues;
|
|
@@ -5006,6 +5011,9 @@ function positiveSafeSequenceHint(value) {
|
|
|
5006
5011
|
const parsed = Number(value);
|
|
5007
5012
|
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 0;
|
|
5008
5013
|
}
|
|
5014
|
+
function hasNonEmptyInlineMessage(value) {
|
|
5015
|
+
return isJsonObject(value) && Object.keys(value).length > 0;
|
|
5016
|
+
}
|
|
5009
5017
|
function nonNegativeSafeSequenceHint(value) {
|
|
5010
5018
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return null;
|
|
5011
5019
|
return value;
|
|
@@ -5794,13 +5802,17 @@ var MessageDeliveryEngine = class {
|
|
|
5794
5802
|
this.markPublishedSeq(ns, seq2);
|
|
5795
5803
|
publishedCount += 1;
|
|
5796
5804
|
}
|
|
5805
|
+
} else if (this.isSelfSentGroupMessage(message)) {
|
|
5806
|
+
this.markPublishedSeq(ns, seq2);
|
|
5797
5807
|
} else if (await this.publishPulledMessage("group.message_created", ns, seq2, message, false)) {
|
|
5798
5808
|
this.ensurePullOperationCurrent();
|
|
5799
5809
|
publishedCount += 1;
|
|
5800
5810
|
}
|
|
5801
5811
|
}
|
|
5802
5812
|
this.ensurePullOperationCurrent();
|
|
5803
|
-
|
|
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);
|
|
5804
5816
|
const commitTarget = Math.max(
|
|
5805
5817
|
client._seqTracker.getContiguousSeq(ns),
|
|
5806
5818
|
retentionFloor,
|
|
@@ -6296,38 +6308,9 @@ var MessageDeliveryEngine = class {
|
|
|
6296
6308
|
return;
|
|
6297
6309
|
}
|
|
6298
6310
|
const ns = `group:${groupId}`;
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
if (client._seqTracker.getContiguousSeq(ns) === seqNum) {
|
|
6302
|
-
await this.publishGroupRecallTombstone(groupId, seq2, wrapped);
|
|
6303
|
-
return;
|
|
6304
|
-
}
|
|
6305
|
-
client._repairPushContiguousBound(ns, seqNum, true, "_raw.group.message_recalled");
|
|
6306
|
-
}
|
|
6307
|
-
const pushed = client._pushedSeqs.get(ns);
|
|
6308
|
-
const pending = client._pendingOrderedMsgs.get(ns);
|
|
6309
|
-
if (pushed?.has(seqNum) || pending?.has(seqNum)) {
|
|
6310
|
-
await this.publishGroupRecallTombstone(groupId, seq2, wrapped);
|
|
6311
|
-
return;
|
|
6312
|
-
}
|
|
6313
|
-
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
6314
|
-
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));
|
|
6315
6313
|
await this.publishGroupRecallTombstone(groupId, seq2, wrapped);
|
|
6316
|
-
this.markPublishedSeq(ns, seqNum);
|
|
6317
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
6318
|
-
if (contig > 0) {
|
|
6319
|
-
const ackSeq = this.clampAckSeq("group.ack_messages", "msg_seq", ns, contig);
|
|
6320
|
-
client._transport.call("group.ack_messages", {
|
|
6321
|
-
group_id: groupId,
|
|
6322
|
-
msg_seq: ackSeq,
|
|
6323
|
-
device_id: client._deviceId,
|
|
6324
|
-
slot_id: client._slotId,
|
|
6325
|
-
_rpc_background: true
|
|
6326
|
-
}).catch((e) => {
|
|
6327
|
-
client._clientLog.warn("group recall auto-ack failed: group=" + groupId, e);
|
|
6328
|
-
});
|
|
6329
|
-
}
|
|
6330
|
-
if (contig !== contigBefore) this.persistSeq(ns);
|
|
6331
6314
|
}
|
|
6332
6315
|
async publishAppEvent(event, payload, source = "direct", ns = "", batch) {
|
|
6333
6316
|
const client = this.runtime.client;
|
|
@@ -6392,6 +6375,16 @@ var MessageDeliveryEngine = class {
|
|
|
6392
6375
|
}
|
|
6393
6376
|
return true;
|
|
6394
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
|
+
}
|
|
6395
6388
|
strictTargetString(source, key) {
|
|
6396
6389
|
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
6397
6390
|
return { present: false, valid: false, value: "" };
|
|
@@ -6452,11 +6445,11 @@ var MessageDeliveryEngine = class {
|
|
|
6452
6445
|
const client = this.runtime.client;
|
|
6453
6446
|
client._clientLog.debug(`_onRawMessageReceived enter: from=${data?.from ?? "-"} mid=${data?.message_id ?? "-"} seq=${data?.seq ?? "-"}`);
|
|
6454
6447
|
const ns = isJsonObject(data) && client._aid && data.seq !== void 0 ? `p2p:${client._aid}` : "";
|
|
6455
|
-
const seq2 = isJsonObject(data)
|
|
6456
|
-
if (client._v2Session && ns &&
|
|
6448
|
+
const seq2 = isJsonObject(data) ? positiveSafeSequenceHint(data.seq) : 0;
|
|
6449
|
+
if (client._v2Session && ns && seq2 > 0 && this.messageTargetsCurrentInstance(data)) {
|
|
6457
6450
|
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
6458
6451
|
}
|
|
6459
|
-
const hasInlineObject = isJsonObject(data) &&
|
|
6452
|
+
const hasInlineObject = isJsonObject(data) && hasNonEmptyInlineMessage(data.inline_message);
|
|
6460
6453
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
6461
6454
|
const operation = () => this.processAndPublishMessage(data, inlineGeneration);
|
|
6462
6455
|
client._safeAsync(client._v2Session && ns && !hasInlineObject ? operation() : this.runPushProcessSerialized(ns, operation, inlineGeneration));
|
|
@@ -6468,33 +6461,13 @@ var MessageDeliveryEngine = class {
|
|
|
6468
6461
|
const msg = { ...data };
|
|
6469
6462
|
if (!("type" in msg)) msg.type = "message.recalled";
|
|
6470
6463
|
if (!this.messageTargetsCurrentInstance(msg)) return;
|
|
6471
|
-
const seq2 = msg.seq;
|
|
6472
|
-
if (
|
|
6464
|
+
const seq2 = positiveSafeSequenceHint(msg.seq);
|
|
6465
|
+
if (client._aid && seq2 > 0) {
|
|
6473
6466
|
const ns = `p2p:${client._aid}`;
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
const seqNeedsPull = client._seqTracker.onMessageSeq(ns, seq2);
|
|
6477
|
-
const published = await this.publishOrderedMessage("message.recalled", ns, seq2, msg);
|
|
6478
|
-
const contigAfter = client._seqTracker.getContiguousSeq(ns);
|
|
6479
|
-
if (seqNeedsPull && !published && client._sessionOptions?.background_sync !== false) {
|
|
6480
|
-
client._safeAsync(this.fillP2pGap());
|
|
6481
|
-
}
|
|
6482
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
6483
|
-
if (contig > 0) {
|
|
6484
|
-
const ackSeq = this.clampAckSeq("message.ack", "seq", ns, contig);
|
|
6485
|
-
client._transport.call("message.ack", {
|
|
6486
|
-
seq: ackSeq,
|
|
6487
|
-
device_id: client._deviceId,
|
|
6488
|
-
slot_id: client._slotId,
|
|
6489
|
-
_rpc_background: true
|
|
6490
|
-
}).catch((e) => {
|
|
6491
|
-
client._clientLog.warn(`P2P recall auto-ack failed:${String(e)}`);
|
|
6492
|
-
});
|
|
6493
|
-
}
|
|
6494
|
-
if (contigAfter !== contigBefore) this.persistSeq(ns);
|
|
6495
|
-
return;
|
|
6467
|
+
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
6468
|
+
if (seq2 > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) client._safeAsync(this.fillP2pGap());
|
|
6496
6469
|
}
|
|
6497
|
-
await this.publishMessageRecallTombstone(
|
|
6470
|
+
await this.publishMessageRecallTombstone(msg.seq, msg);
|
|
6498
6471
|
}
|
|
6499
6472
|
async processAndPublishMessage(data, inlineGeneration) {
|
|
6500
6473
|
const client = this.runtime.client;
|
|
@@ -6508,43 +6481,32 @@ var MessageDeliveryEngine = class {
|
|
|
6508
6481
|
return;
|
|
6509
6482
|
}
|
|
6510
6483
|
const legacyPushSeq = positiveSafeSequenceHint(msg.seq);
|
|
6511
|
-
const hasInlineField =
|
|
6484
|
+
const hasInlineField = hasNonEmptyInlineMessage(msg.inline_message);
|
|
6512
6485
|
if (client._v2Session && client._aid && (legacyPushSeq > 0 || hasInlineField)) {
|
|
6513
6486
|
await this.processV2P2PNotification(msg, "v1", inlineGeneration);
|
|
6514
6487
|
return;
|
|
6515
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
|
+
}
|
|
6516
6495
|
const seq2 = msg.seq;
|
|
6517
6496
|
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
if (contig > 0) {
|
|
6531
|
-
const ackSeq = this.clampAckSeq("message.ack", "seq", ns, contig);
|
|
6532
|
-
client._transport.call("message.ack", {
|
|
6533
|
-
seq: ackSeq,
|
|
6534
|
-
device_id: client._deviceId,
|
|
6535
|
-
slot_id: client._slotId,
|
|
6536
|
-
_rpc_background: true
|
|
6537
|
-
}).catch((e) => {
|
|
6538
|
-
client._clientLog.warn(`P2P auto-ack failed:${String(e)}`);
|
|
6539
|
-
});
|
|
6540
|
-
}
|
|
6541
|
-
if (contigAfter !== contigBefore) this.persistSeq(ns);
|
|
6542
|
-
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);
|
|
6543
6509
|
} else {
|
|
6544
|
-
if (encryptedPush) {
|
|
6545
|
-
await client._publishEncryptedPushMessage("message.received", "message.undecryptable", "", seq2 ?? 0, msg, false);
|
|
6546
|
-
return;
|
|
6547
|
-
}
|
|
6548
6510
|
await client._publishAppEvent("message.received", msg, "push");
|
|
6549
6511
|
}
|
|
6550
6512
|
} catch (exc) {
|
|
@@ -6568,13 +6530,13 @@ var MessageDeliveryEngine = class {
|
|
|
6568
6530
|
const client = this.runtime.client;
|
|
6569
6531
|
client._clientLog.debug(`_onRawGroupMessageCreated enter: group_id=${data?.group_id ?? "-"} from=${data?.from ?? "-"} seq=${data?.seq ?? "-"}`);
|
|
6570
6532
|
const groupId = isJsonObject(data) && typeof data.group_id === "string" ? data.group_id.trim() : "";
|
|
6571
|
-
const seq2 = isJsonObject(data) && typeof data.seq === "number" ? data.seq : 0;
|
|
6572
6533
|
const kind = isJsonObject(data) ? String(data.kind ?? "").trim() : "";
|
|
6573
|
-
if (client._v2Session && groupId && kind !== "group.online_unread_hint" && Number.isSafeInteger(seq2) && seq2 > 0) {
|
|
6574
|
-
client._seqTracker.updateMaxSeen(`group:${groupId}`, seq2);
|
|
6575
|
-
}
|
|
6576
6534
|
const ns = groupId ? `group:${groupId}` : "";
|
|
6577
|
-
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);
|
|
6578
6540
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
6579
6541
|
const operation = () => this.processAndPublishGroupMessage(data, inlineGeneration);
|
|
6580
6542
|
client._safeAsync(client._v2Session && ns && !hasInlineObject ? operation() : this.runPushProcessSerialized(ns, operation, inlineGeneration));
|
|
@@ -6595,69 +6557,56 @@ var MessageDeliveryEngine = class {
|
|
|
6595
6557
|
client._groupSynced.add(groupId);
|
|
6596
6558
|
}
|
|
6597
6559
|
const legacyPushSeq = positiveSafeSequenceHint(seq2);
|
|
6598
|
-
const hasInlineField =
|
|
6560
|
+
const hasInlineField = hasNonEmptyInlineMessage(msg.inline_message);
|
|
6599
6561
|
if (client._v2Session && groupId && (legacyPushSeq > 0 || hasInlineField)) {
|
|
6600
6562
|
await this.processGroupV2MessageCreated(msg, "v1", inlineGeneration);
|
|
6601
6563
|
return;
|
|
6602
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
|
+
}
|
|
6603
6571
|
if (payload === void 0 || payload === null || typeof payload === "object" && Object.keys(payload).length === 0) {
|
|
6604
|
-
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");
|
|
6605
6582
|
return;
|
|
6606
6583
|
}
|
|
6607
6584
|
const encryptedPush = client._isEncryptedPushMessage(msg);
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
if (contig2 > 0) {
|
|
6619
|
-
const ackSeq = this.clampAckSeq("group.ack_messages", "msg_seq", ns, contig2);
|
|
6620
|
-
client._transport.call("group.ack_messages", {
|
|
6621
|
-
group_id: groupId,
|
|
6622
|
-
msg_seq: ackSeq,
|
|
6623
|
-
device_id: client._deviceId,
|
|
6624
|
-
slot_id: client._slotId,
|
|
6625
|
-
_rpc_background: true
|
|
6626
|
-
}).catch((e) => {
|
|
6627
|
-
client._clientLog.warn("group recall auto-ack failed: group=" + groupId, e);
|
|
6628
|
-
});
|
|
6629
|
-
}
|
|
6630
|
-
if (contigAfter2 !== contigBefore) this.persistSeq(ns);
|
|
6631
|
-
return;
|
|
6632
|
-
}
|
|
6633
|
-
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);
|
|
6634
|
-
const contigAfter = client._seqTracker.getContiguousSeq(ns);
|
|
6635
|
-
const needPull = seqNeedsPull && !published;
|
|
6636
|
-
if (needPull && client._sessionOptions?.background_sync !== false) {
|
|
6637
|
-
client._safeAsync(this.fillGroupGap(groupId));
|
|
6638
|
-
}
|
|
6639
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
6640
|
-
if (contig > 0) {
|
|
6641
|
-
const ackSeq = this.clampAckSeq("group.ack_messages", "msg_seq", ns, contig);
|
|
6642
|
-
client._transport.call("group.ack_messages", {
|
|
6643
|
-
group_id: groupId,
|
|
6644
|
-
msg_seq: ackSeq,
|
|
6645
|
-
device_id: client._deviceId,
|
|
6646
|
-
slot_id: client._slotId,
|
|
6647
|
-
_rpc_background: true
|
|
6648
|
-
}).catch((e) => {
|
|
6649
|
-
client._clientLog.warn("group message auto-ack failed: group=" + groupId, e);
|
|
6650
|
-
});
|
|
6651
|
-
}
|
|
6652
|
-
if (contigAfter !== contigBefore) this.persistSeq(ns);
|
|
6653
|
-
if (encryptedPush) return;
|
|
6654
|
-
} else {
|
|
6655
|
-
if (encryptedPush) {
|
|
6656
|
-
await client._publishEncryptedPushMessage("group.message_created", "group.message_undecryptable", "", seq2 ?? 0, msg, true);
|
|
6657
|
-
return;
|
|
6658
|
-
}
|
|
6659
|
-
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;
|
|
6660
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");
|
|
6661
6610
|
} catch (exc) {
|
|
6662
6611
|
client._clientLog.warn(`group push processing failed:${String(exc)}`);
|
|
6663
6612
|
if (isJsonObject(data)) {
|
|
@@ -6854,6 +6803,7 @@ var MessageDeliveryEngine = class {
|
|
|
6854
6803
|
client._gapFillDone.add(dedupKey);
|
|
6855
6804
|
this.runtime.delivery.setGapFillActive(true);
|
|
6856
6805
|
let continuationAfterSeq = 0;
|
|
6806
|
+
let pendingAckSeq = 0;
|
|
6857
6807
|
let failed = false;
|
|
6858
6808
|
try {
|
|
6859
6809
|
let nextAfterSeq = afterSeq;
|
|
@@ -6874,9 +6824,9 @@ var MessageDeliveryEngine = class {
|
|
|
6874
6824
|
if (!Array.isArray(events)) return;
|
|
6875
6825
|
const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
6876
6826
|
const eventObjects = events.filter((evt) => isJsonObject(evt));
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
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);
|
|
6880
6830
|
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
6881
6831
|
const retentionFloor = Math.max(
|
|
6882
6832
|
0,
|
|
@@ -6930,21 +6880,7 @@ var MessageDeliveryEngine = class {
|
|
|
6930
6880
|
this.persistSeq(ns);
|
|
6931
6881
|
}
|
|
6932
6882
|
if (eventObjects.length > 0 && ackContig > 0 && ackContig !== pageContigBefore) {
|
|
6933
|
-
|
|
6934
|
-
const ackPromise = client._transport.call("group.ack_events", {
|
|
6935
|
-
group_id: groupId,
|
|
6936
|
-
event_seq: ackContig,
|
|
6937
|
-
device_id: client._deviceId,
|
|
6938
|
-
slot_id: client._slotId,
|
|
6939
|
-
_rpc_background: true
|
|
6940
|
-
});
|
|
6941
|
-
if (singlePage) await ackPromise;
|
|
6942
|
-
else ackPromise.catch((e) => {
|
|
6943
|
-
client._clientLog.warn("group event auto-ack failed: group=" + groupId, e);
|
|
6944
|
-
});
|
|
6945
|
-
} catch (e) {
|
|
6946
|
-
client._clientLog.warn("group event auto-ack failed: group=" + groupId, e);
|
|
6947
|
-
}
|
|
6883
|
+
pendingAckSeq = Math.max(pendingAckSeq, ackContig);
|
|
6948
6884
|
}
|
|
6949
6885
|
this.onPullPage(
|
|
6950
6886
|
ns,
|
|
@@ -6957,15 +6893,29 @@ var MessageDeliveryEngine = class {
|
|
|
6957
6893
|
eventObjects.length > 0 ? Number(eventObjects[eventObjects.length - 1].event_seq ?? 0) : void 0
|
|
6958
6894
|
);
|
|
6959
6895
|
const nextAfter = Math.max(eventSeqs.length > 0 ? Math.max(...eventSeqs) : nextAfterSeq, nextAfterSeq);
|
|
6960
|
-
|
|
6896
|
+
const needsMore = result.has_more === true || client._seqTracker.getMaxSeenSeq(ns) > nextAfter;
|
|
6897
|
+
if (singlePage && needsMore && nextAfter > nextAfterSeq) {
|
|
6961
6898
|
continuationAfterSeq = nextAfter;
|
|
6962
6899
|
}
|
|
6963
|
-
if (eventObjects.length === 0 || nextAfter <= nextAfterSeq ||
|
|
6900
|
+
if (eventObjects.length === 0 || nextAfter <= nextAfterSeq || !needsMore) break;
|
|
6964
6901
|
nextAfterSeq = nextAfter;
|
|
6965
6902
|
}
|
|
6966
6903
|
if (pageCount >= maxPages) {
|
|
6967
6904
|
client._clientLog.warn(`group event gap fill reached max_pages=${maxPages} group=${groupId} after_seq=${nextAfterSeq}`);
|
|
6968
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
|
+
}
|
|
6969
6919
|
} catch (exc) {
|
|
6970
6920
|
failed = true;
|
|
6971
6921
|
client._clientLog.warn(`group event gap-fill failed:${String(exc)}`);
|
|
@@ -7001,41 +6951,15 @@ var MessageDeliveryEngine = class {
|
|
|
7001
6951
|
this.enqueueOnlineUnreadEventHint(data);
|
|
7002
6952
|
return;
|
|
7003
6953
|
}
|
|
7004
|
-
if (this.isSelfJoinGroupChanged(data)) {
|
|
7005
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
7006
|
-
const maxSeen = client._seqTracker.getMaxSeenSeq(ns);
|
|
7007
|
-
if (contig === 0 && maxSeen === 0 && eventSeq > 1) {
|
|
7008
|
-
client._clientLog.debug(`group.changed self-join baseline: group=${groupId}, event_seq=${eventSeq}, baseline=${eventSeq - 1}`);
|
|
7009
|
-
client._seqTracker.forceContiguousSeq(ns, eventSeq - 1);
|
|
7010
|
-
}
|
|
7011
|
-
}
|
|
7012
6954
|
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
6955
|
+
client._seqTracker.updateMaxSeen(ns, eventSeq);
|
|
7013
6956
|
const publishedDuplicate = client._pushedSeqs.get(ns)?.has(eventSeq) === true;
|
|
7014
6957
|
if (eventSeq <= contigBefore || publishedDuplicate) {
|
|
7015
6958
|
client._clientLog.debug(`group.changed skipped duplicate/stale: group=${groupId}, event_seq=${eventSeq}, contiguous=${contigBefore}`);
|
|
7016
|
-
if (eventSeq <= contigBefore) {
|
|
7017
|
-
this.fireGroupEventAck(groupId, ns, eventSeq, "group event covered push ack");
|
|
7018
|
-
} else if (contigBefore > 0) {
|
|
7019
|
-
this.fireGroupEventAck(groupId, ns, contigBefore, "group event covered push ack");
|
|
7020
|
-
}
|
|
7021
6959
|
return;
|
|
7022
6960
|
}
|
|
7023
6961
|
this.enqueueOrderedMessage(ns, "group.changed", eventSeq, data);
|
|
7024
|
-
needPull =
|
|
7025
|
-
const ackContig = client._seqTracker.getContiguousSeq(ns);
|
|
7026
|
-
await this.drainOrderedMessages(ns);
|
|
7027
|
-
if (ackContig > 0 && ackContig !== contigBefore) {
|
|
7028
|
-
if (data.action !== "dissolved") this.persistSeq(ns);
|
|
7029
|
-
client._transport.call("group.ack_events", {
|
|
7030
|
-
group_id: groupId,
|
|
7031
|
-
event_seq: ackContig,
|
|
7032
|
-
device_id: client._deviceId,
|
|
7033
|
-
slot_id: client._slotId,
|
|
7034
|
-
_rpc_background: true
|
|
7035
|
-
}).catch((e) => {
|
|
7036
|
-
client._clientLog.warn("group event push auto-ack failed: group=" + groupId, e);
|
|
7037
|
-
});
|
|
7038
|
-
}
|
|
6962
|
+
needPull = eventSeq > contigBefore;
|
|
7039
6963
|
if (needPull && groupId && !data._from_gap_fill && client._sessionOptions?.background_sync !== false) {
|
|
7040
6964
|
client._safeAsync(this.fillGroupEventGap(groupId));
|
|
7041
6965
|
}
|
|
@@ -7468,16 +7392,18 @@ var MessageDeliveryEngine = class {
|
|
|
7468
7392
|
};
|
|
7469
7393
|
if (forceTail || order[0] === "tail") result = await run(true, false, void 0, false, forceTail);
|
|
7470
7394
|
const state = this.syncState(ns);
|
|
7471
|
-
const tailMissedDuringPull = tailCompleted && Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
7472
7395
|
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
7473
|
-
const
|
|
7474
|
-
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);
|
|
7475
7401
|
const backgroundWindowForward = order[0] === "forward" && !headForward;
|
|
7476
7402
|
if (headForward || tailForward || client._sessionOptions?.background_sync !== false && backgroundWindowForward) {
|
|
7477
7403
|
const forwardTarget = Math.max(
|
|
7478
7404
|
headForward ? Math.max(pushSeq, maxSeen) : 0,
|
|
7479
7405
|
tailForward || backgroundWindowForward ? state.tail - 1 : 0,
|
|
7480
|
-
tailMissedDuringPull ?
|
|
7406
|
+
tailMissedDuringPull ? observedUpper : 0
|
|
7481
7407
|
);
|
|
7482
7408
|
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
7483
7409
|
result = await run(
|
|
@@ -7536,16 +7462,18 @@ var MessageDeliveryEngine = class {
|
|
|
7536
7462
|
};
|
|
7537
7463
|
if (forceTail || order[0] === "tail") result = await run(true, false, void 0, false, forceTail);
|
|
7538
7464
|
const state = this.syncState(ns);
|
|
7539
|
-
const tailMissedDuringPull = tailCompleted && Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
7540
7465
|
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
7541
|
-
const
|
|
7542
|
-
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);
|
|
7543
7471
|
const backgroundWindowForward = order[0] === "forward" && !headForward;
|
|
7544
7472
|
if (headForward || tailForward || client._sessionOptions?.background_sync !== false && backgroundWindowForward) {
|
|
7545
7473
|
const forwardTarget = Math.max(
|
|
7546
7474
|
headForward ? Math.max(pushSeq, maxSeen) : 0,
|
|
7547
7475
|
tailForward || backgroundWindowForward ? state.tail - 1 : 0,
|
|
7548
|
-
tailMissedDuringPull ?
|
|
7476
|
+
tailMissedDuringPull ? observedUpper : 0
|
|
7549
7477
|
);
|
|
7550
7478
|
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
7551
7479
|
result = await run(
|
|
@@ -7597,13 +7525,13 @@ var MessageDeliveryEngine = class {
|
|
|
7597
7525
|
if (!row) return;
|
|
7598
7526
|
const groupId = typeof row.group_id === "string" ? row.group_id.trim() : "";
|
|
7599
7527
|
if (!groupId) return;
|
|
7600
|
-
const seq2 = typeof row.seq === "number" ? row.seq : 0;
|
|
7601
7528
|
const eventKind = String(row.kind ?? "").trim();
|
|
7602
7529
|
const ns = this.resolvePendingGroupInlineAckNamespace(`group:${groupId}`);
|
|
7603
|
-
|
|
7530
|
+
const seq2 = positiveSafeSequenceHint(row.seq);
|
|
7531
|
+
if (client._v2Session && eventKind !== "group.online_unread_hint" && seq2 > 0) {
|
|
7604
7532
|
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
7605
7533
|
}
|
|
7606
|
-
const hasInlineObject =
|
|
7534
|
+
const hasInlineObject = hasNonEmptyInlineMessage(row.inline_message) && eventKind !== "group.online_unread_hint";
|
|
7607
7535
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
7608
7536
|
const operation = () => this.processGroupV2MessageCreated(data, "v2", inlineGeneration);
|
|
7609
7537
|
if (hasInlineObject) await this.runPushProcessSerialized(ns, operation, inlineGeneration);
|
|
@@ -7615,7 +7543,6 @@ var MessageDeliveryEngine = class {
|
|
|
7615
7543
|
if (!isJsonObject(data) || !client._v2Session) return;
|
|
7616
7544
|
const groupId = typeof data.group_id === "string" ? data.group_id.trim() : "";
|
|
7617
7545
|
const seq2 = positiveSafeSequenceHint(data.seq);
|
|
7618
|
-
const strictSeq = typeof data.seq === "number" && Number.isSafeInteger(data.seq) && data.seq > 0;
|
|
7619
7546
|
if (!groupId) return;
|
|
7620
7547
|
const eventKind = String(data.kind ?? "").trim();
|
|
7621
7548
|
if (eventKind === "group.online_unread_hint") {
|
|
@@ -7624,11 +7551,12 @@ var MessageDeliveryEngine = class {
|
|
|
7624
7551
|
return;
|
|
7625
7552
|
}
|
|
7626
7553
|
const ns = this.resolvePendingGroupInlineAckNamespace(`group:${groupId}`);
|
|
7627
|
-
const inlinePresent =
|
|
7554
|
+
const inlinePresent = hasNonEmptyInlineMessage(data.inline_message);
|
|
7628
7555
|
if (seq2 <= 0) {
|
|
7629
7556
|
if (inlinePresent) await this.recoverInvalidGroupRealtimeHead(groupId, ns, data.seq);
|
|
7630
7557
|
return;
|
|
7631
7558
|
}
|
|
7559
|
+
client._seqTracker.updateMaxSeen(ns, seq2);
|
|
7632
7560
|
const inline = this.inlineMessage(data);
|
|
7633
7561
|
const inlineMatches = inline !== null && this.inlineGroupBindingMatches(data, inline, groupId, seq2, expectedInlineVersion);
|
|
7634
7562
|
const pendingInline = this.pendingGroupInlineAcks?.get(ns);
|
|
@@ -7649,13 +7577,12 @@ var MessageDeliveryEngine = class {
|
|
|
7649
7577
|
}
|
|
7650
7578
|
if (inlineMatches && !this.isInlineGenerationCurrent(inlineGeneration)) return;
|
|
7651
7579
|
const before = this.syncState(ns);
|
|
7652
|
-
if (strictSeq || !inlinePresent) client._seqTracker.updateMaxSeen(ns, seq2);
|
|
7653
7580
|
if (seq2 <= before.ack && before.ack >= before.tail - 1) {
|
|
7654
7581
|
const canonicalNs = this.resolvePendingGroupInlineAckNamespace(ns);
|
|
7655
7582
|
const pending = this.pendingGroupInlineAcks?.get(canonicalNs);
|
|
7656
|
-
if (pending && seq2 >= pending.seq) {
|
|
7583
|
+
if (inlinePresent && pending && seq2 >= pending.seq) {
|
|
7657
7584
|
this.retryPendingGroupInlineAck(canonicalNs, pending.seq, "covered inline Group ack", seq2);
|
|
7658
|
-
} else if (
|
|
7585
|
+
} else if (inlineMatches) {
|
|
7659
7586
|
this.fireGroupV2Ack(
|
|
7660
7587
|
groupId,
|
|
7661
7588
|
ns,
|
|
@@ -7694,7 +7621,7 @@ var MessageDeliveryEngine = class {
|
|
|
7694
7621
|
if (client._v2Session && Number.isSafeInteger(pushSeq) && pushSeq > 0) {
|
|
7695
7622
|
client._seqTracker.updateMaxSeen(ns, pushSeq);
|
|
7696
7623
|
}
|
|
7697
|
-
const hasInlineObject = isJsonObject(data) &&
|
|
7624
|
+
const hasInlineObject = isJsonObject(data) && hasNonEmptyInlineMessage(data.inline_message);
|
|
7698
7625
|
const inlineGeneration = hasInlineObject ? this.captureInlineGeneration() : void 0;
|
|
7699
7626
|
const operation = () => this.processV2P2PNotification(data, "v2", inlineGeneration);
|
|
7700
7627
|
if (hasInlineObject) await this.runPushProcessSerialized(ns, operation, inlineGeneration);
|
|
@@ -7705,10 +7632,10 @@ var MessageDeliveryEngine = class {
|
|
|
7705
7632
|
const client = this.runtime.client;
|
|
7706
7633
|
if (!client._v2Session) return;
|
|
7707
7634
|
const pushSeq = isJsonObject(data) ? positiveSafeSequenceHint(data.seq) : 0;
|
|
7708
|
-
const strictSeq = isJsonObject(data) && typeof data.seq === "number" && Number.isSafeInteger(data.seq) && data.seq > 0;
|
|
7709
7635
|
const ns = client._aid ? `p2p:${client._aid}` : "";
|
|
7710
7636
|
if (!ns) return;
|
|
7711
|
-
|
|
7637
|
+
if (pushSeq > 0) client._seqTracker.updateMaxSeen(ns, pushSeq);
|
|
7638
|
+
const inlinePresent = isJsonObject(data) && hasNonEmptyInlineMessage(data.inline_message);
|
|
7712
7639
|
if (pushSeq <= 0) {
|
|
7713
7640
|
if (inlinePresent) await this.recoverInvalidP2PRealtimeHead(ns, isJsonObject(data) ? data.seq : void 0);
|
|
7714
7641
|
return;
|
|
@@ -7731,10 +7658,9 @@ var MessageDeliveryEngine = class {
|
|
|
7731
7658
|
}
|
|
7732
7659
|
if (inlineMatches && !this.isInlineGenerationCurrent(inlineGeneration)) return;
|
|
7733
7660
|
const before = this.syncState(ns);
|
|
7734
|
-
if (strictSeq || !inlinePresent) client._seqTracker.updateMaxSeen(ns, pushSeq);
|
|
7735
7661
|
if (pushSeq <= before.ack && before.ack >= before.tail - 1) {
|
|
7736
7662
|
const pending = this.pendingP2PInlineAcks?.get(ns);
|
|
7737
|
-
if (pending && pushSeq >= pending.seq) {
|
|
7663
|
+
if (inlinePresent && pending && pushSeq >= pending.seq) {
|
|
7738
7664
|
this.retryPendingP2PInlineAck(ns, pending.seq, "covered inline P2P ack", pushSeq);
|
|
7739
7665
|
} else if (inlineMatches) {
|
|
7740
7666
|
this.fireP2PV2Ack(pushSeq, "P2P inline covered push ack", inlineGeneration);
|
|
@@ -15405,12 +15331,15 @@ function validateAgentMdDocument(content, opts = {}) {
|
|
|
15405
15331
|
if (new TextEncoder().encode(parsed.payload).byteLength > (opts.maxPayloadBytes ?? 4096)) throw new ValidationError("agent.md payload exceeds 4096 bytes");
|
|
15406
15332
|
if (parsed.fields && new TextEncoder().encode(String(content)).byteLength - new TextEncoder().encode(parsed.payload).byteLength > AGENT_MD_MAX_SIGNATURE_BYTES) throw new ValidationError(`agent.md signature block exceeds ${AGENT_MD_MAX_SIGNATURE_BYTES} bytes`);
|
|
15407
15333
|
const meta = frontmatter(parsed.payload);
|
|
15408
|
-
for (const key of ["aid", "name", "type", "version"
|
|
15334
|
+
for (const key of ["aid", "name", "type", "version"]) if (!(key in meta)) throw new ValidationError(`agent.md frontmatter missing ${key}`);
|
|
15409
15335
|
if (typeof meta.aid !== "string" || !AID_RE.test(meta.aid)) throw new ValidationError("agent.md frontmatter aid has invalid format");
|
|
15410
15336
|
if (opts.expectedAid && meta.aid.toLowerCase() !== opts.expectedAid.trim().toLowerCase()) throw new ValidationError("agent.md frontmatter aid does not match local AID");
|
|
15411
|
-
for (const key of ["name", "type"
|
|
15337
|
+
for (const key of ["name", "type"]) if (typeof meta[key] !== "string" || !String(meta[key]).trim()) throw new ValidationError(`agent.md frontmatter ${key} must be a non-empty string`);
|
|
15412
15338
|
if (typeof meta.version !== "string" || !SEMVER_RE.test(meta.version)) throw new ValidationError("agent.md version must be SemVer MAJOR.MINOR.PATCH");
|
|
15413
|
-
if (
|
|
15339
|
+
if ("description" in meta) {
|
|
15340
|
+
if (typeof meta.description !== "string") throw new ValidationError("agent.md frontmatter description must be a string");
|
|
15341
|
+
if (Array.from(meta.description).length > 100) throw new ValidationError("agent.md description exceeds 100 characters");
|
|
15342
|
+
}
|
|
15414
15343
|
if (meta.tags !== void 0 && (!Array.isArray(meta.tags) || meta.tags.some((item) => typeof item !== "string"))) throw new ValidationError("agent.md tags must be an array of strings");
|
|
15415
15344
|
const fields = parsed.fields;
|
|
15416
15345
|
if (fields) {
|
|
@@ -15677,6 +15606,11 @@ var SIGNED_METHODS = /* @__PURE__ */ new Set([
|
|
|
15677
15606
|
"group.v2.get_proposal",
|
|
15678
15607
|
"group.kick",
|
|
15679
15608
|
"group.add_member",
|
|
15609
|
+
"group.invite_member",
|
|
15610
|
+
"group.list_my_invites",
|
|
15611
|
+
"group.accept_invite",
|
|
15612
|
+
"group.reject_invite",
|
|
15613
|
+
"group.revoke_invite",
|
|
15680
15614
|
"group.leave",
|
|
15681
15615
|
"group.remove_member",
|
|
15682
15616
|
"group.update",
|
|
@@ -15829,7 +15763,9 @@ var NON_IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
|
|
|
15829
15763
|
"mail.send",
|
|
15830
15764
|
"group.send",
|
|
15831
15765
|
"group.create",
|
|
15832
|
-
"group.
|
|
15766
|
+
"group.accept_invite",
|
|
15767
|
+
"group.reject_invite",
|
|
15768
|
+
"group.revoke_invite",
|
|
15833
15769
|
"group.kick",
|
|
15834
15770
|
"group.remove_member",
|
|
15835
15771
|
"group.leave",
|
|
@@ -16855,6 +16791,8 @@ var RpcPipeline = class {
|
|
|
16855
16791
|
}
|
|
16856
16792
|
postprocessMessagePull(params2, result) {
|
|
16857
16793
|
const client = this.runtime.client;
|
|
16794
|
+
const isTail = String(result.window_mode ?? params2.window_mode ?? "").trim().toLowerCase() === "tail";
|
|
16795
|
+
if (isTail) return;
|
|
16858
16796
|
const messages = result.messages;
|
|
16859
16797
|
const rawMessages = (Array.isArray(messages) ? messages : []).filter(isJsonObject);
|
|
16860
16798
|
if (!client._aid || !client._seqTracker) {
|
|
@@ -16862,9 +16800,9 @@ var RpcPipeline = class {
|
|
|
16862
16800
|
}
|
|
16863
16801
|
const ns = `p2p:${client._aid}`;
|
|
16864
16802
|
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
16865
|
-
|
|
16866
|
-
|
|
16867
|
-
|
|
16803
|
+
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq) ? result.contiguous_seq : void 0;
|
|
16804
|
+
if (contiguousSeq === void 0) client._seqTracker.onPullResult(ns, rawMessages, Number(params2.after_seq ?? 0) || 0);
|
|
16805
|
+
else client._seqTracker.onPullResult(ns, rawMessages, Number(params2.after_seq ?? 0) || 0, contiguousSeq);
|
|
16868
16806
|
const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
|
|
16869
16807
|
if (retentionFloor > 0) {
|
|
16870
16808
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
@@ -16883,6 +16821,8 @@ var RpcPipeline = class {
|
|
|
16883
16821
|
if (Array.isArray(result.messages)) {
|
|
16884
16822
|
result.messages = result.messages.map((message) => normalizeGroupMentionMode(message));
|
|
16885
16823
|
}
|
|
16824
|
+
const isTail = String(result.window_mode ?? params2.window_mode ?? "").trim().toLowerCase() === "tail";
|
|
16825
|
+
if (isTail) return;
|
|
16886
16826
|
const gid = String(params2.group_id ?? params2.group_aid ?? "").trim();
|
|
16887
16827
|
if (!gid || !client._seqTracker) {
|
|
16888
16828
|
return;
|
|
@@ -16891,17 +16831,17 @@ var RpcPipeline = class {
|
|
|
16891
16831
|
const rawMessages = (Array.isArray(messages) ? messages : []).filter(isJsonObject);
|
|
16892
16832
|
const ns = `group:${gid}`;
|
|
16893
16833
|
const contigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
16894
|
-
|
|
16895
|
-
|
|
16896
|
-
|
|
16834
|
+
const contiguousSeq = Number.isSafeInteger(result.contiguous_seq) ? result.contiguous_seq : void 0;
|
|
16835
|
+
const afterSeq = Number(params2.after_message_seq ?? params2.after_seq ?? 0) || 0;
|
|
16836
|
+
if (contiguousSeq === void 0) client._seqTracker.onPullResult(ns, rawMessages, afterSeq);
|
|
16837
|
+
else client._seqTracker.onPullResult(ns, rawMessages, afterSeq, contiguousSeq);
|
|
16897
16838
|
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
16898
16839
|
const retentionFloor = Math.max(
|
|
16899
16840
|
0,
|
|
16900
16841
|
Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0),
|
|
16901
16842
|
Number(cursor?.retention_floor_seq ?? 0)
|
|
16902
16843
|
);
|
|
16903
|
-
const
|
|
16904
|
-
const visibilityFloor = isTail ? 0 : Math.max(
|
|
16844
|
+
const visibilityFloor = Math.max(
|
|
16905
16845
|
0,
|
|
16906
16846
|
Math.max(0, Number(result.earliest_available_message_seq ?? 1) - 1),
|
|
16907
16847
|
Number(cursor?.join_seq ?? 0)
|
|
@@ -16910,7 +16850,7 @@ var RpcPipeline = class {
|
|
|
16910
16850
|
if (effectiveFloor > 0) {
|
|
16911
16851
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
16912
16852
|
if (contig < effectiveFloor) {
|
|
16913
|
-
client._clientLog?.info?.(`group.pull floor advance: ns=${ns} contiguous=${contig} -> effective_floor=${effectiveFloor} retention_floor=${retentionFloor} visibility_floor=${visibilityFloor} mode
|
|
16853
|
+
client._clientLog?.info?.(`group.pull floor advance: ns=${ns} contiguous=${contig} -> effective_floor=${effectiveFloor} retention_floor=${retentionFloor} visibility_floor=${visibilityFloor} mode=forward`);
|
|
16914
16854
|
client._seqTracker.forceContiguousSeq(ns, effectiveFloor);
|
|
16915
16855
|
}
|
|
16916
16856
|
}
|
|
@@ -18443,6 +18383,21 @@ var MessageFacade = class extends RpcFacade {
|
|
|
18443
18383
|
return this.call("message.query_online", params2);
|
|
18444
18384
|
}
|
|
18445
18385
|
};
|
|
18386
|
+
function normalizeInviteParams(params2) {
|
|
18387
|
+
const out = stripNil2(params2);
|
|
18388
|
+
const rawGroupId = out.group_id ?? out.groupId ?? out.group_aid ?? out.groupAid;
|
|
18389
|
+
if (rawGroupId !== void 0) {
|
|
18390
|
+
out.group_id = normalizeGroupId(rawGroupId);
|
|
18391
|
+
delete out.groupId;
|
|
18392
|
+
delete out.group_aid;
|
|
18393
|
+
delete out.groupAid;
|
|
18394
|
+
}
|
|
18395
|
+
for (const [alias, canonical] of [["inviteId", "invite_id"], ["inviteeAid", "invitee_aid"]]) {
|
|
18396
|
+
if (out[canonical] === void 0 && out[alias] !== void 0) out[canonical] = out[alias];
|
|
18397
|
+
delete out[alias];
|
|
18398
|
+
}
|
|
18399
|
+
return out;
|
|
18400
|
+
}
|
|
18446
18401
|
var MailFacade = class extends RpcFacade {
|
|
18447
18402
|
send(params2) {
|
|
18448
18403
|
return this.call("mail.send", params2);
|
|
@@ -18555,6 +18510,32 @@ var GroupFacade = class extends RpcFacade {
|
|
|
18555
18510
|
addMember(params2) {
|
|
18556
18511
|
return this.call("group.add_member", params2);
|
|
18557
18512
|
}
|
|
18513
|
+
async inviteCall(method, params2) {
|
|
18514
|
+
const normalized = normalizeInviteParams(params2);
|
|
18515
|
+
try {
|
|
18516
|
+
const result = await this.call(method, normalized);
|
|
18517
|
+
await this.client._onGroupInviteActionResult?.(method, normalized, result);
|
|
18518
|
+
return result;
|
|
18519
|
+
} catch (error) {
|
|
18520
|
+
await this.client._onGroupInviteActionResult?.(method, normalized, void 0, error);
|
|
18521
|
+
throw error;
|
|
18522
|
+
}
|
|
18523
|
+
}
|
|
18524
|
+
inviteMember(params2) {
|
|
18525
|
+
return this.inviteCall("group.invite_member", params2);
|
|
18526
|
+
}
|
|
18527
|
+
listMyInvites(params2) {
|
|
18528
|
+
return this.inviteCall("group.list_my_invites", params2);
|
|
18529
|
+
}
|
|
18530
|
+
acceptInvite(params2) {
|
|
18531
|
+
return this.inviteCall("group.accept_invite", params2);
|
|
18532
|
+
}
|
|
18533
|
+
rejectInvite(params2) {
|
|
18534
|
+
return this.inviteCall("group.reject_invite", params2);
|
|
18535
|
+
}
|
|
18536
|
+
revokeInvite(params2) {
|
|
18537
|
+
return this.inviteCall("group.revoke_invite", params2);
|
|
18538
|
+
}
|
|
18558
18539
|
getMembers(params2) {
|
|
18559
18540
|
return this.call("group.get_members", params2);
|
|
18560
18541
|
}
|
|
@@ -23942,6 +23923,22 @@ function deduplicateForwardPageMessages(value, afterSeq) {
|
|
|
23942
23923
|
}
|
|
23943
23924
|
return [...bySeq.entries()].sort(([a], [b]) => a - b).map(([, row]) => row);
|
|
23944
23925
|
}
|
|
23926
|
+
function contiguousPullSeq(afterSeq, seqs, proof) {
|
|
23927
|
+
let contiguous = seqs.length > 0 ? Math.max(afterSeq, ...seqs) : afterSeq;
|
|
23928
|
+
const serverProof = safeNonNegativeSeq(proof);
|
|
23929
|
+
return serverProof !== null ? Math.max(contiguous, serverProof) : contiguous;
|
|
23930
|
+
}
|
|
23931
|
+
function deduplicatePulledResults(messages) {
|
|
23932
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23933
|
+
return messages.filter((message) => {
|
|
23934
|
+
if (!isJsonObject(message)) return true;
|
|
23935
|
+
const seq2 = safeNonNegativeSeq(message.seq);
|
|
23936
|
+
if (seq2 === null || seq2 <= 0) return true;
|
|
23937
|
+
if (seen.has(seq2)) return false;
|
|
23938
|
+
seen.add(seq2);
|
|
23939
|
+
return true;
|
|
23940
|
+
});
|
|
23941
|
+
}
|
|
23945
23942
|
function shouldContinueForwardPage({
|
|
23946
23943
|
rawCount,
|
|
23947
23944
|
nextAfterSeq,
|
|
@@ -23950,10 +23947,11 @@ function shouldContinueForwardPage({
|
|
|
23950
23947
|
hasMoreField,
|
|
23951
23948
|
hasMore,
|
|
23952
23949
|
serverHead,
|
|
23953
|
-
pendingAckSeq
|
|
23950
|
+
pendingAckSeq,
|
|
23951
|
+
observedUpper
|
|
23954
23952
|
}) {
|
|
23955
23953
|
if (rawCount <= 0 || nextAfter <= nextAfterSeq) return false;
|
|
23956
|
-
if (hasMore || serverHead > nextAfter || pendingAckSeq > 0) return true;
|
|
23954
|
+
if (hasMore || serverHead > nextAfter || pendingAckSeq > 0 || observedUpper > nextAfter) return true;
|
|
23957
23955
|
return !hasMoreField && limit > 0 && rawCount >= limit;
|
|
23958
23956
|
}
|
|
23959
23957
|
function validateTailPage(result, afterSeq, pageLimit) {
|
|
@@ -24692,7 +24690,7 @@ var V2E2EECoordinator = class {
|
|
|
24692
24690
|
client._clientLog.warn(`V2 sender IK pending group bootstrap failed group=${groupId}: ${String(formatE2EEError(exc))}`);
|
|
24693
24691
|
}
|
|
24694
24692
|
}
|
|
24695
|
-
if (!session.getPeerIK(fromAid, senderDeviceId)) {
|
|
24693
|
+
if (typeof session.getPeerIK === "function" && !session.getPeerIK(fromAid, senderDeviceId)) {
|
|
24696
24694
|
await this.getV2SenderPubDer(fromAid, senderDeviceId);
|
|
24697
24695
|
}
|
|
24698
24696
|
}
|
|
@@ -24728,6 +24726,7 @@ var V2E2EECoordinator = class {
|
|
|
24728
24726
|
client._v2SenderIKPending.delete(key);
|
|
24729
24727
|
const seq2 = Number(entry.msg.seq ?? 0);
|
|
24730
24728
|
if (entry.groupId) {
|
|
24729
|
+
if (client._delivery.isSelfSentGroupMessage?.(entry.msg)) continue;
|
|
24731
24730
|
plaintext = normalizeGroupMentionMode(plaintext, entry.msg, entry.msg.envelope_json);
|
|
24732
24731
|
plaintext.group_id = entry.groupId;
|
|
24733
24732
|
await client._publishPulledMessage("group.message_created", `group:${entry.groupId}`, seq2, plaintext, false, "pending_retry");
|
|
@@ -24920,6 +24919,9 @@ var V2E2EECoordinator = class {
|
|
|
24920
24919
|
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}`);
|
|
24921
24920
|
return null;
|
|
24922
24921
|
}
|
|
24922
|
+
if (publish && !history && client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
24923
|
+
return plaintext;
|
|
24924
|
+
}
|
|
24923
24925
|
if (publish) {
|
|
24924
24926
|
if (orderedPublish) {
|
|
24925
24927
|
await client._delivery.publishOrderedMessage(
|
|
@@ -24941,13 +24943,6 @@ var V2E2EECoordinator = class {
|
|
|
24941
24943
|
async decodeInlineGroupMessage(msg, groupId, groupAid) {
|
|
24942
24944
|
return await this.decodeGroupWindowMessage(msg, groupId, groupAid, false, false, "inline_push");
|
|
24943
24945
|
}
|
|
24944
|
-
async applyTailFloor(ns, floor) {
|
|
24945
|
-
const client = this.client;
|
|
24946
|
-
if (!ns || floor <= 0 || client._seqTracker.getContiguousSeq(ns) >= floor) return;
|
|
24947
|
-
client._seqTracker.forceContiguousSeq(ns, floor);
|
|
24948
|
-
client._persistSeq(ns);
|
|
24949
|
-
await client._saveSeqTrackerState?.();
|
|
24950
|
-
}
|
|
24951
24946
|
async pullV2TailInternal(params2, deferPublish = false) {
|
|
24952
24947
|
const client = this.client;
|
|
24953
24948
|
if (params2.window_mode !== "tail") throw new ValidationError("window_mode must equal tail");
|
|
@@ -24957,9 +24952,6 @@ var V2E2EECoordinator = class {
|
|
|
24957
24952
|
const ns = client._aid ? `p2p:${client._aid}` : "";
|
|
24958
24953
|
if (ns) client._delivery.onPullStarted?.(ns);
|
|
24959
24954
|
const result = await client._callRawV2Rpc("message.v2.pull", { window_mode: "tail", after_seq: afterSeq, limit, _rpc_foreground: true });
|
|
24960
|
-
const floor = Number(result.retention_floor_seq ?? 0);
|
|
24961
|
-
const previous = ns ? client._seqTracker.getSyncState(ns) : null;
|
|
24962
|
-
await this.applyTailFloor(ns, Number.isSafeInteger(floor) ? floor : 0);
|
|
24963
24955
|
const page = validateTailPage(result, afterSeq, limit);
|
|
24964
24956
|
if (ns) {
|
|
24965
24957
|
client._seqTracker.commitTailWindow(ns, {
|
|
@@ -24977,7 +24969,6 @@ var V2E2EECoordinator = class {
|
|
|
24977
24969
|
if (plaintext) decoded.push(plaintext);
|
|
24978
24970
|
}
|
|
24979
24971
|
const ack = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
|
|
24980
|
-
if (previous && ack > previous.ack) await this.ackV2(ack);
|
|
24981
24972
|
if (ns) client._delivery.onPullPage?.(
|
|
24982
24973
|
ns,
|
|
24983
24974
|
decoded.length,
|
|
@@ -25097,6 +25088,11 @@ var V2E2EECoordinator = class {
|
|
|
25097
25088
|
const pageContigBefore = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
|
|
25098
25089
|
const pageTrackerSnapshot = ns && typeof client._seqTracker.snapshotNamespace === "function" ? client._seqTracker.snapshotNamespace(ns) : null;
|
|
25099
25090
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
25091
|
+
const pageContiguousSeq = contiguousPullSeq(
|
|
25092
|
+
pageContigBefore,
|
|
25093
|
+
seqs,
|
|
25094
|
+
result.contiguous_seq
|
|
25095
|
+
);
|
|
25100
25096
|
const deferredKeyFetches = /* @__PURE__ */ new Map();
|
|
25101
25097
|
let blockedSeq = 0;
|
|
25102
25098
|
const pageDecryptedBefore = decrypted.length;
|
|
@@ -25188,11 +25184,12 @@ var V2E2EECoordinator = class {
|
|
|
25188
25184
|
const serverAckSeq = parsedServerAckSeq ?? 0;
|
|
25189
25185
|
const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
|
|
25190
25186
|
if (ns) {
|
|
25191
|
-
const commitTarget =
|
|
25187
|
+
const commitTarget = Math.max(
|
|
25192
25188
|
pageContigBefore,
|
|
25193
25189
|
Number.isFinite(retentionFloor) ? retentionFloor : 0,
|
|
25194
25190
|
pageCount === 1 ? deferredServerCursor : 0,
|
|
25195
|
-
|
|
25191
|
+
serverAckSeq,
|
|
25192
|
+
blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq
|
|
25196
25193
|
);
|
|
25197
25194
|
let ackSeq = pageContigBefore;
|
|
25198
25195
|
let contigAdvanced = false;
|
|
@@ -25230,10 +25227,10 @@ var V2E2EECoordinator = class {
|
|
|
25230
25227
|
this.recordForwardCursor(ns, serverAckSeq, ackSeq);
|
|
25231
25228
|
}
|
|
25232
25229
|
const knownServerAckSeq = hasServerAckSeq ? serverAckSeq : pageCount === 1 ? deferredServerCursor : 0;
|
|
25233
|
-
const ackNeeded =
|
|
25230
|
+
const ackNeeded = ackSeq > 0 && ackSeq > lastAutoAckSeq && (hasServerAckSeq && ackSeq > serverAckSeq || contigAdvanced && ackSeq > knownServerAckSeq);
|
|
25234
25231
|
if (ackNeeded) {
|
|
25235
25232
|
this.recordForwardAck(ns, ackSeq);
|
|
25236
|
-
const nextAfter2 = Math.max(
|
|
25233
|
+
const nextAfter2 = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
25237
25234
|
const canContinuePage = blockedSeq <= 0 && messages.length > 0 && nextAfter2 > nextAfterSeq;
|
|
25238
25235
|
if (canContinuePage) {
|
|
25239
25236
|
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
@@ -25254,7 +25251,7 @@ var V2E2EECoordinator = class {
|
|
|
25254
25251
|
client._seqTracker.getContiguousSeq(ns),
|
|
25255
25252
|
pageMaxSeq
|
|
25256
25253
|
);
|
|
25257
|
-
const nextAfter = Math.max(
|
|
25254
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
25258
25255
|
const rawCount = messages.length;
|
|
25259
25256
|
if (blockedSeq > 0) break;
|
|
25260
25257
|
const shouldContinue = shouldContinueForwardPage({
|
|
@@ -25265,7 +25262,8 @@ var V2E2EECoordinator = class {
|
|
|
25265
25262
|
hasMoreField,
|
|
25266
25263
|
hasMore,
|
|
25267
25264
|
serverHead,
|
|
25268
|
-
pendingAckSeq
|
|
25265
|
+
pendingAckSeq,
|
|
25266
|
+
observedUpper: typeof client._seqTracker.getMaxSeenSeq === "function" ? client._seqTracker.getMaxSeenSeq(ns) : nextAfter
|
|
25269
25267
|
});
|
|
25270
25268
|
if (!shouldContinue) break;
|
|
25271
25269
|
if (pullGateKey && opts?.gateLocked && client._rpcPipeline?.yieldPullGate) {
|
|
@@ -25289,7 +25287,7 @@ var V2E2EECoordinator = class {
|
|
|
25289
25287
|
}
|
|
25290
25288
|
}
|
|
25291
25289
|
client._delivery.onPullWorkSettled?.();
|
|
25292
|
-
return decrypted;
|
|
25290
|
+
return deduplicatePulledResults(decrypted);
|
|
25293
25291
|
}
|
|
25294
25292
|
async confirmForwardP2PAck(upToSeq, inlineGeneration) {
|
|
25295
25293
|
const ns = this.client._aid ? `p2p:${this.client._aid}` : "";
|
|
@@ -25375,10 +25373,7 @@ var V2E2EECoordinator = class {
|
|
|
25375
25373
|
if (isJsonObject(result)) {
|
|
25376
25374
|
const seq2 = Number(result.seq ?? 0);
|
|
25377
25375
|
if (seq2 > 0) {
|
|
25378
|
-
|
|
25379
|
-
client._seqTracker.onMessageSeq(ns, seq2);
|
|
25380
|
-
client._markPublishedSeq(ns, seq2);
|
|
25381
|
-
await client._saveSeqTrackerState();
|
|
25376
|
+
client._markPublishedSeq(`group:${gid}`, seq2);
|
|
25382
25377
|
}
|
|
25383
25378
|
}
|
|
25384
25379
|
return client._delivery.attachSendResultEnvelope("group.send", withExplicitGroupAid({
|
|
@@ -25398,10 +25393,7 @@ var V2E2EECoordinator = class {
|
|
|
25398
25393
|
if (isJsonObject(result)) {
|
|
25399
25394
|
const seq2 = Number(result.seq ?? 0);
|
|
25400
25395
|
if (seq2 > 0) {
|
|
25401
|
-
|
|
25402
|
-
client._seqTracker.onMessageSeq(ns, seq2);
|
|
25403
|
-
client._markPublishedSeq(ns, seq2);
|
|
25404
|
-
await client._saveSeqTrackerState();
|
|
25396
|
+
client._markPublishedSeq(`group:${gid}`, seq2);
|
|
25405
25397
|
}
|
|
25406
25398
|
}
|
|
25407
25399
|
return client._delivery.attachSendResultEnvelope("group.send", withExplicitGroupAid({
|
|
@@ -25440,9 +25432,6 @@ var V2E2EECoordinator = class {
|
|
|
25440
25432
|
}, groupAid));
|
|
25441
25433
|
const resultAid = String(result.group_aid ?? result.groupAid ?? "").trim();
|
|
25442
25434
|
if (resultAid) groupAid = resultAid;
|
|
25443
|
-
const floor = Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0);
|
|
25444
|
-
const previous = client._seqTracker.getSyncState(ns);
|
|
25445
|
-
await this.applyTailFloor(ns, Number.isSafeInteger(floor) ? floor : 0);
|
|
25446
25435
|
const page = validateTailPage(result, afterSeq, limit);
|
|
25447
25436
|
client._seqTracker.commitTailWindow(ns, {
|
|
25448
25437
|
windowStartSeq: page.windowStart,
|
|
@@ -25459,7 +25448,6 @@ var V2E2EECoordinator = class {
|
|
|
25459
25448
|
if (plaintext) decoded.push(plaintext);
|
|
25460
25449
|
}
|
|
25461
25450
|
const ack = client._seqTracker.getContiguousSeq(ns);
|
|
25462
|
-
if (ack > previous.ack) await this.ackGroupV2(groupId, ack, groupAid);
|
|
25463
25451
|
if (ownsCursor) client._delivery.onPullPage?.(
|
|
25464
25452
|
ns,
|
|
25465
25453
|
decoded.length,
|
|
@@ -25616,6 +25604,11 @@ var V2E2EECoordinator = class {
|
|
|
25616
25604
|
const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
|
|
25617
25605
|
const pageTrackerSnapshot = typeof client._seqTracker.snapshotNamespace === "function" ? client._seqTracker.snapshotNamespace(ns) : null;
|
|
25618
25606
|
const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
|
|
25607
|
+
const pageContiguousSeq = contiguousPullSeq(
|
|
25608
|
+
pageContigBefore,
|
|
25609
|
+
seqs,
|
|
25610
|
+
result.contiguous_seq
|
|
25611
|
+
);
|
|
25619
25612
|
const deferredKeyFetches = /* @__PURE__ */ new Map();
|
|
25620
25613
|
let blockedSeq = 0;
|
|
25621
25614
|
const pageDecryptedBefore = decrypted.length;
|
|
@@ -25653,7 +25646,11 @@ var V2E2EECoordinator = class {
|
|
|
25653
25646
|
};
|
|
25654
25647
|
v1Msg = normalizeGroupMentionMode(v1Msg, msg, msg.envelope_json);
|
|
25655
25648
|
attachGatewayProximity(v1Msg, msg);
|
|
25656
|
-
|
|
25649
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
25650
|
+
await client._publishPulledMessage("group.message_created", ns, seq2, v1Msg, false);
|
|
25651
|
+
} else {
|
|
25652
|
+
client._markPublishedSeq(ns, seq2);
|
|
25653
|
+
}
|
|
25657
25654
|
decrypted.push(v1Msg);
|
|
25658
25655
|
continue;
|
|
25659
25656
|
}
|
|
@@ -25697,7 +25694,11 @@ var V2E2EECoordinator = class {
|
|
|
25697
25694
|
if (plaintext2) {
|
|
25698
25695
|
plaintext2.group_id = gid;
|
|
25699
25696
|
plaintext2.group_aid = eventGroupAid;
|
|
25700
|
-
|
|
25697
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
25698
|
+
await client._publishPulledMessage("group.message_created", ns, seq2, plaintext2, false);
|
|
25699
|
+
} else {
|
|
25700
|
+
client._markPublishedSeq(ns, seq2);
|
|
25701
|
+
}
|
|
25701
25702
|
decrypted.push(plaintext2);
|
|
25702
25703
|
}
|
|
25703
25704
|
}
|
|
@@ -25725,7 +25726,11 @@ var V2E2EECoordinator = class {
|
|
|
25725
25726
|
plaintext = normalizeGroupMentionMode(plaintext, msg, msg.envelope_json);
|
|
25726
25727
|
plaintext.group_id = gid;
|
|
25727
25728
|
plaintext.group_aid = eventGroupAid;
|
|
25728
|
-
|
|
25729
|
+
if (!client._delivery.isSelfSentGroupMessage?.(msg)) {
|
|
25730
|
+
await client._publishPulledMessage("group.message_created", ns, seq2, plaintext, false);
|
|
25731
|
+
} else {
|
|
25732
|
+
client._markPublishedSeq(ns, seq2);
|
|
25733
|
+
}
|
|
25729
25734
|
decrypted.push(plaintext);
|
|
25730
25735
|
}
|
|
25731
25736
|
const hasServerCursor = cursor !== null && Object.prototype.hasOwnProperty.call(cursor, "current_seq");
|
|
@@ -25741,11 +25746,12 @@ var V2E2EECoordinator = class {
|
|
|
25741
25746
|
Number(cursor?.join_seq ?? 0)
|
|
25742
25747
|
);
|
|
25743
25748
|
const effectiveFloor = Math.max(retentionFloor, visibilityFloor);
|
|
25744
|
-
const commitTarget =
|
|
25749
|
+
const commitTarget = Math.max(
|
|
25745
25750
|
pageContigBefore,
|
|
25746
25751
|
Number.isFinite(effectiveFloor) ? effectiveFloor : 0,
|
|
25747
25752
|
ownsCursor && pageCount === 1 ? deferredServerCursor : 0,
|
|
25748
|
-
|
|
25753
|
+
cursorCurrentSeq,
|
|
25754
|
+
blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq
|
|
25749
25755
|
);
|
|
25750
25756
|
let ackSeq = pageContigBefore;
|
|
25751
25757
|
let contigAdvanced = false;
|
|
@@ -25795,10 +25801,10 @@ var V2E2EECoordinator = class {
|
|
|
25795
25801
|
this.recordForwardCursor(ns, cursorCurrentSeq, ackSeq);
|
|
25796
25802
|
}
|
|
25797
25803
|
const knownServerCursorSeq = hasServerCursor ? cursorCurrentSeq : ownsCursor && pageCount === 1 ? deferredServerCursor : 0;
|
|
25798
|
-
const ackNeeded =
|
|
25804
|
+
const ackNeeded = ackSeq > 0 && ackSeq > lastAutoAckSeq && ownsCursor && (hasServerCursor && ackSeq > cursorCurrentSeq || contigAdvanced && ackSeq > knownServerCursorSeq);
|
|
25799
25805
|
if (ackNeeded) {
|
|
25800
25806
|
this.recordForwardAck(ns, ackSeq);
|
|
25801
|
-
const nextAfter2 = Math.max(
|
|
25807
|
+
const nextAfter2 = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
25802
25808
|
const canContinuePage = blockedSeq <= 0 && messages.length > 0 && nextAfter2 > nextAfterSeq && ownsCursor;
|
|
25803
25809
|
if (canContinuePage) {
|
|
25804
25810
|
pendingAckSeq = Math.max(pendingAckSeq, ackSeq);
|
|
@@ -25808,7 +25814,7 @@ var V2E2EECoordinator = class {
|
|
|
25808
25814
|
lastAutoAckSeq = Math.max(lastAutoAckSeq, ackSeq);
|
|
25809
25815
|
}
|
|
25810
25816
|
}
|
|
25811
|
-
const nextAfter = Math.max(
|
|
25817
|
+
const nextAfter = Math.max(pageContiguousSeq, nextAfterSeq);
|
|
25812
25818
|
if (!ownsCursor) break;
|
|
25813
25819
|
const rawCount = messages.length;
|
|
25814
25820
|
if (blockedSeq > 0) break;
|
|
@@ -25820,7 +25826,8 @@ var V2E2EECoordinator = class {
|
|
|
25820
25826
|
hasMoreField,
|
|
25821
25827
|
hasMore,
|
|
25822
25828
|
serverHead,
|
|
25823
|
-
pendingAckSeq
|
|
25829
|
+
pendingAckSeq,
|
|
25830
|
+
observedUpper: typeof client._seqTracker.getMaxSeenSeq === "function" ? client._seqTracker.getMaxSeenSeq(ns) : nextAfter
|
|
25824
25831
|
});
|
|
25825
25832
|
if (!shouldContinue) break;
|
|
25826
25833
|
if (pullGateKey && opts?.gateLocked && client._rpcPipeline?.yieldPullGate) {
|
|
@@ -25846,7 +25853,7 @@ var V2E2EECoordinator = class {
|
|
|
25846
25853
|
}
|
|
25847
25854
|
}
|
|
25848
25855
|
client._delivery.onPullWorkSettled?.();
|
|
25849
|
-
return decrypted;
|
|
25856
|
+
return deduplicatePulledResults(decrypted);
|
|
25850
25857
|
}
|
|
25851
25858
|
async confirmForwardGroupAck(groupId, upToSeq, groupAid) {
|
|
25852
25859
|
const ns = `group:${String(groupId ?? "").trim()}`;
|
|
@@ -26683,7 +26690,8 @@ var MEMBERSHIP_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
|
26683
26690
|
"group.review_join_request",
|
|
26684
26691
|
"group.batch_review_join_request",
|
|
26685
26692
|
"group.use_invite_code",
|
|
26686
|
-
"group.request_join"
|
|
26693
|
+
"group.request_join",
|
|
26694
|
+
"group.accept_invite"
|
|
26687
26695
|
]);
|
|
26688
26696
|
var SPK_REGISTRATION_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
26689
26697
|
"group.create",
|
|
@@ -29412,6 +29420,7 @@ var RECONNECT_MIN_BASE_DELAY_SECONDS = 1;
|
|
|
29412
29420
|
var RECONNECT_MAX_BASE_DELAY_SECONDS = 64;
|
|
29413
29421
|
var TOKEN_REFRESH_CHECK_INTERVAL_MS = 3e4;
|
|
29414
29422
|
var MAX_NOTIFY_PAYLOAD_SIZE = 64 * 1024;
|
|
29423
|
+
var GROUP_INVITE_METADATA_KEY = "group_invite_pending_v1";
|
|
29415
29424
|
function clampReconnectDelaySeconds(value, fallback, upper = RECONNECT_MAX_BASE_DELAY_SECONDS) {
|
|
29416
29425
|
const parsed = Number(value);
|
|
29417
29426
|
const seconds = Number.isFinite(parsed) ? parsed : fallback;
|
|
@@ -29804,6 +29813,9 @@ var _AUNClient = class _AUNClient {
|
|
|
29804
29813
|
__publicField(this, "_mailFacade");
|
|
29805
29814
|
__publicField(this, "_groupFacade");
|
|
29806
29815
|
__publicField(this, "_streamFacade");
|
|
29816
|
+
__publicField(this, "_groupInvitePending", /* @__PURE__ */ new Map());
|
|
29817
|
+
__publicField(this, "_groupInviteStateAid", null);
|
|
29818
|
+
__publicField(this, "_groupInviteStateLoad", null);
|
|
29807
29819
|
/**
|
|
29808
29820
|
* 处理 V2 push 通知:自动 pull + decrypt + emit。
|
|
29809
29821
|
*/
|
|
@@ -29927,6 +29939,15 @@ var _AUNClient = class _AUNClient {
|
|
|
29927
29939
|
this._dispatcher.subscribe("_raw.group.changed", (data) => {
|
|
29928
29940
|
this._onRawGroupChanged(data);
|
|
29929
29941
|
});
|
|
29942
|
+
this._dispatcher.subscribe("_raw.group.invite_created", (data) => {
|
|
29943
|
+
this._safeAsync(this._onRawGroupInviteReceived(data, "push"));
|
|
29944
|
+
});
|
|
29945
|
+
this._dispatcher.subscribe("_raw.group.invite_received", (data) => {
|
|
29946
|
+
this._safeAsync(this._onRawGroupInviteReceived(data, "push"));
|
|
29947
|
+
});
|
|
29948
|
+
this._dispatcher.subscribe("_raw.group.invite_finalized", (data) => {
|
|
29949
|
+
this._safeAsync(this._onRawGroupInviteFinalized(data));
|
|
29950
|
+
});
|
|
29930
29951
|
this._dispatcher.subscribe("_raw.peer.v2.message_received", (data) => {
|
|
29931
29952
|
this._safeAsync(this._onV2PushNotification(data));
|
|
29932
29953
|
});
|
|
@@ -30474,6 +30495,8 @@ var _AUNClient = class _AUNClient {
|
|
|
30474
30495
|
}
|
|
30475
30496
|
this._aidStore = store;
|
|
30476
30497
|
const payload = { ...params2 };
|
|
30498
|
+
const initialMembers = payload.members;
|
|
30499
|
+
delete payload.members;
|
|
30477
30500
|
if (payload.group_name === void 0 && payload.groupName !== void 0) {
|
|
30478
30501
|
payload.group_name = payload.groupName;
|
|
30479
30502
|
delete payload.groupName;
|
|
@@ -30503,7 +30526,8 @@ var _AUNClient = class _AUNClient {
|
|
|
30503
30526
|
const result2 = { ...createdMap, ...boundMap, group: { ...createdGroup, ...boundGroup } };
|
|
30504
30527
|
const postprocessParams2 = { ...payload };
|
|
30505
30528
|
delete postprocessParams2._defer_group_ready_postprocess;
|
|
30506
|
-
|
|
30529
|
+
const processed2 = await this._groupState.postprocessResult("group.create", postprocessParams2, result2);
|
|
30530
|
+
return await this._inviteInitialGroupMembers(processed2, groupId, initialMembers);
|
|
30507
30531
|
}
|
|
30508
30532
|
const pendingKey = `create:${String(payload.group_name).trim().toLowerCase()}`;
|
|
30509
30533
|
const keystore = store._keystore;
|
|
@@ -30553,7 +30577,29 @@ var _AUNClient = class _AUNClient {
|
|
|
30553
30577
|
}
|
|
30554
30578
|
const postprocessParams = { ...payload };
|
|
30555
30579
|
delete postprocessParams._defer_group_ready_postprocess;
|
|
30556
|
-
|
|
30580
|
+
const processed = await this._groupState.postprocessResult("group.create", postprocessParams, result);
|
|
30581
|
+
return await this._inviteInitialGroupMembers(processed, String(group.group_id ?? groupAid).trim(), initialMembers);
|
|
30582
|
+
}
|
|
30583
|
+
async _inviteInitialGroupMembers(result, groupId, members) {
|
|
30584
|
+
const invites = [];
|
|
30585
|
+
const inviteErrors = [];
|
|
30586
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30587
|
+
if (Array.isArray(members)) {
|
|
30588
|
+
for (const item of members) {
|
|
30589
|
+
const aid = typeof item === "string" ? item.trim() : isJsonObject(item) ? String(item.aid ?? "").trim() : "";
|
|
30590
|
+
const memberType = isJsonObject(item) ? String(item.member_type ?? "").trim() : "";
|
|
30591
|
+
if (!aid || aid === String(this._aid ?? this._currentAid?.aid ?? "").trim() || seen.has(aid)) continue;
|
|
30592
|
+
seen.add(aid);
|
|
30593
|
+
const params2 = { group_id: groupId, invitee_aid: aid };
|
|
30594
|
+
if (memberType) params2.member_type = memberType;
|
|
30595
|
+
try {
|
|
30596
|
+
invites.push(await this.group.inviteMember(params2));
|
|
30597
|
+
} catch (err) {
|
|
30598
|
+
inviteErrors.push({ aid, error: err instanceof Error ? err.message : String(err) });
|
|
30599
|
+
}
|
|
30600
|
+
}
|
|
30601
|
+
}
|
|
30602
|
+
return { ...isJsonObject(result) ? result : {}, invites, invite_errors: inviteErrors };
|
|
30557
30603
|
}
|
|
30558
30604
|
_groupAgentMdContent(groupAid, params2 = {}, group = {}) {
|
|
30559
30605
|
const explicit = params2.group_agent_md ?? params2.groupAgentMd ?? params2.content;
|
|
@@ -31135,6 +31181,239 @@ var _AUNClient = class _AUNClient {
|
|
|
31135
31181
|
const member = isJsonObject(result.member) ? result.member : null;
|
|
31136
31182
|
return member ? String(member.group_id ?? member.groupId ?? member.group_aid ?? member.groupAid ?? "") : "";
|
|
31137
31183
|
}
|
|
31184
|
+
groupInviteKey(groupId, inviteeAid) {
|
|
31185
|
+
const group = normalizeGroupId(groupId);
|
|
31186
|
+
const invitee = String(inviteeAid ?? "").trim().toLowerCase();
|
|
31187
|
+
return group && invitee ? `${group}
|
|
31188
|
+
${invitee}` : "";
|
|
31189
|
+
}
|
|
31190
|
+
async ensureGroupInviteStateLoaded() {
|
|
31191
|
+
const aid = String(this._aid ?? "").trim();
|
|
31192
|
+
if (!aid) {
|
|
31193
|
+
this._groupInvitePending.clear();
|
|
31194
|
+
this._groupInviteStateAid = null;
|
|
31195
|
+
return;
|
|
31196
|
+
}
|
|
31197
|
+
if (this._groupInviteStateAid === aid) return;
|
|
31198
|
+
if (this._groupInviteStateLoad) {
|
|
31199
|
+
await this._groupInviteStateLoad;
|
|
31200
|
+
if (this._groupInviteStateAid === aid) return;
|
|
31201
|
+
}
|
|
31202
|
+
this._groupInviteStateLoad = (async () => {
|
|
31203
|
+
this._groupInvitePending.clear();
|
|
31204
|
+
this._groupInviteStateAid = aid;
|
|
31205
|
+
const getter = this._tokenStore?.getMetadata;
|
|
31206
|
+
if (typeof getter !== "function") return;
|
|
31207
|
+
try {
|
|
31208
|
+
const raw = await getter.call(this._tokenStore, aid, GROUP_INVITE_METADATA_KEY);
|
|
31209
|
+
const parsed = raw ? JSON.parse(String(raw)) : {};
|
|
31210
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
31211
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
31212
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
31213
|
+
this._groupInvitePending.set(key, value);
|
|
31214
|
+
}
|
|
31215
|
+
}
|
|
31216
|
+
} catch (exc) {
|
|
31217
|
+
this._clientLog.debug(`group invite state restore skipped: ${String(exc)}`);
|
|
31218
|
+
}
|
|
31219
|
+
})().finally(() => {
|
|
31220
|
+
this._groupInviteStateLoad = null;
|
|
31221
|
+
});
|
|
31222
|
+
return this._groupInviteStateLoad;
|
|
31223
|
+
}
|
|
31224
|
+
async persistGroupInviteState() {
|
|
31225
|
+
const aid = String(this._aid ?? "").trim();
|
|
31226
|
+
const setter = this._tokenStore?.setMetadata;
|
|
31227
|
+
if (!aid || typeof setter !== "function") return;
|
|
31228
|
+
const state = {};
|
|
31229
|
+
for (const [key, value] of this._groupInvitePending) state[key] = value;
|
|
31230
|
+
try {
|
|
31231
|
+
await setter.call(this._tokenStore, aid, GROUP_INVITE_METADATA_KEY, JSON.stringify(state));
|
|
31232
|
+
} catch (exc) {
|
|
31233
|
+
this._clientLog.debug(`group invite state persist skipped: ${String(exc)}`);
|
|
31234
|
+
}
|
|
31235
|
+
}
|
|
31236
|
+
inviteArray(value, singular) {
|
|
31237
|
+
const values = Array.isArray(value) ? value : singular !== void 0 ? [singular] : [];
|
|
31238
|
+
return [...new Set(values.map((item) => String(item ?? "").trim()).filter(Boolean))];
|
|
31239
|
+
}
|
|
31240
|
+
inviteBool(value) {
|
|
31241
|
+
return value === true || value === 1 || String(value ?? "").trim().toLowerCase() === "true";
|
|
31242
|
+
}
|
|
31243
|
+
async _onRawGroupInviteReceived(data, source = "push") {
|
|
31244
|
+
if (!isJsonObject(data)) return;
|
|
31245
|
+
const groupId = normalizeGroupId(data.group_id ?? data.groupId ?? data.group_aid ?? data.groupAid);
|
|
31246
|
+
const inviteeAid = String(data.invitee_aid ?? data.inviteeAid ?? this._aid ?? "").trim();
|
|
31247
|
+
if (!groupId || !inviteeAid || this._aid && inviteeAid.toLowerCase() !== this._aid.toLowerCase()) return;
|
|
31248
|
+
if (String(data.status ?? "pending").trim().toLowerCase() !== "pending") {
|
|
31249
|
+
await this._onRawGroupInviteFinalized(data);
|
|
31250
|
+
return;
|
|
31251
|
+
}
|
|
31252
|
+
await this.ensureGroupInviteStateLoaded();
|
|
31253
|
+
const key = this.groupInviteKey(groupId, inviteeAid);
|
|
31254
|
+
if (!key) return;
|
|
31255
|
+
const inviteIds = this.inviteArray(data.invite_ids, data.invite_id);
|
|
31256
|
+
const inviterAids = this.inviteArray(data.inviter_aids, data.inviter_aid);
|
|
31257
|
+
const existing = this._groupInvitePending.get(key);
|
|
31258
|
+
if (existing) {
|
|
31259
|
+
existing.invite_ids = [.../* @__PURE__ */ new Set([...this.inviteArray(existing.invite_ids), ...inviteIds])];
|
|
31260
|
+
existing.inviter_aids = [.../* @__PURE__ */ new Set([...this.inviteArray(existing.inviter_aids), ...inviterAids])];
|
|
31261
|
+
await this.persistGroupInviteState();
|
|
31262
|
+
return;
|
|
31263
|
+
}
|
|
31264
|
+
const payload = {
|
|
31265
|
+
...data,
|
|
31266
|
+
group_id: groupId,
|
|
31267
|
+
group_aid: groupId,
|
|
31268
|
+
invitee_aid: inviteeAid,
|
|
31269
|
+
invite_ids: inviteIds,
|
|
31270
|
+
inviter_aids: inviterAids,
|
|
31271
|
+
role: data.role ?? "member",
|
|
31272
|
+
member_type: data.member_type ?? data.memberType ?? "human",
|
|
31273
|
+
created_at: data.created_at ?? data.createdAt ?? 0,
|
|
31274
|
+
expires_at: data.expires_at ?? data.expiresAt ?? 0,
|
|
31275
|
+
status: "pending"
|
|
31276
|
+
};
|
|
31277
|
+
delete payload.groupId;
|
|
31278
|
+
delete payload.groupAid;
|
|
31279
|
+
delete payload.inviteeAid;
|
|
31280
|
+
delete payload.inviterAid;
|
|
31281
|
+
this._groupInvitePending.set(key, payload);
|
|
31282
|
+
await this.persistGroupInviteState();
|
|
31283
|
+
await this._publishAppEvent("group.invite_received", JSON.parse(JSON.stringify(payload)), source);
|
|
31284
|
+
}
|
|
31285
|
+
async _onRawGroupInviteFinalized(data) {
|
|
31286
|
+
if (!isJsonObject(data)) return;
|
|
31287
|
+
await this.ensureGroupInviteStateLoaded();
|
|
31288
|
+
const groupId = normalizeGroupId(data.group_id ?? data.groupId ?? data.group_aid ?? data.groupAid);
|
|
31289
|
+
const inviteeAid = String(data.invitee_aid ?? data.inviteeAid ?? this._aid ?? "").trim();
|
|
31290
|
+
if (this._aid && inviteeAid.toLowerCase() !== this._aid.toLowerCase()) return;
|
|
31291
|
+
const inviteId = String(data.invite_id ?? "").trim();
|
|
31292
|
+
const key = this.groupInviteKey(groupId, inviteeAid);
|
|
31293
|
+
const status = String(data.status ?? "").trim().toLowerCase();
|
|
31294
|
+
const aggregateStatus = String(data.aggregate_status ?? data.aggregateStatus ?? "").trim().toLowerCase();
|
|
31295
|
+
const pendingIds = this.inviteArray(data.pending_invite_ids ?? data.pendingInviteIds);
|
|
31296
|
+
const pendingInviters = this.inviteArray(data.pending_inviter_aids ?? data.pendingInviterAids);
|
|
31297
|
+
const finalizedIds = this.inviteBool(data.remaining_pending) && inviteId ? [inviteId] : this.inviteArray(data.invite_ids, data.invite_id);
|
|
31298
|
+
const finalizedInviters = this.inviteArray(data.inviter_aids, data.inviter_aid);
|
|
31299
|
+
const leavesPending = this.inviteBool(data.remaining_pending) || this.inviteBool(data.pending) || status === "pending" || aggregateStatus === "pending" || pendingIds.length > 0;
|
|
31300
|
+
let changed = false;
|
|
31301
|
+
const candidates = [];
|
|
31302
|
+
if (key) {
|
|
31303
|
+
const current = this._groupInvitePending.get(key);
|
|
31304
|
+
if (current) candidates.push([key, current]);
|
|
31305
|
+
}
|
|
31306
|
+
if (candidates.length === 0 && inviteId) {
|
|
31307
|
+
for (const [itemKey, item] of this._groupInvitePending) {
|
|
31308
|
+
if (this.inviteArray(item.invite_ids).includes(inviteId)) candidates.push([itemKey, item]);
|
|
31309
|
+
}
|
|
31310
|
+
}
|
|
31311
|
+
for (const [itemKey, item] of candidates) {
|
|
31312
|
+
if (!leavesPending) {
|
|
31313
|
+
this._groupInvitePending.delete(itemKey);
|
|
31314
|
+
changed = true;
|
|
31315
|
+
continue;
|
|
31316
|
+
}
|
|
31317
|
+
const currentIds = this.inviteArray(item.invite_ids);
|
|
31318
|
+
const currentInviters = this.inviteArray(item.inviter_aids);
|
|
31319
|
+
const finalizedIndexes = new Set(currentIds.map((id, index) => finalizedIds.includes(id) ? index : -1).filter((index) => index >= 0));
|
|
31320
|
+
const nextIds = pendingIds.length > 0 ? pendingIds : finalizedIds.length > 0 ? currentIds.filter((id) => !finalizedIds.includes(id)) : currentIds;
|
|
31321
|
+
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;
|
|
31322
|
+
if (nextIds.length === 0) {
|
|
31323
|
+
this._groupInvitePending.delete(itemKey);
|
|
31324
|
+
} else {
|
|
31325
|
+
item.invite_ids = nextIds;
|
|
31326
|
+
item.inviter_aids = nextInviters;
|
|
31327
|
+
}
|
|
31328
|
+
changed = true;
|
|
31329
|
+
}
|
|
31330
|
+
if (changed) await this.persistGroupInviteState();
|
|
31331
|
+
}
|
|
31332
|
+
async _onGroupInviteActionResult(method, params2, result, error) {
|
|
31333
|
+
if (method === "group.list_my_invites" && !error && (isJsonObject(result) || Array.isArray(result))) {
|
|
31334
|
+
await this.restoreGroupInvitesFromResult(result, params2);
|
|
31335
|
+
return;
|
|
31336
|
+
}
|
|
31337
|
+
if (!["group.accept_invite", "group.reject_invite", "group.revoke_invite"].includes(method)) return;
|
|
31338
|
+
const text3 = String(error instanceof Error ? error.message : error ?? "").toLowerCase();
|
|
31339
|
+
const resultStatus = isJsonObject(result) ? String(result.status ?? "").toLowerCase() : "";
|
|
31340
|
+
const aggregateResultStatus = isJsonObject(result) ? String(result.aggregate_status ?? result.aggregateStatus ?? "").toLowerCase() : "";
|
|
31341
|
+
const terminalStatus = resultStatus || aggregateResultStatus;
|
|
31342
|
+
const pendingResult = resultStatus === "pending" || aggregateResultStatus === "pending" || isJsonObject(result) && (this.inviteBool(result.remaining_pending) || this.inviteBool(result.pending));
|
|
31343
|
+
if (pendingResult) {
|
|
31344
|
+
if (isJsonObject(result) && (this.inviteBool(result.remaining_pending) || this.inviteArray(result.pending_invite_ids ?? result.pendingInviteIds).length > 0)) {
|
|
31345
|
+
await this._onRawGroupInviteFinalized({ ...params2, ...result });
|
|
31346
|
+
}
|
|
31347
|
+
return;
|
|
31348
|
+
}
|
|
31349
|
+
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));
|
|
31350
|
+
if (!terminal) return;
|
|
31351
|
+
await this._onRawGroupInviteFinalized({
|
|
31352
|
+
...params2,
|
|
31353
|
+
...isJsonObject(result) ? result : {},
|
|
31354
|
+
status: terminalStatus || "ended"
|
|
31355
|
+
});
|
|
31356
|
+
}
|
|
31357
|
+
async restoreGroupInvitesFromResult(result, requestParams = {}) {
|
|
31358
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31359
|
+
const visitedPages = /* @__PURE__ */ new Set();
|
|
31360
|
+
let current = result;
|
|
31361
|
+
let currentParams = { ...requestParams };
|
|
31362
|
+
let finalPage = false;
|
|
31363
|
+
while (!finalPage) {
|
|
31364
|
+
const root = Array.isArray(current) ? null : isJsonObject(current) ? current : null;
|
|
31365
|
+
const nestedValue = root && isJsonObject(root.data) ? root.data : root;
|
|
31366
|
+
const nested = nestedValue ?? {};
|
|
31367
|
+
const rawItems = Array.isArray(nested.items) ? nested.items : Array.isArray(nested.invites) ? nested.invites : Array.isArray(current) ? current : [];
|
|
31368
|
+
for (const item of rawItems) {
|
|
31369
|
+
if (!isJsonObject(item)) continue;
|
|
31370
|
+
const status = String(item.status ?? "pending").toLowerCase();
|
|
31371
|
+
const gid = normalizeGroupId(item.group_id ?? item.group_aid ?? item.groupId ?? item.groupAid);
|
|
31372
|
+
const aid = String(item.invitee_aid ?? item.inviteeAid ?? this._aid ?? "").trim();
|
|
31373
|
+
if (this._aid && aid.toLowerCase() !== this._aid.toLowerCase()) continue;
|
|
31374
|
+
const key = this.groupInviteKey(gid, aid);
|
|
31375
|
+
if (status === "pending" && key) {
|
|
31376
|
+
seen.add(key);
|
|
31377
|
+
await this._onRawGroupInviteReceived(item, "pull");
|
|
31378
|
+
} else if (key) {
|
|
31379
|
+
seen.add(key);
|
|
31380
|
+
await this._onRawGroupInviteFinalized(item);
|
|
31381
|
+
}
|
|
31382
|
+
}
|
|
31383
|
+
const hasMore = this.inviteBool(nested.has_more ?? nested.hasMore ?? (root ? root.has_more ?? root.hasMore : void 0));
|
|
31384
|
+
if (!hasMore) {
|
|
31385
|
+
finalPage = true;
|
|
31386
|
+
break;
|
|
31387
|
+
}
|
|
31388
|
+
const page = Number(nested.page ?? root?.page ?? currentParams.page ?? 1);
|
|
31389
|
+
const nextPageValue = nested.next_page ?? nested.nextPage ?? root?.next_page ?? root?.nextPage;
|
|
31390
|
+
const nextPage = Number(nextPageValue ?? page + 1);
|
|
31391
|
+
if (!Number.isFinite(nextPage) || nextPage <= 0 || visitedPages.has(nextPage) || nextPage === page) break;
|
|
31392
|
+
visitedPages.add(page);
|
|
31393
|
+
currentParams = { ...currentParams, page: nextPage };
|
|
31394
|
+
if (currentParams.size === void 0) {
|
|
31395
|
+
const size = nested.size ?? root?.size;
|
|
31396
|
+
if (size !== void 0) currentParams.size = size;
|
|
31397
|
+
}
|
|
31398
|
+
current = await this.call("group.list_my_invites", currentParams);
|
|
31399
|
+
}
|
|
31400
|
+
await this.ensureGroupInviteStateLoaded();
|
|
31401
|
+
let changed = false;
|
|
31402
|
+
for (const key of this._groupInvitePending.keys()) {
|
|
31403
|
+
if (!seen.has(key)) {
|
|
31404
|
+
this._groupInvitePending.delete(key);
|
|
31405
|
+
changed = true;
|
|
31406
|
+
}
|
|
31407
|
+
}
|
|
31408
|
+
if (changed) await this.persistGroupInviteState();
|
|
31409
|
+
}
|
|
31410
|
+
async restoreGroupInvitesAfterConnect() {
|
|
31411
|
+
if (!this._aid || this._state !== "connected") return;
|
|
31412
|
+
const result = await this.call("group.list_my_invites", { page: 1, size: 200, _rpc_background: true });
|
|
31413
|
+
if (isJsonObject(result) || Array.isArray(result)) {
|
|
31414
|
+
await this.restoreGroupInvitesFromResult(result, { page: 1, size: 200, _rpc_background: true });
|
|
31415
|
+
}
|
|
31416
|
+
}
|
|
31138
31417
|
async _onRawGroupChanged(data) {
|
|
31139
31418
|
const tStart = Date.now();
|
|
31140
31419
|
const action = String(data?.action ?? "");
|
|
@@ -31465,6 +31744,7 @@ var _AUNClient = class _AUNClient {
|
|
|
31465
31744
|
}
|
|
31466
31745
|
this._lifecycle.assertConnectionAttemptOwner(connectionOwner);
|
|
31467
31746
|
this._startBackgroundTasks();
|
|
31747
|
+
this._safeAsync(this.restoreGroupInvitesAfterConnect());
|
|
31468
31748
|
const connectionKind = String(params2.connection_kind ?? "long");
|
|
31469
31749
|
const isShortConnection = connectionKind === "short";
|
|
31470
31750
|
const hasExplicitBackgroundSync = Object.prototype.hasOwnProperty.call(params2, "background_sync");
|
|
@@ -32175,20 +32455,7 @@ var _AUNClient = class _AUNClient {
|
|
|
32175
32455
|
return this._delivery.clampAckParams(method, params2);
|
|
32176
32456
|
}
|
|
32177
32457
|
_repairPushContiguousBound(ns, pushSeq, hasPayload, label) {
|
|
32178
|
-
|
|
32179
|
-
return ns ? this._seqTracker.getContiguousSeq(ns) : 0;
|
|
32180
|
-
}
|
|
32181
|
-
const contig = this._seqTracker.getContiguousSeq(ns);
|
|
32182
|
-
const shouldRepair = contig > pushSeq;
|
|
32183
|
-
if (!shouldRepair) return contig;
|
|
32184
|
-
const repairedTo = Math.max(0, pushSeq - 1);
|
|
32185
|
-
this._seqTracker.repairContiguousSeq(ns, repairedTo);
|
|
32186
|
-
const repaired = this._seqTracker.getContiguousSeq(ns);
|
|
32187
|
-
this._persistRepairedSeq(ns);
|
|
32188
|
-
this._clientLog.warn(
|
|
32189
|
-
`${label} push repaired contiguous_seq: ns=${ns} payload=${hasPayload} push_seq=${pushSeq} contiguous=${contig}->${repaired}`
|
|
32190
|
-
);
|
|
32191
|
-
return repaired;
|
|
32458
|
+
return ns ? this._seqTracker.getContiguousSeq(ns) : 0;
|
|
32192
32459
|
}
|
|
32193
32460
|
async _ensureV2SessionReady(method, errorMessage3) {
|
|
32194
32461
|
if (!this._v2SessionMatchesIdentity()) {
|