@agentunion/fastaun-browser 0.4.13 → 0.5.1

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 (223) hide show
  1. package/CHANGELOG.md +536 -386
  2. package/_packed_docs/CHANGELOG-validators.md +144 -0
  3. package/_packed_docs/CHANGELOG.md +536 -386
  4. package/_packed_docs/INDEX.md +159 -84
  5. package/_packed_docs/KITE_DOCS_GUIDE.md +48 -31
  6. package/_packed_docs/agent.md/SCHEMA.md +2 -0
  7. package/_packed_docs/agent.md/examples/codeagent-claudecode.md +2 -0
  8. package/_packed_docs/agent.md/examples/human-developer.md +2 -0
  9. package/_packed_docs/agent.md/examples/openclaw-lobster.md +2 -0
  10. package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +2 -0
  11. package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +2 -0
  12. package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +266 -686
  13. package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +331 -0
  14. package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +2 -0
  15. package/_packed_docs/design/AUNClient/346/213/206/345/210/206/351/207/215/346/236/204/346/211/247/350/241/214/346/226/271/346/241/210.md +2 -0
  16. package/_packed_docs/design/E2EE_V2/347/256/200/345/214/226/344/270/2721DH/345/212/240Per-AID_Wrap/346/226/271/346/241/210.md +2 -0
  17. package/_packed_docs/design//350/267/250/350/257/255/350/250/200/345/256/271/345/231/250E2E/346/265/213/350/257/225/346/226/271/346/241/210.md +2 -0
  18. package/_packed_docs/protocol/00-/346/200/273/350/247/210/344/270/216/345/210/206/345/261/202.md +2 -0
  19. package/_packed_docs/protocol/00A-/350/256/276/350/256/241/345/216/237/345/210/231-/344/270/272Agent/350/200/214/347/224/237.md +2 -0
  20. 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 +2 -0
  21. package/_packed_docs/protocol/02-/350/257/201/344/271/246/344/270/216/344/277/241/344/273/273/344/275/223/347/263/273.md +2 -0
  22. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +2 -0
  23. package/_packed_docs/protocol/04-Peer-/345/255/220/345/215/217/350/256/256.md +2 -0
  24. package/_packed_docs/protocol/05-Relay-/345/255/220/345/215/217/350/256/256.md +2 -0
  25. 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 +2 -0
  26. package/_packed_docs/protocol/08-AUN-E2EE-Group.md +296 -900
  27. package/_packed_docs/protocol/08-AUN-E2EE.md +2 -0
  28. package/_packed_docs/protocol/09-/345/256/211/345/205/250/350/200/203/350/231/221.md +2 -0
  29. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +66 -173
  30. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +55 -0
  31. package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +2 -0
  32. package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +2 -0
  33. package/_packed_docs/protocol/14-/344/272/244/344/272/222/346/234/272/345/210/266-/345/223/215/345/272/224/346/250/241/345/274/217/344/270/216/350/207/252/344/270/273/346/250/241/345/274/217.md +2 -0
  34. package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +2 -0
  35. package/_packed_docs/protocol/16-/347/263/273/347/273/237/347/233/256/345/275/225/344/277/235/346/212/244/346/226/271/346/241/210.md +177 -0
  36. package/_packed_docs/protocol/README.md +4 -1
  37. package/_packed_docs/protocol/agent.md/SCHEMA.md +2 -0
  38. package/_packed_docs/protocol/agent.md/examples/codeagent-claudecode.md +2 -0
  39. package/_packed_docs/protocol/agent.md/examples/human-developer.md +2 -0
  40. package/_packed_docs/protocol/agent.md/examples/openclaw-lobster.md +2 -0
  41. package/_packed_docs/protocol/aun-docs-guide.md +2 -0
  42. package/_packed_docs/protocol/index.md +10 -3
  43. package/_packed_docs/protocol//350/215/211/346/241/210-agent.md/347/255/276/345/220/215/345/215/217/350/256/256.md +2 -0
  44. package/_packed_docs/protocol//350/215/211/346/241/210-/346/213/222/347/273/235/344/277/241/345/217/267/345/215/217/350/256/256.md +2 -0
  45. package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +2 -0
  46. package/_packed_docs/protocol//351/231/204/345/275/225B-/346/211/251/345/261/225/346/200/247/346/214/207/345/215/227.md +2 -0
  47. package/_packed_docs/protocol//351/231/204/345/275/225C-/347/247/201/351/222/245/347/256/241/347/220/206/344/270/216/350/272/253/344/273/275/346/201/242/345/244/215.md +2 -0
  48. package/_packed_docs/protocol//351/231/204/345/275/225D-Root_CA_/346/262/273/347/220/206/346/234/272/345/210/266.md +2 -0
  49. package/_packed_docs/protocol//351/231/204/345/275/225E-Root_CA_/345/207/206/345/205/245/346/265/201/347/250/213.md +2 -0
  50. package/_packed_docs/protocol//351/231/204/345/275/225F-Issuer_CA_/347/224/263/350/257/267/346/265/201/347/250/213.md +2 -0
  51. package/_packed_docs/protocol//351/231/204/345/275/225G-AID_/345/255/244/345/204/277/351/242/204/351/230/262/344/270/216/346/225/221/346/217/264/346/234/272/345/210/266.md +2 -0
  52. package/_packed_docs/protocol//351/231/204/345/275/225H-Identity/346/234/215/345/212/241/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  53. package/_packed_docs/protocol//351/231/204/345/275/225I-/350/267/250/345/237/237/346/266/210/346/201/257/350/267/257/347/224/261/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  54. package/_packed_docs/protocol//351/231/204/345/275/225J-/345/256/242/346/210/267/347/253/257/346/216/245/345/205/245/347/244/272/344/276/213.md +2 -0
  55. package/_packed_docs/protocol//351/231/204/345/275/225K-Agent_Web/345/217/221/347/216/260/345/215/217/350/256/256.md +2 -0
  56. package/_packed_docs/protocol//351/231/204/345/275/225L-E2EE/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  57. package/_packed_docs/protocol//351/231/204/345/275/225M-JWT/350/256/244/350/257/201/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  58. package/_packed_docs/protocol//351/231/204/345/275/225N-/345/210/206/345/270/203/345/274/217Trace/345/215/217/350/256/256.md +2 -0
  59. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +2 -0
  60. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +2 -0
  61. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +2 -0
  62. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +2 -0
  63. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +6 -252
  64. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +219 -177
  65. package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +4 -1
  66. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +2 -0
  67. package/_packed_docs/sdk/09-collab-rpc-manual.md +581 -0
  68. package/_packed_docs/sdk/09-custody-api-manual.md +2 -0
  69. package/_packed_docs/sdk/09-group-rpc-manual.md +301 -634
  70. package/_packed_docs/sdk/09-message-rpc-manual.md +2 -0
  71. package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -0
  72. package/_packed_docs/sdk/09-payload-reference.md +2 -0
  73. package/_packed_docs/sdk/09-proxy-rpc-manual.md +2 -0
  74. package/_packed_docs/sdk/09-storage-rpc-manual.md +984 -274
  75. package/_packed_docs/sdk/09-stream-rpc-manual.md +2 -0
  76. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +36 -23
  77. package/_packed_docs/sdk/E2EE_V2/346/266/210/346/201/257/351/200/232/344/277/241/346/227/266/345/272/217/345/233/276.md +2 -0
  78. package/_packed_docs/sdk/INDEX.md +47 -30
  79. package/_packed_docs/sdk/Notify/351/200/232/347/237/245/346/226/271/346/241/210.md +2 -0
  80. package/_packed_docs/sdk/README.md +17 -15
  81. package/dist/aid-store.d.ts +25 -0
  82. package/dist/aid-store.d.ts.map +1 -1
  83. package/dist/aid-store.js +89 -8
  84. package/dist/aid-store.js.map +1 -1
  85. package/dist/bundle.js +19615 -16870
  86. package/dist/client/delivery.d.ts +15 -2
  87. package/dist/client/delivery.d.ts.map +1 -1
  88. package/dist/client/delivery.js +303 -54
  89. package/dist/client/delivery.js.map +1 -1
  90. package/dist/client/group-state.d.ts.map +1 -1
  91. package/dist/client/group-state.js +36 -14
  92. package/dist/client/group-state.js.map +1 -1
  93. package/dist/client/lifecycle.js +2 -2
  94. package/dist/client/lifecycle.js.map +1 -1
  95. package/dist/client/rpc-pipeline.d.ts +2 -0
  96. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  97. package/dist/client/rpc-pipeline.js +235 -82
  98. package/dist/client/rpc-pipeline.js.map +1 -1
  99. package/dist/client/v2-e2ee.d.ts +14 -1
  100. package/dist/client/v2-e2ee.d.ts.map +1 -1
  101. package/dist/client/v2-e2ee.js +300 -121
  102. package/dist/client/v2-e2ee.js.map +1 -1
  103. package/dist/client.d.ts +36 -4
  104. package/dist/client.d.ts.map +1 -1
  105. package/dist/client.js +460 -57
  106. package/dist/client.js.map +1 -1
  107. package/dist/collab/client.d.ts +47 -0
  108. package/dist/collab/client.d.ts.map +1 -0
  109. package/dist/collab/client.js +136 -0
  110. package/dist/collab/client.js.map +1 -0
  111. package/dist/collab/errors.d.ts +16 -0
  112. package/dist/collab/errors.d.ts.map +1 -0
  113. package/dist/collab/errors.js +60 -0
  114. package/dist/collab/errors.js.map +1 -0
  115. package/dist/collab/index.d.ts +4 -0
  116. package/dist/collab/index.d.ts.map +1 -0
  117. package/dist/collab/index.js +4 -0
  118. package/dist/collab/index.js.map +1 -0
  119. package/dist/collab/types.d.ts +111 -0
  120. package/dist/collab/types.d.ts.map +1 -0
  121. package/dist/collab/types.js +2 -0
  122. package/dist/collab/types.js.map +1 -0
  123. package/dist/crypto.d.ts +6 -0
  124. package/dist/crypto.d.ts.map +1 -1
  125. package/dist/crypto.js +6 -0
  126. package/dist/crypto.js.map +1 -1
  127. package/dist/errors.d.ts +0 -20
  128. package/dist/errors.d.ts.map +1 -1
  129. package/dist/errors.js +9 -37
  130. package/dist/errors.js.map +1 -1
  131. package/dist/facades.d.ts +94 -0
  132. package/dist/facades.d.ts.map +1 -0
  133. package/dist/facades.js +389 -0
  134. package/dist/facades.js.map +1 -0
  135. package/dist/group-fs.d.ts +120 -0
  136. package/dist/group-fs.d.ts.map +1 -0
  137. package/dist/group-fs.js +539 -0
  138. package/dist/group-fs.js.map +1 -0
  139. package/dist/group-id.d.ts +9 -12
  140. package/dist/group-id.d.ts.map +1 -1
  141. package/dist/group-id.js +41 -63
  142. package/dist/group-id.js.map +1 -1
  143. package/dist/group-resources.d.ts +98 -0
  144. package/dist/group-resources.d.ts.map +1 -0
  145. package/dist/group-resources.js +635 -0
  146. package/dist/group-resources.js.map +1 -0
  147. package/dist/index.d.ts +8 -3
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +10 -1
  150. package/dist/index.js.map +1 -1
  151. package/dist/keystore/index.d.ts +2 -54
  152. package/dist/keystore/index.d.ts.map +1 -1
  153. package/dist/keystore/indexeddb-identity-store.d.ts +3 -0
  154. package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
  155. package/dist/keystore/indexeddb-identity-store.js +65 -0
  156. package/dist/keystore/indexeddb-identity-store.js.map +1 -1
  157. package/dist/keystore/indexeddb-shared.d.ts +3 -17
  158. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  159. package/dist/keystore/indexeddb-shared.js +4 -47
  160. package/dist/keystore/indexeddb-shared.js.map +1 -1
  161. package/dist/keystore/indexeddb-token-store.d.ts +1 -64
  162. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  163. package/dist/keystore/indexeddb-token-store.js +45 -774
  164. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  165. package/dist/logger.d.ts +2 -0
  166. package/dist/logger.d.ts.map +1 -1
  167. package/dist/logger.js +4 -0
  168. package/dist/logger.js.map +1 -1
  169. package/dist/register-flow.d.ts +1 -0
  170. package/dist/register-flow.d.ts.map +1 -1
  171. package/dist/register-flow.js +3 -0
  172. package/dist/register-flow.js.map +1 -1
  173. package/dist/service-proxy.d.ts +1 -0
  174. package/dist/service-proxy.d.ts.map +1 -1
  175. package/dist/service-proxy.js +15 -3
  176. package/dist/service-proxy.js.map +1 -1
  177. package/dist/storage/errors.d.ts +28 -0
  178. package/dist/storage/errors.d.ts.map +1 -0
  179. package/dist/storage/errors.js +65 -0
  180. package/dist/storage/errors.js.map +1 -0
  181. package/dist/storage/index.d.ts +2 -0
  182. package/dist/storage/index.d.ts.map +1 -0
  183. package/dist/storage/index.js +2 -0
  184. package/dist/storage/index.js.map +1 -0
  185. package/dist/storage/lowlevel.d.ts +322 -0
  186. package/dist/storage/lowlevel.d.ts.map +1 -0
  187. package/dist/storage/lowlevel.js +471 -0
  188. package/dist/storage/lowlevel.js.map +1 -0
  189. package/dist/storage/types.d.ts +59 -0
  190. package/dist/storage/types.d.ts.map +1 -0
  191. package/dist/storage/types.js +113 -0
  192. package/dist/storage/types.js.map +1 -0
  193. package/dist/storage/vfs.d.ts +166 -0
  194. package/dist/storage/vfs.d.ts.map +1 -0
  195. package/dist/storage/vfs.js +457 -0
  196. package/dist/storage/vfs.js.map +1 -0
  197. package/dist/tools/cross-sdk-agent.d.ts +3 -0
  198. package/dist/tools/cross-sdk-agent.d.ts.map +1 -0
  199. package/dist/tools/cross-sdk-agent.js +1376 -0
  200. package/dist/tools/cross-sdk-agent.js.map +1 -0
  201. package/dist/transport.d.ts +5 -0
  202. package/dist/transport.d.ts.map +1 -1
  203. package/dist/transport.js +125 -12
  204. package/dist/transport.js.map +1 -1
  205. package/dist/types.d.ts +39 -56
  206. package/dist/types.d.ts.map +1 -1
  207. package/dist/v2/session/session.d.ts +2 -0
  208. package/dist/v2/session/session.d.ts.map +1 -1
  209. package/dist/v2/session/session.js +58 -22
  210. package/dist/v2/session/session.js.map +1 -1
  211. package/dist/v2/state/commitment.d.ts +1 -1
  212. package/dist/v2/state/commitment.d.ts.map +1 -1
  213. package/dist/v2/state/commitment.js +5 -3
  214. package/dist/v2/state/commitment.js.map +1 -1
  215. package/dist/validators.d.ts +35 -0
  216. package/dist/validators.d.ts.map +1 -0
  217. package/dist/validators.js +127 -0
  218. package/dist/validators.js.map +1 -0
  219. package/dist/version.d.ts +1 -1
  220. package/dist/version.d.ts.map +1 -1
  221. package/dist/version.js +1 -1
  222. package/dist/version.js.map +1 -1
  223. package/package.json +44 -44
