@agentunion/fastaun 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 (94) 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 +2 -0
  21. package/dist/agent-md-schema.js +45 -10
  22. package/dist/agent-md-schema.js.map +1 -1
  23. package/dist/agent-md.d.ts +47 -2
  24. package/dist/agent-md.js +493 -33
  25. package/dist/agent-md.js.map +1 -1
  26. package/dist/aid-store.d.ts +9 -59
  27. package/dist/aid-store.js +135 -245
  28. package/dist/aid-store.js.map +1 -1
  29. package/dist/aid.js +19 -5
  30. package/dist/aid.js.map +1 -1
  31. package/dist/auth.d.ts +6 -1
  32. package/dist/auth.js +428 -15
  33. package/dist/auth.js.map +1 -1
  34. package/dist/cert-utils.d.ts +1 -1
  35. package/dist/cert-utils.js +19 -7
  36. package/dist/cert-utils.js.map +1 -1
  37. package/dist/client/delivery.d.ts +2 -1
  38. package/dist/client/delivery.js +143 -52
  39. package/dist/client/delivery.js.map +1 -1
  40. package/dist/client/rpc-pipeline.js +22 -5
  41. package/dist/client/rpc-pipeline.js.map +1 -1
  42. package/dist/client/v2-e2ee.d.ts +1 -0
  43. package/dist/client/v2-e2ee.js +93 -29
  44. package/dist/client/v2-e2ee.js.map +1 -1
  45. package/dist/client.d.ts +84 -1
  46. package/dist/client.js +749 -28
  47. package/dist/client.js.map +1 -1
  48. package/dist/errors.js +4 -3
  49. package/dist/errors.js.map +1 -1
  50. package/dist/events.d.ts +5 -1
  51. package/dist/events.js +47 -6
  52. package/dist/events.js.map +1 -1
  53. package/dist/facades.d.ts +83 -3
  54. package/dist/facades.js +98 -4
  55. package/dist/facades.js.map +1 -1
  56. package/dist/index.d.ts +8 -4
  57. package/dist/index.js +3 -2
  58. package/dist/index.js.map +1 -1
  59. package/dist/keystore/aid-db.d.ts +5 -0
  60. package/dist/keystore/aid-db.js +48 -0
  61. package/dist/keystore/aid-db.js.map +1 -1
  62. package/dist/keystore/index.d.ts +8 -0
  63. package/dist/keystore/local-identity-store.js +10 -3
  64. package/dist/keystore/local-identity-store.js.map +1 -1
  65. package/dist/keystore/local-token-store.d.ts +6 -1
  66. package/dist/keystore/local-token-store.js +24 -1
  67. package/dist/keystore/local-token-store.js.map +1 -1
  68. package/dist/org-protocol.d.ts +98 -0
  69. package/dist/org-protocol.js +1689 -0
  70. package/dist/org-protocol.js.map +1 -0
  71. package/dist/ownership-proof.d.ts +82 -5
  72. package/dist/ownership-proof.js +327 -31
  73. package/dist/ownership-proof.js.map +1 -1
  74. package/dist/ownership-v21.d.ts +178 -0
  75. package/dist/ownership-v21.js +635 -0
  76. package/dist/ownership-v21.js.map +1 -0
  77. package/dist/ownership-workflow.d.ts +82 -0
  78. package/dist/ownership-workflow.js +872 -0
  79. package/dist/ownership-workflow.js.map +1 -0
  80. package/dist/seq-tracker.d.ts +1 -0
  81. package/dist/seq-tracker.js +10 -1
  82. package/dist/seq-tracker.js.map +1 -1
  83. package/dist/tools/cross-sdk-agent.d.ts +89 -1
  84. package/dist/tools/cross-sdk-agent.js +338 -7
  85. package/dist/tools/cross-sdk-agent.js.map +1 -1
  86. package/dist/transport.d.ts +7 -0
  87. package/dist/transport.js +108 -4
  88. package/dist/transport.js.map +1 -1
  89. package/dist/v2/e2ee/decrypt.d.ts +1 -0
  90. package/dist/v2/e2ee/decrypt.js +9 -1
  91. package/dist/v2/e2ee/decrypt.js.map +1 -1
  92. package/dist/version.d.ts +1 -1
  93. package/dist/version.js +1 -1
  94. package/package.json +1 -1
