@agentunion/fastaun 0.5.17 → 0.5.18

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/_packed_docs/CHANGELOG.md +41 -0
  3. package/_packed_docs/INDEX.md +28 -3
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +11 -5
  5. package/_packed_docs/agent.md/SCHEMA.md +37 -18
  6. 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 +23 -17
  7. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +4 -2
  8. package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +95 -6
  9. package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +19 -4
  10. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +25 -2
  11. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +42 -4
  12. package/_packed_docs/sdk/09-storage-rpc-manual.md +25 -4
  13. package/_packed_docs/sdk/INDEX.md +3 -2
  14. package/dist/agent-md-schema.js +2 -0
  15. package/dist/agent-md-schema.js.map +1 -1
  16. package/dist/agent-md.d.ts +1 -1
  17. package/dist/agent-md.js +3 -1
  18. package/dist/agent-md.js.map +1 -1
  19. package/dist/aid-store.d.ts +58 -0
  20. package/dist/aid-store.js +234 -3
  21. package/dist/aid-store.js.map +1 -1
  22. package/dist/aid.d.ts +17 -1
  23. package/dist/aid.js +48 -2
  24. package/dist/aid.js.map +1 -1
  25. package/dist/client/delivery.d.ts +2 -0
  26. package/dist/client/delivery.js +124 -19
  27. package/dist/client/delivery.js.map +1 -1
  28. package/dist/client/rpc-pipeline.js +7 -9
  29. package/dist/client/rpc-pipeline.js.map +1 -1
  30. package/dist/client/v2-e2ee.d.ts +7 -1
  31. package/dist/client/v2-e2ee.js +815 -515
  32. package/dist/client/v2-e2ee.js.map +1 -1
  33. package/dist/client.d.ts +3 -0
  34. package/dist/client.js +67 -7
  35. package/dist/client.js.map +1 -1
  36. package/dist/facades.d.ts +2 -0
  37. package/dist/facades.js +6 -0
  38. package/dist/facades.js.map +1 -1
  39. package/dist/index.d.ts +3 -2
  40. package/dist/index.js +1 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/ownership-proof.d.ts +40 -0
  43. package/dist/ownership-proof.js +140 -0
  44. package/dist/ownership-proof.js.map +1 -0
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +8 -8
@@ -1460,6 +1460,24 @@ export class MessageDeliveryEngine {
1460
1460
  return false;
1461
1461
  return senderDevice.trim() === String(client._deviceId).trim();
1462
1462
  }