@@ -1,9 +1,13 @@
1
1
  import { slotIsolationKey } from '../config.js';
2
2
  import { normalizeGroupId } from '../group-id.js';
3
- import { isJsonObject } from '../types.js';
3
+ import { ConnectionState, isJsonObject } from '../types.js';
4
4
  const PUSHED_SEQS_LIMIT = 50_000;
5
5
  const PENDING_ORDERED_LIMIT = 50_000;
6
6
  const GROUP_RECALL_SEEN_LIMIT = 10_000;
7
+ const SEQ_TRACKER_PERSIST_FLUSH_DELAY_MS = 200;
8
+ const P2P_GAP_FILL_RETRY_LIMIT = 12;
9
+ const P2P_GAP_FILL_RETRY_BASE_MS = 1000;
10
+ const P2P_GAP_FILL_RETRY_MAX_MS = 5000;
7
11
  const APP_MESSAGE_ENVELOPE_KEYS = [
8
12
  'module_id', 'message_type', 'type', 'kind', 'version',
9
13
  'from', 'from_aid', 'sender_aid', 'to', 'to_aid', 'group_id',
@@ -24,6 +28,33 @@ const APP_GROUP_EVENT_ENVELOPE_KEYS = [
24
28
  function formatDeliveryError(error) {
25
29
  return error instanceof Error ? error : String(error);
26
30
  }
31
+ function isTransientGapFillError(error) {
32
+ const text = (error instanceof Error ? error.message : String(error)).toLowerCase();
33
+ return text.includes('no_service')
34
+ || text.includes('service plane unavailable')
35
+ || text.includes('transport not connected')
36
+ || text.includes('transport closed')
37
+ || text.includes('websocket closed')
38
+ || text.includes('websocket is not open')
39
+ || text.includes('connection closed')
40
+ || text.includes('socket closed');
41
+ }
42
+ function p2pAppEventFromPlainPullMessage(message) {
43
+ const payload = message.payload;
44
+ const payloadType = isJsonObject(payload)
45
+ ? String(payload.type ?? '').trim()
46
+ : '';
47
+ if (payloadType === 'message.recalled' || payloadType === 'message.recall' || message.type === 'message.recalled') {
48
+ return {
49
+ event: 'message.recalled',
50
+ payload: {
51
+ ...message,
52
+ ...(isJsonObject(payload) ? payload : {}),
53
+ },
54
+ };
55
+ }
56
+ return { event: 'message.received', payload: message };
57
+ }
27
58
  export class MessageDeliveryEngine {
28
59
  runtime;
29
60
  constructor(runtime) {
@@ -52,6 +83,34 @@ export class MessageDeliveryEngine {
52
83
  client._pushedSeqs.set(ns, new Set(keep));
53
84
  }
54
85
  }
86
+ fireGroupEventAck(groupId, ns, eventSeq, label) {
87
+ const client = this.runtime.client;
88
+ const ackSeq = this.clampAckSeq('group.ack_events', 'event_seq', ns, eventSeq);
89
+ if (ackSeq <= 0)
90
+ return;
91
+ void client.call('group.ack_events', {
92
+ group_id: groupId,
93
+ event_seq: ackSeq,
94
+ device_id: client._deviceId,
95
+ slot_id: client._slotId,
96
+ _rpc_background: true,
97
+ }).catch((e) => {
98
+ client._clientLog.warn(`${label} failed: group=${groupId}`, e);
99
+ });
100
+ }
101
+ fireGroupV2Ack(groupId, ns, seq, label) {
102
+ const client = this.runtime.client;
103
+ const ackSeq = this.clampAckSeq('group.v2.ack', 'up_to_seq', ns, seq);
104
+ if (ackSeq <= 0)
105
+ return;
106
+ void client._callRawV2Rpc('group.v2.ack', {
107
+ group_id: groupId,
108
+ up_to_seq: ackSeq,
109
+ _rpc_background: true,
110
+ }).catch((e) => {
111
+ client._clientLog.debug(`${label} failed: group=${groupId} seq=${ackSeq} err=${String(e)}`);
112
+ });
113
+ }
55
114
  enqueueOrderedMessage(ns, event, seq, payload) {
56
115
  const client = this.runtime.client;
57
116
  let queue = client._pendingOrderedMsgs.get(ns);
@@ -83,7 +142,8 @@ export class MessageDeliveryEngine {
83
142
  const eventPayload = payload;
84
143
  client._groupState?.handleGroupChangedV2Membership?.(eventPayload);
85
144
  if (eventPayload.action === 'dissolved') {
86
- const groupId = normalizeGroupId(String(eventPayload.group_id ?? '')) || String(eventPayload.group_id ?? '').trim();
145
+ const rawGroupId = eventPayload.group_aid ?? eventPayload.group_id ?? '';
146
+ const groupId = normalizeGroupId(String(rawGroupId)) || String(rawGroupId).trim();
87
147
  if (groupId)
88
148
  client._cleanupDissolvedGroup?.(groupId);
89
149
  }
@@ -478,10 +538,11 @@ export class MessageDeliveryEngine {
478
538
  msg_seq: ackSeq,
479
539
  device_id: client._deviceId,
480
540
  slot_id: client._slotId,
541
+ _rpc_background: true,
481
542
  }).catch((e) => { client._clientLog.warn('group recall auto-ack failed: group=' + groupId, e); });
482
543
  }
483
544
  if (contig !== contigBefore)
484
- this.saveSeqTrackerState();
545
+ this.persistSeq(ns);
485
546
  }
486
547
  async publishAppEvent(event, payload) {
487
548
  const client = this.runtime.client;
@@ -564,10 +625,11 @@ export class MessageDeliveryEngine {
564
625
  seq: ackSeq,
565
626
  device_id: client._deviceId,
566
627
  slot_id: client._slotId,
628
+ _rpc_background: true,
567
629
  }).catch((e) => { client._clientLog.warn(`P2P auto-ack failed:${String(e)}`); });
568
630
  }
569
631
  if (contigAfter !== contigBefore)
570
- this.saveSeqTrackerState();
632
+ this.persistSeq(ns);
571
633
  if (encryptedPush)
572
634
  return;
573
635
  }