@@ -175,9 +175,8 @@ export class MessageDeliveryEngine {
175
175
  const pageInlineGeneration = this.captureInlineAckGeneration();
176
176
  const deferredServerCursor = Number(coordinator.pendingForwardCursor(ns, pageContigBefore) ?? 0);
177
177
  const deferredForwardAck = Number(coordinator.pendingForwardAck(ns, pageContigBefore) ?? 0);
178
- const pageTrackerSnapshot = typeof client._seqTracker.snapshotNamespace === 'function'
179
- ? client._seqTracker.snapshotNamespace(ns)
180
- : null;
178
+ let pageTrackerSnapshot = null;
179
+ let trackerMutated = false;
181
180
  response._contig_before = pageContigBefore;
182
181
  const cursor = isJsonObject(response.cursor)
183
182
  ? response.cursor
@@ -225,6 +224,18 @@ export class MessageDeliveryEngine {
225
224
  }
226
225
  }
227
226
  this.ensurePullOperationCurrent(ns);
227
+ if (pageInlineGeneration !== this.captureInlineAckGeneration())
228
+ throw new Error('pull invalidated');
229
+ const previousWindow = client._seqTracker.getSyncState(ns);
230
+ const scanTarget = Math.max(pageContigBefore, ...messages.map((message) => positiveSafeSequenceHint(message.seq)), positiveSafeSequenceHint(response.contiguous_seq), retentionFloor, visibilityFloor, deferredServerCursor);
231
+ const deliveryTarget = scanTarget >= previousWindow.tail - 1
232
+ ? Math.max(scanTarget, previousWindow.head) : scanTarget;
233
+ await this.drainOrderedMessages(ns, undefined, false, false, 'pull', undefined, deliveryTarget);
234
+ this.ensurePullOperationCurrent(ns);
235
+ if (pageInlineGeneration !== this.captureInlineAckGeneration())
236
+ throw new Error('pull invalidated');
237
+ pageTrackerSnapshot = client._seqTracker.snapshotNamespace?.(ns) ?? null;
238
+ trackerMutated = true;
228
239
  client._seqTracker.onPullResult(ns, messages, afterSeq, Number.isSafeInteger(result.contiguous_seq)
229
240
  ? result.contiguous_seq
230
241
  : undefined);
@@ -233,16 +244,19 @@ export class MessageDeliveryEngine {
233
244
  client._seqTracker.forceContiguousSeq(ns, commitTarget);
234
245
  }
235
246
  if (client._seqTracker.getContiguousSeq(ns) !== pageContigBefore) {
236
- this.ensurePullOperationCurrent(ns);
237
- await this.drainOrderedMessages(ns, undefined, false, false, 'pull');
238
247
  this.ensurePullOperationCurrent(ns);
239
248
  await client._commitSeqTrackerState(ns);
249
+ this.ensurePullOperationCurrent(ns);
250
+ if (pageInlineGeneration !== this.captureInlineAckGeneration())
251
+ throw new Error('pull invalidated');
240
252
  }
241
253
  committed = true;
242
254
  }
