@agentunion/fastaun-browser 0.5.18 → 0.5.19

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 (118) hide show
  1. package/CHANGELOG.md +44 -2
  2. package/_packed_docs/CHANGELOG.md +44 -2
  3. package/_packed_docs/INDEX.md +136 -14
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +42 -16
  5. package/_packed_docs/agent.md/SCHEMA.md +245 -205
  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 +42 -15
  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 -4
  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 +45 -134
  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 +5 -20
  10. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +28 -9
  11. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +22 -27
  12. package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
  13. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +5 -2
  14. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +250 -283
  15. package/_packed_docs/sdk/09-group-rpc-manual.md +46 -14
  16. package/_packed_docs/sdk/09-message-rpc-manual.md +40 -2
  17. package/_packed_docs/sdk/09-storage-rpc-manual.md +74 -64
  18. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +25 -5
  19. package/_packed_docs/sdk/INDEX.md +76 -17
  20. package/dist/agent-md-schema.d.ts +3 -0
  21. package/dist/agent-md-schema.d.ts.map +1 -1
  22. package/dist/agent-md-schema.js +45 -11
  23. package/dist/agent-md-schema.js.map +1 -1
  24. package/dist/agent-md.d.ts +45 -2
  25. package/dist/agent-md.d.ts.map +1 -1
  26. package/dist/agent-md.js +519 -30
  27. package/dist/agent-md.js.map +1 -1
  28. package/dist/aid-store.d.ts +12 -46
  29. package/dist/aid-store.d.ts.map +1 -1
  30. package/dist/aid-store.js +113 -246
  31. package/dist/aid-store.js.map +1 -1
  32. package/dist/aid.d.ts.map +1 -1
  33. package/dist/aid.js +20 -7
  34. package/dist/aid.js.map +1 -1
  35. package/dist/auth.d.ts +4 -1
  36. package/dist/auth.d.ts.map +1 -1
  37. package/dist/auth.js +343 -23
  38. package/dist/auth.js.map +1 -1
  39. package/dist/bundle.js +37330 -32005
  40. package/dist/cert-utils.d.ts +1 -1
  41. package/dist/cert-utils.d.ts.map +1 -1
  42. package/dist/cert-utils.js +19 -7
  43. package/dist/cert-utils.js.map +1 -1
  44. package/dist/client/delivery.d.ts +15 -1
  45. package/dist/client/delivery.d.ts.map +1 -1
  46. package/dist/client/delivery.js +147 -51
  47. package/dist/client/delivery.js.map +1 -1
  48. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  49. package/dist/client/rpc-pipeline.js +19 -5
  50. package/dist/client/rpc-pipeline.js.map +1 -1
  51. package/dist/client/v2-e2ee.d.ts +1 -0
  52. package/dist/client/v2-e2ee.d.ts.map +1 -1
  53. package/dist/client/v2-e2ee.js +104 -30
  54. package/dist/client/v2-e2ee.js.map +1 -1
  55. package/dist/client.d.ts +100 -1
  56. package/dist/client.d.ts.map +1 -1
  57. package/dist/client.js +1204 -23
  58. package/dist/client.js.map +1 -1
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js +3 -2
  61. package/dist/errors.js.map +1 -1
  62. package/dist/events.d.ts +4 -0
  63. package/dist/events.d.ts.map +1 -1
  64. package/dist/events.js +41 -1
  65. package/dist/events.js.map +1 -1
  66. package/dist/facades.d.ts +82 -2
  67. package/dist/facades.d.ts.map +1 -1
  68. package/dist/facades.js +98 -4
  69. package/dist/facades.js.map +1 -1
  70. package/dist/index.d.ts +7 -3
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +3 -2
  73. package/dist/index.js.map +1 -1
  74. package/dist/keystore/index.d.ts +17 -0
  75. package/dist/keystore/index.d.ts.map +1 -1
  76. package/dist/keystore/indexeddb-shared.d.ts +10 -1
  77. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  78. package/dist/keystore/indexeddb-shared.js +111 -0
  79. package/dist/keystore/indexeddb-shared.js.map +1 -1
  80. package/dist/keystore/indexeddb-token-store.d.ts +7 -1
  81. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  82. package/dist/keystore/indexeddb-token-store.js +30 -1
  83. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  84. package/dist/org-protocol.d.ts +98 -0
  85. package/dist/org-protocol.d.ts.map +1 -0
  86. package/dist/org-protocol.js +1742 -0
  87. package/dist/org-protocol.js.map +1 -0
  88. package/dist/ownership-proof.d.ts +93 -5
  89. package/dist/ownership-proof.d.ts.map +1 -1
  90. package/dist/ownership-proof.js +239 -53
  91. package/dist/ownership-proof.js.map +1 -1
  92. package/dist/ownership-v21.d.ts +177 -0
  93. package/dist/ownership-v21.d.ts.map +1 -0
  94. package/dist/ownership-v21.js +609 -0
  95. package/dist/ownership-v21.js.map +1 -0
  96. package/dist/ownership-workflow.d.ts +146 -0
  97. package/dist/ownership-workflow.d.ts.map +1 -0
  98. package/dist/ownership-workflow.js +1066 -0
  99. package/dist/ownership-workflow.js.map +1 -0
  100. package/dist/seq-tracker.d.ts +1 -0
  101. package/dist/seq-tracker.d.ts.map +1 -1
  102. package/dist/seq-tracker.js +10 -2
  103. package/dist/seq-tracker.js.map +1 -1
  104. package/dist/tools/cross-sdk-agent.d.ts +82 -0
  105. package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
  106. package/dist/tools/cross-sdk-agent.js +332 -7
  107. package/dist/tools/cross-sdk-agent.js.map +1 -1
  108. package/dist/transport.d.ts +6 -0
  109. package/dist/transport.d.ts.map +1 -1
  110. package/dist/transport.js +88 -2
  111. package/dist/transport.js.map +1 -1
  112. package/dist/v2/e2ee/decrypt.d.ts +1 -0
  113. package/dist/v2/e2ee/decrypt.d.ts.map +1 -1
  114. package/dist/v2/e2ee/decrypt.js +9 -1
  115. package/dist/v2/e2ee/decrypt.js.map +1 -1
  116. package/dist/version.d.ts +1 -1
  117. package/dist/version.js +1 -1
  118. package/package.json +1 -1
