@agentunion/fastaun-browser 0.5.19 → 0.5.21

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 (154) hide show
  1. package/CHANGELOG.md +176 -78
  2. package/_packed_docs/CHANGELOG.md +176 -78
  3. package/_packed_docs/INDEX.md +288 -269
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +101 -95
  5. package/_packed_docs/agent.md/SCHEMA.md +7 -7
  6. package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/344/270/216/346/215/242owner/347/274/226/346/216/222/346/226/271/346/241/210.md +530 -0
  7. package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/345/256/214/346/225/264/350/256/276/350/256/241/344/270/216/345/256/236/346/226/275/350/256/241/345/210/222.md +685 -0
  8. package/_packed_docs/agent.md/working/agent.md-schema/344/270/216/347/255/276/345/217/221/351/252/214/347/255/276/346/265/201/347/250/213/346/276/204/346/270/205.md +349 -0
  9. package/_packed_docs/agent.md/working//346/234/254/345/234/260Docker/346/265/213/350/257/225Bug/346/270/205/345/215/225.md +40 -0
  10. 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 +11 -11
  11. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +372 -331
  12. package/_packed_docs/protocol/08-AUN-E2EE.md +17 -12
  13. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +676 -676
  14. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +8 -12
  15. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +445 -0
  16. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
  17. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +666 -0
  18. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
  19. package/_packed_docs/protocol/agent.md/SCHEMA.md +1 -1
  20. package/_packed_docs/sdk/0.5.21-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +368 -0
  21. package/_packed_docs/sdk/0.5.21-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +350 -0
  22. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
  23. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +5 -1
  24. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +64 -64
  25. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +70 -63
  26. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +43 -40
  27. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +179 -19
  28. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +50 -49
  29. package/_packed_docs/sdk/09-group-rpc-manual.md +261 -254
  30. package/_packed_docs/sdk/09-message-rpc-manual.md +253 -160
  31. package/_packed_docs/sdk/09-storage-rpc-manual.md +18 -26
  32. package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +71 -0
  33. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +88 -0
  34. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +105 -92
  35. package/_packed_docs/sdk/INDEX.md +197 -167
  36. package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
  37. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
  38. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +930 -0
  39. package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
  40. package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +363 -0
  41. package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +553 -0
  42. package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
  43. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +480 -0
  44. package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
  45. package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
  46. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +173 -0
  47. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +211 -0
  48. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
  49. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
  50. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
  51. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
  52. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
  53. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
  54. package/dist/agent-md-schema.d.ts +16 -4
  55. package/dist/agent-md-schema.d.ts.map +1 -1
  56. package/dist/agent-md-schema.js +65 -30
  57. package/dist/agent-md-schema.js.map +1 -1
  58. package/dist/agent-md.d.ts +35 -3
  59. package/dist/agent-md.d.ts.map +1 -1
  60. package/dist/agent-md.js +384 -150
  61. package/dist/agent-md.js.map +1 -1
  62. package/dist/aid-store.d.ts +59 -0
  63. package/dist/aid-store.d.ts.map +1 -1
  64. package/dist/aid-store.js +202 -16
  65. package/dist/aid-store.js.map +1 -1
  66. package/dist/aid.d.ts +4 -1
  67. package/dist/aid.d.ts.map +1 -1
  68. package/dist/aid.js +24 -42
  69. package/dist/aid.js.map +1 -1
  70. package/dist/auth.d.ts +1 -1
  71. package/dist/auth.d.ts.map +1 -1
  72. package/dist/auth.js +89 -18
  73. package/dist/auth.js.map +1 -1
  74. package/dist/bundle.js +6410 -1848
  75. package/dist/cert-utils.d.ts +50 -1
  76. package/dist/cert-utils.d.ts.map +1 -1
  77. package/dist/cert-utils.js +123 -56
  78. package/dist/cert-utils.js.map +1 -1
  79. package/dist/client/delivery.d.ts +108 -16
  80. package/dist/client/delivery.d.ts.map +1 -1
  81. package/dist/client/delivery.js +1411 -184
  82. package/dist/client/delivery.js.map +1 -1
  83. package/dist/client/rpc-pipeline.d.ts +4 -1
  84. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  85. package/dist/client/rpc-pipeline.js +203 -117
  86. package/dist/client/rpc-pipeline.js.map +1 -1
  87. package/dist/client/v2-e2ee.d.ts +22 -3
  88. package/dist/client/v2-e2ee.d.ts.map +1 -1
  89. package/dist/client/v2-e2ee.js +1312 -684
  90. package/dist/client/v2-e2ee.js.map +1 -1
  91. package/dist/client.d.ts +23 -2
  92. package/dist/client.d.ts.map +1 -1
  93. package/dist/client.js +419 -101
  94. package/dist/client.js.map +1 -1
  95. package/dist/config.d.ts +4 -0
  96. package/dist/config.d.ts.map +1 -1
  97. package/dist/config.js +1 -0
  98. package/dist/config.js.map +1 -1
  99. package/dist/crypto.d.ts.map +1 -1
  100. package/dist/crypto.js +8 -6
  101. package/dist/crypto.js.map +1 -1
  102. package/dist/events.d.ts +24 -3
  103. package/dist/events.d.ts.map +1 -1
  104. package/dist/events.js +171 -29
  105. package/dist/events.js.map +1 -1
  106. package/dist/facades.d.ts +42 -1
  107. package/dist/facades.d.ts.map +1 -1
  108. package/dist/facades.js +368 -12
  109. package/dist/facades.js.map +1 -1
  110. package/dist/index.d.ts +6 -4
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +1 -1
  113. package/dist/index.js.map +1 -1
  114. package/dist/keystore/index.d.ts +14 -1
  115. package/dist/keystore/index.d.ts.map +1 -1
  116. package/dist/keystore/indexeddb-identity-store.d.ts +4 -0
  117. package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
  118. package/dist/keystore/indexeddb-identity-store.js +30 -13
  119. package/dist/keystore/indexeddb-identity-store.js.map +1 -1
  120. package/dist/keystore/indexeddb-shared.d.ts +19 -2
  121. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  122. package/dist/keystore/indexeddb-shared.js +193 -6
  123. package/dist/keystore/indexeddb-shared.js.map +1 -1
  124. package/dist/keystore/indexeddb-token-store.d.ts +15 -2
  125. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  126. package/dist/keystore/indexeddb-token-store.js +308 -27
  127. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  128. package/dist/org-protocol.d.ts +45 -0
  129. package/dist/org-protocol.d.ts.map +1 -1
  130. package/dist/org-protocol.js +827 -21
  131. package/dist/org-protocol.js.map +1 -1
  132. package/dist/ownership-v21.d.ts +43 -9
  133. package/dist/ownership-v21.d.ts.map +1 -1
  134. package/dist/ownership-v21.js +183 -81
  135. package/dist/ownership-v21.js.map +1 -1
  136. package/dist/ownership-workflow.d.ts +36 -1
  137. package/dist/ownership-workflow.d.ts.map +1 -1
  138. package/dist/ownership-workflow.js +610 -89
  139. package/dist/ownership-workflow.js.map +1 -1
  140. package/dist/seq-tracker.d.ts +2 -0
  141. package/dist/seq-tracker.d.ts.map +1 -1
  142. package/dist/seq-tracker.js +3 -2
  143. package/dist/seq-tracker.js.map +1 -1
  144. package/dist/tools/cross-sdk-agent.d.ts +61 -3
  145. package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
  146. package/dist/tools/cross-sdk-agent.js +524 -45
  147. package/dist/tools/cross-sdk-agent.js.map +1 -1
  148. package/dist/transport.d.ts +4 -0
  149. package/dist/transport.d.ts.map +1 -1
  150. package/dist/transport.js +64 -30
  151. package/dist/transport.js.map +1 -1
  152. package/dist/version.d.ts +1 -1
  153. package/dist/version.js +1 -1
  154. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import { normalizeSlotId, slotIsolationKey } from '../config.js';
