@agentunion/fastaun 0.5.15 → 0.5.17
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 +311 -271
- package/_packed_docs/CHANGELOG.md +311 -271
- package/_packed_docs/INDEX.md +8 -2
- package/_packed_docs/KITE_DOCS_GUIDE.md +2 -0
- package/_packed_docs/agent.md/SCHEMA.md +7 -0
- 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 +1178 -1178
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +1213 -1213
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +58 -43
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +80 -17
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +27 -6
- package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +7 -4
- package/_packed_docs/sdk/09-group-rpc-manual.md +167 -35
- package/_packed_docs/sdk/09-message-rpc-manual.md +72 -42
- package/_packed_docs/sdk/09-storage-rpc-manual.md +23 -14
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +16 -12
- package/_packed_docs/sdk/INDEX.md +12 -12
- package/dist/agent-md-schema.js +6 -0
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +3 -0
- package/dist/agent-md.js +9 -1
- package/dist/agent-md.js.map +1 -1
- package/dist/client/delivery.d.ts +17 -0
- package/dist/client/delivery.js +140 -12
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.d.ts +4 -0
- package/dist/client/group-state.js +63 -0
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/rpc-pipeline.js +22 -5
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +10 -1
- package/dist/client/v2-e2ee.js +187 -36
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.js +56 -13
- package/dist/client.js.map +1 -1
- package/dist/facades.d.ts +5 -0
- package/dist/facades.js +5 -0
- package/dist/facades.js.map +1 -1
- package/dist/group-fs.js +7 -5
- package/dist/group-fs.js.map +1 -1
- package/dist/storage/vfs.d.ts +1 -0
- package/dist/storage/vfs.js +61 -6
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.js +31 -1
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/types.d.ts +16 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -8
package/dist/client/v2-e2ee.js
CHANGED
|
@@ -773,6 +773,12 @@ export class V2E2EECoordinator {
|
|
|
773
773
|
}
|
|
774
774
|
continue;
|
|
775
775
|
}
|
|
776
|
+
if (!entry.groupId && String(entry.msg.storage ?? '') === 'volatile') {
|
|
777
|
+
await this.publishPendingV2VolatileMessage(entry.msg, plaintext, 'pending_retry');
|
|
778
|
+
pending.delete(key);
|
|
779
|
+
client._clientLog.debug(`V2 sender IK pending retry delivered: key=${key}`);
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
776
782
|
pending.delete(key);
|
|
777
783
|
const seq = Number(entry.msg.seq ?? 0);
|
|
778
784
|
if (entry.groupId) {
|
|
@@ -795,6 +801,30 @@ export class V2E2EECoordinator {
|
|
|
795
801
|
}
|
|
796
802
|
}
|
|
797
803
|
}
|
|
804
|
+
async publishPendingV2VolatileMessage(rawMessage, plaintext, source) {
|
|
805
|
+
const delivery = this.client._delivery;
|
|
806
|
+
const claim = delivery.beginVolatileDelivery(rawMessage);
|
|
807
|
+
if (claim === 'inflight')
|
|
808
|
+
return;
|
|
809
|
+
if (claim === 'seen') {
|
|
810
|
+
await delivery.ackVolatileMessages([rawMessage], true, false);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
try {
|
|
814
|
+
const publicMessage = delivery.publicVolatileMessage(plaintext);
|
|
815
|
+
for (const key of ['storage', 'volatile_cursor', 'created_at', 'expires_at', 'persist']) {
|
|
816
|
+
if (Object.prototype.hasOwnProperty.call(rawMessage, key))
|
|
817
|
+
publicMessage[key] = rawMessage[key];
|
|
818
|
+
}
|
|
819
|
+
const appEvent = delivery.p2pAppEventForMessage(publicMessage);
|
|
820
|
+
await this.client._publishAppEvent(appEvent.event, appEvent.payload, source);
|
|
821
|
+
delivery.markVolatileSeen(rawMessage);
|
|
822
|
+
}
|
|
823
|
+
finally {
|
|
824
|
+
delivery.finishVolatileDelivery(rawMessage);
|
|
825
|
+
}
|
|
826
|
+
await delivery.ackVolatileMessages([rawMessage], true, false);
|
|
827
|
+
}
|
|
798
828
|
async buildV2P2PEnvelope(opts) {
|
|
799
829
|
const client = this.client;
|
|
800
830
|
if (!client._v2Session) {
|
|
@@ -841,6 +871,10 @@ export class V2E2EECoordinator {
|
|
|
841
871
|
if (peerDevices.length === 0) {
|
|
842
872
|
throw new E2EEError(`V2 bootstrap: no devices found for ${to}`);
|
|
843
873
|
}
|
|
874
|
+
const targetDeviceId = String(opts.deviceId ?? '').trim();
|
|
875
|
+
if (targetDeviceId && !peerDevices.some((dev) => String(dev.device_id ?? '').trim() === targetDeviceId)) {
|
|
876
|
+
throw new E2EEError(`V2 bootstrap: target device ${targetDeviceId} not found for ${to}`);
|
|
877
|
+
}
|
|
844
878
|
let targetSet = useCache ? this.getTargetSetCache(to) : undefined;
|
|
845
879
|
if (targetSet) {
|
|
846
880
|
targetSet = this.cloneP2PTargetSet(targetSet);
|
|
@@ -926,6 +960,20 @@ export class V2E2EECoordinator {
|
|
|
926
960
|
if (targetSet.targets.length === 0) {
|
|
927
961
|
throw new E2EEError(`V2 bootstrap: no usable devices found for ${to}`);
|
|
928
962
|
}
|
|
963
|
+
if (targetDeviceId) {
|
|
964
|
+
let peerTargetFound = false;
|
|
965
|
+
targetSet.targets = targetSet.targets.filter((target) => {
|
|
966
|
+
const isPeerTarget = target.aid === to
|
|
967
|
+
&& (target.deviceId === targetDeviceId || (wrapPolicy.scope === 'aid' && !target.deviceId))
|
|
968
|
+
&& target.role !== 'self_sync';
|
|
969
|
+
if (isPeerTarget)
|
|
970
|
+
peerTargetFound = true;
|
|
971
|
+
return isPeerTarget || target.role === 'self_sync';
|
|
972
|
+
});
|
|
973
|
+
if (!peerTargetFound) {
|
|
974
|
+
throw new E2EEError(`V2 bootstrap: target device ${targetDeviceId} not found for ${to}`);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
929
977
|
const envelope = encryptP2PMessage(session.getSenderIdentity(), targetSet, opts.payload, {
|
|
930
978
|
messageId: opts.messageId,
|
|
931
979
|
timestamp: opts.timestamp,
|
|
@@ -954,6 +1002,7 @@ export class V2E2EECoordinator {
|
|
|
954
1002
|
const client = this.client;
|
|
955
1003
|
await client._ensureV2SessionReady('message.send', 'V2 session not initialized; encrypted message.send requires V2 (V1 E2EE removed)');
|
|
956
1004
|
const toAid = String(to ?? '').trim();
|
|
1005
|
+
const targetDeviceId = String(opts?.deviceId ?? '').trim();
|
|
957
1006
|
if (!toAid)
|
|
958
1007
|
throw new ValidationError("message.send requires 'to'");
|
|
959
1008
|
if (!isJsonObject(payload))
|
|
@@ -971,6 +1020,7 @@ export class V2E2EECoordinator {
|
|
|
971
1020
|
payload,
|
|
972
1021
|
messageId,
|
|
973
1022
|
timestamp: opts?.timestamp,
|
|
1023
|
+
deviceId: targetDeviceId || undefined,
|
|
974
1024
|
protectedHeaders: opts?.protectedHeaders,
|
|
975
1025
|
context: opts?.context,
|
|
976
1026
|
useCache,
|
|
@@ -979,6 +1029,8 @@ export class V2E2EECoordinator {
|
|
|
979
1029
|
to: toAid,
|
|
980
1030
|
payload: envelope,
|
|
981
1031
|
message_id: messageId,
|
|
1032
|
+
...(targetDeviceId ? { device_id: targetDeviceId } : {}),
|
|
1033
|
+
...(opts?.ttl !== undefined ? { ttl: opts.ttl } : {}),
|
|
982
1034
|
encrypt: false,
|
|
983
1035
|
_skip_send_result_envelope: true,
|
|
984
1036
|
});
|
|
@@ -992,6 +1044,7 @@ export class V2E2EECoordinator {
|
|
|
992
1044
|
payload,
|
|
993
1045
|
message_id: messageId,
|
|
994
1046
|
timestamp: opts?.timestamp,
|
|
1047
|
+
ttl: opts?.ttl,
|
|
995
1048
|
protected_headers: opts?.protectedHeaders,
|
|
996
1049
|
context: opts?.context,
|
|
997
1050
|
}, result, true);
|
|
@@ -1007,6 +1060,7 @@ export class V2E2EECoordinator {
|
|
|
1007
1060
|
payload,
|
|
1008
1061
|
message_id: messageId,
|
|
1009
1062
|
timestamp: opts?.timestamp,
|
|
1063
|
+
ttl: opts?.ttl,
|
|
1010
1064
|
protected_headers: opts?.protectedHeaders,
|
|
1011
1065
|
context: opts?.context,
|
|
1012
1066
|
}, result, true);
|
|
@@ -1223,6 +1277,7 @@ export class V2E2EECoordinator {
|
|
|
1223
1277
|
}), true);
|
|
1224
1278
|
}
|
|
1225
1279
|
const decrypted = [];
|
|
1280
|
+
let volatileCursor = String(opts?.afterVolatileCursor ?? client._delivery.volatilePullCursor?.() ?? '').trim();
|
|
1226
1281
|
let nextAfterSeq = opts?.force ? afterSeq : (afterSeq || (ns ? client._seqTracker.getContiguousSeq(ns) : 0));
|
|
1227
1282
|
let pullGateKey = ns
|
|
1228
1283
|
? pullGateKeyForClient(client, 'message.v2.pull', {
|
|
@@ -1237,17 +1292,31 @@ export class V2E2EECoordinator {
|
|
|
1237
1292
|
const maxPages = Math.max(1, Math.min(100, Math.trunc(Number(opts?.maxPages ?? 100) || 100)));
|
|
1238
1293
|
while (pageCount < maxPages) {
|
|
1239
1294
|
pageCount += 1;
|
|
1295
|
+
const requestedVolatileCursor = volatileCursor;
|
|
1240
1296
|
const ackUpToSeq = pendingAckSeq;
|
|
1241
1297
|
const inlineAckGeneration = ackUpToSeq > 0
|
|
1242
1298
|
? client._delivery.captureP2PInlineAckGeneration()
|
|
1243
1299
|
: null;
|
|
1244
1300
|
client._clientLog.debug(`message.v2.pull page request: page=${pageCount}, after_seq=${nextAfterSeq}, limit=${limit}, ack_up_to_seq=${ackUpToSeq}, ns=${ns || '<none>'}`);
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1301
|
+
let result;
|
|
1302
|
+
try {
|
|
1303
|
+
result = await client._callRawV2Rpc('message.v2.pull', {
|
|
1304
|
+
after_seq: nextAfterSeq,
|
|
1305
|
+
limit,
|
|
1306
|
+
...(volatileCursor ? { after_volatile_cursor: volatileCursor } : {}),
|
|
1307
|
+
...(opts?.force ? { force: true } : {}),
|
|
1308
|
+
...(ackUpToSeq > 0 ? { ack_up_to_seq: ackUpToSeq } : {}),
|
|
1309
|
+
}, pullGateKey);
|
|
1310
|
+
}
|
|
1311
|
+
catch (exc) {
|
|
1312
|
+
if (!volatileCursor || !String(exc instanceof Error ? exc.message : exc).toLowerCase().includes('volatile cursor epoch mismatch')) {
|
|
1313
|
+
throw exc;
|
|
1314
|
+
}
|
|
1315
|
+
client._delivery.resetVolatilePullCursor?.();
|
|
1316
|
+
volatileCursor = '';
|
|
1317
|
+
pageCount -= 1;
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1251
1320
|
if (ackUpToSeq > 0) {
|
|
1252
1321
|
const actualAckSeq = client._delivery.resolveP2PPullAckSeq(result, ackUpToSeq);
|
|
1253
1322
|
if (actualAckSeq >= ackUpToSeq) {
|
|
@@ -1266,10 +1335,16 @@ export class V2E2EECoordinator {
|
|
|
1266
1335
|
}
|
|
1267
1336
|
}
|
|
1268
1337
|
const pageMessages = (Array.isArray(result?.messages) ? result.messages : []);
|
|
1338
|
+
const volatileMessages = client._delivery.volatileMessages?.(pageMessages) ?? [];
|
|
1339
|
+
if (volatileMessages.length > 0) {
|
|
1340
|
+
decrypted.push(...await this.publishV2VolatileMessages(volatileMessages, 'pull', true));
|
|
1341
|
+
volatileCursor = String(client._delivery.volatilePullCursor?.() ?? '').trim();
|
|
1342
|
+
}
|
|
1269
1343
|
const messages = deduplicateForwardPageMessages(pageMessages, nextAfterSeq);
|
|
1270
1344
|
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
1271
1345
|
const hasMoreField = Object.prototype.hasOwnProperty.call(result, 'has_more');
|
|
1272
1346
|
const hasMore = result.has_more === true;
|
|
1347
|
+
const volatileHasMore = result.volatile_has_more === true;
|
|
1273
1348
|
const serverHead = safeNonNegativeSeq(cursor?.latest_seq) ?? 0;
|
|
1274
1349
|
client._clientLog.debug(`message.v2.pull page response: page=${pageCount}, raw_count=${messages.length}, stale_count=${Math.max(0, pageMessages.length - messages.length)}, has_more=${String(result.has_more ?? '')}, server_head=${serverHead}, server_ack_seq=${String(result.server_ack_seq ?? '')}`);
|
|
1275
1350
|
for (const msg of messages) {
|
|
@@ -1469,7 +1544,7 @@ export class V2E2EECoordinator {
|
|
|
1469
1544
|
const rawCount = messages.length;
|
|
1470
1545
|
if (blockedSeq > 0)
|
|
1471
1546
|
break;
|
|
1472
|
-
const
|
|
1547
|
+
const shouldContinuePersistent = shouldContinueForwardPage({
|
|
1473
1548
|
rawCount,
|
|
1474
1549
|
nextAfterSeq,
|
|
1475
1550
|
nextAfter,
|
|
@@ -1480,7 +1555,11 @@ export class V2E2EECoordinator {
|
|
|
1480
1555
|
observedUpper: Math.max(client._seqTracker.getMaxSeenSeq(ns), Number(client._pendingP2pPullUpper?.get?.(ns) ?? 0)),
|
|
1481
1556
|
pendingAckSeq,
|
|
1482
1557
|
});
|
|
1483
|
-
|
|
1558
|
+
const shouldContinueVolatile = (hasMore || volatileHasMore)
|
|
1559
|
+
&& volatileMessages.length > 0
|
|
1560
|
+
&& Boolean(volatileCursor)
|
|
1561
|
+
&& volatileCursor !== requestedVolatileCursor;
|
|
1562
|
+
if (!shouldContinuePersistent && !shouldContinueVolatile)
|
|
1484
1563
|
break;
|
|
1485
1564
|
if (pullGateKey && opts?.gateLocked && client._rpcPipeline?.yieldPullGate) {
|
|
1486
1565
|
const nextKey = pullGateKeyForClient(client, 'message.v2.pull', {
|
|
@@ -1518,6 +1597,73 @@ export class V2E2EECoordinator {
|
|
|
1518
1597
|
throw error;
|
|
1519
1598
|
}
|
|
1520
1599
|
}
|
|
1600
|
+
async publishV2VolatileMessages(messages, source, advanceCursor) {
|
|
1601
|
+
const client = this.client;
|
|
1602
|
+
if (!client._v2Session)
|
|
1603
|
+
return [];
|
|
1604
|
+
const processed = [];
|
|
1605
|
+
const plaintextMessages = [];
|
|
1606
|
+
let complete = true;
|
|
1607
|
+
for (const rawMessage of messages) {
|
|
1608
|
+
const claim = client._delivery.beginVolatileDelivery(rawMessage);
|
|
1609
|
+
if (claim === 'seen') {
|
|
1610
|
+
processed.push(rawMessage);
|
|
1611
|
+
continue;
|
|
1612
|
+
}
|
|
1613
|
+
if (claim === 'inflight') {
|
|
1614
|
+
complete = false;
|
|
1615
|
+
continue;
|
|
1616
|
+
}
|
|
1617
|
+
let plaintext;
|
|
1618
|
+
try {
|
|
1619
|
+
if (this.isEncryptedPushMessage(rawMessage)) {
|
|
1620
|
+
plaintext = await client._decryptV2Message(rawMessage, true, true, true, true, undefined, false, source);
|
|
1621
|
+
}
|
|
1622
|
+
else {
|
|
1623
|
+
const legacy = isJsonObject(rawMessage.legacy_v1)
|
|
1624
|
+
? rawMessage.legacy_v1
|
|
1625
|
+
: {};
|
|
1626
|
+
plaintext = {
|
|
1627
|
+
message_id: String(rawMessage.message_id ?? ''),
|
|
1628
|
+
from: String(rawMessage.from_aid ?? rawMessage.from ?? ''),
|
|
1629
|
+
to: String(legacy.to ?? rawMessage.to ?? client._aid ?? ''),
|
|
1630
|
+
type: String(rawMessage.type ?? ''),
|
|
1631
|
+
timestamp: rawMessage.t_server ?? rawMessage.timestamp,
|
|
1632
|
+
payload: legacy.payload !== undefined ? legacy.payload : rawMessage.payload,
|
|
1633
|
+
encrypted: false,
|
|
1634
|
+
};
|
|
1635
|
+
for (const key of ['context', 'protected_headers', 'headers', 'client_signature']) {
|
|
1636
|
+
if (Object.prototype.hasOwnProperty.call(rawMessage, key))
|
|
1637
|
+
plaintext[key] = rawMessage[key];
|
|
1638
|
+
}
|
|
1639
|
+
if (rawMessage.sender_device_id !== undefined)
|
|
1640
|
+
plaintext.sender_device_id = rawMessage.sender_device_id;
|
|
1641
|
+
attachGatewayProximity(plaintext, rawMessage);
|
|
1642
|
+
}
|
|
1643
|
+
if (!plaintext) {
|
|
1644
|
+
complete = false;
|
|
1645
|
+
continue;
|
|
1646
|
+
}
|
|
1647
|
+
const publicMessage = client._delivery.publicVolatileMessage(plaintext);
|
|
1648
|
+
for (const key of ['storage', 'volatile_cursor', 'created_at', 'expires_at', 'persist']) {
|
|
1649
|
+
if (Object.prototype.hasOwnProperty.call(rawMessage, key))
|
|
1650
|
+
publicMessage[key] = rawMessage[key];
|
|
1651
|
+
}
|
|
1652
|
+
const appEvent = client._delivery.p2pAppEventForMessage(publicMessage);
|
|
1653
|
+
await client._publishAppEvent(appEvent.event, appEvent.payload, source);
|
|
1654
|
+
client._delivery.markVolatileSeen(rawMessage);
|
|
1655
|
+
processed.push(rawMessage);
|
|
1656
|
+
plaintextMessages.push(publicMessage);
|
|
1657
|
+
}
|
|
1658
|
+
finally {
|
|
1659
|
+
client._delivery.finishVolatileDelivery(rawMessage);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
if (processed.length > 0) {
|
|
1663
|
+
await client._delivery.ackVolatileMessages(processed, true, advanceCursor && complete && processed.length === messages.length);
|
|
1664
|
+
}
|
|
1665
|
+
return plaintextMessages;
|
|
1666
|
+
}
|
|
1521
1667
|
async confirmForwardP2PAck(upToSeq) {
|
|
1522
1668
|
const ns = this.client._aid ? `p2p:${this.client._aid}` : '';
|
|
1523
1669
|
try {
|
|
@@ -1533,28 +1679,41 @@ export class V2E2EECoordinator {
|
|
|
1533
1679
|
throw exc;
|
|
1534
1680
|
}
|
|
1535
1681
|
}
|
|
1536
|
-
async ackV2(upToSeq) {
|
|
1537
|
-
return this.ackV2WithConfirmation(upToSeq, false);
|
|
1682
|
+
async ackV2(upToSeq, opts) {
|
|
1683
|
+
return this.ackV2WithConfirmation(upToSeq, false, opts);
|
|
1538
1684
|
}
|
|
1539
1685
|
async ackV2ForForward(upToSeq) {
|
|
1540
1686
|
return this.ackV2WithConfirmation(upToSeq, true);
|
|
1541
1687
|
}
|
|
1542
|
-
async ackV2WithConfirmation(upToSeq, requireServerWatermark) {
|
|
1688
|
+
async ackV2WithConfirmation(upToSeq, requireServerWatermark, opts) {
|
|
1543
1689
|
const client = this.client;
|
|
1544
1690
|
const ns = client._aid ? `p2p:${client._aid}` : '';
|
|
1545
|
-
|
|
1546
|
-
|
|
1691
|
+
const volatileCursors = Array.isArray(opts?.volatileCursors) ? opts?.volatileCursors : [];
|
|
1692
|
+
const volatileIds = Array.isArray(opts?.volatileIds) ? opts?.volatileIds : [];
|
|
1693
|
+
let seq = Number(upToSeq ?? ((volatileCursors.length > 0 || volatileIds.length > 0)
|
|
1694
|
+
? 0
|
|
1695
|
+
: (ns ? client._seqTracker.getContiguousSeq(ns) : 0)));
|
|
1696
|
+
if ((!Number.isFinite(seq) || seq <= 0) && volatileCursors.length === 0 && volatileIds.length === 0) {
|
|
1547
1697
|
client._clientLog.debug(`message.v2.ack skipped: ns=${ns || '<none>'}, up_to_seq=${String(upToSeq ?? '')}`);
|
|
1548
1698
|
return { acked: 0 };
|
|
1549
1699
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1700
|
+
if (Number.isFinite(seq) && seq > 0) {
|
|
1701
|
+
seq = client._clampAckSeq('message.v2.ack', 'up_to_seq', ns, seq);
|
|
1702
|
+
}
|
|
1703
|
+
else {
|
|
1704
|
+
seq = 0;
|
|
1705
|
+
}
|
|
1706
|
+
if (seq <= 0 && volatileCursors.length === 0 && volatileIds.length === 0)
|
|
1552
1707
|
return { acked: 0 };
|
|
1553
1708
|
const inlineAckGeneration = client._delivery.captureP2PInlineAckGeneration();
|
|
1554
1709
|
const v2SessionAtStart = client._v2Session;
|
|
1555
1710
|
const v2RuntimeGenerationAtStart = Number(client._v2RuntimeGeneration ?? 0);
|
|
1556
1711
|
client._clientLog.debug(`message.v2.ack send: ns=${ns || '<none>'}, up_to_seq=${seq}`);
|
|
1557
|
-
const raw = await client._callRawV2Rpc('message.v2.ack', {
|
|
1712
|
+
const raw = await client._callRawV2Rpc('message.v2.ack', {
|
|
1713
|
+
...(seq > 0 ? { up_to_seq: seq } : {}),
|
|
1714
|
+
...(volatileCursors.length > 0 ? { volatile_cursors: volatileCursors } : {}),
|
|
1715
|
+
...(volatileIds.length > 0 ? { volatile_ids: volatileIds } : {}),
|
|
1716
|
+
});
|
|
1558
1717
|
const result = isJsonObject(raw)
|
|
1559
1718
|
? { ...raw }
|
|
1560
1719
|
: { result: raw };
|
|
@@ -1566,7 +1725,7 @@ export class V2E2EECoordinator {
|
|
|
1566
1725
|
}
|
|
1567
1726
|
result.ack_seq = actualAckSeq;
|
|
1568
1727
|
result.success = true;
|
|
1569
|
-
if (inlineAckGeneration !== null) {
|
|
1728
|
+
if (seq > 0 && inlineAckGeneration !== null) {
|
|
1570
1729
|
client._delivery.onP2PV2AckSucceeded(actualAckSeq, inlineAckGeneration);
|
|
1571
1730
|
}
|
|
1572
1731
|
if (v2SessionAtStart
|
|
@@ -1664,7 +1823,6 @@ export class V2E2EECoordinator {
|
|
|
1664
1823
|
let epoch = 0;
|
|
1665
1824
|
let stateCommitment = { state_version: 0, state_hash: '', state_chain: '' };
|
|
1666
1825
|
let wrapPolicy = normalizeV2WrapPolicy(undefined);
|
|
1667
|
-
let usedCachedBootstrap = false;
|
|
1668
1826
|
const cached = useCache ? this.getBootstrapCacheEntry(cacheKey) : undefined;
|
|
1669
1827
|
if (cached && Date.now() - Number(cached.cachedAt ?? 0) < V2_BOOTSTRAP_TTL_MS) {
|
|
1670
1828
|
allDevices = (cached.devices ?? []);
|
|
@@ -1672,7 +1830,6 @@ export class V2E2EECoordinator {
|
|
|
1672
1830
|
epoch = Number(cached.epoch ?? 0) || 0;
|
|
1673
1831
|
stateCommitment = cached.stateCommitment ?? stateCommitment;
|
|
1674
1832
|
wrapPolicy = cached.wrapPolicy ?? wrapPolicy;
|
|
1675
|
-
usedCachedBootstrap = true;
|
|
1676
1833
|
client._clientLog.debug(`group.v2.bootstrap cache hit: group=${groupId}, devices=${allDevices.length}, audit=${auditRecipientsRaw.length}, epoch=${epoch}, state_version=${stateCommitment.state_version}`);
|
|
1677
1834
|
}
|
|
1678
1835
|
else {
|
|
@@ -1736,13 +1893,10 @@ export class V2E2EECoordinator {
|
|
|
1736
1893
|
targets.push(target);
|
|
1737
1894
|
}
|
|
1738
1895
|
if (targets.length === 0) {
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
});
|
|
1744
|
-
}
|
|
1745
|
-
throw new E2EEError(`V2 group: no target devices for group ${groupId}`);
|
|
1896
|
+
throw new E2EEError(`V2 group: no target devices for group ${groupId}; bootstrap may be stale`, {
|
|
1897
|
+
code: V2_GROUP_STALE_BOOTSTRAP_CODE,
|
|
1898
|
+
data: { expected_peer_aids: [] },
|
|
1899
|
+
});
|
|
1746
1900
|
}
|
|
1747
1901
|
for (const dev of auditRecipientsRaw) {
|
|
1748
1902
|
const target = await client._v2BuildTargetFromDevice({
|
|
@@ -1761,13 +1915,10 @@ export class V2E2EECoordinator {
|
|
|
1761
1915
|
targetSet = this.cloneGroupTargetSet(targetSet);
|
|
1762
1916
|
}
|
|
1763
1917
|
if (targetSet.targets.length === 0) {
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
});
|
|
1769
|
-
}
|
|
1770
|
-
throw new E2EEError(`V2 group: no target devices for group ${groupId}`);
|
|
1918
|
+
throw new E2EEError(`V2 group: no target devices for group ${groupId}; bootstrap may be stale`, {
|
|
1919
|
+
code: V2_GROUP_STALE_BOOTSTRAP_CODE,
|
|
1920
|
+
data: { expected_peer_aids: [] },
|
|
1921
|
+
});
|
|
1771
1922
|
}
|
|
1772
1923
|
const envelope = encryptGroupMessage(session.getSenderIdentity(), groupId, epoch, targetSet.targets, opts.payload, {
|
|
1773
1924
|
messageId: opts.messageId,
|
|
@@ -2751,7 +2902,6 @@ export class V2E2EECoordinator {
|
|
|
2751
2902
|
seq: msg.seq,
|
|
2752
2903
|
timestamp: (msg.timestamp ?? msg.t_server),
|
|
2753
2904
|
device_id: msg.device_id,
|
|
2754
|
-
slot_id: msg.slot_id,
|
|
2755
2905
|
_decrypt_error: 'encrypted push payload is not decryptable on raw push path',
|
|
2756
2906
|
_decrypt_stage: 'push_envelope',
|
|
2757
2907
|
};
|
|
@@ -2795,13 +2945,14 @@ export class V2E2EECoordinator {
|
|
|
2795
2945
|
encrypted: true,
|
|
2796
2946
|
e2ee,
|
|
2797
2947
|
};
|
|
2948
|
+
const senderDeviceId = String(aad.from_device ?? '').trim();
|
|
2949
|
+
if (senderDeviceId)
|
|
2950
|
+
result.sender_device_id = senderDeviceId;
|
|
2798
2951
|
result.direction = fromAid && fromAid === client._aid ? 'outbound_sync' : 'inbound';
|
|
2799
2952
|
if (msg.t_server !== undefined)
|
|
2800
2953
|
result.t_server = msg.t_server;
|
|
2801
2954
|
if (msg.device_id !== undefined)
|
|
2802
2955
|
result.device_id = msg.device_id;
|
|
2803
|
-
if (msg.slot_id !== undefined)
|
|
2804
|
-
result.slot_id = msg.slot_id;
|
|
2805
2956
|
attachGatewayProximity(result, msg);
|
|
2806
2957
|
if (group) {
|
|
2807
2958
|
result.group_id = (msg.group_id ?? aad.group_id ?? envelope.group_id);
|