@agentunion/fastaun-browser 0.5.4 → 0.5.6
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.
- package/CHANGELOG.md +130 -94
- package/_packed_docs/AUN/347/246/273/347/272/277/346/216/250/351/200/201/346/216/245/345/205/245/344/270/216/346/274/224/347/244/272/346/214/207/345/215/227.md +290 -0
- package/_packed_docs/AUN/347/246/273/347/272/277/346/216/250/351/200/201/346/234/215/345/212/241/346/236/266/346/236/204/344/270/216/350/257/246/347/273/206/345/256/236/347/216/260/350/256/241/345/210/222-codex.md +994 -0
- package/_packed_docs/AUN/347/246/273/347/272/277/346/216/250/351/200/201/346/234/215/345/212/241/350/277/220/347/273/264/344/270/216/345/217/221/345/270/203/346/214/207/345/215/227.md +144 -0
- package/_packed_docs/CHANGELOG.md +130 -94
- package/_packed_docs/INDEX.md +127 -69
- package/_packed_docs/KITE_DOCS_GUIDE.md +63 -29
- package/_packed_docs/audit/AUN/346/234/215/345/212/241Go/345/214/226/351/207/215/346/236/204/347/262/276/347/273/206/345/214/226/346/272/220/347/240/201/345/256/241/346/237/245-20260718.md +366 -0
- package/_packed_docs/aun/345/205/254/347/275/221/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +227 -0
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +1004 -0
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +999 -0
- package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +6 -4
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +58 -20
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +219 -247
- package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +14 -14
- package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +3 -3
- 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 +165 -421
- package/_packed_docs/protocol/README.md +1 -0
- package/_packed_docs/protocol/aun-docs-guide.md +7 -4
- package/_packed_docs/protocol/index.md +25 -19
- package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +62 -17
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +22 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +67 -78
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +6 -2
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +50 -14
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +18 -5
- package/_packed_docs/sdk/09-group-rpc-manual.md +312 -282
- package/_packed_docs/sdk/09-message-rpc-manual.md +142 -103
- package/_packed_docs/sdk/09-payload-reference.md +1 -1
- package/_packed_docs/sdk/09-stream-rpc-manual.md +8 -8
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +26 -17
- package/_packed_docs/sdk/INDEX.md +42 -34
- package/_packed_docs/sdk/README.md +7 -6
- package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/344/273/243/347/240/201/345/256/241/346/237/245/351/227/256/351/242/230/346/270/205/345/215/225.md +229 -0
- package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/346/224/271/351/200/240/346/226/271/346/241/210.md +750 -0
- package/dist/agent-md.d.ts +4 -5
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +66 -43
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +2 -6
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +20 -14
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +30 -11
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +3297 -1023
- package/dist/client/delivery.d.ts +75 -8
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +1419 -245
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.d.ts.map +1 -1
- package/dist/client/group-state.js +27 -24
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.d.ts.map +1 -1
- package/dist/client/lifecycle.js +48 -4
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/mention-mode.d.ts +7 -0
- package/dist/client/mention-mode.d.ts.map +1 -0
- package/dist/client/mention-mode.js +184 -0
- package/dist/client/mention-mode.js.map +1 -0
- package/dist/client/peers.d.ts +1 -1
- package/dist/client/peers.d.ts.map +1 -1
- package/dist/client/peers.js +26 -3
- package/dist/client/peers.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +22 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +309 -74
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +25 -2
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +606 -97
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +24 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +404 -215
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +4 -1
- package/dist/errors.js.map +1 -1
- package/dist/facades.d.ts +3 -0
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +91 -53
- package/dist/facades.js.map +1 -1
- package/dist/group-index.d.ts +6 -1
- package/dist/group-index.d.ts.map +1 -1
- package/dist/group-index.js +44 -25
- package/dist/group-index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/keystore/index.d.ts +10 -5
- package/dist/keystore/index.d.ts.map +1 -1
- package/dist/keystore/indexeddb-identity-store.d.ts +0 -12
- package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-identity-store.js +0 -60
- package/dist/keystore/indexeddb-identity-store.js.map +1 -1
- package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.js +9 -5
- package/dist/keystore/indexeddb-shared.js.map +1 -1
- package/dist/keystore/indexeddb-token-store.d.ts +3 -1
- package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-token-store.js +47 -2
- package/dist/keystore/indexeddb-token-store.js.map +1 -1
- package/dist/register-flow.d.ts.map +1 -1
- package/dist/register-flow.js +28 -3
- package/dist/register-flow.js.map +1 -1
- package/dist/seq-tracker.d.ts +28 -8
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +218 -61
- package/dist/seq-tracker.js.map +1 -1
- package/dist/storage/vfs.d.ts +1 -0
- package/dist/storage/vfs.d.ts.map +1 -1
- package/dist/storage/vfs.js +26 -2
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.js +376 -10
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +12 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +218 -101
- package/dist/transport.js.map +1 -1
- package/dist/v2/session/session.d.ts.map +1 -1
- package/dist/v2/session/session.js +3 -4
- package/dist/v2/session/session.js.map +1 -1
- package/dist/v2/state/commitment.d.ts.map +1 -1
- package/dist/v2/state/commitment.js +1 -2
- package/dist/v2/state/commitment.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -5
- package/dist/group-resources.d.ts +0 -98
- package/dist/group-resources.d.ts.map +0 -1
- package/dist/group-resources.js +0 -635
- package/dist/group-resources.js.map +0 -1
- package/dist/keystore/indexeddb.d.ts +0 -179
- package/dist/keystore/indexeddb.d.ts.map +0 -1
- package/dist/keystore/indexeddb.js +0 -2031
- package/dist/keystore/indexeddb.js.map +0 -1
- package/dist/namespaces/auth.d.ts +0 -98
- package/dist/namespaces/auth.d.ts.map +0 -1
- package/dist/namespaces/auth.js +0 -992
- package/dist/namespaces/auth.js.map +0 -1
- package/dist/namespaces/custody.d.ts +0 -51
- package/dist/namespaces/custody.d.ts.map +0 -1
- package/dist/namespaces/custody.js +0 -302
- package/dist/namespaces/custody.js.map +0 -1
- package/dist/namespaces/meta.d.ts +0 -109
- package/dist/namespaces/meta.d.ts.map +0 -1
- package/dist/namespaces/meta.js +0 -549
- package/dist/namespaces/meta.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { normalizeSlotId, slotIsolationKey } from '../config.js';
|
|
2
|
-
import { ClientSignatureError, ConnectionError, PermissionError,
|
|
3
|
-
import { normalizeGroupId } from '../group-id.js';
|
|
2
|
+
import { ClientSignatureError, ConnectionError, PermissionError, ValidationError } from '../errors.js';
|
|
4
3
|
import { validateAIDFormat, validateGroupIDFormat } from '../validators.js';
|
|
5
4
|
import { p1363ToDer, pemToArrayBuffer, uint8ToBase64 } from '../crypto.js';
|
|
6
5
|
import { ConnectionState, isJsonObject, } from '../types.js';
|
|
6
|
+
import { normalizeGroupMentionMode, normalizeGroupSettingsResponse } from './mention-mode.js';
|
|
7
7
|
const INTERNAL_ONLY_METHODS = new Set([
|
|
8
8
|
'auth.login1',
|
|
9
9
|
'auth.aid_login1',
|
|
@@ -22,11 +22,11 @@ const PROTECTED_HEADERS_METHODS = new Set([
|
|
|
22
22
|
const SIGNED_METHODS = new Set([
|
|
23
23
|
'message.send',
|
|
24
24
|
'message.v2.put_peer_pk', 'message.v2.bootstrap',
|
|
25
|
-
'message.v2.group_bootstrap', 'message.v2.pull',
|
|
25
|
+
'message.v2.group_bootstrap', 'message.v2.pull', 'message.history',
|
|
26
26
|
'message.v2.ack',
|
|
27
27
|
'group.send',
|
|
28
28
|
'group.v2.put_group_pk', 'group.v2.bootstrap',
|
|
29
|
-
'group.v2.send', 'group.v2.pull', 'group.v2.ack',
|
|
29
|
+
'group.v2.send', 'group.v2.pull', 'group.history', 'group.v2.ack',
|
|
30
30
|
'group.v2.propose_state', 'group.v2.confirm_state',
|
|
31
31
|
'group.v2.get_proposal',
|
|
32
32
|
'group.kick', 'group.add_member',
|
|
@@ -167,6 +167,8 @@ function isTransientV2PullFallbackError(error) {
|
|
|
167
167
|
}
|
|
168
168
|
export class RpcPipeline {
|
|
169
169
|
runtime;
|
|
170
|
+
pullGateStates = new Map();
|
|
171
|
+
bypassedRealtimePulls = new Map();
|
|
170
172
|
constructor(runtime) {
|
|
171
173
|
this.runtime = runtime;
|
|
172
174
|
}
|
|
@@ -217,7 +219,8 @@ export class RpcPipeline {
|
|
|
217
219
|
if (encrypt) {
|
|
218
220
|
await client._ensureV2SessionReady('group.send', 'V2 session not initialized; encrypted group.send requires V2 (V1 E2EE removed)');
|
|
219
221
|
client._clientLog.debug('call route: group.send -> V2 encrypted send');
|
|
220
|
-
return await client._sendGroupV2(String(p.
|
|
222
|
+
return await client._sendGroupV2(String(p.group_id ?? p.group_aid ?? ''), p.payload ?? {}, {
|
|
223
|
+
groupAid: String(p.group_aid ?? '').trim() || undefined,
|
|
221
224
|
messageId: String(p.message_id ?? '') || undefined,
|
|
222
225
|
timestamp: p.timestamp,
|
|
223
226
|
protectedHeaders: client._protectedHeadersFromParams(p),
|
|
@@ -246,9 +249,11 @@ export class RpcPipeline {
|
|
|
246
249
|
}
|
|
247
250
|
const pullGateKey = this.pullGateKeyForCall(method, p);
|
|
248
251
|
if (pullGateKey) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
+
if (this.isPullResponseProcessing(pullGateKey)) {
|
|
253
|
+
client._clientLog.debug(`pull skipped while processing pull response: method=${method} key=${pullGateKey}`);
|
|
254
|
+
return this.emptyPullResultForCall(method);
|
|
255
|
+
}
|
|
256
|
+
return await this.runPullSerialized(pullGateKey, async () => await this.callImplInner(method, p, skipSendResultEnvelope), this.pullGateBackgroundForCall(method, p));
|
|
252
257
|
}
|
|
253
258
|
return await runWithRpcPriority(() => this.callImplInner(method, p, skipSendResultEnvelope));
|
|
254
259
|
}
|
|
@@ -258,6 +263,8 @@ export class RpcPipeline {
|
|
|
258
263
|
try {
|
|
259
264
|
await client._ensureV2SessionReady('message.pull');
|
|
260
265
|
client._clientLog.debug(`call route: ${method} -> V2 pull`);
|
|
266
|
+
if (p.window_mode === 'tail')
|
|
267
|
+
return await client._v2E2EE.pullV2TailInternal(p);
|
|
261
268
|
const messages = await client._pullV2(Number(p.after_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, { force: p.force === true });
|
|
262
269
|
return { messages };
|
|
263
270
|
}
|
|
@@ -268,29 +275,45 @@ export class RpcPipeline {
|
|
|
268
275
|
client._clientLog.warn(`message.pull V2 route unavailable, fallback to plain pull: ${exc instanceof Error ? exc.message : String(exc)}`);
|
|
269
276
|
}
|
|
270
277
|
}
|
|
278
|
+
if (method === 'message.history') {
|
|
279
|
+
await client._ensureV2SessionReady('message.history');
|
|
280
|
+
return await client._v2E2EE.historyV2Internal(p);
|
|
281
|
+
}
|
|
271
282
|
if (method === 'message.v2.ack' || (method === 'message.ack' && hasMatchingV2Session(client))) {
|
|
272
283
|
await client._ensureV2SessionReady('message.ack');
|
|
273
284
|
client._clientLog.debug(`call route: ${method} -> V2 ack`);
|
|
274
|
-
return await client._ackV2(
|
|
285
|
+
return await client._ackV2((p.seq ?? p.up_to_seq));
|
|
275
286
|
}
|
|
276
287
|
if ((method === 'group.v2.pull' || method === 'group.pull') && p.group_id && (method === 'group.v2.pull' || hasMatchingV2Session(client))) {
|
|
277
288
|
await client._ensureV2SessionReady('group.pull');
|
|
278
289
|
client._clientLog.debug(`call route: ${method} -> V2 pull`);
|
|
290
|
+
if (p.window_mode === 'tail')
|
|
291
|
+
return await client._v2E2EE.pullGroupV2TailInternal(p);
|
|
279
292
|
const hasExplicitAfterSeq = 'after_seq' in p || 'after_message_seq' in p;
|
|
280
293
|
const cursorParams = client._explicitGroupCursorParams(p);
|
|
281
294
|
const ownsCursor = Object.keys(cursorParams).length === 0 || client._groupCursorTargetsCurrentInstance(cursorParams);
|
|
282
295
|
const pullOpts = {};
|
|
283
296
|
if (hasExplicitAfterSeq)
|
|
284
297
|
pullOpts.explicitAfterSeq = true;
|
|
298
|
+
if (p.force === true)
|
|
299
|
+
pullOpts.force = true;
|
|
285
300
|
if (Object.keys(cursorParams).length > 0)
|
|
286
301
|
pullOpts.cursorParams = cursorParams;
|
|
287
302
|
if (!ownsCursor)
|
|
288
303
|
pullOpts.ownsCursor = false;
|
|
289
304
|
if (String(p.group_id ?? '').trim())
|
|
290
305
|
pullOpts.wireGroupId = String(p.group_id).trim();
|
|
291
|
-
|
|
306
|
+
if (String(p.group_aid ?? '').trim())
|
|
307
|
+
pullOpts.groupAid = String(p.group_aid).trim();
|
|
308
|
+
const messages = await client._pullGroupV2(String(p.group_id ?? p.group_aid), Number(p.after_seq ?? p.after_message_seq ?? 0) || 0, Number(p.limit ?? 50) || 50, Object.keys(pullOpts).length > 0 ? pullOpts : undefined);
|
|
292
309
|
return { messages };
|
|
293
310
|
}
|
|
311
|
+
if (method === 'group.history') {
|
|
312
|
+
if (!String(p.group_id ?? p.group_aid ?? '').trim())
|
|
313
|
+
throw new ValidationError('group.history requires group_id');
|
|
314
|
+
await client._ensureV2SessionReady('group.history');
|
|
315
|
+
return await client._v2E2EE.historyGroupV2Internal(p);
|
|
316
|
+
}
|
|
294
317
|
if ((method === 'group.v2.ack' || method === 'group.ack_messages') && p.group_id && (method === 'group.v2.ack' || hasMatchingV2Session(client))) {
|
|
295
318
|
await client._ensureV2SessionReady('group.ack_messages');
|
|
296
319
|
client._clientLog.debug(`call route: ${method} -> V2 ack`);
|
|
@@ -299,7 +322,7 @@ export class RpcPipeline {
|
|
|
299
322
|
if (!ownsCursor) {
|
|
300
323
|
return await client._rawGroupAckMessages(p);
|
|
301
324
|
}
|
|
302
|
-
return await client._ackGroupV2(
|
|
325
|
+
return await client._ackGroupV2((p.group_id ?? p.group_aid), (p.seq ?? p.msg_seq ?? p.up_to_seq), p.group_aid);
|
|
303
326
|
}
|
|
304
327
|
await this.applyClientSignature(method, p);
|
|
305
328
|
const callTimeout = NON_IDEMPOTENT_METHODS.has(method) ? NON_IDEMPOTENT_TIMEOUT : undefined;
|
|
@@ -307,9 +330,10 @@ export class RpcPipeline {
|
|
|
307
330
|
let result = callTimeout
|
|
308
331
|
? await client._transport.call(method, p, callTimeout, undefined, rpcBackground)
|
|
309
332
|
: await client._transport.call(method, p, undefined, undefined, rpcBackground);
|
|
333
|
+
const sendResultModeSource = result;
|
|
310
334
|
result = await this.postprocessResult(method, p, result);
|
|
311
335
|
if (!skipSendResultEnvelope) {
|
|
312
|
-
result = client._delivery.attachSendResultEnvelope(method, p, result, Boolean(p.encrypted));
|
|
336
|
+
result = client._delivery.attachSendResultEnvelope(method, p, result, Boolean(p.encrypted), sendResultModeSource);
|
|
313
337
|
}
|
|
314
338
|
return result;
|
|
315
339
|
}
|
|
@@ -501,22 +525,166 @@ export class RpcPipeline {
|
|
|
501
525
|
// ── Pull Gate(序列化同一 key 的并发 pull)──────────────────
|
|
502
526
|
pullGateKeyForCall(method, params) {
|
|
503
527
|
const client = this.runtime.client;
|
|
504
|
-
if (method === 'message.pull' || method === 'message.v2.pull') {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const
|
|
509
|
-
|
|
528
|
+
if (method === 'message.pull' || method === 'message.v2.pull' || method === 'message.history') {
|
|
529
|
+
if (!client._aid)
|
|
530
|
+
return '';
|
|
531
|
+
const mode = method === 'message.history' ? 'history' : params.window_mode === 'tail' ? 'tail' : 'forward';
|
|
532
|
+
const cursor = mode === 'history'
|
|
533
|
+
? `before=${String(params.before_seq)}`
|
|
534
|
+
: `after=${String(params.after_seq ?? 0)}|force=${String(Boolean(params.force))}`;
|
|
535
|
+
return `p2p:${client._aid}|${mode}|${cursor}|limit=${String(params.limit)}`;
|
|
536
|
+
}
|
|
537
|
+
if (method === 'group.pull' || method === 'group.v2.pull' || method === 'group.history') {
|
|
538
|
+
const gid = String(params.group_id ?? params.group_aid ?? '').trim();
|
|
539
|
+
if (!gid)
|
|
540
|
+
return '';
|
|
541
|
+
const mode = method === 'group.history' ? 'history' : params.window_mode === 'tail' ? 'tail' : 'forward';
|
|
542
|
+
const cursor = mode === 'history'
|
|
543
|
+
? `before=${String(params.before_seq)}`
|
|
544
|
+
: `after=${String(params.after_seq ?? params.after_message_seq ?? 0)}|force=${String(Boolean(params.force))}`;
|
|
545
|
+
return `group:${gid}|${mode}|${cursor}|limit=${String(params.limit)}`;
|
|
510
546
|
}
|
|
511
547
|
if (method === 'group.pull_events') {
|
|
512
|
-
const gid = String(params.
|
|
513
|
-
return gid
|
|
548
|
+
const gid = String(params.group_id ?? params.group_aid ?? '').trim();
|
|
549
|
+
return gid
|
|
550
|
+
? `group_event:${gid}|forward|after=${String(params.after_event_seq ?? 0)}|limit=${String(params.limit)}`
|
|
551
|
+
: '';
|
|
552
|
+
}
|
|
553
|
+
return '';
|
|
554
|
+
}
|
|
555
|
+
pullGateBackgroundForCall(method, params) {
|
|
556
|
+
if (method === 'message.history' || method === 'group.history')
|
|
557
|
+
return false;
|
|
558
|
+
if (['message.pull', 'message.v2.pull', 'group.pull', 'group.v2.pull'].includes(method)) {
|
|
559
|
+
return params.window_mode !== 'tail';
|
|
560
|
+
}
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
pullGateName(key) {
|
|
564
|
+
if (key.startsWith('p2p:'))
|
|
565
|
+
return 'p2p_message';
|
|
566
|
+
if (key.startsWith('group:'))
|
|
567
|
+
return 'group_message';
|
|
568
|
+
if (key.startsWith('group_event:'))
|
|
569
|
+
return 'group_event';
|
|
570
|
+
return `other:${key}`;
|
|
571
|
+
}
|
|
572
|
+
pullGateState(key) {
|
|
573
|
+
const name = this.pullGateName(key);
|
|
574
|
+
let state = this.pullGateStates.get(name);
|
|
575
|
+
if (!state) {
|
|
576
|
+
state = { active: null, foreground: [], background: [], byKey: new Map() };
|
|
577
|
+
this.pullGateStates.set(name, state);
|
|
578
|
+
}
|
|
579
|
+
return state;
|
|
580
|
+
}
|
|
581
|
+
realtimePullNamespace(key) {
|
|
582
|
+
for (const marker of ['|tail|', '|forward|']) {
|
|
583
|
+
const index = key.indexOf(marker);
|
|
584
|
+
if (index > 0)
|
|
585
|
+
return key.slice(0, index);
|
|
514
586
|
}
|
|
515
587
|
return '';
|
|
516
588
|
}
|
|
589
|
+
pullScopeKey(key) {
|
|
590
|
+
const index = key.indexOf('|');
|
|
591
|
+
return index < 0 ? key : key.slice(0, index);
|
|
592
|
+
}
|
|
593
|
+
isPullResponseProcessing(key) {
|
|
594
|
+
const responseKeys = this.runtime.client._pullResponseKeys;
|
|
595
|
+
return Boolean(key) && (responseKeys?.get(this.pullScopeKey(key)) ?? 0) > 0;
|
|
596
|
+
}
|
|
597
|
+
emptyPullResultForCall(method) {
|
|
598
|
+
if (method === 'group.pull_events')
|
|
599
|
+
return { events: [], count: 0 };
|
|
600
|
+
return { messages: [], count: 0 };
|
|
601
|
+
}
|
|
602
|
+
trackBypassedRealtimePull(key, delta) {
|
|
603
|
+
const ns = this.realtimePullNamespace(key);
|
|
604
|
+
if (!ns)
|
|
605
|
+
return;
|
|
606
|
+
const next = Math.max(0, (this.bypassedRealtimePulls.get(ns) ?? 0) + delta);
|
|
607
|
+
if (next === 0)
|
|
608
|
+
this.bypassedRealtimePulls.delete(ns);
|
|
609
|
+
else
|
|
610
|
+
this.bypassedRealtimePulls.set(ns, next);
|
|
611
|
+
}
|
|
612
|
+
async executeBypassedPull(key, operation, background) {
|
|
613
|
+
this.trackBypassedRealtimePull(key, 1);
|
|
614
|
+
try {
|
|
615
|
+
return await this.executePullOperation(operation, background);
|
|
616
|
+
}
|
|
617
|
+
finally {
|
|
618
|
+
this.trackBypassedRealtimePull(key, -1);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
hasPendingRealtimePull(ns) {
|
|
622
|
+
const normalized = String(ns ?? '').trim();
|
|
623
|
+
if (!normalized || (!normalized.startsWith('p2p:') && !normalized.startsWith('group:')))
|
|
624
|
+
return false;
|
|
625
|
+
if (this.isPullResponseProcessing(normalized))
|
|
626
|
+
return true;
|
|
627
|
+
if ((this.bypassedRealtimePulls.get(normalized) ?? 0) > 0)
|
|
628
|
+
return true;
|
|
629
|
+
const state = this.pullGateStates.get(this.pullGateName(normalized));
|
|
630
|
+
if (!state)
|
|
631
|
+
return false;
|
|
632
|
+
const matches = (job) => {
|
|
633
|
+
if (!job)
|
|
634
|
+
return false;
|
|
635
|
+
return this.realtimePullNamespace(job.key) === normalized;
|
|
636
|
+
};
|
|
637
|
+
return matches(state.active)
|
|
638
|
+
|| state.foreground.some(matches)
|
|
639
|
+
|| state.background.some(matches);
|
|
640
|
+
}
|
|
641
|
+
async tryRunInlineRealtime(ns, seq, operation) {
|
|
642
|
+
const normalized = String(ns ?? '').trim();
|
|
643
|
+
if ((!normalized.startsWith('p2p:') && !normalized.startsWith('group:'))
|
|
644
|
+
|| !Number.isSafeInteger(seq) || seq <= 0 || typeof operation !== 'function') {
|
|
645
|
+
return { acquired: false };
|
|
646
|
+
}
|
|
647
|
+
const client = this.runtime.client;
|
|
648
|
+
if (this.isPullResponseProcessing(normalized)
|
|
649
|
+
|| (this.bypassedRealtimePulls.get(normalized) ?? 0) > 0) {
|
|
650
|
+
return { acquired: false };
|
|
651
|
+
}
|
|
652
|
+
for (const [key, gate] of client._pullGates?.entries?.() ?? []) {
|
|
653
|
+
if (gate?.inflight && this.pullScopeKey(key) === normalized)
|
|
654
|
+
return { acquired: false };
|
|
655
|
+
}
|
|
656
|
+
const key = `${normalized}|inline|seq=${seq}`;
|
|
657
|
+
const state = this.pullGateState(key);
|
|
658
|
+
if (state.active !== null || state.foreground.length > 0 || state.background.length > 0) {
|
|
659
|
+
return { acquired: false };
|
|
660
|
+
}
|
|
661
|
+
const guard = {
|
|
662
|
+
key,
|
|
663
|
+
background: false,
|
|
664
|
+
inline: true,
|
|
665
|
+
operation,
|
|
666
|
+
promise: Promise.resolve(undefined),
|
|
667
|
+
resolve: () => { },
|
|
668
|
+
reject: () => { },
|
|
669
|
+
timer: null,
|
|
670
|
+
};
|
|
671
|
+
state.active = guard;
|
|
672
|
+
try {
|
|
673
|
+
return { acquired: true, value: await operation() };
|
|
674
|
+
}
|
|
675
|
+
finally {
|
|
676
|
+
if (state.active === guard)
|
|
677
|
+
state.active = null;
|
|
678
|
+
this.drainPullGate(state);
|
|
679
|
+
this.armQueuedPullTimers(state);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
517
682
|
tryAcquirePullGate(key) {
|
|
518
683
|
if (!key)
|
|
519
684
|
return 0;
|
|
685
|
+
const serialized = this.pullGateStates.get(this.pullGateName(key));
|
|
686
|
+
if (serialized?.active?.inline === true)
|
|
687
|
+
return null;
|
|
520
688
|
const client = this.runtime.client;
|
|
521
689
|
const now = Date.now();
|
|
522
690
|
const gate = client._pullGates.get(key) ?? { inflight: false, startedAt: 0, token: 0 };
|
|
@@ -541,23 +709,95 @@ export class RpcPipeline {
|
|
|
541
709
|
gate.inflight = false;
|
|
542
710
|
gate.startedAt = 0;
|
|
543
711
|
}
|
|
544
|
-
async runPullSerialized(key, operation) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
while (token === null && Date.now() <= deadline) {
|
|
549
|
-
await this._sleep(25);
|
|
550
|
-
token = this.tryAcquirePullGate(key);
|
|
551
|
-
}
|
|
552
|
-
if (token === null) {
|
|
553
|
-
throw new StateError(`pull already in-flight for ${key}`);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
try {
|
|
557
|
-
return await operation();
|
|
712
|
+
async runPullSerialized(key, operation, background = false) {
|
|
713
|
+
if (key && this.isPullResponseProcessing(key)) {
|
|
714
|
+
this.runtime.client._clientLog.debug(`pull skipped while processing pull response: key=${key}`);
|
|
715
|
+
return [];
|
|
558
716
|
}
|
|
559
|
-
|
|
560
|
-
this.
|
|
717
|
+
if (!key)
|
|
718
|
+
return await this.executePullOperation(operation, background);
|
|
719
|
+
const state = this.pullGateState(key);
|
|
720
|
+
const timeoutMs = Math.max(0, Number(this.runtime.client._PULL_GATE_QUEUE_TIMEOUT_MS ?? 3_000) || 0);
|
|
721
|
+
const existing = state.byKey.get(key);
|
|
722
|
+
if (existing) {
|
|
723
|
+
if (state.active?.inline === true)
|
|
724
|
+
return await existing.promise;
|
|
725
|
+
return await this.waitForCoalesced(existing.promise, timeoutMs, operation, background, key);
|
|
726
|
+
}
|
|
727
|
+
let resolve;
|
|
728
|
+
let reject;
|
|
729
|
+
const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
730
|
+
const job = { key, background, operation, promise, resolve, reject, timer: null };
|
|
731
|
+
(background ? state.background : state.foreground).push(job);
|
|
732
|
+
state.byKey.set(key, job);
|
|
733
|
+
this.drainPullGate(state);
|
|
734
|
+
if (state.active !== job && state.active?.inline !== true) {
|
|
735
|
+
job.timer = setTimeout(() => this.bypassQueuedPull(state, job), timeoutMs);
|
|
736
|
+
}
|
|
737
|
+
return await promise;
|
|
738
|
+
}
|
|
739
|
+
async executePullOperation(operation, background) {
|
|
740
|
+
if (background)
|
|
741
|
+
return await this.runtime.client._withBackgroundRpc(operation);
|
|
742
|
+
return await operation();
|
|
743
|
+
}
|
|
744
|
+
waitForCoalesced(shared, timeoutMs, operation, background, key) {
|
|
745
|
+
return new Promise((resolve, reject) => {
|
|
746
|
+
let settled = false;
|
|
747
|
+
const timer = setTimeout(() => {
|
|
748
|
+
if (settled)
|
|
749
|
+
return;
|
|
750
|
+
settled = true;
|
|
751
|
+
this.runtime.client._clientLog.warn(`pull gate coalesced wait timeout, bypass: gate=${this.pullGateName(key)} key=${key}`);
|
|
752
|
+
void this.executeBypassedPull(key, operation, background).then(resolve, reject);
|
|
753
|
+
}, timeoutMs);
|
|
754
|
+
shared.then((value) => { if (!settled) {
|
|
755
|
+
settled = true;
|
|
756
|
+
clearTimeout(timer);
|
|
757
|
+
resolve(value);
|
|
758
|
+
} }, (error) => { if (!settled) {
|
|
759
|
+
settled = true;
|
|
760
|
+
clearTimeout(timer);
|
|
761
|
+
reject(error);
|
|
762
|
+
} });
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
bypassQueuedPull(state, job) {
|
|
766
|
+
if (state.active === job)
|
|
767
|
+
return;
|
|
768
|
+
const queue = job.background ? state.background : state.foreground;
|
|
769
|
+
const index = queue.indexOf(job);
|
|
770
|
+
if (index < 0)
|
|
771
|
+
return;
|
|
772
|
+
queue.splice(index, 1);
|
|
773
|
+
if (state.byKey.get(job.key) === job)
|
|
774
|
+
state.byKey.delete(job.key);
|
|
775
|
+
job.timer = null;
|
|
776
|
+
this.runtime.client._clientLog.warn(`pull gate queue timeout, bypass: gate=${this.pullGateName(job.key)} key=${job.key}`);
|
|
777
|
+
void this.executeBypassedPull(job.key, job.operation, job.background).then(job.resolve, job.reject);
|
|
778
|
+
}
|
|
779
|
+
drainPullGate(state) {
|
|
780
|
+
if (state.active)
|
|
781
|
+
return;
|
|
782
|
+
const job = state.foreground.shift() ?? state.background.shift();
|
|
783
|
+
if (!job)
|
|
784
|
+
return;
|
|
785
|
+
state.active = job;
|
|
786
|
+
if (job.timer)
|
|
787
|
+
clearTimeout(job.timer);
|
|
788
|
+
void this.executePullOperation(job.operation, job.background).then(job.resolve, job.reject).finally(() => {
|
|
789
|
+
if (state.active === job)
|
|
790
|
+
state.active = null;
|
|
791
|
+
if (state.byKey.get(job.key) === job)
|
|
792
|
+
state.byKey.delete(job.key);
|
|
793
|
+
this.drainPullGate(state);
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
armQueuedPullTimers(state) {
|
|
797
|
+
const timeoutMs = Math.max(0, Number(this.runtime.client._PULL_GATE_QUEUE_TIMEOUT_MS ?? 3_000) || 0);
|
|
798
|
+
for (const job of [...state.foreground, ...state.background]) {
|
|
799
|
+
if (!job.timer)
|
|
800
|
+
job.timer = setTimeout(() => this.bypassQueuedPull(state, job), timeoutMs);
|
|
561
801
|
}
|
|
562
802
|
}
|
|
563
803
|
async rawCall(method, params, options) {
|
|
@@ -584,6 +824,12 @@ export class RpcPipeline {
|
|
|
584
824
|
async postprocessResult(method, params, result) {
|
|
585
825
|
const client = this.runtime.client;
|
|
586
826
|
let next = result;
|
|
827
|
+
if ((method === 'group.send' || method === 'group.v2.send') && isJsonObject(next)) {
|
|
828
|
+
next = normalizeGroupMentionMode(next);
|
|
829
|
+
}
|
|
830
|
+
if (method === 'group.get_settings' || method === 'group.set_settings') {
|
|
831
|
+
next = normalizeGroupSettingsResponse(next);
|
|
832
|
+
}
|
|
587
833
|
if (method === 'group.thought.get' && isJsonObject(next)) {
|
|
588
834
|
client._clientLog?.debug?.(`group.thought.get transport result: found=${String(next.found ?? '')}, raw_count=${Array.isArray(next.thoughts) ? next.thoughts.length : 0}`);
|
|
589
835
|
next = await client._decryptGroupThoughts(next);
|
|
@@ -616,12 +862,12 @@ export class RpcPipeline {
|
|
|
616
862
|
if (rawMessages.length) {
|
|
617
863
|
client._seqTracker.onPullResult(ns, rawMessages, Number(params.after_seq ?? 0) || 0);
|
|
618
864
|
}
|
|
619
|
-
const
|
|
620
|
-
if (
|
|
865
|
+
const retentionFloor = Math.max(0, Number(result.retention_floor_seq ?? 0));
|
|
866
|
+
if (retentionFloor > 0) {
|
|
621
867
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
622
|
-
if (contig <
|
|
623
|
-
client._clientLog?.info?.(`message.pull retention-floor advance: ns=${ns} contiguous=${contig} ->
|
|
624
|
-
client._seqTracker.forceContiguousSeq(ns,
|
|
868
|
+
if (contig < retentionFloor) {
|
|
869
|
+
client._clientLog?.info?.(`message.pull retention-floor advance: ns=${ns} contiguous=${contig} -> retention_floor_seq=${retentionFloor}`);
|
|
870
|
+
client._seqTracker.forceContiguousSeq(ns, retentionFloor);
|
|
625
871
|
}
|
|
626
872
|
}
|
|
627
873
|
if (client._seqTracker.getContiguousSeq(ns) !== contigBefore) {
|
|
@@ -631,7 +877,10 @@ export class RpcPipeline {
|
|
|
631
877
|
}
|
|
632
878
|
postprocessGroupPull(params, result) {
|
|
633
879
|
const client = this.runtime.client;
|
|
634
|
-
|
|
880
|
+
if (Array.isArray(result.messages)) {
|
|
881
|
+
result.messages = result.messages.map((message) => normalizeGroupMentionMode(message));
|
|
882
|
+
}
|
|
883
|
+
const gid = String(params.group_id ?? params.group_aid ?? '').trim();
|
|
635
884
|
if (!gid || !client._seqTracker) {
|
|
636
885
|
return;
|
|
637
886
|
}
|
|
@@ -643,12 +892,15 @@ export class RpcPipeline {
|
|
|
643
892
|
client._seqTracker.onPullResult(ns, rawMessages, Number(params.after_message_seq ?? params.after_seq ?? 0) || 0);
|
|
644
893
|
}
|
|
645
894
|
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
646
|
-
const
|
|
647
|
-
|
|
895
|
+
const retentionFloor = Math.max(0, Number(result.retention_floor_message_seq ?? result.retention_floor_seq ?? 0), Number(cursor?.retention_floor_seq ?? 0));
|
|
896
|
+
const isTail = String(result.window_mode ?? params.window_mode ?? '').trim().toLowerCase() === 'tail';
|
|
897
|
+
const visibilityFloor = isTail ? 0 : Math.max(0, Math.max(0, Number(result.earliest_available_message_seq ?? 1) - 1), Number(cursor?.join_seq ?? 0));
|
|
898
|
+
const effectiveFloor = Math.max(retentionFloor, visibilityFloor);
|
|
899
|
+
if (effectiveFloor > 0) {
|
|
648
900
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
649
|
-
if (contig <
|
|
650
|
-
client._clientLog?.info?.(`group.pull
|
|
651
|
-
client._seqTracker.forceContiguousSeq(ns,
|
|
901
|
+
if (contig < effectiveFloor) {
|
|
902
|
+
client._clientLog?.info?.(`group.pull floor advance: ns=${ns} contiguous=${contig} -> effective_floor=${effectiveFloor} retention_floor=${retentionFloor} visibility_floor=${visibilityFloor} mode=${isTail ? 'tail' : 'forward'}`);
|
|
903
|
+
client._seqTracker.forceContiguousSeq(ns, effectiveFloor);
|
|
652
904
|
}
|
|
653
905
|
}
|
|
654
906
|
if (client._seqTracker.getContiguousSeq(ns) !== contigBefore) {
|
|
@@ -685,33 +937,16 @@ export class RpcPipeline {
|
|
|
685
937
|
return;
|
|
686
938
|
}
|
|
687
939
|
const record = params;
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
const normalizedGroupId = normalizeGroupId(rawGroupId);
|
|
699
|
-
if (normalizedGroupId) {
|
|
700
|
-
if (normalizedGroupId !== rawGroupId) {
|
|
701
|
-
this.runtime.client._clientLog?.debug?.(`call group identifier normalized: ${key}=${rawGroupId} -> ${normalizedGroupId} method=${method}`);
|
|
702
|
-
}
|
|
703
|
-
const existingGroupId = String(record.group_id ?? record.groupId ?? '').trim();
|
|
704
|
-
if (key === 'group_id' || key === 'groupId') {
|
|
705
|
-
params.group_id = rawGroupId;
|
|
706
|
-
}
|
|
707
|
-
else if (existingGroupId) {
|
|
708
|
-
params.group_id = existingGroupId;
|
|
709
|
-
}
|
|
710
|
-
else {
|
|
711
|
-
params.group_id = normalizedGroupId;
|
|
712
|
-
}
|
|
713
|
-
params.group_aid = normalizedGroupId;
|
|
714
|
-
}
|
|
940
|
+
const rawGroupId = String(record.group_id ?? record.groupId ?? '').trim();
|
|
941
|
+
const rawGroupAid = String(record.group_aid ?? record.groupAid ?? '').trim();
|
|
942
|
+
if (rawGroupId) {
|
|
943
|
+
params.group_id = rawGroupId;
|
|
944
|
+
}
|
|
945
|
+
else if (rawGroupAid) {
|
|
946
|
+
params.group_id = rawGroupAid;
|
|
947
|
+
}
|
|
948
|
+
if (rawGroupAid) {
|
|
949
|
+
params.group_aid = rawGroupAid;
|
|
715
950
|
}
|
|
716
951
|
delete record.groupAid;
|
|
717
952
|
delete record.groupId;
|