1
+ import { _INTERNAL_MESSAGE_FLOW_LIMITS, normalizeSlotId, slotIsolationKey } from '../config.js';
2
2
  import { ClientSignatureError, ConnectionError, PermissionError, TimeoutError, ValidationError } from '../errors.js';
3
- import { parseCertMetadata } from '../cert-utils.js';
3
+ import { parseCertMetadata, verifySignatureWithCert } from '../cert-utils.js';
4
4
  import { orgRequestParams, validateOrgRequestJSON } from '../org-protocol.js';
5
5
  import { canonicalJson as canonicalClientRequest } from '../v2/crypto/canonical.js';
6
6
  import { validateAIDFormat, validateGroupIDFormat } from '../validators.js';
@@ -36,6 +36,7 @@ const SIGNED_METHODS = new Set([
36
36
  'message.v2.put_peer_pk', 'message.v2.bootstrap',
37
37
  'message.v2.group_bootstrap', 'message.v2.pull', 'message.history',
38
38
  'message.v2.ack',
39
+ 'message.peers',
39
40
  'group.send',
40
41
  'group.v2.put_group_pk', 'group.v2.bootstrap',
41
42
  'group.v2.send', 'group.v2.pull', 'group.history', 'group.v2.ack',
@@ -185,6 +186,9 @@ function hasMatchingV2Session(client) {
185
186
  return true;
186
187
  return session.aid === client._aid && session.deviceId === client._deviceId;
187
188
  }
189
+ function isP2pNamespace(namespace) {
190
+ return namespace.startsWith('p2p:') || namespace.startsWith('p2p.peer.v1/');
191
+ }
188
192
  function isTransientV2PullFallbackError(error) {
189
193
  const text = (error instanceof Error ? error.message : String(error)).toLowerCase();
190
194
  return text.includes('no_service') || text.includes('service plane unavailable');
@@ -199,6 +203,12 @@ export class RpcPipeline {
199
203
  this.runtime = runtime;
200
204
  }
201
205
  async call(method, params) {
206
+ return this._call(method, params);
207
+ }
208
+ async _callWithSent(method, params, onSent) {
209
+ return this._call(method, params, onSent);
210
+ }
211
+ async _call(method, params, onSent) {
202
212
  const client = this.runtime.client;
203
213
  const tStart = Date.now();
204
214
  const volatileCursor = method === 'message.pull'
@@ -206,7 +216,7 @@ export class RpcPipeline {
206
216
  : '';
207
217
  client._clientLog.debug(`call enter: method=${method}`);
208
218
  try {
209
- const result = await this.callImpl(method, params);
219
+ const result = await this.callImpl(method, params, onSent);
210
220
  client._clientLog.debug(`call exit: elapsed=${Date.now() - tStart}ms method=${method}`);
211
221
  return result;
212
222
  }
@@ -216,7 +226,7 @@ export class RpcPipeline {
216
226
  const retryParams = { ...(params ?? {}) };
217
227
  delete retryParams.after_volatile_cursor;
218
228
  delete retryParams.client_signature;
219
- const result = await this.callImpl(method, retryParams);
229
+ const result = await this.callImpl(method, retryParams, onSent);
220
230
  client._clientLog.debug(`call exit: elapsed=${Date.now() - tStart}ms method=${method}`);
221
231
  return result;
222
232
  }
@@ -224,11 +234,21 @@ export class RpcPipeline {
224
234
  throw err;
225
235
  }
226
236
  }
227
- async callImpl(method, params) {
237
+ async callImpl(method, params, onSent) {
228
238
  const client = this.runtime.client;
229
239
  const preflight = this.preflight(method, params);
230
240
  const p = preflight.params;
231
241
  const rpcBackground = preflight.rpcBackground;
242
+ if (client._p2pPeerPullEnabled) {
243
+ if (method === 'message.peers')
244
+ return await client._delivery.peers(p, rpcBackground);
245
+ if (method === 'message.pull' || method === 'message.v2.pull')
246
+ return await client._delivery.pullPeers(p, rpcBackground);
247
+ if (method === 'message.history')
248
+ return await client._v2E2EE.historyPeerV2(p);
249
+ if (method === 'message.ack' || method === 'message.v2.ack')
250
+ return await client._v2E2EE.ackPeerV2(p);
251
+ }
232
252
  const runWithRpcPriority = async (operation) => {
233
253
  if (!rpcBackground)
234
254
  return await operation();
@@ -248,6 +268,7 @@ export class RpcPipeline {
248
268
  messageId: String(p.message_id ?? '') || undefined,
249
269
  timestamp: p.timestamp,
250
270
  ttl: p.ttl,
271
+ needRender: p.need_render !== false,
251
272
  deviceId: String(p.device_id ?? '').trim() || String(p.to_device_id ?? '').trim() || undefined,
252
273
  protectedHeaders: client._protectedHeadersFromParams(p),
253
274
  context: isJsonObject(p.context) ? p.context : undefined,
@@ -265,6 +286,7 @@ export class RpcPipeline {
265
286
  groupAid: String(p.group_aid ?? '').trim() || undefined,
266
287
  messageId: String(p.message_id ?? '') || undefined,
267
288
  timestamp: p.timestamp,
289
+ needRender: p.need_render !== false,
268
290
  protectedHeaders: client._protectedHeadersFromParams(p),
269
291
  context: isJsonObject(p.context) ? p.context : undefined,
270
292
  });
@@ -291,11 +313,15 @@ export class RpcPipeline {
291
313
  }
292
314
  const pullGateKey = this.pullGateKeyForCall(method, p);
293
315
  if (pullGateKey) {
294
- return await this.runPullSerialized(pullGateKey, async () => await this.callImplInner(method, p, skipSendResultEnvelope, deferGroupReadyPostprocess, this.pullScopeKey(pullGateKey)), rpcBackground && this.pullGateBackgroundForCall(method, p));
316
+ if (method === 'group.history' || method === 'group.pull' || method === 'group.v2.pull') {
317
+ p._rpc_background = rpcBackground;
318
+ return await this.runPullNamespaceSerialized(pullGateKey, async () => await this.callImplInner(method, p, skipSendResultEnvelope, deferGroupReadyPostprocess, this.pullScopeKey(pullGateKey), onSent), rpcBackground && this.pullGateBackgroundForCall(method, p));
319
+ }
320
+ return await this.runPullSerialized(pullGateKey, async () => await this.callImplInner(method, p, skipSendResultEnvelope, deferGroupReadyPostprocess, this.pullScopeKey(pullGateKey), onSent), rpcBackground && this.pullGateBackgroundForCall(method, p));
295
321
  }
296
- return await runWithRpcPriority(() => this.callImplInner(method, p, skipSendResultEnvelope, deferGroupReadyPostprocess));
322
+ return await runWithRpcPriority(() => this.callImplInner(method, p, skipSendResultEnvelope, deferGroupReadyPostprocess, undefined, onSent));
297
323
  }
298
- async callImplInner(method, p, skipSendResultEnvelope = false, deferGroupReadyPostprocess = false, pullNamespace = '') {
324
+ async callImplInner(method, p, skipSendResultEnvelope = false, deferGroupReadyPostprocess = false, pullNamespace = '', onSent) {
299
325
  const client = this.runtime.client;
300
326
  if (method === 'message.v2.pull' || (method === 'message.pull' && hasMatchingV2Session(client))) {
301
327
  try {
@@ -339,12 +365,13 @@ export class RpcPipeline {
339
365
  await client._ensureV2SessionReady('group.pull');
340
366
  client._clientLog.debug(`call route: ${method} -> V2 pull`);
341
367
  if (p.window_mode === 'tail')
342
- return await client._v2E2EE.pullGroupV2TailInternal(p);
368
+ return await client._v2E2EE.pullGroupV2TailInternal(p, false, true);
343
369
  const hasExplicitAfterSeq = 'after_seq' in p || 'after_message_seq' in p;
344
370
  const cursorParams = this.explicitGroupCursorParams(p);
345
371
  const ownsCursor = Object.keys(cursorParams).length === 0 || this.groupCursorTargetsCurrentInstance(cursorParams);
346
372
  const pullOpts = {
347
373
  gateLocked: true,
374
+ background: p._rpc_background === true,
348
375
  };
349
376
  if (hasExplicitAfterSeq)
350
377
  pullOpts.explicitAfterSeq = true;
@@ -377,16 +404,24 @@ export class RpcPipeline {
377
404
  }
378
405
  return await client._ackGroupV2((p.group_id ?? p.group_aid), (p.seq ?? p.msg_seq ?? p.up_to_seq), p.group_aid);
379
406
  }
407
+ const rpcBackground = p._rpc_foreground === true ? false
408
+ : (typeof p._rpc_background === 'boolean' ? p._rpc_background : client._backgroundRpcDepth > 0);
409
+ delete p._rpc_background;
410
+ delete p._rpc_foreground;
380
411
  await this.applyClientSignature(method, p);
381
412
  const callTimeout = NON_IDEMPOTENT_METHODS.has(method) ? NON_IDEMPOTENT_TIMEOUT : undefined;
382
- const rpcBackground = client._backgroundRpcDepth > 0;
383
413
  const invokeTransport = () => {
384
- const request = callTimeout
385
- ? client._transport.call(method, p, callTimeout, undefined, rpcBackground)
386
- : client._transport.call(method, p, undefined, undefined, rpcBackground);
414
+ const request = onSent
415
+ ? client._transport['_callWithSent'](method, p, onSent, callTimeout, undefined, rpcBackground)
416
+ : callTimeout
417
+ ? client._transport.call(method, p, callTimeout, undefined, rpcBackground)
418
+ : client._transport.call(method, p, undefined, undefined, rpcBackground);
387
419
  return this.bindActivePullCancellation(method, p, request);
388
420
  };
389
- let result = await this.transportCallWithIdentityRecovery(invokeTransport, method, p);
421
+ const invoke = () => this.transportCallWithIdentityRecovery(invokeTransport, method, p);
422
+ let result = method === 'group.pull'
423
+ ? await this.runPullSerialized(this.pullGateKeyForCall(method, p), invoke, rpcBackground)
424
+ : await invoke();
390
425
  const sendResultModeSource = result;
391
426
  result = await this.postprocessResult(method, p, result, {
392
427
  skipGroupState: deferGroupReadyPostprocess,
@@ -407,7 +442,8 @@ export class RpcPipeline {
407
442
  }
408
443
  const p = { ...(params ?? {}) };
409
444
  this.mergeInstanceProtectedHeaders(method, p);
410
- const rpcBackground = Boolean(p._rpc_background) || client._backgroundRpcDepth > 0;
445
+ const rpcBackground = Boolean(p._rpc_background)
446
+ || (!['message.peers', 'message.pull', 'message.v2.pull', 'group.pull', 'group.v2.pull', 'group.pull_events'].includes(method) && client._backgroundRpcDepth > 0);
411
447
  delete p._rpc_background;
412
448
  if (method === 'message.send' || method === 'group.send') {
413
449
  this.normalizeOutboundMessagePayload(p, method);
@@ -520,7 +556,7 @@ export class RpcPipeline {
520
556
  }
521
557
  params.device_id = client._deviceId;
522
558
  params.slot_id = client._slotId;
523
- if ((method === 'message.pull' || method === 'message.v2.pull') && params.after_volatile_cursor === undefined) {
559
+ if (!client._p2pPeerPullEnabled && (method === 'message.pull' || method === 'message.v2.pull') && params.after_volatile_cursor === undefined) {
524
560
  const volatileCursor = client._delivery.volatilePullCursor();
525
561
  if (volatileCursor)
526
562
  params.after_volatile_cursor = volatileCursor;
@@ -585,6 +621,12 @@ export class RpcPipeline {
585
621
  const paramsHash = Array.from(new Uint8Array(paramsHashBuf))
586
622
  .map(b => b.toString(16).padStart(2, '0'))
587
623
  .join('');
624
+ if (params.client_signature !== undefined) {
625
+ const existing = params.client_signature;
626
+ if (!isJsonObject(existing) || existing.aid !== aid || existing.cert_fingerprint !== await signingCertFingerprint(certPem) || existing.params_hash !== paramsHash || typeof existing.timestamp !== 'string' || !/^\d+$/.test(existing.timestamp) || typeof existing.signature !== 'string' || !await verifySignatureWithCert(certPem, existing.signature, new TextEncoder().encode(`${method}|${aid}|${existing.timestamp}|${paramsHash}`)))
627
+ throw new Error('已有客户端签名与请求内容不一致');
628
+ return;
629
+ }
588
630
  const signData = new TextEncoder().encode(`${method}|${aid}|${ts}|${paramsHash}`);
589
631
  const cryptoKey = await signingPrivateKey(currentAid.privateKeyPem);
590
632
  const sigP1363 = await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, cryptoKey, signData);
@@ -611,12 +653,18 @@ export class RpcPipeline {
611
653
  if (method === 'message.pull' || method === 'message.v2.pull' || method === 'message.history') {
612
654
  if (!client._aid)
613
655
  return '';
656
+ const sender = String(params.sender_aid ?? params.peer_aid ?? '').trim();
657
+ if (client._p2pPeerPullEnabled && !sender)
658
+ return '';
659
+ const peerNamespace = sender && (client._p2pPeerPullEnabled || params.cursor_scope === 'peer')
660
+ ? `p2p.peer.v1/${btoa(String.fromCharCode(...new TextEncoder().encode(sender))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')}`
661
+ : '';
614
662
  const mode = method === 'message.history' ? 'history' : params.window_mode === 'tail' ? 'tail' : 'forward';
615
663
  const cursor = mode === 'history'
616
664
  ? `before=${String(params.before_seq)}`
617
665
  : `after=${String(params.after_seq ?? 0)}`;
618
666
  const limit = mode === 'forward' ? (Number(params.limit ?? 50) || 50) : params.limit;
619
- return `p2p:${client._aid}|mode=${mode}|cursor=${cursor}|volatile=${String(params.after_volatile_cursor ?? '')}|force=${String(Boolean(params.force))}|limit=${String(limit)}`;
667
+ return `${peerNamespace || `p2p:${client._aid}`}|mode=${mode}|cursor=${cursor}|volatile=${String(params.after_volatile_cursor ?? '')}|force=${String(Boolean(params.force))}|limit=${String(limit)}`;
620
668
  }
621
669
  if (method === 'group.pull' || method === 'group.v2.pull' || method === 'group.history') {
622
670
  const gid = String(params.group_id ?? params.group_aid ?? '').trim();
@@ -653,14 +701,15 @@ export class RpcPipeline {
653
701
  void key;
654
702
  return 'pull';
655
703
  }
656
- pullGateState(key) {
657
- const name = this.pullGateName(key);
704
+ pullGateState(key, namespaceOnly = false) {
705
+ const name = namespaceOnly ? 'pull-namespace' : this.pullGateName(key);
658
706
  let state = this.pullGateStates.get(name);
659
707
  if (!state) {
660
- state = { active: null, foreground: [], background: [], byKey: new Map(), lifecycle: new Map(), watchdog: null };
708
+ state = { networkLimited: !namespaceOnly, activeByNamespace: new Map(), foreground: [], background: [], byKey: new Map(), lifecycle: new Map(), watchdog: null, backgroundPeerDispatches: 0 };
661
709
  this.pullGateStates.set(name, state);
662
710
  }
663
- this.startPullGateWatchdog(state, name);
711
+ if (state.networkLimited)
712
+ this.startPullGateWatchdog(state, name);
664
713
  return state;
665
714
  }
666
715
  pullGateOperationTimeoutMs() {
@@ -687,21 +736,23 @@ export class RpcPipeline {
687
736
  }
688
737
  }
689
738
  checkPullGate(state, name) {
690
- const active = state.active;
691
- if (!active) {
739
+ const activeJobs = [...state.activeByNamespace.values()];
740
+ if (activeJobs.length === 0) {
692
741
  this.drainPullGate(state);
693
742
  return;
694
743
  }
695
- if (!active.pullingStartedAt || Date.now() - active.pullingStartedAt < this.pullGateOperationTimeoutMs())
696
- return;
697
- if (active.timedOut)
698
- return;
699
- active.timedOut = true;
700
- active.invalidated = true;
701
- active.cancel?.();
702
- const err = new TimeoutError(`pull gate timeout: ${active.namespace}`, { retryable: true });
703
- this.runtime.client._clientLog?.warn(`pull gate watchdog timeout: gate=${name} key=${active.key}`);
704
- active.reject(err);
744
+ for (const active of activeJobs) {
745
+ if (!active.pullingStartedAt || Date.now() - active.pullingStartedAt < this.pullGateOperationTimeoutMs())
746
+ continue;
747
+ if (active.timedOut)
748
+ continue;
749
+ active.timedOut = true;
750
+ active.invalidated = true;
751
+ active.cancel?.();
752
+ const err = new TimeoutError(`pull gate timeout: ${active.namespace}`, { retryable: true });
753
+ this.runtime.client._clientLog?.warn(`pull gate watchdog timeout: gate=${name} key=${active.key}`);
754
+ active.reject(err);
755
+ }
705
756
  }
706
757
  realtimePullNamespace(key) {
707
758
  for (const marker of ['|tail|', '|forward|']) {
@@ -721,7 +772,7 @@ export class RpcPipeline {
721
772
  if (typeof cancel !== 'function' || !key)
722
773
  return request;
723
774
  const state = this.pullGateStates.get(this.pullGateName(key));
724
- const active = state?.active;
775
+ const active = [...(state?.activeByNamespace.values() ?? [])].find((candidate) => candidate.key === key);
725
776
  if (!active || active.key !== key || active.timedOut || active.invalidated)
726
777
  return request;
727
778
  const boundCancel = () => cancel.call(request);
@@ -742,30 +793,29 @@ export class RpcPipeline {
742
793
  }
743
794
  hasPendingRealtimePull(ns) {
744
795
  const normalized = String(ns ?? '').trim();
745
- if (!normalized || (!normalized.startsWith('p2p:') && !normalized.startsWith('group:')))
796
+ if (!normalized || (!isP2pNamespace(normalized) && !normalized.startsWith('group:')))
746
797
  return false;
747
798
  if (this.isPullResponseProcessing(normalized))
748
799
  return true;
749
- const state = this.pullGateStates.get(this.pullGateName(normalized));
750
- if (!state)
751
- return false;
752
800
  const matches = (job) => {
753
801
  if (!job)
754
802
  return false;
755
803
  return this.realtimePullNamespace(job.key) === normalized;
756
804
  };
757
- return matches(state.active)
805
+ return [...this.pullGateStates.values()].some((state) => [...state.activeByNamespace.values()].some(matches)
758
806
  || state.foreground.some(matches)
759
- || state.background.some(matches);
807
+ || state.background.some(matches));
760
808
  }
761
809
  hasPullActivity(namespace, includePending = true) {
762
810
  const ns = String(namespace ?? '').trim();
763
- if ((!ns.startsWith('p2p:') && !ns.startsWith('group:'))
811
+ if ((!isP2pNamespace(ns) && !ns.startsWith('group:') && !ns.startsWith('group_event:'))
764
812
  || this.inlineRealtimeScopes.has(ns))
765
813
  return true;
766
814
  const client = this.runtime.client;
767
815
  if ((client._pullResponseKeys?.get?.(ns) ?? 0) > 0)
768
816
  return true;
817
+ if (isP2pNamespace(ns) && client._v2E2EE?.hasPeerPageActivity?.(ns))
818
+ return true;
769
819
  const pendingP2p = client._pendingP2pPullUpper;
770
820
  const pendingGroup = client._pendingGroupPullUpper;
771
821
  if (includePending && ((pendingP2p?.get(ns) ?? 0) > 0 || (pendingGroup?.get(ns) ?? 0) > 0
@@ -773,7 +823,7 @@ export class RpcPipeline {
773
823
  return true;
774
824
  for (const marker of client._gapFillDone ?? []) {
775
825
  const value = String(marker ?? '').trim();
776
- if (ns.startsWith('p2p:') && (value.startsWith('p2p_pull:') || value.startsWith('p2p_pull_retry:')))
826
+ if (isP2pNamespace(ns) && (value.startsWith(`p2p_pull:${ns}`) || value.startsWith(`p2p_pull_retry:${ns}`)))
777
827
  return true;
778
828
  if (ns.startsWith('group:') && value.startsWith(`group_pull:${ns}`))
779
829
  return true;
@@ -782,17 +832,15 @@ export class RpcPipeline {
782
832
  if (gate?.inflight && this.pullScopeKey(key) === ns)
783
833
  return true;
784
834
  }
785
- const state = this.pullGateStates.get(this.pullGateName(ns));
786
- if (!state)
787
- return false;
788
835
  const matches = (job) => job !== null && job.namespace === ns;
789
- return matches(state.active) || state.foreground.some(matches) || state.background.some(matches);
836
+ return [...this.pullGateStates.values()].some((state) => [...state.activeByNamespace.values()].some(matches)
837
+ || state.foreground.some(matches) || state.background.some(matches));
790
838
  }
791
839
  hasAnyPullActivity() {
792
840
  if (this.pullWorkTokens.size > 0)
793
841
  return true;
794
842
  for (const state of this.pullGateStates.values()) {
795
- if (state.active || state.foreground.length > 0 || state.background.length > 0)
843
+ if (state.activeByNamespace.size > 0 || state.foreground.length > 0 || state.background.length > 0)
796
844
  return true;
797
845
  }
798
846
  return false;
@@ -816,7 +864,7 @@ export class RpcPipeline {
816
864
  }
817
865
  async tryRunInlineRealtime(ns, seq, operation) {
818
866
  const normalized = String(ns ?? '').trim();
819
- if ((!normalized.startsWith('p2p:') && !normalized.startsWith('group:'))
867
+ if ((!isP2pNamespace(normalized) && !normalized.startsWith('group:'))
820
868
  || !Number.isSafeInteger(seq) || seq <= 0 || typeof operation !== 'function') {
821
869
  return { acquired: false };
822
870
  }
@@ -833,7 +881,9 @@ export class RpcPipeline {
833
881
  }
834
882
  const key = `${normalized}|inline|seq=${seq}`;
835
883
  const state = this.pullGateState(key);
836
- if (state.active !== null || state.foreground.length > 0 || state.background.length > 0) {
884
+ if (state.activeByNamespace.has(normalized)
885
+ || state.foreground.some((job) => job.namespace === normalized)
886
+ || state.background.some((job) => job.namespace === normalized)) {
837
887
  return { acquired: false };
838
888
  }
839
889
  const guard = {
@@ -864,11 +914,13 @@ export class RpcPipeline {
864
914
  }
865
915
  finally {
866
916
  this.inlineRealtimeScopes.delete(normalized);
867
- if (state.active === guard)
868
- state.active = null;
869
- this.drainPullGate(state);
917
+ if (state.activeByNamespace.get(normalized) === guard)
918
+ state.activeByNamespace.delete(normalized);
919
+ for (const queuedState of this.pullGateStates.values()) {
920
+ this.drainPullGate(queuedState);
921
+ this.armQueuedPullTimers(queuedState);
922
+ }
870
923
  this.runtime.client._delivery?.onPullGateIdle?.(normalized);
871
- this.armQueuedPullTimers(state);
872
924
  }
873
925
  }
874
926
  tryAcquirePullGate(key) {
@@ -877,7 +929,7 @@ export class RpcPipeline {
877
929
  if (this.inlineRealtimeScopes.has(this.pullScopeKey(key)))
878
930
  return null;
879
931
  const serialized = this.pullGateStates.get(this.pullGateName(key));
880
- if (serialized?.active?.inline === true)
932
+ if ([...(serialized?.activeByNamespace.values() ?? [])].some((job) => job.inline === true))
881
933
  return null;
882
934
  const client = this.runtime.client;
883
935
  const now = Date.now();
@@ -907,8 +959,10 @@ export class RpcPipeline {
907
959
  const ns = this.pullScopeKey(namespace);
908
960
  if (!ns)
909
961
  return true;
910
- const active = this.pullGateStates.get(this.pullGateName(ns))?.active;
911
- return !active || active.namespace !== ns || (!active.timedOut && !active.invalidated);
962
+ return [...this.pullGateStates.values()].every((state) => {
963
+ const active = state.activeByNamespace.get(ns);
964
+ return !active || active.namespace !== ns || (!active.timedOut && !active.invalidated);
965
+ });
912
966
  }
913
967
  invalidatePulls() {
914
968
  if (this.pullInvalidationWait)
@@ -917,8 +971,8 @@ export class RpcPipeline {
917
971
  const waits = [];
918
972
  for (const state of this.pullGateStates.values()) {
919
973
  const jobs = new Set();
920
- if (state.active)
921
- jobs.add(state.active);
974
+ for (const active of state.activeByNamespace.values())
975
+ jobs.add(active);
922
976
  for (const job of state.foreground)
923
977
  jobs.add(job);
924
978
  for (const job of state.background)
@@ -960,7 +1014,10 @@ export class RpcPipeline {
960
1014
  pullInvalidationInProgress() {
961
1015
  return this.pullInvalidationWait !== null;
962
1016
  }
963
- async runPullSerialized(key, operation, background = false) {
1017
+ async runPullNamespaceSerialized(key, operation, background = false) {
1018
+ return await this.runPullSerialized(key, operation, background, true);
1019
+ }
1020
+ async runPullSerialized(key, operation, background = false, namespaceOnly = false) {
964
1021
  if (this.pullInvalidationInProgress()) {
965
1022
  throw new Error('pull invalidated');
966
1023
  }
@@ -978,12 +1035,12 @@ export class RpcPipeline {
978
1035
  releasePullWork();
979
1036
  }
980
1037
  }
981
- const state = this.pullGateState(key);
1038
+ const state = this.pullGateState(key, namespaceOnly);
982
1039
  const namespace = this.pullScopeKey(key);
983
1040
  const candidate = state.byKey.get(key);
984
1041
  const existing = candidate && !candidate.timedOut && !candidate.invalidated ? candidate : null;
985
1042
  if (existing) {
986
- if (!background && existing.background && existing !== state.active) {
1043
+ if (!background && existing.background && ![...state.activeByNamespace.values()].includes(existing)) {
987
1044
  const index = state.background.indexOf(existing);
988
1045
  if (index >= 0)
989
1046
  state.background.splice(index, 1);
@@ -1014,7 +1071,8 @@ export class RpcPipeline {
1014
1071
  (background ? state.background : state.foreground).push(job);
1015
1072
  state.byKey.set(key, job);
1016
1073
  this.drainPullGate(state);
1017
- this.checkPullGate(state, this.pullGateName(key));
1074
+ if (state.networkLimited)
1075
+ this.checkPullGate(state, this.pullGateName(key));
1018
1076
  return await promise;
1019
1077
  }
1020
1078
  async executePullOperation(operation, background) {
@@ -1032,8 +1090,8 @@ export class RpcPipeline {
1032
1090
  return;
1033
1091
  const state = this.pullGateState(key);
1034
1092
  const namespace = this.pullScopeKey(key);
1035
- const job = state.active?.key === key ? state.active : null;
1036
- if (!job || state.active !== job)
1093
+ const job = [...state.activeByNamespace.values()].find((candidate) => candidate.key === key) ?? null;
1094
+ if (!job)
1037
1095
  return;
1038
1096
  const replacementKey = String(nextKey || key);
1039
1097
  if (state.byKey.get(job.key) === job)
@@ -1046,7 +1104,7 @@ export class RpcPipeline {
1046
1104
  state.lifecycle.set(namespace, 'pulled');
1047
1105
  job.suspended = true;
1048
1106
  job.resume = new Promise((resolve) => { job.resumeResolve = resolve; });
1049
- state.active = null;
1107
+ state.activeByNamespace.delete(namespace);
1050
1108
  (job.background ? state.background : state.foreground).push(job);
1051
1109
  this.drainPullGate(state);
1052
1110
  if (job.resume) {
@@ -1066,69 +1124,92 @@ export class RpcPipeline {
1066
1124
  if (!ns)
1067
1125
  return;
1068
1126
  const state = this.pullGateStates.get(this.pullGateName(ns));
1069
- if (!state || state.active?.namespace !== ns)
1127
+ if (!state || !state.activeByNamespace.has(ns))
1070
1128
  return;
1071
1129
  state.lifecycle.set(ns, lifecycle);
1072
1130
  }
1073
1131
  drainPullGate(state) {
1074
- if (state.active)
1075
- return;
1132
+ const peerForward = (job) => job.background && job.namespace.startsWith('p2p.peer.v1/')
1133
+ && job.key.includes('|peer=background|') && job.key.includes('|tail=false|') && job.key.includes('|force=false|');
1134
+ const priority = (job) => peerForward(job)
1135
+ ? this.runtime.client._delivery?.peerBackgroundPullPriority?.(job.namespace) : undefined;
1076
1136
  const takeRunnable = (queue) => {
1077
- const index = queue.findIndex((candidate) => !this.inlineRealtimeScopes.has(candidate.namespace));
1137
+ let index = queue.findIndex((candidate) => (!this.inlineRealtimeScopes.has(candidate.namespace)
1138
+ && !state.activeByNamespace.has(candidate.namespace)));
1139
+ if (index >= 0 && queue === state.background && peerForward(queue[index])
1140
+ && (state.backgroundPeerDispatches + 1) % _INTERNAL_MESSAGE_FLOW_LIMITS.pullMaxInflight !== 0) {
1141
+ let best = priority(queue[index]);
1142
+ if (best !== undefined)
1143
+ for (let next = index + 1; next < queue.length; next += 1) {
1144
+ const hint = priority(queue[next]);
1145
+ if (hint === undefined)
1146
+ break;
1147
+ if (!this.inlineRealtimeScopes.has(queue[next].namespace) && !state.activeByNamespace.has(queue[next].namespace) && hint < best) {
1148
+ index = next;
1149
+ best = hint;
1150
+ }
1151
+ }
1152
+ }
1078
1153
  return index >= 0 ? queue.splice(index, 1)[0] : undefined;
1079
1154
  };
1080
- const foregroundJob = takeRunnable(state.foreground);
1081
- const foregroundDrained = foregroundJob !== undefined && state.foreground.length === 0;
1082
- const job = foregroundJob ?? takeRunnable(state.background);
1083
- if (!job)
1084
- return;
1085
- state.active = job;
1086
- this.runtime.client._delivery?.onPullStarted?.(job.namespace);
1087
- if (foregroundDrained)
1088
- this.runtime.client._delivery?.onForegroundPullsDrained?.();
1089
- if (job.timer)
1090
- clearTimeout(job.timer);
1091
- job.pullingStartedAt = Date.now();
1092
- job.timedOut = false;
1093
- state.lifecycle.set(job.namespace, 'pulling');
1094
- const resumeResolve = job.resumeResolve;
1095
- job.resume = null;
1096
- job.resumeResolve = null;
1097
- if (job.suspended) {
1098
- job.suspended = false;
1099
- resumeResolve?.();
1100
- return;
1155
+ while (state.activeByNamespace.size < _INTERNAL_MESSAGE_FLOW_LIMITS.pullMaxInflight) {
1156
+ const foregroundJob = takeRunnable(state.foreground);
1157
+ const foregroundDrained = foregroundJob !== undefined && state.foreground.length === 0;
1158
+ const job = foregroundJob ?? takeRunnable(state.background);
1159
+ if (!job)
1160
+ break;
1161
+ if (peerForward(job))
1162
+ state.backgroundPeerDispatches = (state.backgroundPeerDispatches + 1) % _INTERNAL_MESSAGE_FLOW_LIMITS.pullMaxInflight;
1163
+ state.activeByNamespace.set(job.namespace, job);
1164
+ this.runtime.client._delivery?.onPullStarted?.(job.namespace);
1165
+ if (foregroundDrained)
1166
+ this.runtime.client._delivery?.onForegroundPullsDrained?.();
1167
+ if (job.timer)
1168
+ clearTimeout(job.timer);
1169
+ job.pullingStartedAt = Date.now();
1170
+ job.timedOut = false;
1171
+ state.lifecycle.set(job.namespace, 'pulling');
1172
+ const resumeResolve = job.resumeResolve;
1173
+ job.resume = null;
1174
+ job.resumeResolve = null;
1175
+ if (job.suspended) {
1176
+ job.suspended = false;
1177
+ resumeResolve?.();
1178
+ continue;
1179
+ }
1180
+ job.running = true;
1181
+ let failed = false;
1182
+ void this.executePullOperation(job.operation, state.networkLimited && job.background).then((value) => { if (!job.timedOut && !job.invalidated)
1183
+ job.resolve(value); }, (error) => {
1184
+ failed = true;
1185
+ if (!job.timedOut && !job.invalidated)
1186
+ job.reject(error);
1187
+ }).finally(() => {
1188
+ this.pullWorkTokens.delete(job.workToken);
1189
+ state.lifecycle.set(job.namespace, 'idle');
1190
+ if (state.activeByNamespace.get(job.namespace) === job)
1191
+ state.activeByNamespace.delete(job.namespace);
1192
+ if (state.byKey.get(job.key) === job)
1193
+ state.byKey.delete(job.key);
1194
+ this.drainPullGate(state);
1195
+ job.settledResolve?.();
1196
+ job.settledResolve = null;
1197
+ if (!job.invalidated)
1198
+ this.runtime.client._delivery?.onPullGateIdle?.(job.namespace);
1199
+ if (failed || job.invalidated)
1200
+ this.runtime.client._delivery?.onPullAborted?.();
1201
+ this.runtime.client._delivery?.onPullWorkSettled?.();
1202
+ });
1101
1203
  }
1102
- job.running = true;
1103
- let failed = false;
1104
- void this.executePullOperation(job.operation, job.background).then((value) => { if (!job.timedOut && !job.invalidated)
1105
- job.resolve(value); }, (error) => {
1106
- failed = true;
1107
- if (!job.timedOut && !job.invalidated)
1108
- job.reject(error);
1109
- }).finally(() => {
1110
- this.pullWorkTokens.delete(job.workToken);
1111
- state.lifecycle.set(job.namespace, 'idle');
1112
- if (state.active === job)
1113
- state.active = null;
1114
- if (state.byKey.get(job.key) === job)
1115
- state.byKey.delete(job.key);
1116
- this.drainPullGate(state);
1117
- job.settledResolve?.();
1118
- job.settledResolve = null;
1119
- if (!job.invalidated)
1120
- this.runtime.client._delivery?.onPullGateIdle?.(job.namespace);
1121
- if (failed || job.invalidated)
1122
- this.runtime.client._delivery?.onPullAborted?.();
1123
- this.runtime.client._delivery?.onPullWorkSettled?.();
1124
- });
1125
1204
  }
1126
1205
  armQueuedPullTimers(_state) { }
1127
1206
  async rawCall(method, params, options) {
1128
1207
  const client = this.runtime.client;
1129
1208
  const payload = { ...(params ?? {}) };
1130
- const rpcBackground = Boolean(payload._rpc_background) || client._backgroundRpcDepth > 0 || options?.background === true;
1209
+ const rpcBackground = options?.background ?? (!Boolean(payload._rpc_foreground)
1210
+ && (Boolean(payload._rpc_background) || client._backgroundRpcDepth > 0));
1131
1211
  delete payload._rpc_background;
1212
+ delete payload._rpc_foreground;
1132
1213
  const signed = options?.signed ?? true;
1133
1214
  if (signed || method.startsWith('org.')) {
1134
1215
  await this.applyClientSignature(method, payload);
@@ -1146,9 +1227,14 @@ export class RpcPipeline {
1146
1227
  request = client._transport.call(method, payload);
1147
1228
  return this.bindActivePullCancellation(method, payload, request, options?.pullGateKey ?? '');
1148
1229
  };
1149
- const result = await this.transportCallWithIdentityRecovery(invokeTransport, method, payload);
1150
- this.throwIfPullInvalidated(this.pullScopeKey(options?.pullGateKey || this.pullGateKeyForCall(method, payload)));
1151
- return result;
1230
+ try {
1231
+ const result = await this.transportCallWithIdentityRecovery(invokeTransport, method, payload);
1232
+ this.throwIfPullInvalidated(this.pullScopeKey(options?.pullGateKey || this.pullGateKeyForCall(method, payload)));
1233
+ return result;
1234
+ }
1235
+ finally {
1236
+ client._delivery?.requestBackgroundPullRecovery?.();
1237
+ }
1152
1238
  }
1153
1239
  async transportCallWithIdentityRecovery(operation, method, params) {
1154
1240
  try {