1463
+ isSelfSentP2PMessage(message) {
1464
+ if (!isJsonObject(message))
1465
+ return false;
1466
+ const client = this.runtime.client;
1467
+ if (String(message.direction ?? '').trim() !== 'outbound_sync')
1468
+ return false;
1469
+ const selfAid = String(client._aid ?? '').trim().toLowerCase();
1470
+ const senderAid = String(message.sender_aid ?? message.from_aid ?? message.from ?? '').trim().toLowerCase();
1471
+ if (!selfAid || senderAid !== selfAid)
1472
+ return false;
1473
+ const senderDevice = Object.prototype.hasOwnProperty.call(message, 'sender_device_id')
1474
+ ? message.sender_device_id
1475
+ : message.from_device_id;
1476
+ return typeof senderDevice === 'string'
1477
+ && Boolean(senderDevice.trim())
1478
+ && Boolean(String(client._deviceId ?? '').trim())
1479
+ && senderDevice.trim() === String(client._deviceId).trim();
1480
+ }
1463
1481
  async runPushProcessSerialized(ns, operation, inlineGeneration) {
1464
1482
  const client = this.runtime.client;
1465
1483
  if (inlineGeneration === undefined) {
@@ -1589,7 +1607,7 @@ export class MessageDeliveryEngine {
1589
1607
  // 在旧 seq tracking / ordered publish 之前转入前台 Tail 协调器。
1590
1608
  const inlinePresent = hasNonEmptyInlineMessage(msg.inline_message);
1591
1609
  const legacyPushSeq = this.realtimeHeadSeq(msg.seq, inlinePresent);
1592
- if (client._v2Session && client._aid && (msg.seq !== undefined && msg.seq !== null || inlinePresent)) {
1610
+ if ((client._v2Session || inlinePresent) && client._aid && (msg.seq !== undefined && msg.seq !== null || inlinePresent)) {
1593
1611
  if (legacyPushSeq === null) {
1594
1612
  if (inlinePresent)
1595
1613
  await this.recoverInvalidP2PRealtimeHead(`p2p:${client._aid}`, msg.seq);
@@ -1606,10 +1624,18 @@ export class MessageDeliveryEngine {
1606
1624
  const ns = `p2p:${client._aid}`;
1607
1625
  if (seq > 0)
1608
1626
  client._seqTracker.updateMaxSeen(ns, seq);
1627
+ if (encryptedPush) {
1628
+ if (Number(seq) > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) {
1629
+ client._clientLog.debug(`P2P push triggering Forward: ns=${ns}, seq=${seq}, contiguous=${client._seqTracker.getContiguousSeq(ns)}`);
1630
+ this.fillP2pGap().catch((exc) => client._clientLog.warn(`background gap fill trigger failed: ${formatDeliveryError(exc)}`));
1631
+ }
1632
+ return;
1633
+ }
1609
1634
  if (Number(seq) > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) {
1610
1635
  client._clientLog.debug(`P2P push triggering Forward: ns=${ns}, seq=${seq}, contiguous=${client._seqTracker.getContiguousSeq(ns)}`);
1611
1636
  this.fillP2pGap().catch((exc) => client._clientLog.warn(`background gap fill trigger failed: ${formatDeliveryError(exc)}`));
1612
1637
  }
1638
+ await this.publishOrderedMessage('message.received', ns, seq, msg, 'push');
1613
1639
  return;
1614
1640
  }
1615
1641
  else {
@@ -1617,6 +1643,8 @@ export class MessageDeliveryEngine {
1617
1643
  await client._publishEncryptedPushMessage('message.received', 'message.undecryptable', '', seq ?? 0, msg, false);
1618
1644
  return;
1619
1645
  }
1646
+ if (this.isSelfSentP2PMessage(msg))
1647
+ return;
1620
1648
  await client._publishAppEvent('message.received', msg, 'push');
1621
1649
  }
1622
1650
  }
@@ -1671,7 +1699,7 @@ export class MessageDeliveryEngine {
1671
1699
  // 不能让 payload 路径直接推进旧 ordered publish 状态。
1672
1700
  const inlinePresent = hasNonEmptyInlineMessage(msg.inline_message);
1673
1701
  const legacyPushSeq = this.realtimeHeadSeq(seq, inlinePresent);
1674
- if (client._v2Session && groupId && (seq !== undefined && seq !== null || inlinePresent)) {
1702
+ if ((client._v2Session || inlinePresent) && groupId && (seq !== undefined && seq !== null || inlinePresent)) {
1675
1703
  if (legacyPushSeq === null) {
1676
1704
  if (inlinePresent)
1677
1705
  await this.recoverInvalidGroupRealtimeHead(groupId, `group:${groupId}`, seq);
@@ -1694,10 +1722,20 @@ export class MessageDeliveryEngine {
1694
1722
  const ns = `group:${groupId}`;
1695
1723
  if (seq > 0)
1696
1724
  client._seqTracker.updateMaxSeen(ns, seq);
1725
+ if (encryptedPush) {
1726
+ if (Number(seq) > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) {
1727
+ client._clientLog.debug(`group push triggering Forward: group=${groupId}, seq=${seq}, contiguous=${client._seqTracker.getContiguousSeq(ns)}`);
1728
+ this.fillGroupGap(groupId).catch((exc) => client._clientLog.warn(`background gap fill trigger failed: ${formatDeliveryError(exc)}`));
1729
+ }
1730
+ return;
1731
+ }
1697
1732
  if (Number(seq) > client._seqTracker.getContiguousSeq(ns) && client._sessionOptions?.background_sync !== false) {
1698
1733
  client._clientLog.debug(`group push triggering Forward: group=${groupId}, seq=${seq}, contiguous=${client._seqTracker.getContiguousSeq(ns)}`);
1699
1734
  this.fillGroupGap(groupId).catch((exc) => client._clientLog.warn(`background gap fill trigger failed: ${formatDeliveryError(exc)}`));
1700
1735
  }
1736
+ if (!this.isSelfSentGroupMessage(msg)) {
1737
+ await this.publishOrderedMessage('group.message_created', ns, seq, msg, 'group-push');
1738
+ }
1701
1739
  return;
1702
1740
  }
1703
1741
  else {
@@ -2374,7 +2412,7 @@ export class MessageDeliveryEngine {
2374
2412
  after_seq: state.ack,
2375
2413
  limit: pageLimit,
2376
2414
  ...(headForward ? { max_pages: Math.max(2, requiredPages) } : order[0] === 'tail' ? { max_pages: requiredPages } : {}),
2377
- }, !foregroundForward, headForward || tailMissedDuringPull);
2415
+ }, true, headForward || tailMissedDuringPull);
2378
2416
  }
2379
2417
  if (tailHead !== null && this.syncState(ns).ack < this.syncState(ns).tail - 1) {
2380
2418
  this.scheduleRealtimeWindowForward(ns);
@@ -2451,7 +2489,7 @@ export class MessageDeliveryEngine {
2451
2489
  after_seq: state.ack,
2452
2490
  limit: pageLimit,
2453
2491
  ...(headForward ? { max_pages: Math.max(2, requiredPages) } : order[0] === 'tail' ? { max_pages: requiredPages } : {}),
2454
- }, !foregroundForward, headForward || tailMissedDuringPull);
2492
+ }, true, headForward || tailMissedDuringPull);
2455
2493
  }
2456
2494
  if (tailHead !== null && this.syncState(ns).ack < this.syncState(ns).tail - 1) {
2457
2495
  this.scheduleRealtimeWindowForward(ns, groupId);
@@ -2722,10 +2760,10 @@ export class MessageDeliveryEngine {
2722
2760
  const pending = client._pendingOrderedMsgs.get(ns);
2723
2761
  return !pending || pending.size === 0;
2724
2762
  }
2725
- async decodeInlineP2P(row) {
2763
+ async decodeInlineP2P(row, deferStatus) {
2726
2764
  const client = this.runtime.client;
2727
2765
  if (this.inlineRowKind(row) === 'v2') {
2728
- const decrypted = await client._decryptV2PushMessage(row);
2766
+ const decrypted = await client._decryptV2PushMessage(row, deferStatus);
2729
2767
  return isJsonObject(decrypted) ? decrypted : null;
2730
2768
  }
2731
2769
  const legacy = isJsonObject(row.legacy_v1) ? row.legacy_v1 : null;
@@ -2750,16 +2788,20 @@ export class MessageDeliveryEngine {
2750
2788
  timestamp: row.t_server,
2751
2789
  payload: payload,
2752
2790
  encrypted: false,
2753
- direction: String(row.direction ?? '').trim() || (fromAid && fromAid === client._aid ? 'outbound_sync' : 'inbound'),
2754
2791
  };
2792
+ const direction = String(row.direction ?? '').trim();
2793
+ if (direction)
2794
+ result.direction = direction;
2795
+ else if (fromAid && fromAid !== client._aid)
2796
+ result.direction = 'inbound';
2755
2797
  if (row.sender_device_id !== undefined)
2756
2798
  result.sender_device_id = row.sender_device_id;
2757
2799
  return result;
2758
2800
  }
2759
- async decodeInlineGroup(row, groupId, groupAid) {
2801
+ async decodeInlineGroup(row, groupId, groupAid, deferStatus) {
2760
2802
  const client = this.runtime.client;
2761
2803
  if (this.inlineRowKind(row) === 'v2') {
2762
- const decrypted = await client._decryptV2PushMessage(row);
2804
+ const decrypted = await client._decryptV2PushMessage(row, deferStatus);
2763
2805
  if (!isJsonObject(decrypted))
2764
2806
  return null;
2765
2807
  const decoded = decrypted;
@@ -2825,9 +2867,13 @@ export class MessageDeliveryEngine {
2825
2867
  const snapshot = typeof tracker.snapshotNamespace === 'function' ? tracker.snapshotNamespace(ns) : null;
2826
2868
  let delivered = false;
2827
2869
  try {
2828
- const published = client._publishAppEvent(event, payload, 'inline-push');
2829
- if (isPromiseLike(published))
2830
- await published;
2870
+ const selfSync = (event === 'message.received' && this.isSelfSentP2PMessage(payload))
2871
+ || (event === 'group.message_created' && this.isSelfSentGroupMessage(payload));
2872
+ if (!selfSync) {
2873
+ const published = client._publishAppEvent(event, payload, 'inline-push');
2874
+ if (isPromiseLike(published))
2875
+ await published;
2876
+ }
2831
2877
  if (!this.inlineGenerationIsCurrent(generation))
2832
2878
  return false;
2833
2879
  delivered = true;
@@ -2864,6 +2910,34 @@ export class MessageDeliveryEngine {
2864
2910
  return false;
2865
2911
  }
2866
2912
  }
2913
+ async commitInlineTerminalDecryptSeq(ns, seq, generation) {
2914
+ const client = this.runtime.client;
2915
+ const tracker = client._seqTracker;
2916
+ if (!this.inlineGenerationIsCurrent(generation) || !this.inlineStateIsCaughtUp(ns, seq))
2917
+ return false;
2918
+ const snapshot = typeof tracker.snapshotNamespace === 'function' ? tracker.snapshotNamespace(ns) : null;
2919
+ try {
2920
+ const needsPull = Boolean(tracker.onMessageSeq(ns, seq));
2921
+ tracker.commitTailWindow(ns, {
2922
+ windowStartSeq: seq,
2923
+ headSeq: seq,
2924
+ coveredThroughSeq: seq,
2925
+ pageLimit: 1,
2926
+ });
2927
+ const committed = this.syncState(ns);
2928
+ if (needsPull || committed.ack !== seq || committed.tail !== seq || committed.head !== seq) {
2929
+ throw new Error('inline realtime terminal cursor did not collapse after consume');
2930
+ }
2931
+ await client._commitSeqTrackerState(ns);
2932
+ return true;
2933
+ }
2934
+ catch (exc) {
2935
+ if (typeof tracker.restoreNamespaceSnapshot === 'function')
2936
+ tracker.restoreNamespaceSnapshot(ns, snapshot);
2937
+ client._clientLog.debug(`inline realtime terminal consume rolled back: ns=${ns} seq=${seq} err=${formatDeliveryError(exc)}`);
2938
+ return false;
2939
+ }
2940
+ }
2867
2941
  async tryConsumeInlineP2P(head, ns, pushSeq, expectedVersion, inlineGeneration) {
2868
2942
  const client = this.runtime.client;
2869
2943
  if (!isJsonObject(head.inline_message))
@@ -2883,7 +2957,14 @@ export class MessageDeliveryEngine {
2883
2957
  return false;
2884
2958
  let committed = false;
2885
2959
  try {
2886
- const decoded = await this.decodeInlineP2P(row);
2960
+ const decryptStatus = {};
2961
+ const decoded = await this.decodeInlineP2P(row, decryptStatus);
2962
+ if (!decoded && decryptStatus.terminal) {
2963
+ if (!await this.commitInlineTerminalDecryptSeq(ns, pushSeq, generation))
2964
+ return false;
2965
+ committed = this.markPendingP2PInlineAckCommitted(ns, pushSeq);
2966
+ return committed;
2967
+ }
2887
2968
  if (!this.inlineGenerationIsCurrent(generation) || !decoded || !this.inlineStateIsCaughtUp(ns, pushSeq)
2888
2969
  || !this.decodedInlineMatches(head, decoded, pushSeq))
2889
2970
  return false;
@@ -2921,7 +3002,14 @@ export class MessageDeliveryEngine {
2921
3002
  return false;
2922
3003
  let committed = false;
2923
3004
  try {
2924
- const decoded = await this.decodeInlineGroup(row, groupId, groupAid || groupId);
3005
+ const decryptStatus = {};
3006
+ const decoded = await this.decodeInlineGroup(row, groupId, groupAid || groupId, decryptStatus);
3007
+ if (!decoded && decryptStatus.terminal) {
3008
+ if (!await this.commitInlineTerminalDecryptSeq(ns, pushSeq, generation))
3009
+ return false;
3010
+ committed = this.markPendingGroupInlineAckCommitted(ns, pushSeq);
3011
+ return committed;
3012
+ }
2925
3013
  if (!this.inlineGenerationIsCurrent(generation) || !decoded || !this.inlineStateIsCaughtUp(ns, pushSeq)
2926
3014
  || !this.decodedInlineMatches(head, decoded, pushSeq, groupId))
2927
3015
  return false;
@@ -3040,13 +3128,14 @@ export class MessageDeliveryEngine {
3040
3128
  const client = this.runtime.client;
3041
3129
  if (inlineGeneration !== undefined && !this.inlineGenerationIsCurrent(inlineGeneration))
3042
3130
  return;
3043
- if (!client._v2Session)
3044
- return;
3045
3131
  const pushData = isJsonObject(data) ? data : null;
3046
3132
  const rawPushSeq = pushData?.seq;
3047
3133
  const ns = client._aid ? `p2p:${client._aid}` : '';
3048
3134
  if (!pushData || !ns)
3049
3135
  return;
3136
+ const inlinePresent = hasNonEmptyInlineMessage(pushData.inline_message);
3137
+ if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent))
3138
+ return;
3050
3139
  if (this.isVolatileMessage(pushData)) {
3051
3140
  await client._v2E2EE.publishV2VolatileMessages([pushData], 'push', false);
3052
3141
  return;
@@ -3057,7 +3146,6 @@ export class MessageDeliveryEngine {
3057
3146
  this.enqueueOnlineUnreadP2pHint(pushData);
3058
3147
  return;
3059
3148
  }
3060
- const inlinePresent = hasNonEmptyInlineMessage(pushData.inline_message);
3061
3149
  const pushSeq = this.realtimeHeadSeq(rawPushSeq, inlinePresent);
3062
3150
  if (pushSeq === null) {
3063
3151
  if (inlinePresent) {
@@ -3154,8 +3242,8 @@ export class MessageDeliveryEngine {
3154
3242
  const client = this.runtime.client;
3155
3243
  if (inlineGeneration !== undefined && !this.inlineGenerationIsCurrent(inlineGeneration))
3156
3244
  return;
3157
- if (!isJsonObject(data) || !client._v2Session) {
3158
- client._clientLog.debug(`_onRawGroupV2MessageCreated skipped: is_object=${String(isJsonObject(data))}, has_v2_session=${String(!!client._v2Session)}`);
3245
+ if (!isJsonObject(data)) {
3246
+ client._clientLog.debug('_onRawGroupV2MessageCreated skipped: is_object=false');
3159
3247
  return;
3160
3248
  }
3161
3249
  const d = data;
@@ -3163,6 +3251,8 @@ export class MessageDeliveryEngine {
3163
3251
  const groupId = typeof d.group_id === 'string' ? d.group_id.trim() : '';
3164
3252
  const rawSeq = d.seq;
3165
3253
  const inlinePresent = hasNonEmptyInlineMessage(d.inline_message);
3254
+ if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent))
3255
+ return;
3166
3256
  const seq = this.realtimeHeadSeq(rawSeq, inlinePresent);
3167
3257
  if (!groupId) {
3168
3258
  client._clientLog.debug(`_onRawGroupV2MessageCreated skipped: group=${groupId || '<empty>'}, seq=${String(d.seq ?? '')}`);
@@ -3739,6 +3829,11 @@ export class MessageDeliveryEngine {
3739
3829
  client._pendingOrderedMsgs.delete(ns);
3740
3830
  return false;
3741
3831
  }
3832
+ if (event === 'message.received' && this.isSelfSentP2PMessage(payload)) {
3833
+ this.markPublishedSeq(ns, seqNum);
3834
+ client._clientLog.debug(`publish ordered skipped current-device self-sync: ns=${ns}, seq=${seqNum}`);
3835
+ return false;
3836
+ }
3742
3837
  const contig = client._seqTracker.getContiguousSeq(ns);
3743
3838
  if (seqNum > contig && seqNum !== contig + 1) {
3744
3839
  client._clientLog.debug(`publish ordered enqueue(gap): event=${event}, ns=${ns}, seq=${seqNum}, contiguous=${contig}`);
@@ -3752,6 +3847,11 @@ export class MessageDeliveryEngine {
3752
3847
  client._clientLog.debug(`publish ordered skipped after-drain duplicate: event=${event}, ns=${ns}, seq=${seqNum}`);
3753
3848
  return false;
3754
3849
  }
3850
+ if (event === 'message.received' && this.isSelfSentP2PMessage(payload)) {
3851
+ this.markPublishedSeq(ns, seqNum);
3852
+ client._clientLog.debug(`publish pulled skipped current-device self-sync: ns=${ns}, seq=${seqNum}`);
3853
+ return false;
3854
+ }
3755
3855
  const queue = client._pendingOrderedMsgs.get(ns);
3756
3856
  queue?.delete(seqNum);
3757
3857
  if (queue && queue.size === 0)
@@ -3799,6 +3899,11 @@ export class MessageDeliveryEngine {
3799
3899
  client._pendingOrderedMsgs.delete(ns);
3800
3900
  return false;
3801
3901
  }
3902
+ if (event === 'message.received' && this.isSelfSentP2PMessage(payload)) {
3903
+ this.markPublishedSeq(ns, seqNum);
3904
+ client._clientLog.debug('publish pulled skipped current-device self-sync');
3905
+ return source === 'inline_push';
3906
+ }
3802
3907
  await this.drainOrderedMessages(ns, seqNum, true, persist, source);
3803
3908
  if (pullScoped)
3804
3909
  this.ensurePullOperationCurrent(ns);