@@ -1000,11 +1000,12 @@ export class V2E2EECoordinator {
1000
1000
  client._clientLog.debug(`V2 sender IK pending retry delivered: key=${key}`);
1001
1001
  continue;
1002
1002
  }
1003
- client._v2SenderIKPending.delete(key);
1004
1003
  const seq = Number(entry.msg.seq ?? 0);
1005
1004
  if (entry.groupId) {
1006
- if (client._delivery.isSelfSentGroupMessage?.(entry.msg))
1005
+ if (client._delivery.isSelfSentGroupMessage?.(entry.msg)) {
1006
+ client._v2SenderIKPending.delete(key);
1007
1007
  continue;
1008
+ }
1008
1009
  plaintext = normalizeGroupMentionMode(plaintext, entry.msg, entry.msg.envelope_json);
1009
1010
  plaintext.group_id = entry.groupId;
1010
1011
  await client._publishPulledMessage('group.message_created', `group:${entry.groupId}`, seq, plaintext, false, 'pending_retry');
@@ -1012,6 +1013,7 @@ export class V2E2EECoordinator {
1012
1013
  else {
1013
1014
  await client._publishPulledMessage('message.received', `p2p:${client._aid ?? ''}`, seq, plaintext, false, 'pending_retry');
1014
1015
  }
1016
+ client._v2SenderIKPending.delete(key);
1015
1017
  client._clientLog.debug(`V2 sender IK pending retry delivered: key=${key}`);
1016
1018
  }
1017
1019
  }
@@ -1110,6 +1112,12 @@ export class V2E2EECoordinator {
1110
1112
  history_error: { code: 'decrypt_failed', message: reason },
1111
1113
  };
1112
1114
  }