@@ -641,10 +703,11 @@ export class MessageDeliveryEngine {
641
703
  msg_seq: ackSeq,
642
704
  device_id: client._deviceId,
643
705
  slot_id: client._slotId,
706
+ _rpc_background: true,
644
707
  }).catch((e) => { client._clientLog.warn('group recall auto-ack failed: group=' + groupId, e); });
645
708
  }
646
709
  if (contigAfter !== contigBefore)
647
- this.saveSeqTrackerState();
710
+ this.persistSeq(ns);
648
711
  return;
649
712
  }
650
713
  const published = encryptedPush
@@ -663,10 +726,11 @@ export class MessageDeliveryEngine {
663
726
  msg_seq: ackSeq,
664
727
  device_id: client._deviceId,
665
728
  slot_id: client._slotId,
729
+ _rpc_background: true,
666
730
  }).catch((e) => { client._clientLog.warn('group message auto-ack failed: group=' + groupId, e); });
667
731
  }
668
732
  if (contigAfter !== contigBefore)
669
- this.saveSeqTrackerState();
733
+ this.persistSeq(ns);
670
734
  if (encryptedPush)
671
735
  return;
672
736
  }
@@ -706,7 +770,7 @@ export class MessageDeliveryEngine {
706
770
  const afterSeq = client._seqTracker.getContiguousSeq(ns);
707
771
  try {
708
772
  if (client._v2Session) {
709
- await client._pullGroupV2Internal({ group_id: groupId, after_seq: afterSeq, limit: 50 });
773
+ await client._withBackgroundRpc(() => client._pullGroupV2Internal({ group_id: groupId, after_seq: afterSeq, limit: 50 }));
710
774
  return;
711
775
  }
712
776
  const result = await client.call('group.pull', {
@@ -714,6 +778,7 @@ export class MessageDeliveryEngine {
714
778
  after_message_seq: afterSeq,
715
779
  device_id: client._deviceId,
716
780
  limit: 50,
781
+ _rpc_background: true,
717
782
  });
718
783
  if (isJsonObject(result)) {
719
784
  const messages = result.messages;
@@ -752,9 +817,26 @@ export class MessageDeliveryEngine {
752
817
  }
753
818
  await client._publishAppEvent('group.message_created', notification);
754
819
  }
755
- async fillP2pGap() {
820
+ scheduleP2pGapRetry(ns, retryAttempt) {
821
+ const client = this.runtime.client;
822
+ if (retryAttempt > P2P_GAP_FILL_RETRY_LIMIT)
823
+ return;
824
+ const retryKey = `p2p_pull_retry:${ns}`;
825
+ if (client._gapFillDone.has(retryKey))
826
+ return;
827
+ const delayMs = Math.min(P2P_GAP_FILL_RETRY_BASE_MS * retryAttempt, P2P_GAP_FILL_RETRY_MAX_MS);
828
+ client._gapFillDone.add(retryKey);
829
+ client._clientLog.debug(`P2P message gap-fill retry scheduled: ns=${ns} attempt=${retryAttempt} delay_ms=${delayMs}`);
830
+ globalThis.setTimeout(() => {
831
+ client._gapFillDone.delete(retryKey);
832
+ if (client.state !== ConnectionState.READY || client._closing)
833
+ return;
834
+ client._safeAsync(this.fillP2pGap(retryAttempt));
835
+ }, delayMs);
836
+ }
837
+ async fillP2pGap(retryAttempt = 0) {
756
838
  const client = this.runtime.client;
757
- if (client._state !== 'connected' || client._closing)
839
+ if (client.state !== ConnectionState.READY || client._closing)
758
840
  return;
759
841
  if (!client._aid)
760
842
  return;
@@ -767,24 +849,64 @@ export class MessageDeliveryEngine {
767
849
  this.runtime.delivery.setGapFillActive(true);
768
850
  let filled = 0;
769
851
  try {
770
- const messages = await client._pullV2(afterSeq, 50);
852
+ const messages = await client._withBackgroundRpc(() => client._pullV2(afterSeq, 50));
771
853
  filled = messages.length;
772
854
  this.prunePushedSeqs(ns);
773
855
  }
774
856
  catch (exc) {
775
- client._clientLog.warn(`P2P message gap-fill failed:${String(formatDeliveryError(exc))}`);
857
+ const transient = isTransientGapFillError(exc);
858
+ if (transient) {
859
+ try {
860
+ filled = await this.fillP2pGapWithPlainPull(ns, afterSeq);
861
+ this.prunePushedSeqs(ns);
862
+ client._clientLog.warn(`P2P message gap-fill V2 unavailable, used plain pull fallback:${String(formatDeliveryError(exc))}`);
863
+ }
864
+ catch (fallbackExc) {
865
+ client._clientLog.warn(`P2P message gap-fill plain fallback failed:${String(formatDeliveryError(fallbackExc))}`);
866
+ this.scheduleP2pGapRetry(ns, retryAttempt + 1);
867
+ }
868
+ }
869
+ else {
870
+ client._clientLog.warn(`P2P message gap-fill failed:${String(formatDeliveryError(exc))}`);
871
+ }
776
872
  }
777
873
  finally {
778
874
  client._gapFillDone.delete(dedupKey);
779
875
  this.runtime.delivery.setGapFillActive(false);
780
- if (filled > 0 && client._seqTracker.getContiguousSeq(ns) > afterSeq) {
781
- client._safeAsync(this.fillP2pGap());
876
+ }
877
+ }
878
+ async fillP2pGapWithPlainPull(ns, afterSeq) {
879
+ const client = this.runtime.client;
880
+ const params = {
881
+ after_seq: afterSeq,
882
+ limit: 50,
883
+ device_id: client._deviceId,
884
+ slot_id: client._slotId,
885
+ _rpc_background: true,
886
+ };
887
+ const raw = await client._transport.call('message.pull', params, undefined, undefined, true);
888
+ const result = typeof client._rpcPipeline?.postprocessResult === 'function'
889
+ ? await client._rpcPipeline.postprocessResult('message.pull', params, raw)
890
+ : raw;
891
+ const messages = (isJsonObject(result) && Array.isArray(result.messages))
892
+ ? result.messages
893
+ : [];
894
+ let published = 0;
895
+ for (const item of messages) {
896
+ if (!isJsonObject(item))
897
+ continue;
898
+ const msg = item;
899
+ const seq = Number(msg.seq ?? 0);
900
+ const appEvent = p2pAppEventFromPlainPullMessage(msg);
901
+ if (await this.publishPulledMessage(appEvent.event, ns, seq, appEvent.payload)) {
902
+ published += 1;
782
903
  }
783
904
  }
905
+ return published;
784
906
  }
785
907
  async fillGroupGap(groupId) {
786
908
  const client = this.runtime.client;
787
- if (client._state !== 'connected' || client._closing)
909
+ if (client.state !== ConnectionState.READY || client._closing)
788
910
  return;
789
911
  groupId = normalizeGroupId(groupId) || String(groupId ?? '').trim();
790
912
  if (!groupId)
@@ -798,7 +920,7 @@ export class MessageDeliveryEngine {
798
920
  this.runtime.delivery.setGapFillActive(true);
799
921
  let filled = 0;
800
922
  try {
801
- const messages = await client._pullGroupV2(groupId, afterSeq, 50);
923
+ const messages = await client._withBackgroundRpc(() => client._pullGroupV2(groupId, afterSeq, 50));
802
924
  filled = messages.length;
803
925
  this.prunePushedSeqs(ns);
804
926
  }
@@ -815,7 +937,10 @@ export class MessageDeliveryEngine {
815
937
  }
816
938
  async fillGroupEventGap(groupId) {
817
939
  const client = this.runtime.client;
818
- if (client._state !== 'connected' || client._closing)
940
+ if (client.state !== ConnectionState.READY || client._closing)
941
+ return;
942
+ groupId = normalizeGroupId(groupId) || String(groupId ?? '').trim();
943
+ if (!groupId)
819
944
  return;
820
945
  const ns = `group_event:${groupId}`;
821
946
  const afterSeq = client._seqTracker.getContiguousSeq(ns);
@@ -835,6 +960,7 @@ export class MessageDeliveryEngine {
835
960
  after_event_seq: nextAfterSeq,
836
961
  device_id: client._deviceId,
837
962
  limit: 50,
963
+ _rpc_background: true,
838
964
  });
839
965
  if (!isJsonObject(result))
840
966
  return;
@@ -884,7 +1010,7 @@ export class MessageDeliveryEngine {
884
1010
  const ackContig = client._seqTracker.getContiguousSeq(ns);
885
1011
  await this.drainOrderedMessages(ns);
886
1012
  if (ackContig !== pageContigBefore && !hasDissolvedEvent) {
887
- this.saveSeqTrackerState();
1013
+ this.persistSeq(ns);
888
1014
  }
889
1015
  if (eventObjects.length > 0 && ackContig > 0 && ackContig !== pageContigBefore) {
890
1016
  const ackSeq = this.clampAckSeq('group.ack_events', 'event_seq', ns, ackContig);
@@ -893,6 +1019,7 @@ export class MessageDeliveryEngine {
893
1019
  event_seq: ackSeq,
894
1020
  device_id: client._deviceId,
895
1021
  slot_id: client._slotId,
1022
+ _rpc_background: true,
896
1023
  }).catch((e) => { client._clientLog.warn('group event auto-ack failed: group=' + groupId, e); });
897
1024
  }
898
1025
  const nextAfter = Math.max(eventSeqs.length > 0 ? Math.max(...eventSeqs) : nextAfterSeq, nextAfterSeq);
@@ -914,6 +1041,7 @@ export class MessageDeliveryEngine {
914
1041
  }
915
1042
  async handleGroupChangedEventSeq(data, groupId) {
916
1043
  const client = this.runtime.client;
1044
+ groupId = normalizeGroupId(groupId) || String(groupId ?? '').trim();
917
1045
  let needPull = false;
918
1046
  const rawEventSeq = data.event_seq;
919
1047
  const eventSeq = Number(rawEventSeq);
@@ -931,8 +1059,15 @@ export class MessageDeliveryEngine {
931
1059
  }
932
1060
  }
933
1061
  const contigBefore = client._seqTracker.getContiguousSeq(ns);
934
- if (eventSeq <= contigBefore || client._pushedSeqs.get(ns)?.has(eventSeq)) {
1062
+ const publishedDuplicate = client._pushedSeqs.get(ns)?.has(eventSeq) === true;
1063
+ if (eventSeq <= contigBefore || publishedDuplicate) {
935
1064
  client._clientLog.debug(`group.changed skipped duplicate/stale: group=${groupId}, event_seq=${eventSeq}, contiguous=${contigBefore}`);
1065
+ if (eventSeq <= contigBefore) {
1066
+ this.fireGroupEventAck(groupId, ns, eventSeq, 'group event covered push ack');
1067
+ }
1068
+ else if (contigBefore > 0) {
1069
+ this.fireGroupEventAck(groupId, ns, contigBefore, 'group event covered push ack');
1070
+ }
936
1071
  return;
937
1072
  }
938
1073
  this.enqueueOrderedMessage(ns, 'group.changed', eventSeq, data);
@@ -941,13 +1076,14 @@ export class MessageDeliveryEngine {
941
1076
  await this.drainOrderedMessages(ns);
942
1077
  if (ackContig > 0 && ackContig !== contigBefore) {
943
1078
  if (data.action !== 'dissolved')
944
- this.saveSeqTrackerState();
1079
+ this.persistSeq(ns);
945
1080
  const ackSeq = this.clampAckSeq('group.ack_events', 'event_seq', ns, ackContig);
946
1081
  client._transport.call('group.ack_events', {
947
1082
  group_id: groupId,
948
1083
  event_seq: ackSeq,
949
1084
  device_id: client._deviceId,
950
1085
  slot_id: client._slotId,
1086
+ _rpc_background: true,
951
1087
  }).catch((e) => {
952
1088
  client._clientLog.warn('group event push auto-ack failed: group=' + groupId, e);
953
1089
  });
@@ -990,7 +1126,7 @@ export class MessageDeliveryEngine {
990
1126
  this.runtime.delivery.setOnlineUnreadHintDrainActive(true);
991
1127
  try {
992
1128
  while (client._onlineUnreadHintQueue.size > 0) {
993
- if (client.state !== 'ready')
1129
+ if (client.state !== ConnectionState.READY)
994
1130
  return;
995
1131
  if (client._sessionOptions?.background_sync === false)
996
1132
  return;
@@ -1048,8 +1184,9 @@ export class MessageDeliveryEngine {
1048
1184
  const ns = `group:${groupId}`;
1049
1185
  client._seqTracker.updateMaxSeen(ns, seq);
1050
1186
  const contigBefore = client._seqTracker.getContiguousSeq(ns);
1051
- if (contigBefore === seq) {
1187
+ if (contigBefore === seq || (eventKind === 'group.online_unread_hint' && contigBefore > seq)) {
1052
1188
  client._clientLog.debug(`_onRawGroupV2MessageCreated duplicate push already covered: group=${groupId} seq=${seq}`);
1189
+ this.fireGroupV2Ack(groupId, ns, seq, 'group v2 covered push ack');
1053
1190
  return;
1054
1191
  }
1055
1192
  const afterSeq = client._repairPushContiguousBound(ns, seq, false, '_raw.group.v2.message_created');
@@ -1061,7 +1198,7 @@ export class MessageDeliveryEngine {
1061
1198
  client._gapFillDone.add(dedupKey);
1062
1199
  try {
1063
1200
  client._clientLog.debug(`_onRawGroupV2MessageCreated -> group.v2.pull group=${groupId} after_seq=${afterSeq}`);
1064
- const messages = await client._pullGroupV2(groupId, afterSeq, 50);
1201
+ const messages = await client._withBackgroundRpc(() => client._pullGroupV2(groupId, afterSeq, 50));
1065
1202
  client._clientLog.debug(`_onRawGroupV2MessageCreated pulled ${messages.length} msgs for group=${groupId}`);
1066
1203
  }
1067
1204
  finally {
@@ -1103,12 +1240,12 @@ export class MessageDeliveryEngine {
1103
1240
  const published = await client._publishOrderedMessage('message.received', ns, pushSeq, decrypted);
1104
1241
  const newContig = client._seqTracker.getContiguousSeq(ns);
1105
1242
  if (newContig !== contigBefore) {
1106
- client._saveSeqTrackerState();
1243
+ this.persistSeq(ns);
1107
1244
  }
1108
1245
  if (newContig > 0 && newContig !== contigBefore) {
1109
1246
  const ackSeq = this.clampAckSeq('message.v2.ack', 'up_to_seq', ns, newContig);
1110
1247
  try {
1111
- await client._callRawV2Rpc('message.v2.ack', { up_to_seq: ackSeq });
1248
+ await client._callRawV2Rpc('message.v2.ack', { up_to_seq: ackSeq, _rpc_background: true });
1112
1249
  }
1113
1250
  catch (e) {
1114
1251
  client._clientLog.debug(`V2 P2P push-ack failed: ${e}`);
@@ -1138,7 +1275,7 @@ export class MessageDeliveryEngine {
1138
1275
  try {
1139
1276
  do {
1140
1277
  this.runtime.delivery.setV2PullPending(false);
1141
- await client._pullV2();
1278
+ await client._withBackgroundRpc(() => client._pullV2());
1142
1279
  const newContig = ns ? client._seqTracker.getContiguousSeq(ns) : -1;
1143
1280
  client._clientLog.debug(`_onV2PushNotification pull done: contiguous_seq=${contigBefore}->${newContig} (push_seq=${pushSeq || 'null'})`);
1144
1281
  } while (client._v2PullPending);
@@ -1265,50 +1402,141 @@ export class MessageDeliveryEngine {
1265
1402
  }
1266
1403
  return newState;
1267
1404
  }
1268
- saveSeqTrackerState() {
1405
+ async saveSeqTrackerState() {
1269
1406
  const client = this.runtime.client;
1270
- if (!client._aid)
1407
+ const context = this.currentSeqTrackerContext();
1408
+ if (!context) {
1409
+ await this.flushSeqTrackerPending();
1271
1410
  return;
1411
+ }
1272
1412
  const state = client._seqTracker.exportState();
1273
- if (Object.keys(state).length === 0)
1413
+ const pending = this.seqTrackerPending();
1414
+ if (pending.size > 0 && client._seqTrackerPendingPersistContext === context) {
1415
+ const liveNamespaces = new Set(Object.keys(state));
1416
+ for (const ns of [...pending.keys()]) {
1417
+ if (!liveNamespaces.has(ns))
1418
+ pending.delete(ns);
1419
+ }
1420
+ if (pending.size === 0)
1421
+ client._seqTrackerPendingPersistContext = null;
1422
+ }
1423
+ if (Object.keys(state).length > 0)
1424
+ this.mergeSeqTrackerPending(context, state);
1425
+ await this.flushSeqTrackerPending();
1426
+ }
1427
+ persistSeq(ns, forceSeq) {
1428
+ const client = this.runtime.client;
1429
+ const context = this.currentSeqTrackerContext();
1430
+ if (!context) {
1431
+ void this.flushSeqTrackerPending();
1432
+ return;
1433
+ }
1434
+ const seq = forceSeq ?? client._seqTracker.getContiguousSeq(ns);
1435
+ if (!ns || !Number.isFinite(seq) || seq <= 0)
1436
+ return;
1437
+ if (forceSeq !== undefined) {
1438
+ client._seqTracker.forceContiguousSeq(ns, seq);
1439
+ }
1440
+ this.mergeSeqTrackerPending(context, { [ns]: seq });
1441
+ this.scheduleSeqTrackerFlush();
1442
+ }
1443
+ async flushSeqTrackerPending() {
1444
+ const client = this.runtime.client;
1445
+ this.cancelSeqTrackerFlushTimer();
1446
+ const context = client._seqTrackerPendingPersistContext;
1447
+ const pending = this.seqTrackerPending();
1448
+ if (!context || pending.size === 0) {
1449
+ client._seqTrackerPendingPersistContext = null;
1450
+ return;
1451
+ }
1452
+ const [aid, deviceId, slotId] = JSON.parse(context);
1453
+ const state = Object.fromEntries(pending.entries());
1454
+ pending.clear();
1455
+ client._seqTrackerPendingPersistContext = null;
1456
+ await this.writeSeqTrackerState(aid, deviceId, slotId, state);
1457
+ }
1458
+ dropSeqTrackerPending(ns) {
1459
+ const client = this.runtime.client;
1460
+ const pending = this.seqTrackerPending();
1461
+ pending.delete(ns);
1462
+ if (pending.size === 0) {
1463
+ client._seqTrackerPendingPersistContext = null;
1464
+ this.cancelSeqTrackerFlushTimer();
1465
+ }
1466
+ }
1467
+ currentSeqTrackerContext() {
1468
+ const client = this.runtime.client;
1469
+ if (!client._aid)
1470
+ return null;
1471
+ return JSON.stringify([client._aid, client._deviceId, client._slotId]);
1472
+ }
1473
+ seqTrackerPending() {
1474
+ const client = this.runtime.client;
1475
+ if (!(client._seqTrackerPendingPersist instanceof Map)) {
1476
+ client._seqTrackerPendingPersist = new Map();
1477
+ }
1478
+ return client._seqTrackerPendingPersist;
1479
+ }
1480
+ mergeSeqTrackerPending(context, state) {
1481
+ const client = this.runtime.client;
1482
+ const pending = this.seqTrackerPending();
1483
+ const pendingContext = client._seqTrackerPendingPersistContext;
1484
+ if (pendingContext && pendingContext !== context && pending.size > 0) {
1485
+ void this.flushSeqTrackerPending();
1486
+ }
1487
+ client._seqTrackerPendingPersistContext = context;
1488
+ for (const [ns, seq] of Object.entries(state)) {
1489
+ const seqNum = Number(seq);
1490
+ if (ns && Number.isFinite(seqNum) && seqNum > 0) {
1491
+ pending.set(ns, seqNum);
1492
+ }
1493
+ }
1494
+ }
1495
+ scheduleSeqTrackerFlush() {
1496
+ const client = this.runtime.client;
1497
+ const pending = this.seqTrackerPending();
1498
+ if (pending.size === 0)
1499
+ return;
1500
+ if (client._seqTrackerFlushTimer)
1501
+ return;
1502
+ client._seqTrackerFlushTimer = setTimeout(() => {
1503
+ client._seqTrackerFlushTimer = null;
1504
+ void this.flushSeqTrackerPending();
1505
+ }, SEQ_TRACKER_PERSIST_FLUSH_DELAY_MS);
1506
+ }
1507
+ cancelSeqTrackerFlushTimer() {
1508
+ const client = this.runtime.client;
1509
+ if (client._seqTrackerFlushTimer) {
1510
+ clearTimeout(client._seqTrackerFlushTimer);
1511
+ client._seqTrackerFlushTimer = null;
1512
+ }
1513
+ }
1514
+ async writeSeqTrackerState(aid, deviceId, slotId, state) {
1515
+ const client = this.runtime.client;
1516
+ if (!aid || Object.keys(state).length === 0)
1274
1517
  return;
1275
1518
  try {
1276
1519
  const saveFn = client._tokenStore.saveSeq?.bind(client._tokenStore);
1277
1520
  if (typeof saveFn === 'function') {
1278
- for (const [ns, seq] of Object.entries(state)) {
1279
- saveFn(client._aid, client._deviceId, client._slotId, ns, seq).catch((exc) => {
1280
- client._dispatcher.publish('seq_tracker.persist_error', {
1281
- phase: 'save',
1282
- aid: client._aid,
1283
- device_id: client._deviceId,
1284
- slot_id: client._slotId,
1285
- error: String(exc),
1286
- }).catch(() => { });
1287
- });
1288
- }
1521
+ await Promise.all(Object.entries(state).map(([ns, seq]) => saveFn(aid, deviceId, slotId, ns, seq)));
1289
1522
  return;
1290
1523
  }
1291
1524
  if (typeof client._tokenStore.updateInstanceState === 'function') {
1292
- client._tokenStore.updateInstanceState(client._aid, client._deviceId, client._slotId, (current) => {
1293
- current.seq_tracker_state = state;
1525
+ await client._tokenStore.updateInstanceState(aid, deviceId, slotId, (current) => {
1526
+ const existing = isJsonObject(current.seq_tracker_state)
1527
+ ? { ...current.seq_tracker_state }
1528
+ : {};
1529
+ current.seq_tracker_state = { ...existing, ...state };
1294
1530
  return current;
1295
- }).catch((exc) => {
1296
- client._dispatcher.publish('seq_tracker.persist_error', {
1297
- phase: 'save',
1298
- aid: client._aid,
1299
- device_id: client._deviceId,
1300
- slot_id: client._slotId,
1301
- error: String(exc),
1302
- }).catch(() => { });
1303
1531
  });
1304
1532
  }
1305
1533
  }
1306
1534
  catch (exc) {
1307
1535
  client._dispatcher.publish('seq_tracker.persist_error', {
1308
1536
  phase: 'save',
1309
- aid: client._aid,
1310
- device_id: client._deviceId,
1311
- slot_id: client._slotId,
1537
+ aid,
1538
+ device_id: deviceId,
1539
+ slot_id: slotId,
1312
1540
  error: String(exc),
1313
1541
  }).catch(() => { });
1314
1542
  }
@@ -1318,6 +1546,7 @@ export class MessageDeliveryEngine {
1318
1546
  if (!client._aid || !ns)
1319
1547
  return;
1320
1548
  const seq = client._seqTracker.getContiguousSeq(ns);
1549
+ this.dropSeqTrackerPending(ns);
1321
1550
  try {
1322
1551
  if (seq > 0 && typeof client._tokenStore.saveSeq === 'function') {
1323
1552
  client._tokenStore.saveSeq(client._aid, client._deviceId, client._slotId, ns, seq).catch((exc) => {
@@ -1332,8 +1561,21 @@ export class MessageDeliveryEngine {
1332
1561
  });
1333
1562
  return;
1334
1563
  }
1564
+ if (seq <= 0 && typeof client._tokenStore.updateInstanceState === 'function') {
1565
+ Promise.resolve(client._tokenStore.updateInstanceState(client._aid, client._deviceId, client._slotId, (current) => {
1566
+ if (isJsonObject(current.seq_tracker_state)) {
1567
+ const next = { ...current.seq_tracker_state };
1568
+ delete next[ns];
1569
+ current.seq_tracker_state = next;
1570
+ }
1571
+ return current;
1572
+ })).catch((exc) => {
1573
+ client._clientLog.debug(`delete repaired seq failed: ns=${ns} err=${formatDeliveryError(exc)}`);
1574
+ });
1575
+ return;
1576
+ }
1335
1577
  if (seq > 0) {
1336
- this.saveSeqTrackerState();
1578
+ void this.saveSeqTrackerState();
1337
1579
  }
1338
1580
  }
1339
1581
  catch (exc) {
@@ -1395,6 +1637,7 @@ export class MessageDeliveryEngine {
1395
1637
  const ready = [...queue.keys()]
1396
1638
  .filter((seq) => seq <= contig && (beforeSeq === undefined || seq < beforeSeq))
1397
1639
  .sort((a, b) => a - b);
1640
+ let delivered = false;
1398
1641
  for (const seq of ready) {
1399
1642
  const item = queue.get(seq);
1400
1643
  queue.delete(seq);
@@ -1402,9 +1645,13 @@ export class MessageDeliveryEngine {
1402
1645
  continue;
1403
1646
  await this.publishOrderedQueueItem(ns, item.event, seq, item.payload);
1404
1647
  this.markPublishedSeq(ns, seq);
1648
+ delivered = true;
1405
1649
  }
1406
- if (queue.size === 0)
1650
+ if (queue.size === 0) {
1407
1651
  client._pendingOrderedMsgs.delete(ns);
1652
+ if (delivered)
1653
+ await this.saveSeqTrackerState();
1654
+ }
1408
1655
  }
1409
1656
  async publishOrderedMessage(event, ns, seq, payload) {
1410
1657
  const client = this.runtime.client;
@@ -1435,6 +1682,8 @@ export class MessageDeliveryEngine {
1435
1682
  await this.publishOrderedQueueItem(ns, event, seqNum, payload);
1436
1683
  this.markPublishedSeq(ns, seqNum);
1437
1684
  await this.drainOrderedMessages(ns);
1685
+ if (!client._pendingOrderedMsgs.get(ns))
1686
+ await this.saveSeqTrackerState();
1438
1687
  return true;
1439
1688
  }
1440
1689
  async publishPulledMessage(event, ns, seq, payload) {