@agentunion/fastaun 0.5.20 → 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 (107) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/_packed_docs/CHANGELOG.md +47 -0
  3. package/_packed_docs/INDEX.md +453 -440
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +164 -161
  5. 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
  6. 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
  7. 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
  8. 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
  9. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1433 -1392
  10. package/_packed_docs/protocol/08-AUN-E2EE.md +17 -12
  11. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +2 -0
  12. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +666 -658
  13. 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
  14. 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
  15. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
  16. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +5 -1
  17. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +64 -64
  18. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +4 -1
  19. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +42 -39
  20. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +147 -14
  21. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +48 -47
  22. package/_packed_docs/sdk/09-group-rpc-manual.md +5 -2
  23. package/_packed_docs/sdk/09-message-rpc-manual.md +250 -160
  24. 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
  25. 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
  26. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +134 -130
  27. package/_packed_docs/sdk/INDEX.md +239 -221
  28. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +930 -922
  29. 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 +106 -43
  30. 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 +180 -9
  31. 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 -708
  32. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +480 -476
  33. 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 +1 -1
  34. 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 +2 -2
  35. package/dist/agent-md-schema.js +6 -4
  36. package/dist/agent-md-schema.js.map +1 -1
  37. package/dist/agent-md.d.ts +22 -2
  38. package/dist/agent-md.js +84 -67
  39. package/dist/agent-md.js.map +1 -1
  40. package/dist/aid-store.d.ts +13 -0
  41. package/dist/aid-store.js +50 -15
  42. package/dist/aid-store.js.map +1 -1
  43. package/dist/auth.js +4 -0
  44. package/dist/auth.js.map +1 -1
  45. package/dist/cert-utils.d.ts +1 -0
  46. package/dist/cert-utils.js +13 -0
  47. package/dist/cert-utils.js.map +1 -1
  48. package/dist/client/delivery.d.ts +59 -1
  49. package/dist/client/delivery.js +1018 -125
  50. package/dist/client/delivery.js.map +1 -1
  51. package/dist/client/rpc-pipeline.d.ts +4 -1
  52. package/dist/client/rpc-pipeline.js +123 -37
  53. package/dist/client/rpc-pipeline.js.map +1 -1
  54. package/dist/client/v2-e2ee.d.ts +12 -2
  55. package/dist/client/v2-e2ee.js +751 -294
  56. package/dist/client/v2-e2ee.js.map +1 -1
  57. package/dist/client.d.ts +26 -2
  58. package/dist/client.js +379 -63
  59. package/dist/client.js.map +1 -1
  60. package/dist/config.d.ts +4 -0
  61. package/dist/config.js +1 -0
  62. package/dist/config.js.map +1 -1
  63. package/dist/events.d.ts +18 -1
  64. package/dist/events.js +148 -9
  65. package/dist/events.js.map +1 -1
  66. package/dist/facades.d.ts +43 -1
  67. package/dist/facades.js +363 -7
  68. package/dist/facades.js.map +1 -1
  69. package/dist/index.d.ts +5 -3
  70. package/dist/index.js +1 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/keystore/aid-db.d.ts +6 -1
  73. package/dist/keystore/aid-db.js +184 -42
  74. package/dist/keystore/aid-db.js.map +1 -1
  75. package/dist/keystore/index.d.ts +14 -0
  76. package/dist/keystore/local-token-store.d.ts +9 -1
  77. package/dist/keystore/local-token-store.js +79 -14
  78. package/dist/keystore/local-token-store.js.map +1 -1
  79. package/dist/org-protocol.d.ts +45 -0
  80. package/dist/org-protocol.js +754 -11
  81. package/dist/org-protocol.js.map +1 -1
  82. package/dist/ownership-v21.d.ts +16 -3
  83. package/dist/ownership-v21.js +35 -17
  84. package/dist/ownership-v21.js.map +1 -1
  85. package/dist/ownership-workflow.d.ts +17 -0
  86. package/dist/ownership-workflow.js +511 -26
  87. package/dist/ownership-workflow.js.map +1 -1
  88. package/dist/secret-store/file-store.js +84 -0
  89. package/dist/secret-store/file-store.js.map +1 -1
  90. package/dist/seq-tracker.d.ts +1 -0
  91. package/dist/seq-tracker.js +2 -2
  92. package/dist/seq-tracker.js.map +1 -1
  93. package/dist/tools/cross-sdk-agent.d.ts +66 -3
  94. package/dist/tools/cross-sdk-agent.js +466 -36
  95. package/dist/tools/cross-sdk-agent.js.map +1 -1
  96. package/dist/transport.d.ts +3 -0
  97. package/dist/transport.js +98 -44
  98. package/dist/transport.js.map +1 -1
  99. package/dist/types.d.ts +1 -0
  100. package/dist/v2/e2ee/encrypt-group.js +1 -0
  101. package/dist/v2/e2ee/encrypt-group.js.map +1 -1
  102. package/dist/v2/e2ee/encrypt-p2p.js +1 -0
  103. package/dist/v2/e2ee/encrypt-p2p.js.map +1 -1
  104. package/dist/v2/e2ee/types.d.ts +1 -0
  105. package/dist/version.d.ts +1 -1
  106. package/dist/version.js +1 -1
  107. package/package.json +1 -1