243
255
  catch (exc) {
244
- if (this.isPullOperationCurrent(ns) && !committed && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
245
- client._seqTracker.restoreNamespaceSnapshot(ns, pageTrackerSnapshot);
256
+ if (trackerMutated && pageInlineGeneration === this.captureInlineAckGeneration() && this.isPullOperationCurrent(ns)
257
+ && !committed && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
258
+ (client._seqTracker._restoreNamespaceSnapshotPreservingPush ?? client._seqTracker.restoreNamespaceSnapshot)
259
+ .call(client._seqTracker, ns, pageTrackerSnapshot);
246
260
  this.dropSeqTrackerPending(ns);
247
261
  }
248
262
  throw exc;
@@ -702,6 +716,18 @@ export class MessageDeliveryEngine {
702
716
  }
703
717
  this.schedulePendingGroupPullIfNeeded(ns, 'pull-gate-idle');
704
718
  }
719
+ onForegroundPullsDrained() {
720
+ const client = this.runtime.client;
721
+ if (!client._aid || client._sessionOptions?.background_sync === false
722
+ || client.state !== ConnectionState.READY || client._closing)
723
+ return;
724
+ const ns = `p2p:${client._aid}`;
725
+ const state = this.syncState(ns);
726
+ const maxSeen = client._seqTracker.getMaxSeenSeq(ns);
727
+ if (maxSeen <= state.ack && state.ack >= state.tail - 1)
728
+ return;
729
+ client._safeAsync(this.fillP2pGap());
730
+ }
705
731
  recordPendingGroupPull(ns, seq) {
706
732
  if (!ns || !Number.isSafeInteger(seq) || seq <= 0)
707
733
  return;
@@ -792,12 +818,12 @@ export class MessageDeliveryEngine {
792
818
  return;
793
819
  }
794
820
  if (pullResponse) {
795
- const published = client._withPullResponseProcessing(ns, () => this.publishAppEvent(event, payload, source, deliveryContext));
821
+ const published = client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, deliveryContext));
796
822
  if (isPromiseLike(published))
797
823
  await published;
798
824
  }
799
825
  else {
800
- const published = this.publishAppEvent(event, payload, source, deliveryContext);
826
+ const published = client._publishAppEvent(event, payload, source, deliveryContext);
801
827
  if (isPromiseLike(published))
802
828
  await published;
803
829
  }
@@ -806,6 +832,12 @@ export class MessageDeliveryEngine {
806
832
  }
807
833
  async publishOrderedGroupChanged(payload, source = 'ordered') {
808
834
  const client = this.runtime.client;
835
+ const generation = this.captureInlineAckGeneration();
836
+ const published = client._publishAppEvent('group.changed', payload, source);
837
+ if (isPromiseLike(published))
838
+ await published;
839
+ if (generation !== this.captureInlineAckGeneration())
840
+ throw new Error('pull invalidated');
809
841
  if (isJsonObject(payload)) {
810
842
  const eventPayload = payload;
811
843
  client._groupState?.handleGroupChangedV2Membership?.(eventPayload);
@@ -816,9 +848,6 @@ export class MessageDeliveryEngine {
816
848
  client._cleanupDissolvedGroup?.(groupId);
817
849
  }
818
850
  }
819
- const published = client._publishAppEvent('group.changed', payload, source);
820
- if (isPromiseLike(published))
821
- await published;
822
851
  }