1115
+ ensureDeliveryCurrent(ns, generation, inlineGeneration) {
1116
+ if (Number(this.client._v2RuntimeGeneration ?? 0) !== generation
1117
+ || (inlineGeneration !== undefined && !this.client._delivery.isInlineGenerationCurrent(inlineGeneration))
1118
+ || this.client._rpcPipeline?.isPullNamespaceCurrent?.(ns) === false)
1119
+ throw new StateError('pull invalidated');
1120
+ }
1113
1121
  async decodeP2PWindowMessage(msg, publish, history, source, orderedPublish = false) {
1114
1122
  const client = this.client;
1115
1123
  const seq = strictWindowSeq(msg.seq, 'messages[].seq', true);
@@ -1257,6 +1265,8 @@ export class V2E2EECoordinator {
1257
1265
  }
1258
1266
  async pullV2TailInternal(params, deferPublish = false) {
1259
1267
  const client = this.client;
1268
+ const generation = Number(client._v2RuntimeGeneration ?? 0);
1269
+ const inlineGeneration = client._delivery.captureInlineGeneration?.();
1260
1270
  if (params.window_mode !== 'tail')
1261
1271
  throw new ValidationError('window_mode must equal tail');
1262
1272
  if ('ack_up_to_seq' in params || params.force === true)
@@ -1271,19 +1281,27 @@ export class V2E2EECoordinator {
1271
1281
  }, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
1272
1282
  const result = await client._callRawV2Rpc('message.v2.pull', { window_mode: 'tail', after_seq: afterSeq, limit, _rpc_foreground: true }, pullGateKey);
1273
1283
  const page = validateTailPage(result, afterSeq, limit);
1274
- if (ns) {
1275
- client._seqTracker.commitTailWindow(ns, {
1276
- windowStartSeq: page.windowStart, headSeq: page.head, coveredThroughSeq: page.head, pageLimit: limit,
1277
- });
1278
- client._persistSeq(ns);
1279
- await client._saveSeqTrackerState?.();
1280
- }
1281
1284
  const decoded = [];
1282
1285
  for (const msg of page.messages) {
1286
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1283
1287
  const plaintext = await this.decodeP2PWindowMessage(msg, true, false, 'tail', deferPublish);
1284
1288
  if (plaintext)
1285
1289
  decoded.push(plaintext);
1286
1290
  }
1291
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1292
+ if (ns) {
1293
+ const proof = {
1294
+ windowStartSeq: page.windowStart, headSeq: page.head, coveredThroughSeq: page.head, pageLimit: limit,
1295
+ };
1296
+ if (deferPublish)
1297
+ client._delivery.deferTailWindow(ns, proof);
1298
+ else {
1299
+ client._seqTracker.commitTailWindow(ns, proof);
1300
+ client._persistSeq(ns);
1301
+ await client._saveSeqTrackerState?.();
1302
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1303
+ }
1304
+ }
1287
1305
  const ack = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
1288
1306
  if (ns)
1289
1307
  client._delivery.onPullPage?.(ns, decoded.length, result.has_more === true, page.head, typeof result.remaining === 'number' && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null, page.messages.length, ack, page.head);
@@ -1320,6 +1338,8 @@ export class V2E2EECoordinator {
1320
1338
  }
1321
1339
  async pullV2Impl(afterSeq = 0, limit = 50, opts) {
1322
1340
  const client = this.client;
1341
+ const generation = Number(client._v2RuntimeGeneration ?? 0);
1342
+ const inlineGeneration = client._delivery.captureInlineGeneration?.();
1323
1343
  await client._ensureV2SessionReady('message.pull');
1324
1344
  const ns = client._aid ? `p2p:${client._aid}` : '';
1325
1345
  let volatileCursor = String(opts?.afterVolatileCursor ?? client._delivery.volatilePullCursor() ?? '').trim();
@@ -1365,6 +1385,7 @@ export class V2E2EECoordinator {
1365
1385
  const pipelineQueue = new V2PullPageQueue(V2_PULL_PIPELINE_QUEUE_CAPACITY);
1366
1386
  let pipelineProducer = null;
1367
1387
  let pipelineStopped = false;
1388
+ let pipelineResume = null;
1368
1389
  const startPipeline = (startAfterSeq, startVolatileCursor) => {
1369
1390
  if (pipelineRunning || pageCount >= maxPages || limit < V2_PULL_MAX_PAGE_LIMIT)
1370
1391
  return;
@@ -1385,6 +1406,7 @@ export class V2E2EECoordinator {
1385
1406
  if (pipelineStopped)
1386
1407
  break;
1387
1408
  const rawPageMessages = (Array.isArray(result?.messages) ? result.messages : []);
1409
+ const completed = new Promise((resolve) => { pipelineResume = resolve; });
1388
1410
  const enqueued = await pipelineQueue.put({
1389
1411
  result,
1390
1412
  afterSeq: producerAfterSeq,
@@ -1395,6 +1417,9 @@ export class V2E2EECoordinator {
1395
1417
  }, rawPageMessages.length);
1396
1418
  if (!enqueued || pipelineStopped)
1397
1419
  break;
1420
+ await completed;
1421
+ if (pipelineStopped)
1422
+ break;
1398
1423
  const volatileMessages = client._delivery.volatileMessages(rawPageMessages);
1399
1424
  if (volatileMessages.length > 0)
1400
1425
  break;
@@ -1429,6 +1454,8 @@ export class V2E2EECoordinator {
1429
1454
  };
1430
1455
  const stopPipeline = async () => {
1431
1456
  pipelineStopped = true;
1457
+ pipelineResume?.();
1458
+ pipelineResume = null;
1432
1459
  pipelineQueue.close();
1433
1460
  if (pipelineProducer) {
1434
1461
  const producer = pipelineProducer;
@@ -1514,9 +1541,7 @@ export class V2E2EECoordinator {
1514
1541
  .map((msg) => Number(msg.seq ?? 0))
1515
1542
  .filter((seq) => Number.isFinite(seq) && seq > 0);
1516
1543
  const pageContigBefore = ns ? client._seqTracker.getContiguousSeq(ns) : 0;
1517
- const pageTrackerSnapshot = ns && typeof client._seqTracker.snapshotNamespace === 'function'
1518
- ? client._seqTracker.snapshotNamespace(ns)
1519
- : null;
1544
+ let pageTrackerSnapshot;
1520
1545
  const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
1521
1546
  const pageContiguousSeq = contiguousPullSeq(pageContigBefore, seqs, result.contiguous_seq);
1522
1547
  const deferredKeyFetches = new Map();
@@ -1622,10 +1647,18 @@ export class V2E2EECoordinator {
1622
1647
  const serverAckSeq = parsedServerAckSeq ?? 0;
1623
1648
  const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
1624
1649
  if (ns) {
1625
- const commitTarget = Math.max(pageContigBefore, Number.isFinite(retentionFloor) ? retentionFloor : 0, pageCount === 1 ? deferredServerCursor : 0, serverAckSeq, blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq);
1650
+ let commitTarget = Math.max(pageContigBefore, Number.isFinite(retentionFloor) ? retentionFloor : 0, pageCount === 1 ? deferredServerCursor : 0, serverAckSeq, blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq);
1651
+ commitTarget = client._delivery.pendingTailDeliveryThrough?.(ns, commitTarget) ?? commitTarget;
1626
1652
  let ackSeq = pageContigBefore;
1627
1653
  let contigAdvanced = false;
1628
1654
  try {
1655
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1656
+ const state = client._seqTracker.getSyncState?.(ns);
1657
+ const deliveryThrough = client._delivery.pendingTailDeliveryThrough?.(ns, state && commitTarget >= state.tail - 1 ? Math.max(commitTarget, state.head) : commitTarget) ?? (state && commitTarget >= state.tail - 1 ? Math.max(commitTarget, state.head) : commitTarget);
1658
+ await client._drainOrderedMessages(ns, undefined, false, false, deliveryThrough);
1659
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1660
+ pageTrackerSnapshot = client._seqTracker.snapshotNamespace?.(ns);
1661
+ client._delivery.commitPendingTailWindow?.(ns, commitTarget);
1629
1662
  if (commitTarget > pageContigBefore) {
1630
1663
  client._seqTracker.forceContiguousSeq(ns, commitTarget);
1631
1664
  if (retentionFloor > pageContigBefore) {
@@ -1642,19 +1675,23 @@ export class V2E2EECoordinator {
1642
1675
  contigAdvanced = ackSeq !== pageContigBefore;
1643
1676
  if (contigAdvanced) {
1644
1677
  await client._commitSeqTrackerState(ns);
1678
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1645
1679
  if (pageCount === 1 && deferredServerCursor > 0)
1646
1680
  this.clearForwardCursor(ns, ackSeq);
1647
1681
  }
1682
+ client._delivery.completePendingTailWindow?.(ns);
1648
1683
  }
1649
1684
  catch (exc) {
1650
- if (typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
1651
- client._seqTracker.restoreNamespaceSnapshot(ns, pageTrackerSnapshot);
1685
+ if (Number(client._v2RuntimeGeneration ?? 0) === generation
1686
+ && (inlineGeneration === undefined || client._delivery.isInlineGenerationCurrent(inlineGeneration))
1687
+ && client._rpcPipeline?.isPullNamespaceCurrent?.(ns) !== false
1688
+ && pageTrackerSnapshot !== undefined
1689
+ && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
1690
+ client._seqTracker._restoreNamespaceSnapshotPreservingPush(ns, pageTrackerSnapshot);
1652
1691
  }
1653
1692
  client._clientLog.error?.(`message.v2.pull Forward commit rolled back: ns=${ns} target=${commitTarget} error=${formatE2EEError(exc)}`);
1654
1693
  throw exc;
1655
1694
  }
1656
- if (contigAdvanced)
1657
- await client._drainOrderedMessages(ns, undefined, false, false);
1658
1695
  for (const fetch of deferredKeyFetches.values()) {
1659
1696
  this.scheduleSenderIKFetch(fetch.fromAid, fetch.senderDeviceId, fetch.groupId);
1660
1697
  }
@@ -1721,6 +1758,10 @@ export class V2E2EECoordinator {
1721
1758
  });
1722
1759
  if (!shouldContinue)
1723
1760
  break;
1761
+ if (pipelinePage) {
1762
+ pipelineResume?.();
1763
+ pipelineResume = null;
1764
+ }
1724
1765
  if (shouldContinueForPipeline && !volatileAdvanced && !pipelineRunning && limit >= V2_PULL_MAX_PAGE_LIMIT) {
1725
1766
  if (pendingAckSeq > 0) {
1726
1767
  await this.confirmForwardP2PAck(pendingAckSeq);
@@ -1965,6 +2006,8 @@ export class V2E2EECoordinator {
1965
2006
  }
1966
2007
  async pullGroupV2TailInternal(params, deferPublish = false) {
1967
2008
  const client = this.client;
2009
+ const generation = Number(client._v2RuntimeGeneration ?? 0);
2010
+ const inlineGeneration = client._delivery.captureInlineGeneration?.();
1968
2011
  if (params.window_mode !== 'tail')
1969
2012
  throw new ValidationError('window_mode must equal tail');
1970
2013
  if ('ack_up_to_seq' in params || params.force === true)
@@ -2000,18 +2043,26 @@ export class V2E2EECoordinator {
2000
2043
  if (resultAid)
2001
2044
  groupAid = resultAid;
2002
2045
  const page = validateTailPage(result, afterSeq, limit);
2003
- client._seqTracker.commitTailWindow(ns, {
2004
- windowStartSeq: page.windowStart, headSeq: page.head, coveredThroughSeq: page.head, pageLimit: limit,
2005
- });
2006
- client._persistSeq(ns);
2007
- await client._saveSeqTrackerState?.();
2008
2046
  const decoded = [];
2009
2047
  for (const msg of page.messages) {
2048
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
2010
2049
  client._logMessageDebug?.('tail-raw', 'group.v2.pull', 'group.message_created', msg);
2011
2050
  const plaintext = await this.decodeGroupWindowMessage(msg, groupId, groupAid, true, false, 'tail', deferPublish);
2012
2051
  if (plaintext)
2013
2052
  decoded.push(plaintext);
2014
2053
  }
2054
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
2055
+ const proof = {
2056
+ windowStartSeq: page.windowStart, headSeq: page.head, coveredThroughSeq: page.head, pageLimit: limit,
2057
+ };
2058
+ if (deferPublish)
2059
+ client._delivery.deferTailWindow(ns, proof);
2060
+ else {
2061
+ client._seqTracker.commitTailWindow(ns, proof);
2062
+ client._persistSeq(ns);
2063
+ await client._saveSeqTrackerState?.();
2064
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
2065
+ }
2015
2066
  const ack = client._seqTracker.getContiguousSeq(ns);
2016
2067
  if (ownsCursor)
2017
2068
  client._delivery.onPullPage?.(ns, decoded.length, result.has_more === true, page.head, typeof result.remaining === 'number' && Number.isSafeInteger(result.remaining) && result.remaining >= 0 ? result.remaining : null, page.messages.length, ack, page.head);
@@ -2056,6 +2107,8 @@ export class V2E2EECoordinator {
2056
2107
  }
2057
2108
  async pullGroupV2Impl(groupId, afterSeq = 0, limit = 50, opts) {
2058
2109
  const client = this.client;
2110
+ const generation = Number(client._v2RuntimeGeneration ?? 0);
2111
+ const inlineGeneration = client._delivery.captureInlineGeneration?.();
2059
2112
  await client._ensureV2SessionReady('group.pull');
2060
2113
  const gid = String(groupId ?? '').trim();
2061
2114
  if (!gid)
@@ -2117,6 +2170,7 @@ export class V2E2EECoordinator {
2117
2170
  const pipelineQueue = new V2PullPageQueue(V2_PULL_PIPELINE_QUEUE_CAPACITY);
2118
2171
  let pipelineProducer = null;
2119
2172
  let pipelineStopped = false;
2173
+ let pipelineResume = null;
2120
2174
  const startPipeline = (startAfterSeq) => {
2121
2175
  if (pipelineRunning || pageCount >= maxPages || limit < V2_PULL_MAX_PAGE_LIMIT || !ownsCursor)
2122
2176
  return;
@@ -2136,6 +2190,7 @@ export class V2E2EECoordinator {
2136
2190
  if (pipelineStopped)
2137
2191
  break;
2138
2192
  const pageMessages = (Array.isArray(result?.messages) ? result.messages : []);
2193
+ const completed = new Promise((resolve) => { pipelineResume = resolve; });
2139
2194
  const enqueued = await pipelineQueue.put({
2140
2195
  result,
2141
2196
  afterSeq: producerAfterSeq,
@@ -2146,6 +2201,9 @@ export class V2E2EECoordinator {
2146
2201
  }, pageMessages.length);
2147
2202
  if (!enqueued || pipelineStopped)
2148
2203
  break;
2204
+ await completed;
2205
+ if (pipelineStopped)
2206
+ break;
2149
2207
  const messages = deduplicateForwardPageMessages(pageMessages, producerAfterSeq);
2150
2208
  const seqs = messages.map((msg) => Number(msg.seq ?? 0)).filter((seq) => Number.isFinite(seq) && seq > 0);
2151
2209
  const nextAfter = Math.max(contiguousPullSeq(producerAfterSeq, seqs, result.contiguous_seq), producerAfterSeq);
@@ -2174,6 +2232,8 @@ export class V2E2EECoordinator {
2174
2232
  };
2175
2233
  const stopPipeline = async () => {
2176
2234
  pipelineStopped = true;
2235
+ pipelineResume?.();
2236
+ pipelineResume = null;
2177
2237
  pipelineQueue.close();
2178
2238
  if (pipelineProducer) {
2179
2239
  const producer = pipelineProducer;
@@ -2245,9 +2305,7 @@ export class V2E2EECoordinator {
2245
2305
  .map((msg) => Number(msg.seq ?? 0))
2246
2306
  .filter((seq) => Number.isFinite(seq) && seq > 0);
2247
2307
  const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
2248
- const pageTrackerSnapshot = typeof client._seqTracker.snapshotNamespace === 'function'
2249
- ? client._seqTracker.snapshotNamespace(ns)
2250
- : null;
2308
+ let pageTrackerSnapshot;
2251
2309
  const pageMaxSeq = seqs.length > 0 ? Math.max(...seqs) : nextAfterSeq;
2252
2310
  const pageContiguousSeq = contiguousPullSeq(pageContigBefore, seqs, result.contiguous_seq);
2253
2311
  const deferredKeyFetches = new Map();
@@ -2383,11 +2441,19 @@ export class V2E2EECoordinator {
2383
2441
  const retentionFloor = Math.max(Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0), Number(cursor?.retention_floor_seq ?? 0));
2384
2442
  const visibilityFloor = Math.max(0, Math.max(0, Number(result.earliest_available_message_seq ?? 1) - 1), Number(cursor?.join_seq ?? 0));
2385
2443
  const effectiveFloor = Math.max(retentionFloor, visibilityFloor);
2386
- const commitTarget = Math.max(pageContigBefore, Number.isFinite(effectiveFloor) ? effectiveFloor : 0, ownsCursor && pageCount === 1 ? deferredServerCursor : 0, cursorCurrentSeq, blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq);
2444
+ let commitTarget = Math.max(pageContigBefore, Number.isFinite(effectiveFloor) ? effectiveFloor : 0, ownsCursor && pageCount === 1 ? deferredServerCursor : 0, cursorCurrentSeq, blockedSeq > 0 ? blockedSeq - 1 : pageContiguousSeq);
2445
+ commitTarget = client._delivery.pendingTailDeliveryThrough?.(ns, commitTarget) ?? commitTarget;
2387
2446
  let ackSeq = pageContigBefore;
2388
2447
  let contigAdvanced = false;
2389
2448
  if (ownsCursor) {
2390
2449
  try {
2450
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
2451
+ const state = client._seqTracker.getSyncState?.(ns);
2452
+ const deliveryThrough = client._delivery.pendingTailDeliveryThrough?.(ns, state && commitTarget >= state.tail - 1 ? Math.max(commitTarget, state.head) : commitTarget) ?? (state && commitTarget >= state.tail - 1 ? Math.max(commitTarget, state.head) : commitTarget);
2453
+ await client._drainOrderedMessages(ns, undefined, false, false, deliveryThrough);
2454
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
2455
+ pageTrackerSnapshot = client._seqTracker.snapshotNamespace?.(ns);
2456
+ client._delivery.commitPendingTailWindow?.(ns, commitTarget);
2391
2457
  if (commitTarget > pageContigBefore) {
2392
2458
  client._seqTracker.forceContiguousSeq(ns, commitTarget);
2393
2459
  if (effectiveFloor > pageContigBefore) {
@@ -2404,19 +2470,23 @@ export class V2E2EECoordinator {
2404
2470
  contigAdvanced = ackSeq !== pageContigBefore;
2405
2471
  if (contigAdvanced) {
2406
2472
  await client._commitSeqTrackerState(ns);
2473
+ this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
2407
2474
  if (pageCount === 1 && deferredServerCursor > 0)
2408
2475
  this.clearForwardCursor(ns, ackSeq);
2409
2476
  }
2477
+ client._delivery.completePendingTailWindow?.(ns);
2410
2478
  }
2411
2479
  catch (exc) {
2412
- if (typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
2413
- client._seqTracker.restoreNamespaceSnapshot(ns, pageTrackerSnapshot);
2480
+ if (Number(client._v2RuntimeGeneration ?? 0) === generation
2481
+ && (inlineGeneration === undefined || client._delivery.isInlineGenerationCurrent(inlineGeneration))
2482
+ && client._rpcPipeline?.isPullNamespaceCurrent?.(ns) !== false
2483
+ && pageTrackerSnapshot !== undefined
2484
+ && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
2485
+ client._seqTracker._restoreNamespaceSnapshotPreservingPush(ns, pageTrackerSnapshot);
2414
2486
  }
2415
2487
  client._clientLog.error?.(`group.v2.pull Forward commit rolled back: group=${gid} ns=${ns} target=${commitTarget} error=${formatE2EEError(exc)}`);
2416
2488
  throw exc;
2417
2489
  }
2418
- if (contigAdvanced)
2419
- await client._drainOrderedMessages(ns, undefined, false, false);
2420
2490
  }
2421
2491
  for (const fetch of deferredKeyFetches.values()) {
2422
2492
  this.scheduleSenderIKFetch(fetch.fromAid, fetch.senderDeviceId, fetch.groupId);
@@ -2480,6 +2550,10 @@ export class V2E2EECoordinator {
2480
2550
  });
2481
2551
  if (!shouldContinue)
2482
2552
  break;
2553
+ if (pipelinePage) {
2554
+ pipelineResume?.();
2555
+ pipelineResume = null;
2556
+ }
2483
2557
  if (shouldContinueForPipeline && !pipelineRunning && limit >= V2_PULL_MAX_PAGE_LIMIT) {
2484
2558
  if (pendingAckSeq > 0) {
2485
2559
  await this.confirmForwardGroupAck(gid, pendingAckSeq, groupAid);