@@ -13,6 +13,8 @@ export declare class RpcPipeline {
13
13
  private pullDrainedCheckQueued;
14
14
  constructor(runtime: ClientRuntime);
15
15
  call(method: string, params?: RpcParams): Promise<RpcResult>;
16
+ private _callWithSent;
17
+ private _call;
16
18
  preflight(method: string, params?: RpcParams): RpcPreflightResult;
17
19
  mergeInstanceProtectedHeaders(method: string, params: RpcParams): void;
18
20
  normalizeOutboundMessagePayload(params: RpcParams, method?: string): void;
@@ -43,7 +45,8 @@ export declare class RpcPipeline {
43
45
  isPullNamespaceCurrent(namespace: string): boolean;
44
46
  invalidatePulls(): Promise<void>;
45
47
  private pullInvalidationInProgress;
46
- runPullSerialized<T>(key: string, operation: () => Promise<T> | T, background?: boolean): Promise<T>;
48
+ runPullNamespaceSerialized<T>(key: string, operation: () => Promise<T> | T, background?: boolean): Promise<T>;
49
+ runPullSerialized<T>(key: string, operation: () => Promise<T> | T, background?: boolean, namespaceOnly?: boolean): Promise<T>;
47
50
  private executePullOperation;
48
51
  private throwIfPullInvalidated;
49
52
  yieldPullGate(key: string, nextKey?: string, background?: boolean): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import * as crypto from 'node:crypto';
2
- import { normalizeSlotId, slotIsolationKey } from '../config.js';
2
+ import { _INTERNAL_MESSAGE_FLOW_LIMITS, normalizeSlotId, slotIsolationKey } from '../config.js';
3
3
  import { certTimeError } from '../cert-utils.js';
4
4
  import { orgRequestParams, validateOrgRequestJSON } from '../org-protocol.js';
5
5
  import { canonicalJson as canonicalClientRequest } from '../v2/crypto/canonical.js';
@@ -115,7 +115,6 @@ function getCertFingerprint(certPem) {
115
115
  /** 旧式 tryAcquirePullGate 的防并发窗口。 */
116
116
  const PULL_GATE_STALE_MS = 35_000;
117
117
  const PULL_GATE_OPERATION_TIMEOUT_MS = 35_000;
118
- const PULL_GATE_MAX_ACTIVE = 4;
119
118
  function sameIdentityAdmissionRejection(error, original) {
120
119
  const errorCode = Number(error?.code);
121
120
  const originalCode = Number(original?.code);
@@ -167,6 +166,12 @@ export class RpcPipeline {
167
166
  this.runtime = runtime;
168
167
  }
169
168
  async call(method, params) {
169
+ return this._call(method, params);
170
+ }
171
+ async _callWithSent(method, params, onSent) {
172
+ return this._call(method, params, onSent);
173
+ }
174
+ async _call(method, params, onSent) {
170
175
  const client = this.runtime.client;
171
176
  const generation = client._delivery?.captureInlineAckGeneration?.();
172
177
  const tStart = Date.now();
@@ -194,6 +199,23 @@ export class RpcPipeline {
194
199
  const deferGroupReadyPostprocess = Boolean(p._defer_group_ready_postprocess);
195
200
  delete p._defer_group_ready_postprocess;
196
201
  const pullGateKey = this.pullGateKeyForCall(method, p);
202
+ if (client._p2pPeerPullEnabled && method === 'message.peers')
203
+ return await client._delivery.peers(p, rpcBackground);
204
+ if (client._p2pPeerPullEnabled && (method === 'message.pull' || method === 'message.v2.pull')) {
205
+ await client._ensureV2SessionReady('message.pull');
206
+ return await client._delivery.pullPeers(p, rpcBackground);
207
+ }
208
+ if (client._p2pPeerPullEnabled && method === 'message.history') {
209
+ await client._ensureV2SessionReady('message.history');
210
+ const key = this.pullGateKeyForCall(method, p);
211
+ return await this.runPullNamespaceSerialized(key, () => client._v2E2EE.peerHistoryV2(p), rpcBackground);
212
+ }
213
+ if (client._p2pPeerPullEnabled && (method === 'message.ack' || method === 'message.v2.ack')) {
214
+ const sender = String(p.sender_aid ?? '').trim();
215
+ if (!sender)
216
+ throw new ValidationError('peer ACK requires sender_aid');
217
+ return await client._v2E2EE.ackPeerV2(sender, requestedAckSeq || undefined, Array.isArray(p.volatile_cursors) ? p.volatile_cursors : [], Array.isArray(p.volatile_ids) ? p.volatile_ids : []);
218
+ }
197
219
  const runWithPullResponseScope = async (operation) => {
198
220
  const scope = pullGateNamespace || (pullGateKey ? this.pullScopeKey(pullGateKey) : '');
199
221
  const wrapper = client._withPullResponseProcessing;
@@ -207,9 +229,13 @@ export class RpcPipeline {
207
229
  lockedParams._pull_gate_namespace = this.pullScopeKey(pullGateKey);
208
230
  if (pullBackground)
209
231
  lockedParams._rpc_background = true;
232
+ else
233
+ lockedParams._rpc_foreground = true;
210
234
  if (skipSendResultEnvelope)
211
235
  lockedParams._skip_send_result_envelope = true;
212
- return await this.runPullSerialized(pullGateKey, async () => this.call(method, lockedParams), pullBackground);
236
+ const run = ['group.pull', 'group.v2.pull', 'group.history'].includes(method)
237
+ ? this.runPullNamespaceSerialized.bind(this) : this.runPullSerialized.bind(this);
238
+ return await run(pullGateKey, async () => this.call(method, lockedParams), pullBackground);
213
239
  }
214
240
  if (method === 'message.send') {
215
241
  const encrypt = p.encrypt ?? true;
@@ -222,6 +248,7 @@ export class RpcPipeline {
222
248
  ttl: p.ttl,
223
249
  protectedHeaders: client._protectedHeadersFromParams(p),
224
250
  context: isJsonObject(p.context) ? p.context : undefined,
251
+ needRender: p.need_render,
225
252
  }));
226
253
  }
227
254
  client._maybeAppendEchoTraceSend(p);
@@ -236,6 +263,7 @@ export class RpcPipeline {
236
263
  timestamp: p.timestamp,
237
264
  protectedHeaders: client._protectedHeadersFromParams(p),
238
265
  context: isJsonObject(p.context) ? p.context : undefined,
266
+ needRender: p.need_render,
239
267
  }));
240
268
  }
241
269
  client._maybeAppendEchoTraceSend(p);
@@ -298,12 +326,12 @@ export class RpcPipeline {
298
326
  }
299
327
  await client._ensureV2SessionReady('group.pull');
300
328
  if (p.window_mode === 'tail') {
301
- return await runWithPullResponseScope(() => client._v2E2EE.pullGroupV2TailInternal(p));
329
+ return await runWithPullResponseScope(() => client._v2E2EE.pullGroupV2TailInternal(p, false, true));
302
330
  }
303
331
  const hasExplicitAfterSeq = 'after_seq' in p || 'after_message_seq' in p;
304
332
  const cursorParams = this.explicitGroupCursorParams(p);
305
333
  const ownsCursor = Object.keys(cursorParams).length === 0 || this.groupCursorTargetsCurrentInstance(cursorParams);
306
- const pullOpts = { gateLocked: true };
334
+ const pullOpts = { gateLocked: true, background: rpcBackground };
307
335
  if (hasExplicitAfterSeq)
308
336
  pullOpts.explicitAfterSeq = true;
309
337
  if (p.force === true)
@@ -316,7 +344,7 @@ export class RpcPipeline {
316
344
  pullOpts.wireGroupId = String(p.group_id).trim();
317
345
  if (String(p.group_aid ?? '').trim())
318
346
  pullOpts.groupAid = String(p.group_aid).trim();
319
- const messages = await runWithPullResponseScope(() => runWithRpcPriority(() => client._pullGroupV2(String(p.group_id ?? p.group_aid), Number(p.after_seq ?? p.after_message_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, pullOpts)));
347
+ const messages = await runWithPullResponseScope(() => client._pullGroupV2(String(p.group_id ?? p.group_aid), Number(p.after_seq ?? p.after_message_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, pullOpts));
320
348
  return { messages };
321
349
  }
322
350
  if (method === 'group.history') {
@@ -349,13 +377,15 @@ export class RpcPipeline {
349
377
  client._clientLog.debug(`thought.get transport call start: method=${method}, params=${client._debugJson(client._messageEnvelopeFieldsForDebug(p))}`);
350
378
  }
351
379
  const invokeTransport = () => {
352
- const request = callTimeout
353
- ? (rpcBackground
354
- ? client._transport.call(method, p, callTimeout, undefined, true)
355
- : client._transport.call(method, p, callTimeout))
356
- : (rpcBackground
357
- ? client._transport.call(method, p, undefined, undefined, true)
358
- : client._transport.call(method, p));
380
+ const request = onSent
381
+ ? client._transport['_callWithSent'](method, p, onSent, callTimeout, undefined, rpcBackground)
382
+ : callTimeout
383
+ ? (rpcBackground
384
+ ? client._transport.call(method, p, callTimeout, undefined, true)
385
+ : client._transport.call(method, p, callTimeout))
386
+ : (rpcBackground
387
+ ? client._transport.call(method, p, undefined, undefined, true)
388
+ : client._transport.call(method, p));
359
389
  return this.bindActivePullCancellation(method, p, request);
360
390
  };
361
391
  let result = await this.transportCallWithIdentityRecovery(invokeTransport, method, p);
@@ -392,8 +422,11 @@ export class RpcPipeline {
392
422
  }
393
423
  const p = { ...(params ?? {}) };
394
424
  this.mergeInstanceProtectedHeaders(method, p);
395
- const rpcBackground = Boolean(p._rpc_background) || client._backgroundRpcDepth > 0;
425
+ const rpcBackground = !Boolean(p._rpc_foreground)
426
+ && (Boolean(p._rpc_background)
427
+ || (!['message.peers', 'message.pull', 'message.v2.pull', 'group.pull', 'group.v2.pull', 'group.history', 'group.pull_events'].includes(method) && client._backgroundRpcDepth > 0));
396
428
  delete p._rpc_background;
429
+ delete p._rpc_foreground;
397
430
  if (method === 'message.send' || method === 'group.send') {
398
431
  this.normalizeOutboundMessagePayload(p, method);
399
432
  const messageId = String(p.message_id ?? '').trim();
@@ -430,6 +463,9 @@ export class RpcPipeline {
430
463
  }
431
464
  }
432
465
  validateOutboundCall(method, params) {
466
+ if ((method === 'message.send' || method === 'group.send') && params.need_render !== undefined && typeof params.need_render !== 'boolean') {
467
+ throw new ValidationError('need_render must be a boolean');
468
+ }
433
469
  if (method === 'message.send') {
434
470
  this.validateMessageRecipient(params.to);
435
471
  // 校验目标 AID 格式(拒绝 __system__ 等非法格式)
@@ -492,7 +528,7 @@ export class RpcPipeline {
492
528
  }
493
529
  }
494
530
  injectMessageCursorContext(method, params) {
495
- if (!['message.pull', 'message.v2.pull', 'message.ack', 'message.v2.ack'].includes(method)) {
531
+ if (!['message.pull', 'message.v2.pull', 'message.history', 'message.ack', 'message.v2.ack', 'message.peers'].includes(method)) {
496
532
  return;
497
533
  }
498
534
  const client = this.runtime.client;
@@ -505,6 +541,19 @@ export class RpcPipeline {
505
541
  }
506
542
  params.device_id = client._deviceId;
507
543
  params.slot_id = client._slotId;
544
+ if (client._p2pPeerPullEnabled) {
545
+ if (params.cursor_scope !== undefined && params.cursor_scope !== 'peer')
546
+ throw new ValidationError('new SDK requires peer cursor_scope');
547
+ if (params.sender_aid !== undefined)
548
+ validateAIDFormat(params.sender_aid, 'sender_aid');
549
+ params.cursor_scope = 'peer';
550
+ if ((method === 'message.pull' || method === 'message.v2.pull') && params.sender_aid && !('after_volatile_cursor' in params)) {
551
+ const cursor = client._delivery.peerVolatilePullCursor(String(params.sender_aid));
552
+ if (cursor)
553
+ params.after_volatile_cursor = cursor;
554
+ }
555
+ return;
556
+ }
508
557
  if ((method === 'message.pull' || method === 'message.v2.pull') && !('after_volatile_cursor' in params)) {
509
558
  const cursor = String(client._delivery.volatilePullCursor?.() ?? '').trim();
510
559
  if (cursor)
@@ -610,7 +659,10 @@ export class RpcPipeline {
610
659
  cursor = `after=${String(params.after_seq ?? 0)}`;
611
660
  }
612
661
  const limit = mode === 'forward' ? (Number(params.limit ?? 50) || 50) : params.limit;
613
- return `p2p:${client._aid}|mode=${mode}|cursor=${cursor}|volatile=${String(params.after_volatile_cursor ?? '')}|force=${String(Boolean(params.force))}|limit=${String(limit)}`;
662
+ if (client._p2pPeerPullEnabled && !params.sender_aid)
663
+ return '';
664
+ const namespace = client._p2pPeerPullEnabled ? client._delivery.peerNamespace(String(params.sender_aid)) : `p2p:${client._aid}`;
665
+ return `${namespace}|mode=${mode}|cursor=${cursor}|volatile=${String(params.after_volatile_cursor ?? '')}|force=${String(Boolean(params.force))}|limit=${String(limit)}`;
614
666
  }
615
667
  if (method === 'group.pull' || method === 'group.v2.pull' || method === 'group.history') {
616
668
  const groupId = String(params.group_id ?? params.group_aid ?? '').trim();
@@ -655,14 +707,15 @@ export class RpcPipeline {
655
707
  void key;
656
708
  return 'pull';
657
709
  }
658
- pullGateState(key) {
659
- const name = this.pullGateName(key);
710
+ pullGateState(key, namespaceOnly = false) {
711
+ const name = namespaceOnly ? 'pull-namespace' : this.pullGateName(key);
660
712
  let state = this.pullGateStates.get(name);
661
713
  if (!state) {
662
- state = { activeByNamespace: new Map(), foreground: [], background: [], byKey: new Map(), lifecycle: new Map(), watchdog: null };
714
+ state = { networkLimited: !namespaceOnly, activeByNamespace: new Map(), foreground: [], background: [], backgroundPeerDispatches: 0, byKey: new Map(), lifecycle: new Map(), watchdog: null };
663
715
  this.pullGateStates.set(name, state);
664
716
  }
665
- this.startPullGateWatchdog(state, name);
717
+ if (state.networkLimited)
718
+ this.startPullGateWatchdog(state, name);
666
719
  return state;
667
720
  }
668
721
  pullGateOperationTimeoutMs() {
@@ -740,9 +793,11 @@ export class RpcPipeline {
740
793
  }
741
794
  hasPullActivity(namespace, includePending = true) {
742
795
  const ns = String(namespace ?? '').trim();
743
- if ((!ns.startsWith('p2p:') && !ns.startsWith('group:')) || this.hasInlineRealtimeGuard(ns))
796
+ if ((!ns.startsWith('p2p:') && !ns.startsWith('p2p.peer.v1/') && !ns.startsWith('group:')) || this.hasInlineRealtimeGuard(ns))
744
797
  return true;
745
798
  const client = this.runtime.client;
799
+ if (client._delivery?.hasPeerPageActivity?.(ns))
800
+ return true;
746
801
  if ((client._pullResponseKeys.get(ns) ?? 0) > 0)
747
802
  return true;
748
803
  if (includePending && Number(client._pendingP2pPullUpper?.get?.(ns) ?? 0) > 0)
@@ -769,7 +824,7 @@ export class RpcPipeline {
769
824
  }
770
825
  async tryRunInlineRealtime(namespace, seq, operation) {
771
826
  const ns = String(namespace ?? '').trim();
772
- if ((!ns.startsWith('p2p:') && !ns.startsWith('group:'))
827
+ if ((!ns.startsWith('p2p:') && !ns.startsWith('p2p.peer.v1/') && !ns.startsWith('group:'))
773
828
  || !Number.isSafeInteger(seq) || seq <= 0 || typeof operation !== 'function'
774
829
  || this.hasPullActivity(ns)) {
775
830
  return { acquired: false };
@@ -780,12 +835,11 @@ export class RpcPipeline {
780
835
  }
781
836
  finally {
782
837
  this.inlineRealtimeScopes.delete(ns);
783
- const state = this.pullGateStates.get(this.pullGateName(ns));
784
- if (state) {
838
+ for (const state of this.pullGateStates.values()) {
785
839
  this.drainPullGate(state);
786
- this.runtime.client._delivery?.onPullGateIdle?.(ns);
787
840
  this.armQueuedPullTimers(state);
788
841
  }
842
+ this.runtime.client._delivery?.onPullGateIdle?.(ns);
789
843
  }
790
844
  }
791
845
  tryAcquirePullGate(key) {
@@ -825,8 +879,10 @@ export class RpcPipeline {
825
879
  const ns = this.pullScopeKey(namespace);
826
880
  if (!ns)
827
881
  return true;
828
- const active = this.pullGateStates.get(this.pullGateName(ns))?.activeByNamespace.get(ns);
829
- return !active || active.namespace !== ns || (!active.timedOut && !active.invalidated);
882
+ return [...this.pullGateStates.values()].every((state) => {
883
+ const active = state.activeByNamespace.get(ns);
884
+ return !active || active.namespace !== ns || (!active.timedOut && !active.invalidated);
885
+ });
830
886
  }
831
887
  invalidatePulls() {
832
888
  if (this.pullInvalidationWait)
@@ -859,6 +915,7 @@ export class RpcPipeline {
859
915
  }
860
916
  state.foreground = state.foreground.filter((job) => !jobs.has(job));
861
917
  state.background = state.background.filter((job) => !jobs.has(job));
918
+ state.backgroundPeerDispatches = 0;
862
919
  for (const [key, job] of state.byKey.entries()) {
863
920
  if (jobs.has(job) && !job.running)
864
921
  state.byKey.delete(key);
@@ -877,7 +934,10 @@ export class RpcPipeline {
877
934
  pullInvalidationInProgress() {
878
935
  return this.pullInvalidationWait !== null;
879
936
  }
880
- async runPullSerialized(key, operation, background = false) {
937
+ async runPullNamespaceSerialized(key, operation, background = false) {
938
+ return await this.runPullSerialized(key, operation, background, true);
939
+ }
940
+ async runPullSerialized(key, operation, background = false, namespaceOnly = false) {
881
941
  if (this.runtime.client._dispatcher?._isApplicationHandler?.()) {
882
942
  throw new Error('pull cannot wait inside an application handler');
883
943
  }
@@ -893,7 +953,7 @@ export class RpcPipeline {
893
953
  throw error;
894
954
  }
895
955
  }
896
- const state = this.pullGateState(key);
956
+ const state = this.pullGateState(key, namespaceOnly);
897
957
  const namespace = this.pullScopeKey(key);
898
958
  const active = [...state.activeByNamespace.values()].find((job) => job.key === key && !job.timedOut && !job.invalidated) ?? null;
899
959
  const queuedForeground = state.foreground.find((job) => job.key === key && !job.timedOut && !job.invalidated);
@@ -937,7 +997,8 @@ export class RpcPipeline {
937
997
  queue.push(job);
938
998
  state.byKey.set(key, job);
939
999
  this.drainPullGate(state);
940
- this.checkPullGate(state, this.pullGateName(key));
1000
+ if (state.networkLimited)
1001
+ this.checkPullGate(state, this.pullGateName(key));
941
1002
  return await promise;
942
1003
  }
943
1004
  async executePullOperation(operation, background) {
@@ -1000,15 +1061,40 @@ export class RpcPipeline {
1000
1061
  state.lifecycle.set(ns, lifecycle);
1001
1062
  }
1002
1063
  drainPullGate(state) {
1003
- const takeRunnable = (queue) => {
1004
- const index = queue.findIndex((candidate) => (!this.hasInlineRealtimeGuard(this.pullScopeKey(candidate.key))
1005
- && !state.activeByNamespace.has(candidate.namespace)));
1006
- return index >= 0 ? queue.splice(index, 1)[0] : undefined;
1064
+ const peerForward = (job) => job.background && job.namespace.startsWith('p2p.peer.v1/')
1065
+ && job.key.includes('|mode=forward|') && !job.key.includes('|force=true|');
1066
+ const priority = (job) => peerForward(job)
1067
+ ? this.runtime.client._delivery?.peerPullPriority?.(job.namespace) ?? null : null;
1068
+ const runnable = (candidate) => (!this.hasInlineRealtimeGuard(this.pullScopeKey(candidate.key))
1069
+ && !state.activeByNamespace.has(candidate.namespace));
1070
+ const takeRunnable = (queue, background = false) => {
1071
+ let index = queue.findIndex(runnable);
1072
+ if (index < 0)
1073
+ return;
1074
+ if (background && peerForward(queue[index])
1075
+ && (state.backgroundPeerDispatches + 1) % _INTERNAL_MESSAGE_FLOW_LIMITS.pullMaxInflight !== 0) {
1076
+ let best = priority(queue[index]);
1077
+ if (best !== null) {
1078
+ for (let next = index + 1; next < queue.length; next += 1) {
1079
+ const hint = priority(queue[next]);
1080
+ if (hint === null)
1081
+ break;
1082
+ if (runnable(queue[next]) && hint < best) {
1083
+ best = hint;
1084
+ index = next;
1085
+ }
1086
+ }
1087
+ }
1088
+ }
1089
+ const job = queue.splice(index, 1)[0];
1090
+ if (background && peerForward(job))
1091
+ state.backgroundPeerDispatches += 1;
1092
+ return job;
1007
1093
  };
1008
- while (state.activeByNamespace.size < PULL_GATE_MAX_ACTIVE) {
1094
+ while (state.activeByNamespace.size < _INTERNAL_MESSAGE_FLOW_LIMITS.pullMaxInflight) {
1009
1095
  const foregroundJob = takeRunnable(state.foreground);
1010
1096
  const foregroundDrained = foregroundJob !== undefined && state.foreground.length === 0;
1011
- const job = foregroundJob ?? takeRunnable(state.background);
1097
+ const job = foregroundJob ?? takeRunnable(state.background, true);
1012
1098
  if (!job)
1013
1099
  break;
1014
1100
  state.activeByNamespace.set(job.namespace, job);
@@ -1031,7 +1117,7 @@ export class RpcPipeline {
1031
1117
  continue;
1032
1118
  }
1033
1119
  job.running = true;
1034
- const operationPromise = this.executePullOperation(job.operation, job.background);
1120
+ const operationPromise = this.executePullOperation(job.operation, state.networkLimited && job.background);
1035
1121
  let failed = false;
1036
1122
  void operationPromise
1037
1123
  .then((value) => { if (!job.timedOut && !job.invalidated)