823
852
  isInstanceScopedMessageEvent(event) {
824
853
  return event === 'message.received'
@@ -1131,6 +1160,7 @@ export class MessageDeliveryEngine {
1131
1160
  }
1132
1161
  async publishMessageRecallTombstone(seq, message, source = 'push') {
1133
1162
  const client = this.runtime.client;
1163
+ const generation = this.captureInlineAckGeneration();
1134
1164
  const eventPayload = this.recallEventFromMessage(message);
1135
1165
  if (!eventPayload)
1136
1166
  return false;
@@ -1144,13 +1174,17 @@ export class MessageDeliveryEngine {
1144
1174
  client._clientLog.debug(`message.recalled dedup suppressed: seq=${String(seq)} key=${dedupKey}`);
1145
1175
  return false;
1146
1176
  }
1177
+ await client._publishAppEvent('message.recalled', eventPayload, source);
1178
+ if (generation !== this.captureInlineAckGeneration())
1179
+ throw new Error('pull invalidated');
1180
+ if (this.isPullScopedSource(source))
1181
+ this.ensurePullOperationCurrent(`p2p:${client._aid ?? ''}`);
1147
1182
  seen.set(dedupKey, Date.now());
1148
1183
  if (seen.size > MESSAGE_RECALL_SEEN_LIMIT) {
1149
1184
  const drop = [...seen.entries()].sort((a, b) => a[1] - b[1]).slice(0, seen.size - MESSAGE_RECALL_SEEN_LIMIT);
1150
1185
  for (const [oldKey] of drop)
1151
1186
  seen.delete(oldKey);
1152
1187
  }
1153
- await client._publishAppEvent('message.recalled', eventPayload, source);
1154
1188
  client._clientLog.debug(`message.recalled published: seq=${String(seq)} ids=${JSON.stringify(eventPayload.message_ids)}`);
1155
1189
  return true;
1156
1190
  }
@@ -1235,6 +1269,7 @@ export class MessageDeliveryEngine {
1235
1269
  }
1236
1270
  async publishGroupRecallTombstone(groupId, seq, message, source = 'push') {
1237
1271
  const client = this.runtime.client;
1272
+ const generation = this.captureInlineAckGeneration();
1238
1273
  const eventPayload = this.recallEventFromGroupMessage(message);
1239
1274
  if (!eventPayload)
1240
1275
  return false;
@@ -1250,13 +1285,17 @@ export class MessageDeliveryEngine {
1250
1285
  client._clientLog.debug(`group.message_recalled dedup suppressed: group=${groupId} seq=${String(seq)} key=${dedupKey}`);
1251
1286
  return false;
1252
1287
  }
1288
+ await client._publishAppEvent('group.message_recalled', eventPayload, source);
1289
+ if (generation !== this.captureInlineAckGeneration())
1290
+ throw new Error('pull invalidated');
1291
+ if (this.isPullScopedSource(source))
1292
+ this.ensurePullOperationCurrent(`group:${groupId}`);
1253
1293
  seen.set(dedupKey, Date.now());
1254
1294
  if (seen.size > GROUP_RECALL_SEEN_LIMIT) {
1255
1295
  const drop = [...seen.entries()].sort((a, b) => a[1] - b[1]).slice(0, seen.size - GROUP_RECALL_SEEN_LIMIT);
1256
1296
  for (const [oldKey] of drop)
1257
1297
  seen.delete(oldKey);
1258
1298
  }
1259
- await client._publishAppEvent('group.message_recalled', eventPayload, source);
1260
1299
  client._clientLog.debug(`group.message_recalled published: group=${groupId} seq=${String(seq)} ids=${JSON.stringify(eventPayload.message_ids)}`);
1261
1300
  return true;
1262
1301
  }
@@ -1325,11 +1364,14 @@ export class MessageDeliveryEngine {
1325
1364
  const generation = this.deliveryChangedGeneration;
1326
1365
  const normalized = this.normalizePublishedMessagePayload(event, payload, source);
1327
1366
  const dispatcher = client._dispatcher;
1328
- const result = typeof dispatcher.enqueue === 'function'
1329
- ? (dispatcher.enqueue(event, normalized), undefined)
1330
- : typeof dispatcher.publishSyncAware === 'function'
1331
- ? dispatcher.publishSyncAware(event, normalized)
1332
- : dispatcher.publish?.(event, normalized);
1367
+ const result = ['message.received', 'group.message_created', 'message.recalled', 'group.message_recalled', 'group.changed'].includes(event)
1368
+ && typeof dispatcher._publishAndWait === 'function'
1369
+ ? dispatcher._publishAndWait(event, normalized)
1370
+ : typeof dispatcher.enqueue === 'function'
1371
+ ? (dispatcher.enqueue(event, normalized), undefined)
1372
+ : typeof dispatcher.publishSyncAware === 'function'
1373
+ ? dispatcher.publishSyncAware(event, normalized)
1374
+ : dispatcher.publish?.(event, normalized);
1333
1375
  const note = () => {
1334
1376
  if (generation === this.deliveryChangedGeneration) {
1335
1377
  this.noteDeliveryChanged(event, payload, source, deliveryContext);
@@ -1883,6 +1925,7 @@ export class MessageDeliveryEngine {
1883
1925
  if (!groupId)
1884
1926
  return;
1885
1927
  const ns = `group_event:${groupId}`;
1928
+ const generation = this.captureInlineAckGeneration();
1886
1929
  const requestedAfterSeq = Number(options.afterSeq ?? 0);
1887
1930
  const afterSeq = Number.isSafeInteger(requestedAfterSeq) && requestedAfterSeq > 0
1888
1931
  ? requestedAfterSeq
@@ -1905,6 +1948,7 @@ export class MessageDeliveryEngine {
1905
1948
  let filled = 0;
1906
1949
  let continuationAfterSeq = 0;
1907
1950
  let failed = false;
1951
+ let dissolved = false;
1908
1952
  try {
1909
1953
  let nextAfterSeq = afterSeq;
1910
1954
  const maxPages = singlePage ? 1 : 100;
@@ -1934,10 +1978,9 @@ export class MessageDeliveryEngine {
1934
1978
  if (!Array.isArray(events))
1935
1979
  return;
1936
1980
  const pageContigBefore = client._seqTracker.getContiguousSeq(ns);
1981
+ let pageTrackerSnapshot = null;
1982
+ let trackerMutated = false;
1937
1983
  const eventObjects = events.filter((evt) => isJsonObject(evt));
1938
- client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq, Number.isSafeInteger(result.contiguous_seq)
1939
- ? result.contiguous_seq
1940
- : undefined);
1941
1984
  const cursor = isJsonObject(result.cursor)
1942
1985
  ? result.cursor
1943
1986
  : null;
@@ -1947,13 +1990,6 @@ export class MessageDeliveryEngine {
1947
1990
  const earliestAvailable = Number(result.earliest_available_event_seq ?? 0);
1948
1991
  const visibilityFloor = Math.max(0, Number.isFinite(Number(cursor?.join_seq)) ? Number(cursor?.join_seq) : 0, Number.isFinite(earliestAvailable) && earliestAvailable > 0 ? earliestAvailable - 1 : 0);
1949
1992
  const effectiveFloor = Math.max(retentionFloor, serverAckFloor, visibilityFloor);
1950
- if (effectiveFloor > 0) {
1951
- const contigBeforeFloor = client._seqTracker.getContiguousSeq(ns);
1952
- if (contigBeforeFloor < effectiveFloor) {
1953
- client._clientLog.info(`group.pull_events floor advance: ns=${ns} contiguous=${contigBeforeFloor} -> effective_floor=${effectiveFloor} retention_floor=${retentionFloor} server_ack=${serverAckFloor} visibility_floor=${visibilityFloor}`);
1954
- client._seqTracker.forceContiguousSeq(ns, effectiveFloor);
1955
- }
1956
- }
1957
1993
  const eventSeqs = [];
1958
1994
  let hasDissolvedEvent = false;
1959
1995
  let publishedEventCount = 0;
@@ -1983,11 +2019,40 @@ export class MessageDeliveryEngine {
1983
2019
  if (et !== 'group.message_created')
1984
2020
  filled += 1;
1985
2021
  }
1986
- const ackContig = client._seqTracker.getContiguousSeq(ns);
1987
- await this.drainOrderedMessages(ns);
1988
- if (ackContig !== pageContigBefore && !hasDissolvedEvent) {
1989
- this.persistSeq(ns);
2022
+ try {
2023
+ const scanTarget = Math.max(pageContigBefore, effectiveFloor, positiveSafeSequenceHint(result.contiguous_seq), ...eventSeqs);
2024
+ await this.drainOrderedMessages(ns, undefined, false, false, 'pull', undefined, scanTarget);
2025
+ if (generation !== this.captureInlineAckGeneration())
2026
+ throw new Error('pull invalidated');
2027
+ this.ensurePullOperationCurrent(ns);
2028
+ if (hasDissolvedEvent) {
2029
+ dissolved = true;
2030
+ break;
2031
+ }
2032
+ pageTrackerSnapshot = client._seqTracker.snapshotNamespace?.(ns) ?? null;
2033
+ trackerMutated = true;
2034
+ client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq, Number.isSafeInteger(result.contiguous_seq)
2035
+ ? result.contiguous_seq : undefined);
2036
+ if (client._seqTracker.getContiguousSeq(ns) < effectiveFloor) {
2037
+ client._seqTracker.forceContiguousSeq(ns, effectiveFloor);
2038
+ }
2039
+ if (client._seqTracker.getContiguousSeq(ns) !== pageContigBefore && !hasDissolvedEvent) {
2040
+ await client._commitSeqTrackerState(ns);
2041
+ this.ensurePullOperationCurrent(ns);
2042
+ if (generation !== this.captureInlineAckGeneration())
2043
+ throw new Error('pull invalidated');
2044
+ }
1990
2045
  }
2046
+ catch (exc) {
2047
+ if (trackerMutated && generation === this.captureInlineAckGeneration() && this.isPullOperationCurrent(ns)
2048
+ && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
2049
+ (client._seqTracker._restoreNamespaceSnapshotPreservingPush ?? client._seqTracker.restoreNamespaceSnapshot)
2050
+ .call(client._seqTracker, ns, pageTrackerSnapshot);
2051
+ this.dropSeqTrackerPending(ns);
2052
+ }
2053
+ throw exc;
2054
+ }
2055
+ const ackContig = client._seqTracker.getContiguousSeq(ns);
1991
2056
  if (eventObjects.length > 0 && ackContig > 0 && ackContig !== pageContigBefore) {
1992
2057
  const ackSeq = this.clampAckSeq('group.ack_events', 'event_seq', ns, ackContig);
1993
2058
  try {
@@ -2042,13 +2107,13 @@ export class MessageDeliveryEngine {
2042
2107
  if (legacyGateToken !== null && typeof client._releasePullGate === 'function') {
2043
2108
  client._releasePullGate(ns, legacyGateToken);
2044
2109
  }
2045
- if (singlePage && continuationAfterSeq > afterSeq) {
2110
+ if (!dissolved && singlePage && continuationAfterSeq > afterSeq) {
2046
2111
  this.enqueueOnlineUnreadEventHint({
2047
2112
  group_id: groupId,
2048
2113
  _online_hint_after_event_seq: continuationAfterSeq,
2049
2114
  });
2050
2115
  }
2051
- else if (!singlePage && filled > 0 && client._seqTracker.getContiguousSeq(ns) > afterSeq) {
2116
+ else if (!dissolved && !singlePage && filled > 0 && client._seqTracker.getContiguousSeq(ns) > afterSeq) {
2052
2117
  void this.fillGroupEventGap(groupId);
2053
2118
  }
2054
2119
  if (!client._rpcPipeline)
@@ -2864,7 +2929,8 @@ export class MessageDeliveryEngine {
2864
2929
  return false;
2865
2930
  const client = this.runtime.client;
2866
2931
  const tracker = client._seqTracker;
2867
- const snapshot = typeof tracker.snapshotNamespace === 'function' ? tracker.snapshotNamespace(ns) : null;
2932
+ let snapshot = null;
2933
+ let trackerMutated = false;
2868
2934
  let delivered = false;
2869
2935
  try {
2870
2936
  const selfSync = (event === 'message.received' && this.isSelfSentP2PMessage(payload))
@@ -2879,6 +2945,8 @@ export class MessageDeliveryEngine {
2879
2945
  delivered = true;
2880
2946
  if (!this.inlineGenerationIsCurrent(generation))
2881
2947
  return false;
2948
+ snapshot = typeof tracker.snapshotNamespace === 'function' ? tracker.snapshotNamespace(ns) : null;
2949
+ trackerMutated = true;
2882
2950
  const needsPull = Boolean(tracker.onMessageSeq(ns, seq));
2883
2951
  if (!this.inlineGenerationIsCurrent(generation))
2884
2952
  return false;
@@ -2901,9 +2969,10 @@ export class MessageDeliveryEngine {
2901
2969
  return true;
2902
2970
  }
2903
2971
  catch (exc) {
2904
- if (this.inlineGenerationIsCurrent(generation)
2905
- && typeof tracker.restoreNamespaceSnapshot === 'function')
2906
- tracker.restoreNamespaceSnapshot(ns, snapshot);
2972
+ if (trackerMutated && this.inlineGenerationIsCurrent(generation)
2973
+ && typeof tracker.restoreNamespaceSnapshot === 'function') {
2974
+ (tracker._restoreNamespaceSnapshotPreservingPush ?? tracker.restoreNamespaceSnapshot).call(tracker, ns, snapshot);
2975
+ }
2907
2976
  if (this.inlineGenerationIsCurrent(generation) && delivered)
2908
2977
  this.markPublishedSeq(ns, seq);
2909
2978
  client._clientLog.debug(`inline realtime consume rolled back: ns=${ns} seq=${seq} err=${formatDeliveryError(exc)}`);
@@ -2929,11 +2998,13 @@ export class MessageDeliveryEngine {
2929
2998
  throw new Error('inline realtime terminal cursor did not collapse after consume');
2930
2999
  }
2931
3000
  await client._commitSeqTrackerState(ns);
2932
- return true;
3001
+ return this.inlineGenerationIsCurrent(generation);
2933
3002
  }
2934
3003
  catch (exc) {
2935
- if (typeof tracker.restoreNamespaceSnapshot === 'function')
2936
- tracker.restoreNamespaceSnapshot(ns, snapshot);
3004
+ if (this.inlineGenerationIsCurrent(generation)
3005
+ && typeof tracker.restoreNamespaceSnapshot === 'function') {
3006
+ (tracker._restoreNamespaceSnapshotPreservingPush ?? tracker.restoreNamespaceSnapshot).call(tracker, ns, snapshot);
3007
+ }
2937
3008
  client._clientLog.debug(`inline realtime terminal consume rolled back: ns=${ns} seq=${seq} err=${formatDeliveryError(exc)}`);
2938
3009
  return false;
2939
3010
  }
@@ -3711,8 +3782,9 @@ export class MessageDeliveryEngine {
3711
3782
  }
3712
3783
  return params;
3713
3784
  }
3714
- async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, source = 'push', context) {
3785
+ async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, source = 'push', context, throughSeq) {
3715
3786
  const client = this.runtime.client;
3787
+ const generation = this.captureInlineAckGeneration();
3716
3788
  const pullScoped = this.isPullScopedSource(source);
3717
3789
  if (pullScoped)
3718
3790
  this.ensurePullOperationCurrent(ns);
@@ -3728,11 +3800,11 @@ export class MessageDeliveryEngine {
3728
3800
  this.ensurePullOperationCurrent(ns);
3729
3801
  const contig = client._seqTracker.getContiguousSeq(ns);
3730
3802
  const ready = [...queue.keys()]
3731
- .filter((seq) => seq <= contig && (beforeSeq === undefined || seq < beforeSeq))
3803
+ .filter((seq) => seq <= Math.max(contig, throughSeq ?? contig) && (beforeSeq === undefined || seq < beforeSeq))
3732
3804
  .sort((a, b) => a - b);
3733
3805
  let seq = ready[0];
3734
3806
  if (seq === undefined) {
3735
- const nextSeq = contig + 1;
3807
+ const nextSeq = Math.max(contig, throughSeq ?? contig) + 1;
3736
3808
  if (beforeSeq !== undefined && nextSeq >= beforeSeq)
3737
3809
  break;
3738
3810
  if (!queue.has(nextSeq))
@@ -3742,10 +3814,10 @@ export class MessageDeliveryEngine {
3742
3814
  if (seq === undefined)
3743
3815
  continue;
3744
3816
  const item = queue.get(seq);
3745
- queue.delete(seq);
3746
3817
  if (!item)
3747
3818
  continue;
3748
3819
  if (client._pushedSeqs.get(ns)?.has(seq)) {
3820
+ queue.delete(seq);
3749
3821
  client._clientLog.debug(`publish ordered drain skipped duplicate: ns=${ns}, seq=${seq}, event=${item.event}`);
3750
3822
  client._markOrderedSeqDelivered(ns, seq);
3751
3823
  continue;
@@ -3763,10 +3835,18 @@ export class MessageDeliveryEngine {
3763
3835
  }
3764
3836
  }
3765
3837
  await this.publishOrderedQueueItem(ns, item.event, seq, item.payload, itemSource, pullResponse, itemContext);
3838
+ if (generation !== this.captureInlineAckGeneration())
3839
+ throw new Error('pull invalidated');
3766
3840
  if (pullScoped)
3767
3841
  this.ensurePullOperationCurrent(ns);
3842
+ queue.delete(seq);
3843
+ if (item.event === 'group.changed' && isJsonObject(item.payload)
3844
+ && item.payload.action === 'dissolved')
3845
+ break;
3768
3846
  this.markPublishedSeq(ns, seq);
3769
3847
  client._markOrderedSeqDelivered(ns, seq);
3848
+ if (throughSeq !== undefined)
3849
+ throughSeq = Math.max(throughSeq, seq);
3770
3850
  delivered = true;
3771
3851
  client._clientLog.debug(`publish ordered drain delivered: ns=${ns}, seq=${seq}, event=${item.event}`);
3772
3852
  }
@@ -3810,6 +3890,7 @@ export class MessageDeliveryEngine {
3810
3890
  }
3811
3891
  async publishOrderedMessageInternal(event, ns, seq, payload, source, context) {
3812
3892
  const client = this.runtime.client;
3893
+ const generation = this.captureInlineAckGeneration();
3813
3894
  const pullScoped = this.isPullScopedSource(source);
3814
3895
  if (pullScoped)
3815
3896
  this.ensurePullOperationCurrent(ns);
@@ -3853,12 +3934,14 @@ export class MessageDeliveryEngine {
3853
3934
  return false;
3854
3935
  }
3855
3936
  const queue = client._pendingOrderedMsgs.get(ns);
3856
- queue?.delete(seqNum);
3857
- if (queue && queue.size === 0)
3858
- client._pendingOrderedMsgs.delete(ns);
3859
3937
  await this.publishOrderedQueueItem(ns, event, seqNum, payload, source, false, context);
3938
+ if (generation !== this.captureInlineAckGeneration())
3939
+ throw new Error('pull invalidated');
3860
3940
  if (pullScoped)
3861
3941
  this.ensurePullOperationCurrent(ns);
3942
+ queue?.delete(seqNum);
3943
+ if (queue && queue.size === 0)
3944
+ client._pendingOrderedMsgs.delete(ns);
3862
3945
  this.markPublishedSeq(ns, seqNum);
3863
3946
  client._markOrderedSeqDelivered(ns, seqNum);
3864
3947
  client._clientLog.debug(`publish ordered delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
@@ -3872,6 +3955,7 @@ export class MessageDeliveryEngine {
3872
3955
  }
3873
3956
  async publishPulledMessage(event, ns, seq, payload, persist = true, source = 'pull') {
3874
3957
  const client = this.runtime.client;
3958
+ const generation = this.captureInlineAckGeneration();
3875
3959
  const pullScoped = this.isPullScopedSource(source);
3876
3960
  if (pullScoped)
3877
3961
  this.ensurePullOperationCurrent(ns);
@@ -3907,13 +3991,15 @@ export class MessageDeliveryEngine {
3907
3991
  await this.drainOrderedMessages(ns, seqNum, true, persist, source);
3908
3992
  if (pullScoped)
3909
3993
  this.ensurePullOperationCurrent(ns);
3910
- queue?.delete(seqNum);
3911
- if (queue && queue.size === 0)
3912
- client._pendingOrderedMsgs.delete(ns);
3913
3994
  if (event === 'message.recalled') {
3914
3995
  const recallPublished = await this.publishMessageRecallTombstone(seqNum, payload, source);
3996
+ if (generation !== this.captureInlineAckGeneration())
3997
+ throw new Error('pull invalidated');
3915
3998
  if (pullScoped)
3916
3999
  this.ensurePullOperationCurrent(ns);
4000
+ queue?.delete(seqNum);
4001
+ if (queue && queue.size === 0)
4002
+ client._pendingOrderedMsgs.delete(ns);
3917
4003
  this.markPublishedSeq(ns, seqNum);
3918
4004
  client._clientLog.debug(`publish pulled delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
3919
4005
  await this.drainOrderedMessages(ns, undefined, true, persist, source);
@@ -3924,8 +4010,13 @@ export class MessageDeliveryEngine {
3924
4010
  const published = client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source));
3925
4011
  if (isPromiseLike(published))
3926
4012
  await published;
4013
+ if (generation !== this.captureInlineAckGeneration())
4014
+ throw new Error('pull invalidated');
3927
4015
  if (pullScoped)
3928
4016
  this.ensurePullOperationCurrent(ns);
4017
+ queue?.delete(seqNum);
4018
+ if (queue && queue.size === 0)
4019
+ client._pendingOrderedMsgs.delete(ns);
3929
4020
  this.markPublishedSeq(ns, seqNum);
3930
4021
  client._clientLog.debug(`publish pulled delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
3931
4022
  await this.drainOrderedMessages(ns, undefined, true, persist, source);