@agentunion/fastaun-browser 0.5.9 → 0.5.10
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 +32 -0
- package/_packed_docs/CHANGELOG.md +32 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +6 -5
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +43 -8
- package/_packed_docs/sdk/09-group-rpc-manual.md +18 -3
- package/_packed_docs/sdk/09-message-rpc-manual.md +34 -10
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +23 -1
- package/dist/agent-md.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +16 -2
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +812 -205
- package/dist/client/delivery.d.ts +23 -7
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +221 -80
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +6 -6
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.d.ts.map +1 -1
- package/dist/client/lifecycle.js +34 -38
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +4 -0
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +56 -2
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -1
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +22 -6
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +0 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +23 -32
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +31 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +167 -7
- package/dist/events.js.map +1 -1
- package/dist/register-flow.d.ts.map +1 -1
- package/dist/register-flow.js +16 -2
- package/dist/register-flow.js.map +1 -1
- package/dist/transport.d.ts +10 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +283 -29
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -460,7 +460,7 @@ var init_indexeddb_store = __esm({
|
|
|
460
460
|
});
|
|
461
461
|
|
|
462
462
|
// src/version.ts
|
|
463
|
-
var VERSION = "0.5.
|
|
463
|
+
var VERSION = "0.5.10";
|
|
464
464
|
|
|
465
465
|
// src/types.ts
|
|
466
466
|
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
@@ -799,6 +799,15 @@ var EventDispatcher = class {
|
|
|
799
799
|
constructor() {
|
|
800
800
|
__publicField(this, "_log", _noopLog);
|
|
801
801
|
__publicField(this, "_handlers", /* @__PURE__ */ new Map());
|
|
802
|
+
__publicField(this, "_queue", []);
|
|
803
|
+
__publicField(this, "_draining", false);
|
|
804
|
+
__publicField(this, "_drainScheduled", false);
|
|
805
|
+
__publicField(this, "_handlerDepth", 0);
|
|
806
|
+
__publicField(this, "_synchronousHandlerDepth", 0);
|
|
807
|
+
__publicField(this, "_drainPromise", null);
|
|
808
|
+
__publicField(this, "_drainResolve", null);
|
|
809
|
+
__publicField(this, "_closing", false);
|
|
810
|
+
__publicField(this, "_closed", false);
|
|
802
811
|
}
|
|
803
812
|
setLogger(log) {
|
|
804
813
|
this._log = log;
|
|
@@ -827,17 +836,154 @@ var EventDispatcher = class {
|
|
|
827
836
|
this._handlers.delete(event);
|
|
828
837
|
}
|
|
829
838
|
}
|
|
830
|
-
/**
|
|
839
|
+
/**
|
|
840
|
+
* 发布事件。事件总是异步进入 FIFO 队列;调用方 await 时等待该事件处理完成。
|
|
841
|
+
* drain 中派生事件只入队,不等待自身,避免事件处理器互相等待形成死锁。
|
|
842
|
+
*/
|
|
831
843
|
async publish(event, payload) {
|
|
844
|
+
if (this._closed || this._closing) return;
|
|
845
|
+
let resolveItem;
|
|
846
|
+
const itemDone = new Promise((resolve) => {
|
|
847
|
+
resolveItem = resolve;
|
|
848
|
+
});
|
|
849
|
+
this._queue.push({
|
|
850
|
+
run: () => this.dispatchNow(event, payload),
|
|
851
|
+
resolve: resolveItem
|
|
852
|
+
});
|
|
853
|
+
if (this._handlerDepth > 0) return;
|
|
854
|
+
if (this._drainPromise === null) {
|
|
855
|
+
this._drainPromise = new Promise((resolve) => {
|
|
856
|
+
this._drainResolve = resolve;
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
this.scheduleDrain();
|
|
860
|
+
await itemDone;
|
|
861
|
+
}
|
|
862
|
+
/** 将事件放入异步 FIFO 队列,不等待处理器执行完成。 */
|
|
863
|
+
enqueue(event, payload) {
|
|
864
|
+
void this.publish(event, payload).catch((exc) => {
|
|
865
|
+
this._log.warn(`event ${event} enqueue failed:`, exc);
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
/** 将非事件 observer 放入同一 FIFO 队列。 */
|
|
869
|
+
enqueueTask(task) {
|
|
870
|
+
if (this._closed || this._closing) return;
|
|
871
|
+
this._queue.push({
|
|
872
|
+
run: () => this.dispatchTask(task),
|
|
873
|
+
resolve: () => {
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
if (this._drainPromise === null) {
|
|
877
|
+
this._drainPromise = new Promise((resolve) => {
|
|
878
|
+
this._drainResolve = resolve;
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
this.scheduleDrain();
|
|
882
|
+
}
|
|
883
|
+
/** 关闭调度器,排空已经入队的应用事件后拒绝后续事件。 */
|
|
884
|
+
async close() {
|
|
885
|
+
if (this._closed) return;
|
|
886
|
+
this._closing = true;
|
|
887
|
+
if (this._synchronousHandlerDepth > 0) return;
|
|
888
|
+
if (this._drainPromise !== null) await this._drainPromise;
|
|
889
|
+
this.finishClose();
|
|
890
|
+
}
|
|
891
|
+
/** 等待当前队列排空;事件 handler 重入时直接返回,避免自等待。 */
|
|
892
|
+
async flush() {
|
|
893
|
+
if (this._synchronousHandlerDepth > 0) return;
|
|
894
|
+
if (this._drainPromise !== null) await this._drainPromise;
|
|
895
|
+
await Promise.resolve();
|
|
896
|
+
}
|
|
897
|
+
finishClose() {
|
|
898
|
+
if (!this._closing || this._closed || this._draining || this._drainScheduled || this._queue.length > 0) return;
|
|
899
|
+
this._closed = true;
|
|
900
|
+
this._handlers.clear();
|
|
901
|
+
}
|
|
902
|
+
scheduleDrain() {
|
|
903
|
+
if (this._draining || this._drainScheduled || this._queue.length === 0) return;
|
|
904
|
+
this._drainScheduled = true;
|
|
905
|
+
queueMicrotask(() => {
|
|
906
|
+
this._drainScheduled = false;
|
|
907
|
+
void this._drain();
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
async _drain() {
|
|
911
|
+
if (this._draining) return;
|
|
912
|
+
this._draining = true;
|
|
913
|
+
try {
|
|
914
|
+
while (this._queue.length > 0) {
|
|
915
|
+
const item = this._queue.shift();
|
|
916
|
+
try {
|
|
917
|
+
await item.run();
|
|
918
|
+
} catch (exc) {
|
|
919
|
+
this._log.warn("event dispatch failed:", exc);
|
|
920
|
+
} finally {
|
|
921
|
+
item.resolve();
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
} finally {
|
|
925
|
+
this._draining = false;
|
|
926
|
+
const resolve = this._drainResolve;
|
|
927
|
+
this._drainResolve = null;
|
|
928
|
+
this._drainPromise = null;
|
|
929
|
+
resolve?.();
|
|
930
|
+
this.finishClose();
|
|
931
|
+
if (this._queue.length > 0 && !this._closed) {
|
|
932
|
+
if (this._drainPromise === null) {
|
|
933
|
+
this._drainPromise = new Promise((nextResolve) => {
|
|
934
|
+
this._drainResolve = nextResolve;
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
this.scheduleDrain();
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
/** 当前是否正在调用应用 handler 或 observer。供生命周期入口识别重入。 */
|
|
942
|
+
isDispatchingHandler() {
|
|
943
|
+
return this._handlerDepth > 0;
|
|
944
|
+
}
|
|
945
|
+
async dispatchTask(task) {
|
|
946
|
+
let result;
|
|
947
|
+
this._handlerDepth += 1;
|
|
948
|
+
try {
|
|
949
|
+
this._synchronousHandlerDepth += 1;
|
|
950
|
+
result = task();
|
|
951
|
+
} catch (exc) {
|
|
952
|
+
this._log.warn("event task execution exception:", exc);
|
|
953
|
+
this._handlerDepth -= 1;
|
|
954
|
+
return;
|
|
955
|
+
} finally {
|
|
956
|
+
this._synchronousHandlerDepth -= 1;
|
|
957
|
+
}
|
|
958
|
+
try {
|
|
959
|
+
await result;
|
|
960
|
+
} catch (exc) {
|
|
961
|
+
this._log.warn("event task execution exception:", exc);
|
|
962
|
+
} finally {
|
|
963
|
+
this._handlerDepth -= 1;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
async dispatchNow(event, payload) {
|
|
832
967
|
const handlers = [...this._handlers.get(event) ?? []];
|
|
833
968
|
for (const handler of handlers) {
|
|
969
|
+
let result;
|
|
970
|
+
this._handlerDepth += 1;
|
|
834
971
|
try {
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
await result;
|
|
838
|
-
}
|
|
972
|
+
this._synchronousHandlerDepth += 1;
|
|
973
|
+
result = handler(payload);
|
|
839
974
|
} catch (exc) {
|
|
840
975
|
this._log.warn(`event ${event} handler execution exception:`, exc);
|
|
976
|
+
this._handlerDepth -= 1;
|
|
977
|
+
continue;
|
|
978
|
+
} finally {
|
|
979
|
+
this._synchronousHandlerDepth -= 1;
|
|
980
|
+
}
|
|
981
|
+
try {
|
|
982
|
+
await result;
|
|
983
|
+
} catch (exc) {
|
|
984
|
+
this._log.warn(`event ${event} handler execution exception:`, exc);
|
|
985
|
+
} finally {
|
|
986
|
+
this._handlerDepth -= 1;
|
|
841
987
|
}
|
|
842
988
|
}
|
|
843
989
|
}
|
|
@@ -1156,6 +1302,154 @@ var _noopLog3 = { error: () => {
|
|
|
1156
1302
|
}, debug: () => {
|
|
1157
1303
|
} };
|
|
1158
1304
|
var _rpcIdCounter = 0;
|
|
1305
|
+
var WORKER_WEBSOCKET_SOURCE = `
|
|
1306
|
+
let socket = null;
|
|
1307
|
+
self.onmessage = (event) => {
|
|
1308
|
+
const command = event.data || {};
|
|
1309
|
+
if (command.type === 'connect') {
|
|
1310
|
+
try {
|
|
1311
|
+
socket = new WebSocket(command.url);
|
|
1312
|
+
socket.onopen = () => self.postMessage({ type: 'open' });
|
|
1313
|
+
socket.onmessage = (message) => self.postMessage({ type: 'message', data: message.data });
|
|
1314
|
+
socket.onerror = () => self.postMessage({ type: 'error', message: 'websocket error' });
|
|
1315
|
+
socket.onclose = (close) => self.postMessage({
|
|
1316
|
+
type: 'close', code: close.code, reason: close.reason || '', wasClean: close.wasClean === true,
|
|
1317
|
+
});
|
|
1318
|
+
} catch (error) {
|
|
1319
|
+
self.postMessage({ type: 'error', message: error instanceof Error ? error.message : String(error) });
|
|
1320
|
+
}
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
if (command.type === 'send') {
|
|
1324
|
+
try {
|
|
1325
|
+
if (!socket || socket.readyState !== WebSocket.OPEN) throw new Error('websocket is not open');
|
|
1326
|
+
socket.send(command.data);
|
|
1327
|
+
self.postMessage({ type: 'send_result', id: command.id, ok: true });
|
|
1328
|
+
} catch (error) {
|
|
1329
|
+
self.postMessage({
|
|
1330
|
+
type: 'send_result', id: command.id, ok: false,
|
|
1331
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
if (command.type === 'close' && socket) socket.close(command.code, command.reason);
|
|
1337
|
+
};
|
|
1338
|
+
`;
|
|
1339
|
+
var _WorkerWebSocketProxy = class _WorkerWebSocketProxy {
|
|
1340
|
+
constructor(url) {
|
|
1341
|
+
__publicField(this, "readyState", _WorkerWebSocketProxy.CONNECTING);
|
|
1342
|
+
__publicField(this, "onopen", null);
|
|
1343
|
+
__publicField(this, "onmessage", null);
|
|
1344
|
+
__publicField(this, "onerror", null);
|
|
1345
|
+
__publicField(this, "onclose", null);
|
|
1346
|
+
__publicField(this, "_worker");
|
|
1347
|
+
__publicField(this, "_workerUrl");
|
|
1348
|
+
__publicField(this, "_listeners", /* @__PURE__ */ new Map());
|
|
1349
|
+
__publicField(this, "_pendingSends", /* @__PURE__ */ new Map());
|
|
1350
|
+
__publicField(this, "_sendSeq", 0);
|
|
1351
|
+
this._workerUrl = URL.createObjectURL(new Blob([WORKER_WEBSOCKET_SOURCE], { type: "text/javascript" }));
|
|
1352
|
+
try {
|
|
1353
|
+
this._worker = new Worker(this._workerUrl);
|
|
1354
|
+
} catch (error) {
|
|
1355
|
+
URL.revokeObjectURL(this._workerUrl);
|
|
1356
|
+
throw error;
|
|
1357
|
+
}
|
|
1358
|
+
this._worker.onmessage = (event) => this._handleWorkerMessage(event.data);
|
|
1359
|
+
this._worker.onerror = (event) => this._emitError(event.message || "websocket worker error");
|
|
1360
|
+
this._worker.postMessage({ type: "connect", url });
|
|
1361
|
+
}
|
|
1362
|
+
send(data) {
|
|
1363
|
+
if (this.readyState !== _WorkerWebSocketProxy.OPEN) return Promise.reject(new Error("websocket is not open"));
|
|
1364
|
+
const id = ++this._sendSeq;
|
|
1365
|
+
return new Promise((resolve, reject) => {
|
|
1366
|
+
this._pendingSends.set(id, { resolve, reject });
|
|
1367
|
+
try {
|
|
1368
|
+
this._worker.postMessage({ type: "send", id, data });
|
|
1369
|
+
} catch (error) {
|
|
1370
|
+
this._pendingSends.delete(id);
|
|
1371
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
close(code, reason) {
|
|
1376
|
+
if (this.readyState === _WorkerWebSocketProxy.CLOSED) return;
|
|
1377
|
+
this.readyState = _WorkerWebSocketProxy.CLOSING;
|
|
1378
|
+
this._worker.postMessage({ type: "close", code, reason });
|
|
1379
|
+
}
|
|
1380
|
+
addEventListener(type, listener) {
|
|
1381
|
+
const callback = typeof listener === "function" ? listener : (event) => listener.handleEvent(event);
|
|
1382
|
+
const listeners = this._listeners.get(type) ?? /* @__PURE__ */ new Set();
|
|
1383
|
+
listeners.add(callback);
|
|
1384
|
+
this._listeners.set(type, listeners);
|
|
1385
|
+
}
|
|
1386
|
+
removeEventListener(type, listener) {
|
|
1387
|
+
if (typeof listener === "function") this._listeners.get(type)?.delete(listener);
|
|
1388
|
+
}
|
|
1389
|
+
_handleWorkerMessage(reply) {
|
|
1390
|
+
if (reply.type === "send_result" && reply.id !== void 0) {
|
|
1391
|
+
const pending = this._pendingSends.get(reply.id);
|
|
1392
|
+
if (!pending) return;
|
|
1393
|
+
this._pendingSends.delete(reply.id);
|
|
1394
|
+
if (reply.ok) pending.resolve();
|
|
1395
|
+
else pending.reject(new Error(reply.error || "websocket send failed"));
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (reply.type === "open") {
|
|
1399
|
+
this.readyState = _WorkerWebSocketProxy.OPEN;
|
|
1400
|
+
const event = new Event("open");
|
|
1401
|
+
this.onopen?.(event);
|
|
1402
|
+
this._emit("open", event);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
if (reply.type === "message") {
|
|
1406
|
+
const event = new MessageEvent("message", { data: reply.data });
|
|
1407
|
+
this.onmessage?.(event);
|
|
1408
|
+
this._emit("message", event);
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
if (reply.type === "error") {
|
|
1412
|
+
this._emitError(reply.message || "websocket worker error");
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
if (reply.type === "close") {
|
|
1416
|
+
this.readyState = _WorkerWebSocketProxy.CLOSED;
|
|
1417
|
+
for (const pending of this._pendingSends.values()) pending.reject(new Error("websocket closed"));
|
|
1418
|
+
this._pendingSends.clear();
|
|
1419
|
+
const event = new CloseEvent("close", {
|
|
1420
|
+
code: reply.code ?? 1006,
|
|
1421
|
+
reason: reply.reason ?? "",
|
|
1422
|
+
wasClean: reply.wasClean === true
|
|
1423
|
+
});
|
|
1424
|
+
this.onclose?.(event);
|
|
1425
|
+
this._emit("close", event);
|
|
1426
|
+
this._worker.terminate();
|
|
1427
|
+
URL.revokeObjectURL(this._workerUrl);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
_emitError(message) {
|
|
1431
|
+
const event = new ErrorEvent("error", { message });
|
|
1432
|
+
this.onerror?.(event);
|
|
1433
|
+
this._emit("error", event);
|
|
1434
|
+
}
|
|
1435
|
+
_emit(type, event) {
|
|
1436
|
+
for (const listener of [...this._listeners.get(type) ?? []]) listener(event);
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
__publicField(_WorkerWebSocketProxy, "CONNECTING", 0);
|
|
1440
|
+
__publicField(_WorkerWebSocketProxy, "OPEN", 1);
|
|
1441
|
+
__publicField(_WorkerWebSocketProxy, "CLOSING", 2);
|
|
1442
|
+
__publicField(_WorkerWebSocketProxy, "CLOSED", 3);
|
|
1443
|
+
var WorkerWebSocketProxy = _WorkerWebSocketProxy;
|
|
1444
|
+
function createTransportWebSocket(url) {
|
|
1445
|
+
if (typeof Worker === "function" && typeof Blob === "function" && typeof URL !== "undefined" && typeof URL.createObjectURL === "function" && typeof URL.revokeObjectURL === "function") {
|
|
1446
|
+
try {
|
|
1447
|
+
return new WorkerWebSocketProxy(url);
|
|
1448
|
+
} catch {
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
return new WebSocket(url);
|
|
1452
|
+
}
|
|
1159
1453
|
var TRACE_SPAN_DETAIL_FIELDS = [
|
|
1160
1454
|
"method",
|
|
1161
1455
|
"route",
|
|
@@ -1426,6 +1720,10 @@ var RPCTransport = class {
|
|
|
1426
1720
|
__publicField(this, "_traceMode", "off");
|
|
1427
1721
|
// Trace observer:observer(traceInfo) 在每次 RPC/事件携带 _trace 时调用
|
|
1428
1722
|
__publicField(this, "_traceObserver", null);
|
|
1723
|
+
// 每个 transport 实例一个轻量级网络 actor。命令只在此处启动网络操作,
|
|
1724
|
+
// 不等待 RPC 响应,避免应用回调中的 send 反向占住收包路径。
|
|
1725
|
+
__publicField(this, "_actorTail", Promise.resolve());
|
|
1726
|
+
__publicField(this, "_actorBusy", false);
|
|
1429
1727
|
this._dispatcher = opts.eventDispatcher;
|
|
1430
1728
|
this._timeout = opts.timeout ?? 10;
|
|
1431
1729
|
this._connectTimeout = opts.timeout ?? 10;
|
|
@@ -1455,15 +1753,18 @@ var RPCTransport = class {
|
|
|
1455
1753
|
setMetaObserver(observer) {
|
|
1456
1754
|
this._metaObserver = observer;
|
|
1457
1755
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
1756
|
+
_notifyMetaObserver(message) {
|
|
1757
|
+
const observer = this._metaObserver;
|
|
1758
|
+
if (observer === null) return;
|
|
1460
1759
|
const meta = message._meta;
|
|
1461
1760
|
if (!isJsonObject(meta)) return;
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1761
|
+
this._dispatcher.enqueueTask(async () => {
|
|
1762
|
+
try {
|
|
1763
|
+
await observer(meta);
|
|
1764
|
+
} catch (exc) {
|
|
1765
|
+
this._log.debug(`meta_observer raised: ${String(exc)}`);
|
|
1766
|
+
}
|
|
1767
|
+
});
|
|
1467
1768
|
}
|
|
1468
1769
|
/** 设置 trace 模式:off / log / diag */
|
|
1469
1770
|
setTraceMode(mode) {
|
|
@@ -1499,7 +1800,10 @@ var RPCTransport = class {
|
|
|
1499
1800
|
* 连接到 WebSocket URL。
|
|
1500
1801
|
* 等待首条消息,若为 challenge 则返回,否则进入消息路由。
|
|
1501
1802
|
*/
|
|
1502
|
-
|
|
1803
|
+
connect(url) {
|
|
1804
|
+
return this._enqueueActorStart(() => this._connectImpl(url));
|
|
1805
|
+
}
|
|
1806
|
+
async _connectImpl(url) {
|
|
1503
1807
|
const tStart = Date.now();
|
|
1504
1808
|
this._log.debug(`connect enter: url=${url}`);
|
|
1505
1809
|
const setup = await this._withConnectionSetup(async () => {
|
|
@@ -1508,7 +1812,7 @@ var RPCTransport = class {
|
|
|
1508
1812
|
this._lastCloseCode = null;
|
|
1509
1813
|
this._lastCloseReason = "";
|
|
1510
1814
|
const handshake = new Promise((resolve, reject) => {
|
|
1511
|
-
const ws =
|
|
1815
|
+
const ws = createTransportWebSocket(url);
|
|
1512
1816
|
this._ws = ws;
|
|
1513
1817
|
this._closed = false;
|
|
1514
1818
|
let initialResolved = false;
|
|
@@ -1637,7 +1941,10 @@ var RPCTransport = class {
|
|
|
1637
1941
|
return setup.handshake;
|
|
1638
1942
|
}
|
|
1639
1943
|
/** 关闭连接 */
|
|
1640
|
-
|
|
1944
|
+
close() {
|
|
1945
|
+
return this._enqueueActor(() => this._closeImpl());
|
|
1946
|
+
}
|
|
1947
|
+
async _closeImpl() {
|
|
1641
1948
|
await this._withConnectionSetup(() => this._closeUnlocked());
|
|
1642
1949
|
}
|
|
1643
1950
|
/** 已持有连接建立串行权时关闭当前 WebSocket。 */
|
|
@@ -1708,7 +2015,13 @@ var RPCTransport = class {
|
|
|
1708
2015
|
* 发起 JSON-RPC 2.0 调用。
|
|
1709
2016
|
* 返回 result 字段的值;若有 error 字段则抛出映射后的错误。
|
|
1710
2017
|
*/
|
|
1711
|
-
|
|
2018
|
+
call(method, params2, timeout, trace, background = false) {
|
|
2019
|
+
return this._enqueueActorStart(
|
|
2020
|
+
() => this._callImpl(method, params2, timeout, trace, background),
|
|
2021
|
+
() => new TimeoutError(`rpc cancelled: ${method}`, { retryable: true })
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
_callImpl(method, params2, timeout, trace, background = false) {
|
|
1712
2025
|
if (this._closed || !this._ws) {
|
|
1713
2026
|
throw this._notConnectedError();
|
|
1714
2027
|
}
|
|
@@ -1749,7 +2062,7 @@ var RPCTransport = class {
|
|
|
1749
2062
|
this._drainRpcQueue();
|
|
1750
2063
|
}, effectiveTimeout);
|
|
1751
2064
|
const pending = {
|
|
1752
|
-
resolve:
|
|
2065
|
+
resolve: (response) => {
|
|
1753
2066
|
clearTimeout(timer);
|
|
1754
2067
|
const elapsed = Date.now() - tStart;
|
|
1755
2068
|
if (response.error !== void 0) {
|
|
@@ -1767,7 +2080,7 @@ var RPCTransport = class {
|
|
|
1767
2080
|
if (traceId) {
|
|
1768
2081
|
this._log.info(`[trace=${traceId}] rpc_recv method=${method} rpc_id=${rpcId} duration_ms=${elapsed} status=ok`);
|
|
1769
2082
|
}
|
|
1770
|
-
|
|
2083
|
+
this._notifyMetaObserver(response);
|
|
1771
2084
|
const respTrace = response._trace;
|
|
1772
2085
|
if (respTrace && typeof respTrace === "object" && !Array.isArray(respTrace)) {
|
|
1773
2086
|
this._handleResponseTrace(method, "ok", elapsed, respTrace);
|
|
@@ -1815,7 +2128,10 @@ var RPCTransport = class {
|
|
|
1815
2128
|
return Object.assign(promise, { cancel: () => cancelRpc?.() });
|
|
1816
2129
|
}
|
|
1817
2130
|
/** 发送 JSON-RPC 2.0 Notification,不分配 id,也不等待响应。 */
|
|
1818
|
-
|
|
2131
|
+
notify(method, params2) {
|
|
2132
|
+
return this._enqueueActorStart(() => this._notifyImpl(method, params2));
|
|
2133
|
+
}
|
|
2134
|
+
async _notifyImpl(method, params2) {
|
|
1819
2135
|
if (this._closed || !this._ws) {
|
|
1820
2136
|
throw this._notConnectedError();
|
|
1821
2137
|
}
|
|
@@ -1844,6 +2160,58 @@ var RPCTransport = class {
|
|
|
1844
2160
|
});
|
|
1845
2161
|
return run;
|
|
1846
2162
|
}
|
|
2163
|
+
_enqueueActor(operation) {
|
|
2164
|
+
this._actorBusy = true;
|
|
2165
|
+
const run = this._actorTail.then(async () => {
|
|
2166
|
+
return await operation();
|
|
2167
|
+
}, async () => {
|
|
2168
|
+
return await operation();
|
|
2169
|
+
});
|
|
2170
|
+
const tail = run.then(() => void 0, () => void 0);
|
|
2171
|
+
this._actorTail = tail;
|
|
2172
|
+
void tail.then(() => {
|
|
2173
|
+
if (this._actorTail === tail) this._actorBusy = false;
|
|
2174
|
+
});
|
|
2175
|
+
return run;
|
|
2176
|
+
}
|
|
2177
|
+
_enqueueActorStart(operation, cancellationError) {
|
|
2178
|
+
let resolveResult;
|
|
2179
|
+
let rejectResult;
|
|
2180
|
+
const result = new Promise((resolve, reject) => {
|
|
2181
|
+
resolveResult = resolve;
|
|
2182
|
+
rejectResult = reject;
|
|
2183
|
+
});
|
|
2184
|
+
let cancel;
|
|
2185
|
+
let cancelRequested = false;
|
|
2186
|
+
const launch = () => {
|
|
2187
|
+
if (cancelRequested) return;
|
|
2188
|
+
try {
|
|
2189
|
+
const inner = operation();
|
|
2190
|
+
cancel = inner.cancel;
|
|
2191
|
+
inner.then(resolveResult, rejectResult);
|
|
2192
|
+
} catch (err) {
|
|
2193
|
+
rejectResult(err);
|
|
2194
|
+
}
|
|
2195
|
+
};
|
|
2196
|
+
if (this._actorBusy) {
|
|
2197
|
+
const gate = this._actorTail.then(launch, launch);
|
|
2198
|
+
const tail = gate.then(() => void 0, () => void 0);
|
|
2199
|
+
this._actorTail = tail;
|
|
2200
|
+
void tail.then(() => {
|
|
2201
|
+
if (this._actorTail === tail) this._actorBusy = false;
|
|
2202
|
+
});
|
|
2203
|
+
} else {
|
|
2204
|
+
launch();
|
|
2205
|
+
}
|
|
2206
|
+
return Object.assign(result, {
|
|
2207
|
+
cancel: () => {
|
|
2208
|
+
if (cancelRequested) return;
|
|
2209
|
+
cancelRequested = true;
|
|
2210
|
+
if (cancel) cancel();
|
|
2211
|
+
else rejectResult(cancellationError?.() ?? new TimeoutError("rpc cancelled", { retryable: true }));
|
|
2212
|
+
}
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
1847
2215
|
_sendText(payload, context, beforeSend) {
|
|
1848
2216
|
return this._enqueueSend(async () => {
|
|
1849
2217
|
if (beforeSend && !beforeSend()) {
|
|
@@ -1854,7 +2222,7 @@ var RPCTransport = class {
|
|
|
1854
2222
|
}
|
|
1855
2223
|
const ws = this._ws;
|
|
1856
2224
|
try {
|
|
1857
|
-
ws.send(payload);
|
|
2225
|
+
await Promise.resolve(ws.send(payload));
|
|
1858
2226
|
} catch (err) {
|
|
1859
2227
|
throw await this._sendFailureError(context, err, ws);
|
|
1860
2228
|
}
|
|
@@ -1978,7 +2346,14 @@ var RPCTransport = class {
|
|
|
1978
2346
|
const enriched = { ...respTrace, spans };
|
|
1979
2347
|
this._log.info(traceDisplay(method, status, elapsedMs, respTrace, spans));
|
|
1980
2348
|
if (this._traceObserver !== null) {
|
|
1981
|
-
this._traceObserver
|
|
2349
|
+
const observer = this._traceObserver;
|
|
2350
|
+
this._dispatcher.enqueueTask(async () => {
|
|
2351
|
+
try {
|
|
2352
|
+
await observer({ type: "rpc", method, trace: enriched, status, duration_ms: elapsedMs });
|
|
2353
|
+
} catch (err) {
|
|
2354
|
+
this._log.debug(`trace observer raised: ${err instanceof Error ? err.message : String(err)}`);
|
|
2355
|
+
}
|
|
2356
|
+
});
|
|
1982
2357
|
}
|
|
1983
2358
|
} catch (err) {
|
|
1984
2359
|
this._log.debug(`trace handling raised: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -2019,10 +2394,17 @@ var RPCTransport = class {
|
|
|
2019
2394
|
this._backgroundRpcQueue = [];
|
|
2020
2395
|
if (!wasClosed) {
|
|
2021
2396
|
const error = new ConnectionError(`websocket closed: code=${event.code} reason=${event.reason}`);
|
|
2022
|
-
this._dispatcher.publish("connection.error", { error });
|
|
2023
2397
|
if (this._onDisconnect) {
|
|
2024
|
-
|
|
2398
|
+
const onDisconnect = this._onDisconnect;
|
|
2399
|
+
this._dispatcher.enqueueTask(async () => {
|
|
2400
|
+
try {
|
|
2401
|
+
await onDisconnect(error, event.code);
|
|
2402
|
+
} catch (exc) {
|
|
2403
|
+
this._log.warn("[aun_core.transport] disconnect callback exception:", exc);
|
|
2404
|
+
}
|
|
2405
|
+
});
|
|
2025
2406
|
}
|
|
2407
|
+
this._dispatcher.enqueue("connection.error", { error });
|
|
2026
2408
|
}
|
|
2027
2409
|
}
|
|
2028
2410
|
_notConnectedError() {
|
|
@@ -2050,39 +2432,43 @@ var RPCTransport = class {
|
|
|
2050
2432
|
if (method === "challenge") {
|
|
2051
2433
|
this._challenge = message;
|
|
2052
2434
|
this._log.debug("challenge received");
|
|
2053
|
-
this._dispatcher.
|
|
2435
|
+
this._dispatcher.enqueue("connection.challenge", message.params ?? {});
|
|
2054
2436
|
return;
|
|
2055
2437
|
}
|
|
2056
2438
|
if (method.startsWith("event/")) {
|
|
2057
2439
|
const protocolEvent = method.slice(6);
|
|
2058
2440
|
const sdkEvent = EVENT_NAME_MAP[protocolEvent] ?? protocolEvent;
|
|
2059
2441
|
this._log.debug(`event recv: event=${sdkEvent} ${summarizeDict(message.params, DIAG_RESULT_FIELDS)}`);
|
|
2060
|
-
|
|
2442
|
+
this._notifyMetaObserver(message);
|
|
2061
2443
|
const params2 = message.params ?? {};
|
|
2062
2444
|
if ("_trace" in params2) {
|
|
2063
2445
|
const eventTrace = params2._trace;
|
|
2064
2446
|
delete params2._trace;
|
|
2065
2447
|
if (eventTrace && typeof eventTrace === "object" && !Array.isArray(eventTrace)) {
|
|
2066
2448
|
if (this._traceObserver !== null) {
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2449
|
+
const observer = this._traceObserver;
|
|
2450
|
+
const tracePayload = eventTrace;
|
|
2451
|
+
this._dispatcher.enqueueTask(async () => {
|
|
2452
|
+
try {
|
|
2453
|
+
await observer({ type: "event", event: sdkEvent, trace: tracePayload });
|
|
2454
|
+
} catch {
|
|
2455
|
+
}
|
|
2456
|
+
});
|
|
2071
2457
|
}
|
|
2072
2458
|
const traceObj = eventTrace;
|
|
2073
2459
|
this._log.info(`[trace=${String(traceObj.trace_id ?? "")}] event_recv event=${sdkEvent}`);
|
|
2074
2460
|
}
|
|
2075
2461
|
}
|
|
2076
2462
|
if (sdkEvent.startsWith("app.")) {
|
|
2077
|
-
this._dispatcher.
|
|
2463
|
+
this._dispatcher.enqueue(sdkEvent, params2);
|
|
2078
2464
|
return;
|
|
2079
2465
|
}
|
|
2080
|
-
this._dispatcher.
|
|
2466
|
+
this._dispatcher.enqueue(`_raw.${sdkEvent}`, params2);
|
|
2081
2467
|
return;
|
|
2082
2468
|
}
|
|
2083
|
-
|
|
2469
|
+
this._notifyMetaObserver(message);
|
|
2084
2470
|
this._log.debug(`notification recv: method=${method || "<no-method>"}`);
|
|
2085
|
-
this._dispatcher.
|
|
2471
|
+
this._dispatcher.enqueue("notification", message);
|
|
2086
2472
|
}
|
|
2087
2473
|
_decodeMessage(raw) {
|
|
2088
2474
|
if (isJsonObject(raw)) {
|
|
@@ -2806,7 +3192,7 @@ var _AuthFlow = class _AuthFlow {
|
|
|
2806
3192
|
return new Promise((resolve, reject) => {
|
|
2807
3193
|
let ws;
|
|
2808
3194
|
try {
|
|
2809
|
-
ws =
|
|
3195
|
+
ws = createTransportWebSocket(gatewayUrl);
|
|
2810
3196
|
} catch (e) {
|
|
2811
3197
|
reject(new AuthError(`WebSocket \u8FDE\u63A5\u5931\u8D25: ${gatewayUrl}`));
|
|
2812
3198
|
return;
|
|
@@ -2849,7 +3235,19 @@ var _AuthFlow = class _AuthFlow {
|
|
|
2849
3235
|
params: params2
|
|
2850
3236
|
});
|
|
2851
3237
|
this._log.debug(`short RPC request full: ${JSON.stringify(redactRpcLogPayload(JSON.parse(requestPayload)))}`);
|
|
2852
|
-
ws.send(requestPayload);
|
|
3238
|
+
const sendResult = ws.send(requestPayload);
|
|
3239
|
+
if (sendResult && typeof sendResult.then === "function") {
|
|
3240
|
+
void Promise.resolve(sendResult).catch((error) => {
|
|
3241
|
+
if (settled) return;
|
|
3242
|
+
settled = true;
|
|
3243
|
+
globalThis.clearTimeout(timeout);
|
|
3244
|
+
try {
|
|
3245
|
+
ws.close();
|
|
3246
|
+
} catch {
|
|
3247
|
+
}
|
|
3248
|
+
reject(error instanceof Error ? error : new AuthError(String(error)));
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
2853
3251
|
return;
|
|
2854
3252
|
}
|
|
2855
3253
|
if (!isJsonObject(msg) || msg.id !== requestId) return;
|
|
@@ -4507,6 +4905,8 @@ function p2pAppEventFromPlainPullMessage(message) {
|
|
|
4507
4905
|
var MessageDeliveryEngine = class {
|
|
4508
4906
|
constructor(runtime) {
|
|
4509
4907
|
__publicField(this, "runtime");
|
|
4908
|
+
__publicField(this, "pendingPullDeliveryChanges", null);
|
|
4909
|
+
__publicField(this, "deliveryGeneration", 0);
|
|
4510
4910
|
__publicField(this, "realtimeTailResults", null);
|
|
4511
4911
|
__publicField(this, "realtimeSyncing", null);
|
|
4512
4912
|
__publicField(this, "pendingP2pPullUpper", null);
|
|
@@ -4526,6 +4926,8 @@ var MessageDeliveryEngine = class {
|
|
|
4526
4926
|
}
|
|
4527
4927
|
resetInlineAckState() {
|
|
4528
4928
|
this.inlineGeneration += 1;
|
|
4929
|
+
this.deliveryGeneration += 1;
|
|
4930
|
+
this.pendingPullDeliveryChanges = null;
|
|
4529
4931
|
void this.runtime.client._rpcPipeline?.invalidatePulls?.();
|
|
4530
4932
|
this.realtimeSyncing = null;
|
|
4531
4933
|
this.pendingP2pPullUpper = null;
|
|
@@ -4573,6 +4975,67 @@ var MessageDeliveryEngine = class {
|
|
|
4573
4975
|
if (!ns) return;
|
|
4574
4976
|
this.schedulePendingPullIfNeeded(ns, "pull-gate-idle");
|
|
4575
4977
|
}
|
|
4978
|
+
onPullWorkSettled() {
|
|
4979
|
+
const pipeline = this.runtime.client._rpcPipeline;
|
|
4980
|
+
if (pipeline?.hasAnyPullActivity?.() === true) return;
|
|
4981
|
+
void this.flushPullDeliveryChanges();
|
|
4982
|
+
}
|
|
4983
|
+
deliveryChangeNamespace(event, payload, ns = "") {
|
|
4984
|
+
if (event === "message.received") return "p2p";
|
|
4985
|
+
if (event !== "group.message_created") return "";
|
|
4986
|
+
if (!isJsonObject(payload)) return "";
|
|
4987
|
+
const aid = String(this.runtime.client._aid ?? "").trim().toLowerCase();
|
|
4988
|
+
const dot = aid.indexOf(".");
|
|
4989
|
+
const localIssuer = dot > 0 ? aid.slice(dot + 1) : "";
|
|
4990
|
+
const fallback = ns.startsWith("group:") ? ns.slice("group:".length) : "";
|
|
4991
|
+
const groupAid = normalizeGroupAid(payload.group_aid ?? payload.group_id ?? fallback, { localIssuer });
|
|
4992
|
+
return groupAid.includes(".") ? `group:${groupAid}` : "";
|
|
4993
|
+
}
|
|
4994
|
+
isDeliverableMessageBody(event, payload) {
|
|
4995
|
+
if (event !== "message.received" && event !== "group.message_created" || !isJsonObject(payload)) return false;
|
|
4996
|
+
const messageId = typeof payload.message_id === "string" && payload.message_id.trim().length > 0;
|
|
4997
|
+
const seq2 = typeof payload.seq === "number" && Number.isSafeInteger(payload.seq) && payload.seq > 0;
|
|
4998
|
+
return messageId || seq2;
|
|
4999
|
+
}
|
|
5000
|
+
recordDeliveryChange(changes, event, payload, ns, generation) {
|
|
5001
|
+
if (generation !== this.deliveryGeneration || !this.isDeliverableMessageBody(event, payload)) return;
|
|
5002
|
+
const namespace = this.deliveryChangeNamespace(event, payload, ns);
|
|
5003
|
+
if (!namespace) return;
|
|
5004
|
+
changes.set(namespace, (changes.get(namespace) ?? 0) + 1);
|
|
5005
|
+
}
|
|
5006
|
+
deliveryChangesPayload(changes) {
|
|
5007
|
+
return [...changes.entries()].filter(([, deliveredCount]) => deliveredCount > 0).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([namespace, deliveredCount]) => ({ namespace, delivered_count: deliveredCount }));
|
|
5008
|
+
}
|
|
5009
|
+
createDeliveryChangeBatch(trigger) {
|
|
5010
|
+
return { generation: this.deliveryGeneration, trigger, changes: /* @__PURE__ */ new Map(), closed: false };
|
|
5011
|
+
}
|
|
5012
|
+
async flushRealtimeDeliveryChanges(batch) {
|
|
5013
|
+
if (batch.closed) return;
|
|
5014
|
+
batch.closed = true;
|
|
5015
|
+
if (batch.generation !== this.deliveryGeneration) return;
|
|
5016
|
+
if (this.deliveryChangesPayload(batch.changes).length === 0) return;
|
|
5017
|
+
const pendingPull = this.pendingPullDeliveryChanges;
|
|
5018
|
+
this.pendingPullDeliveryChanges = null;
|
|
5019
|
+
if (pendingPull) {
|
|
5020
|
+
for (const [namespace, count] of pendingPull) {
|
|
5021
|
+
batch.changes.set(namespace, (batch.changes.get(namespace) ?? 0) + count);
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
if (batch.generation !== this.deliveryGeneration) return;
|
|
5025
|
+
const changes = this.deliveryChangesPayload(batch.changes);
|
|
5026
|
+
if (changes.length === 0) return;
|
|
5027
|
+
this.runtime.client._dispatcher.enqueue("delivery.changed", { trigger: batch.trigger, changes });
|
|
5028
|
+
}
|
|
5029
|
+
async flushPullDeliveryChanges() {
|
|
5030
|
+
const generation = this.deliveryGeneration;
|
|
5031
|
+
const pending = this.pendingPullDeliveryChanges;
|
|
5032
|
+
if (!pending || pending.size === 0 || generation !== this.deliveryGeneration) return;
|
|
5033
|
+
this.pendingPullDeliveryChanges = null;
|
|
5034
|
+
if (generation !== this.deliveryGeneration) return;
|
|
5035
|
+
const changes = this.deliveryChangesPayload(pending);
|
|
5036
|
+
if (changes.length === 0) return;
|
|
5037
|
+
this.runtime.client._dispatcher.enqueue("delivery.changed", { trigger: "pull_drained", changes });
|
|
5038
|
+
}
|
|
4576
5039
|
recordPendingPull(ns, seq2) {
|
|
4577
5040
|
if (!ns || !Number.isSafeInteger(seq2) || seq2 <= 0) return;
|
|
4578
5041
|
const pending = ns.startsWith("p2p:") ? this.pendingP2pPullUpper ?? /* @__PURE__ */ new Map() : this.pendingGroupPullUpper ?? /* @__PURE__ */ new Map();
|
|
@@ -5147,14 +5610,14 @@ var MessageDeliveryEngine = class {
|
|
|
5147
5610
|
}
|
|
5148
5611
|
return { rawCount: messages.length, publishedCount };
|
|
5149
5612
|
}
|
|
5150
|
-
enqueueOrderedMessage(ns, event, seq2, payload) {
|
|
5613
|
+
enqueueOrderedMessage(ns, event, seq2, payload, source = "push") {
|
|
5151
5614
|
const client = this.runtime.client;
|
|
5152
5615
|
let queue = client._pendingOrderedMsgs.get(ns);
|
|
5153
5616
|
if (!queue) {
|
|
5154
5617
|
queue = /* @__PURE__ */ new Map();
|
|
5155
5618
|
client._pendingOrderedMsgs.set(ns, queue);
|
|
5156
5619
|
}
|
|
5157
|
-
queue.set(seq2, { event, payload });
|
|
5620
|
+
queue.set(seq2, { event, payload, source });
|
|
5158
5621
|
if (queue.size > PENDING_ORDERED_LIMIT) {
|
|
5159
5622
|
const drop = [...queue.keys()].sort((a, b) => a - b).slice(0, queue.size - PENDING_ORDERED_LIMIT);
|
|
5160
5623
|
for (const oldSeq of drop) queue.delete(oldSeq);
|
|
@@ -5163,7 +5626,7 @@ var MessageDeliveryEngine = class {
|
|
|
5163
5626
|
isGroupEventNamespace(ns) {
|
|
5164
5627
|
return ns.startsWith("group_event:");
|
|
5165
5628
|
}
|
|
5166
|
-
async publishOrderedQueueItem(ns, event, seq2, payload, pullResponse = false) {
|
|
5629
|
+
async publishOrderedQueueItem(ns, event, seq2, payload, pullResponse = false, source = "push", batch) {
|
|
5167
5630
|
const client = this.runtime.client;
|
|
5168
5631
|
if (event === "group.changed" && this.isGroupEventNamespace(ns)) {
|
|
5169
5632
|
await this.publishOrderedGroupChanged(payload);
|
|
@@ -5174,10 +5637,10 @@ var MessageDeliveryEngine = class {
|
|
|
5174
5637
|
return;
|
|
5175
5638
|
}
|
|
5176
5639
|
if (pullResponse) {
|
|
5177
|
-
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload));
|
|
5640
|
+
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
5178
5641
|
return;
|
|
5179
5642
|
}
|
|
5180
|
-
await client._publishAppEvent(event, payload);
|
|
5643
|
+
await client._publishAppEvent(event, payload, source, ns, batch);
|
|
5181
5644
|
}
|
|
5182
5645
|
async publishOrderedGroupChanged(payload) {
|
|
5183
5646
|
const client = this.runtime.client;
|
|
@@ -5320,6 +5783,7 @@ var MessageDeliveryEngine = class {
|
|
|
5320
5783
|
setIfPresent("type", firstValue(body.type, params2.type, params2.message_type, params2.payload_type));
|
|
5321
5784
|
setIfPresent("kind", firstValue(body.kind, params2.kind));
|
|
5322
5785
|
setIfPresent("version", firstValue(body.version, params2.version));
|
|
5786
|
+
setIfPresent("message_id", firstValue(params2.message_id, body.message_id, resultObj.message_id));
|
|
5323
5787
|
setIfPresent("timestamp", firstValue(params2.timestamp, resultObj.timestamp, resultObj.created_at, resultObj.t_server, Date.now()));
|
|
5324
5788
|
envelope.encrypted = Boolean(encrypted);
|
|
5325
5789
|
const context = this.envelopeMetadata(params2.context);
|
|
@@ -5597,8 +6061,9 @@ var MessageDeliveryEngine = class {
|
|
|
5597
6061
|
}
|
|
5598
6062
|
if (contig !== contigBefore) this.persistSeq(ns);
|
|
5599
6063
|
}
|
|
5600
|
-
async publishAppEvent(event, payload) {
|
|
6064
|
+
async publishAppEvent(event, payload, source = "", ns = "", batch) {
|
|
5601
6065
|
const client = this.runtime.client;
|
|
6066
|
+
const generation = this.deliveryGeneration;
|
|
5602
6067
|
if ((event === "message.received" || event === "group.message_created") && isJsonObject(payload)) {
|
|
5603
6068
|
client._maybeAppendEchoTraceReceive(payload);
|
|
5604
6069
|
}
|
|
@@ -5617,7 +6082,19 @@ var MessageDeliveryEngine = class {
|
|
|
5617
6082
|
client._clientLog.debug(`agent_md etag inject skipped: ${String(exc)}`);
|
|
5618
6083
|
}
|
|
5619
6084
|
}
|
|
5620
|
-
|
|
6085
|
+
client._dispatcher.enqueue(event, this.normalizePublishedMessagePayload(event, payload));
|
|
6086
|
+
if (generation !== this.deliveryGeneration) return;
|
|
6087
|
+
if (source !== "pull" && source !== "tail" && source !== "pending_retry" && source !== "push" && source !== "inline_push") return;
|
|
6088
|
+
if (source === "push" || source === "inline_push") {
|
|
6089
|
+
const localBatch = batch ?? this.createDeliveryChangeBatch(source);
|
|
6090
|
+
this.recordDeliveryChange(localBatch.changes, event, payload, ns, generation);
|
|
6091
|
+
if (!batch) await this.flushRealtimeDeliveryChanges(localBatch);
|
|
6092
|
+
} else {
|
|
6093
|
+
const changes = this.pendingPullDeliveryChanges ?? /* @__PURE__ */ new Map();
|
|
6094
|
+
this.pendingPullDeliveryChanges = changes;
|
|
6095
|
+
this.recordDeliveryChange(changes, event, payload, ns, generation);
|
|
6096
|
+
if (client._rpcPipeline?.hasAnyPullActivity?.() !== true) await this.flushPullDeliveryChanges();
|
|
6097
|
+
}
|
|
5621
6098
|
}
|
|
5622
6099
|
messageTargetsCurrentInstance(message) {
|
|
5623
6100
|
if (!isJsonObject(message)) return true;
|
|
@@ -5750,7 +6227,7 @@ var MessageDeliveryEngine = class {
|
|
|
5750
6227
|
const client = this.runtime.client;
|
|
5751
6228
|
try {
|
|
5752
6229
|
if (!isJsonObject(data)) {
|
|
5753
|
-
await client._publishAppEvent("message.received", data);
|
|
6230
|
+
await client._publishAppEvent("message.received", data, "push");
|
|
5754
6231
|
return;
|
|
5755
6232
|
}
|
|
5756
6233
|
const msg = { ...data };
|
|
@@ -5795,7 +6272,7 @@ var MessageDeliveryEngine = class {
|
|
|
5795
6272
|
await client._publishEncryptedPushMessage("message.received", "message.undecryptable", "", seq2 ?? 0, msg, false);
|
|
5796
6273
|
return;
|
|
5797
6274
|
}
|
|
5798
|
-
await client._publishAppEvent("message.received", msg);
|
|
6275
|
+
await client._publishAppEvent("message.received", msg, "push");
|
|
5799
6276
|
}
|
|
5800
6277
|
} catch (exc) {
|
|
5801
6278
|
client._clientLog.warn(`P2P push processing failed:${String(exc)}`);
|
|
@@ -5834,7 +6311,7 @@ var MessageDeliveryEngine = class {
|
|
|
5834
6311
|
const client = this.runtime.client;
|
|
5835
6312
|
try {
|
|
5836
6313
|
if (!isJsonObject(data)) {
|
|
5837
|
-
await client._publishAppEvent("group.message_created", data);
|
|
6314
|
+
await client._publishAppEvent("group.message_created", data, "push");
|
|
5838
6315
|
return;
|
|
5839
6316
|
}
|
|
5840
6317
|
const msg = { ...data };
|
|
@@ -5906,7 +6383,7 @@ var MessageDeliveryEngine = class {
|
|
|
5906
6383
|
await client._publishEncryptedPushMessage("group.message_created", "group.message_undecryptable", "", seq2 ?? 0, msg, true);
|
|
5907
6384
|
return;
|
|
5908
6385
|
}
|
|
5909
|
-
await client._publishAppEvent("group.message_created", msg);
|
|
6386
|
+
await client._publishAppEvent("group.message_created", msg, "push");
|
|
5910
6387
|
}
|
|
5911
6388
|
} catch (exc) {
|
|
5912
6389
|
client._clientLog.warn(`group push processing failed:${String(exc)}`);
|
|
@@ -5990,11 +6467,16 @@ var MessageDeliveryEngine = class {
|
|
|
5990
6467
|
P2P_GAP_FILL_RETRY_MAX_MS
|
|
5991
6468
|
);
|
|
5992
6469
|
client._gapFillDone.add(retryKey);
|
|
6470
|
+
const releasePullWork = client._rpcPipeline?.reservePullWork?.() ?? (() => {
|
|
6471
|
+
});
|
|
5993
6472
|
client._clientLog.debug(`P2P message gap-fill retry scheduled: ns=${ns} attempt=${retryAttempt} delay_ms=${delayMs}`);
|
|
5994
6473
|
globalThis.setTimeout(() => {
|
|
5995
6474
|
client._gapFillDone.delete(retryKey);
|
|
5996
|
-
if (client.state !== "ready" /* READY */ || client._closing)
|
|
5997
|
-
|
|
6475
|
+
if (client.state !== "ready" /* READY */ || client._closing) {
|
|
6476
|
+
releasePullWork();
|
|
6477
|
+
return;
|
|
6478
|
+
}
|
|
6479
|
+
client._safeAsync(this.fillP2pGap(retryAttempt).finally(releasePullWork));
|
|
5998
6480
|
}, delayMs);
|
|
5999
6481
|
}
|
|
6000
6482
|
async fillP2pGap(retryAttempt = 0) {
|
|
@@ -6547,7 +7029,7 @@ var MessageDeliveryEngine = class {
|
|
|
6547
7029
|
const tracker = client._seqTracker;
|
|
6548
7030
|
const snapshot = typeof tracker.snapshotNamespace === "function" ? tracker.snapshotNamespace(ns) : null;
|
|
6549
7031
|
try {
|
|
6550
|
-
const published = await this.publishPulledMessage(event, ns, seq2, payload);
|
|
7032
|
+
const published = await this.publishPulledMessage(event, ns, seq2, payload, true, "inline_push");
|
|
6551
7033
|
if (!this.isInlineGenerationCurrent(generation)) return false;
|
|
6552
7034
|
if (!published) return false;
|
|
6553
7035
|
const needsPull = Boolean(tracker.onMessageSeq(ns, seq2));
|
|
@@ -7035,13 +7517,12 @@ var MessageDeliveryEngine = class {
|
|
|
7035
7517
|
}
|
|
7036
7518
|
}
|
|
7037
7519
|
} catch (exc) {
|
|
7038
|
-
client._dispatcher.
|
|
7520
|
+
client._dispatcher.enqueue("seq_tracker.persist_error", {
|
|
7039
7521
|
phase: "restore",
|
|
7040
7522
|
aid,
|
|
7041
7523
|
device_id: deviceId,
|
|
7042
7524
|
slot_id: slotId,
|
|
7043
7525
|
error: String(exc)
|
|
7044
|
-
}).catch(() => {
|
|
7045
7526
|
});
|
|
7046
7527
|
}
|
|
7047
7528
|
}
|
|
@@ -7232,13 +7713,12 @@ var MessageDeliveryEngine = class {
|
|
|
7232
7713
|
} catch (exc) {
|
|
7233
7714
|
const error = formatDeliveryError(exc);
|
|
7234
7715
|
client._clientLog.warn(`save SeqTracker state failed: ${error}`);
|
|
7235
|
-
client._dispatcher.
|
|
7716
|
+
client._dispatcher.enqueue("seq_tracker.persist_error", {
|
|
7236
7717
|
phase: "save",
|
|
7237
7718
|
aid,
|
|
7238
7719
|
device_id: deviceId,
|
|
7239
7720
|
slot_id: slotId,
|
|
7240
7721
|
error: String(error)
|
|
7241
|
-
}).catch(() => {
|
|
7242
7722
|
});
|
|
7243
7723
|
if (throwOnError) throw exc;
|
|
7244
7724
|
}
|
|
@@ -7343,7 +7823,7 @@ var MessageDeliveryEngine = class {
|
|
|
7343
7823
|
}
|
|
7344
7824
|
return params2;
|
|
7345
7825
|
}
|
|
7346
|
-
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true) {
|
|
7826
|
+
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, batch, source = "pull") {
|
|
7347
7827
|
const client = this.runtime.client;
|
|
7348
7828
|
this.ensurePullOperationCurrent();
|
|
7349
7829
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
@@ -7351,15 +7831,39 @@ var MessageDeliveryEngine = class {
|
|
|
7351
7831
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
7352
7832
|
const ready = [...queue.keys()].filter((seq2) => seq2 <= contig && (beforeSeq === void 0 || seq2 < beforeSeq)).sort((a, b) => a - b);
|
|
7353
7833
|
let delivered = false;
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
const
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7834
|
+
const drainBatches = /* @__PURE__ */ new Map();
|
|
7835
|
+
try {
|
|
7836
|
+
for (const seq2 of ready) {
|
|
7837
|
+
this.ensurePullOperationCurrent();
|
|
7838
|
+
const item = queue.get(seq2);
|
|
7839
|
+
queue.delete(seq2);
|
|
7840
|
+
if (!item || client._pushedSeqs.get(ns)?.has(seq2)) continue;
|
|
7841
|
+
const itemSource = item.source ?? source;
|
|
7842
|
+
let itemBatch = batch;
|
|
7843
|
+
if ((itemSource === "push" || itemSource === "inline_push") && (!batch || batch.trigger !== itemSource)) {
|
|
7844
|
+
itemBatch = drainBatches.get(itemSource);
|
|
7845
|
+
if (!itemBatch) {
|
|
7846
|
+
itemBatch = this.createDeliveryChangeBatch(itemSource);
|
|
7847
|
+
drainBatches.set(itemSource, itemBatch);
|
|
7848
|
+
}
|
|
7849
|
+
}
|
|
7850
|
+
await this.publishOrderedQueueItem(
|
|
7851
|
+
ns,
|
|
7852
|
+
item.event,
|
|
7853
|
+
seq2,
|
|
7854
|
+
item.payload,
|
|
7855
|
+
pullResponse,
|
|
7856
|
+
itemSource,
|
|
7857
|
+
itemBatch
|
|
7858
|
+
);
|
|
7859
|
+
this.ensurePullOperationCurrent();
|
|
7860
|
+
this.markPublishedSeq(ns, seq2);
|
|
7861
|
+
delivered = true;
|
|
7862
|
+
}
|
|
7863
|
+
} finally {
|
|
7864
|
+
for (const drainBatch of drainBatches.values()) {
|
|
7865
|
+
await this.flushRealtimeDeliveryChanges(drainBatch);
|
|
7866
|
+
}
|
|
7363
7867
|
}
|
|
7364
7868
|
if (queue.size === 0) {
|
|
7365
7869
|
client._pendingOrderedMsgs.delete(ns);
|
|
@@ -7369,75 +7873,87 @@ var MessageDeliveryEngine = class {
|
|
|
7369
7873
|
}
|
|
7370
7874
|
}
|
|
7371
7875
|
}
|
|
7372
|
-
async publishOrderedMessage(event, ns, seq2, payload) {
|
|
7876
|
+
async publishOrderedMessage(event, ns, seq2, payload, source = "push", operationBatch) {
|
|
7373
7877
|
const client = this.runtime.client;
|
|
7374
|
-
const
|
|
7375
|
-
|
|
7376
|
-
|
|
7878
|
+
const ownsBatch = !operationBatch && (source === "push" || source === "inline_push");
|
|
7879
|
+
const batch = operationBatch ?? (ownsBatch ? this.createDeliveryChangeBatch(source) : void 0);
|
|
7880
|
+
try {
|
|
7881
|
+
const seqNum = Number(seq2);
|
|
7882
|
+
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0) {
|
|
7883
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, false, source, batch);
|
|
7884
|
+
return true;
|
|
7885
|
+
}
|
|
7886
|
+
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
7887
|
+
const queue2 = client._pendingOrderedMsgs.get(ns);
|
|
7888
|
+
queue2?.delete(seqNum);
|
|
7889
|
+
if (queue2 && queue2.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7890
|
+
return false;
|
|
7891
|
+
}
|
|
7892
|
+
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
7893
|
+
if (seqNum > contig) {
|
|
7894
|
+
this.enqueueOrderedMessage(ns, event, seqNum, payload, source);
|
|
7895
|
+
return false;
|
|
7896
|
+
}
|
|
7897
|
+
await this.drainOrderedMessages(ns, seqNum, true, true, batch, source);
|
|
7898
|
+
if (client._pushedSeqs.get(ns)?.has(seqNum)) return false;
|
|
7899
|
+
const queue = client._pendingOrderedMsgs.get(ns);
|
|
7900
|
+
queue?.delete(seqNum);
|
|
7901
|
+
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7902
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, false, source, batch);
|
|
7903
|
+
this.markPublishedSeq(ns, seqNum);
|
|
7904
|
+
await this.drainOrderedMessages(ns, void 0, false, true, batch, source);
|
|
7905
|
+
if (!client._pendingOrderedMsgs.get(ns)) await this.saveSeqTrackerState();
|
|
7377
7906
|
return true;
|
|
7907
|
+
} finally {
|
|
7908
|
+
if (ownsBatch && batch) await this.flushRealtimeDeliveryChanges(batch);
|
|
7378
7909
|
}
|
|
7379
|
-
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
7380
|
-
const queue2 = client._pendingOrderedMsgs.get(ns);
|
|
7381
|
-
queue2?.delete(seqNum);
|
|
7382
|
-
if (queue2 && queue2.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7383
|
-
return false;
|
|
7384
|
-
}
|
|
7385
|
-
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
7386
|
-
if (seqNum > contig) {
|
|
7387
|
-
this.enqueueOrderedMessage(ns, event, seqNum, payload);
|
|
7388
|
-
return false;
|
|
7389
|
-
}
|
|
7390
|
-
await this.drainOrderedMessages(ns, seqNum, true);
|
|
7391
|
-
if (client._pushedSeqs.get(ns)?.has(seqNum)) return false;
|
|
7392
|
-
const queue = client._pendingOrderedMsgs.get(ns);
|
|
7393
|
-
queue?.delete(seqNum);
|
|
7394
|
-
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7395
|
-
await this.publishOrderedQueueItem(ns, event, seqNum, payload);
|
|
7396
|
-
this.markPublishedSeq(ns, seqNum);
|
|
7397
|
-
await this.drainOrderedMessages(ns);
|
|
7398
|
-
if (!client._pendingOrderedMsgs.get(ns)) await this.saveSeqTrackerState();
|
|
7399
|
-
return true;
|
|
7400
7910
|
}
|
|
7401
|
-
async publishPulledMessage(event, ns, seq2, payload, persist = true) {
|
|
7911
|
+
async publishPulledMessage(event, ns, seq2, payload, persist = true, source = "pull", operationBatch) {
|
|
7402
7912
|
const client = this.runtime.client;
|
|
7403
|
-
|
|
7404
|
-
const
|
|
7405
|
-
|
|
7913
|
+
const ownsBatch = !operationBatch && (source === "push" || source === "inline_push");
|
|
7914
|
+
const batch = operationBatch ?? (ownsBatch ? this.createDeliveryChangeBatch(source) : void 0);
|
|
7915
|
+
try {
|
|
7916
|
+
this.ensurePullOperationCurrent();
|
|
7917
|
+
const seqNum = Number(seq2);
|
|
7918
|
+
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0 || !ns) {
|
|
7919
|
+
if (event === "message.recalled") {
|
|
7920
|
+
const published = await client._withPullResponseProcessing(
|
|
7921
|
+
ns,
|
|
7922
|
+
() => this.publishMessageRecallTombstone(seq2, payload)
|
|
7923
|
+
);
|
|
7924
|
+
this.ensurePullOperationCurrent();
|
|
7925
|
+
return published;
|
|
7926
|
+
}
|
|
7927
|
+
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
7928
|
+
this.ensurePullOperationCurrent();
|
|
7929
|
+
return true;
|
|
7930
|
+
}
|
|
7931
|
+
const queue = client._pendingOrderedMsgs.get(ns);
|
|
7932
|
+
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
7933
|
+
queue?.delete(seqNum);
|
|
7934
|
+
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7935
|
+
return false;
|
|
7936
|
+
}
|
|
7937
|
+
await this.drainOrderedMessages(ns, seqNum, false, persist, batch, source);
|
|
7938
|
+
this.ensurePullOperationCurrent();
|
|
7939
|
+
queue?.delete(seqNum);
|
|
7940
|
+
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7406
7941
|
if (event === "message.recalled") {
|
|
7407
7942
|
const published = await client._withPullResponseProcessing(
|
|
7408
7943
|
ns,
|
|
7409
|
-
() => this.publishMessageRecallTombstone(
|
|
7944
|
+
() => this.publishMessageRecallTombstone(seqNum, payload)
|
|
7410
7945
|
);
|
|
7411
7946
|
this.ensurePullOperationCurrent();
|
|
7947
|
+
this.markPublishedSeq(ns, seqNum);
|
|
7412
7948
|
return published;
|
|
7413
7949
|
}
|
|
7414
|
-
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload));
|
|
7415
|
-
this.ensurePullOperationCurrent();
|
|
7416
|
-
return true;
|
|
7417
|
-
}
|
|
7418
|
-
const queue = client._pendingOrderedMsgs.get(ns);
|
|
7419
|
-
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
7420
|
-
queue?.delete(seqNum);
|
|
7421
|
-
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7422
|
-
return false;
|
|
7423
|
-
}
|
|
7424
|
-
await this.drainOrderedMessages(ns, seqNum, false, persist);
|
|
7425
|
-
this.ensurePullOperationCurrent();
|
|
7426
|
-
queue?.delete(seqNum);
|
|
7427
|
-
if (queue && queue.size === 0) client._pendingOrderedMsgs.delete(ns);
|
|
7428
|
-
if (event === "message.recalled") {
|
|
7429
|
-
const published = await client._withPullResponseProcessing(
|
|
7430
|
-
ns,
|
|
7431
|
-
() => this.publishMessageRecallTombstone(seqNum, payload)
|
|
7432
|
-
);
|
|
7950
|
+
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
7433
7951
|
this.ensurePullOperationCurrent();
|
|
7434
7952
|
this.markPublishedSeq(ns, seqNum);
|
|
7435
|
-
return
|
|
7953
|
+
return true;
|
|
7954
|
+
} finally {
|
|
7955
|
+
if (ownsBatch && batch) await this.flushRealtimeDeliveryChanges(batch);
|
|
7436
7956
|
}
|
|
7437
|
-
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload));
|
|
7438
|
-
this.ensurePullOperationCurrent();
|
|
7439
|
-
this.markPublishedSeq(ns, seqNum);
|
|
7440
|
-
return true;
|
|
7441
7957
|
}
|
|
7442
7958
|
};
|
|
7443
7959
|
|
|
@@ -7626,12 +8142,7 @@ var LifecycleController = class {
|
|
|
7626
8142
|
async publishConnectionEvent(owner, event, payload) {
|
|
7627
8143
|
const client = this.runtime.client;
|
|
7628
8144
|
this.assertConnectionAttemptOwner(owner);
|
|
7629
|
-
client.
|
|
7630
|
-
try {
|
|
7631
|
-
await client._dispatcher.publish(event, payload);
|
|
7632
|
-
} finally {
|
|
7633
|
-
client._connectEventDispatchDepth -= 1;
|
|
7634
|
-
}
|
|
8145
|
+
client._dispatcher.enqueue(event, payload);
|
|
7635
8146
|
return this.ownsConnectionAttempt(owner);
|
|
7636
8147
|
}
|
|
7637
8148
|
async cancelConnectionAttemptAndWait() {
|
|
@@ -7939,14 +8450,9 @@ var LifecycleController = class {
|
|
|
7939
8450
|
client._clientLog.warn(`reentrant close failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
7940
8451
|
});
|
|
7941
8452
|
}
|
|
7942
|
-
|
|
8453
|
+
publishLifecycleStopEvent(payload) {
|
|
7943
8454
|
const client = this.runtime.client;
|
|
7944
|
-
client.
|
|
7945
|
-
try {
|
|
7946
|
-
await client._dispatcher.publish("state_change", payload);
|
|
7947
|
-
} finally {
|
|
7948
|
-
client._lifecycleStopEventDispatchDepth -= 1;
|
|
7949
|
-
}
|
|
8455
|
+
client._dispatcher.enqueue("state_change", payload);
|
|
7950
8456
|
}
|
|
7951
8457
|
async withLifecycleStop(operation, kind) {
|
|
7952
8458
|
const client = this.runtime.client;
|
|
@@ -8007,7 +8513,7 @@ var LifecycleController = class {
|
|
|
8007
8513
|
client._stopBackgroundTasks();
|
|
8008
8514
|
if (client._closing) return;
|
|
8009
8515
|
this.runtime.lifecycle.resetForDisconnect("standby");
|
|
8010
|
-
|
|
8516
|
+
this.publishLifecycleStopEvent({ state: client._publicState(client._state) });
|
|
8011
8517
|
client._clientLog.debug(`disconnect exit: elapsed=${Date.now() - tStart}ms`);
|
|
8012
8518
|
}, "disconnect");
|
|
8013
8519
|
} finally {
|
|
@@ -8017,6 +8523,7 @@ var LifecycleController = class {
|
|
|
8017
8523
|
async close() {
|
|
8018
8524
|
const client = this.runtime.client;
|
|
8019
8525
|
const tStart = Date.now();
|
|
8526
|
+
const calledFromHandler = client._dispatcher.isDispatchingHandler();
|
|
8020
8527
|
client._clientLog.debug(`close enter: state=${client._state}`);
|
|
8021
8528
|
this.runtime.lifecycle.setClosing(true);
|
|
8022
8529
|
client._delivery.resetInlineAckState();
|
|
@@ -8025,34 +8532,39 @@ var LifecycleController = class {
|
|
|
8025
8532
|
return;
|
|
8026
8533
|
}
|
|
8027
8534
|
return this.withLifecycleStop(async () => {
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8535
|
+
try {
|
|
8536
|
+
const pullInvalidation = client._rpcPipeline?.invalidatePulls?.();
|
|
8537
|
+
client._rpcPipeline?.stopPullGateWatchdogs?.();
|
|
8538
|
+
client._stopBackgroundTasks();
|
|
8539
|
+
if (client._state === "idle" || client._state === "closed") {
|
|
8540
|
+
const reconnectCancellation2 = client._cancelReconnectAndWait();
|
|
8541
|
+
const connectionCancellation2 = this.cancelConnectionAttemptAndWait();
|
|
8542
|
+
await Promise.all([reconnectCancellation2, connectionCancellation2]);
|
|
8543
|
+
await pullInvalidation;
|
|
8544
|
+
await client._saveSeqTrackerState();
|
|
8545
|
+
this.runtime.lifecycle.setState("closed");
|
|
8546
|
+
client._resetSeqTrackingState();
|
|
8547
|
+
client._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms reason=already_idle`);
|
|
8548
|
+
return;
|
|
8549
|
+
}
|
|
8550
|
+
const reconnectCancellation = client._cancelReconnectAndWait();
|
|
8551
|
+
const connectionCancellation = this.cancelConnectionAttemptAndWait();
|
|
8552
|
+
try {
|
|
8553
|
+
await client._transport.call("auth.logout", {});
|
|
8554
|
+
} catch (err) {
|
|
8555
|
+
client._clientLog.warn(`auth.logout during close failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8556
|
+
}
|
|
8557
|
+
await client._transport.close();
|
|
8558
|
+
await Promise.all([pullInvalidation, reconnectCancellation, connectionCancellation]);
|
|
8036
8559
|
await client._saveSeqTrackerState();
|
|
8037
8560
|
this.runtime.lifecycle.setState("closed");
|
|
8561
|
+
this.publishLifecycleStopEvent({ state: client._publicState(client._state) });
|
|
8038
8562
|
client._resetSeqTrackingState();
|
|
8039
|
-
client._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms
|
|
8040
|
-
|
|
8563
|
+
client._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms`);
|
|
8564
|
+
} finally {
|
|
8565
|
+
const closing = client._dispatcher.close();
|
|
8566
|
+
if (!calledFromHandler) await closing;
|
|
8041
8567
|
}
|
|
8042
|
-
const reconnectCancellation = client._cancelReconnectAndWait();
|
|
8043
|
-
const connectionCancellation = this.cancelConnectionAttemptAndWait();
|
|
8044
|
-
try {
|
|
8045
|
-
await client._transport.call("auth.logout", {});
|
|
8046
|
-
} catch (err) {
|
|
8047
|
-
client._clientLog.warn(`auth.logout during close failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8048
|
-
}
|
|
8049
|
-
await client._transport.close();
|
|
8050
|
-
await Promise.all([pullInvalidation, reconnectCancellation, connectionCancellation]);
|
|
8051
|
-
await client._saveSeqTrackerState();
|
|
8052
|
-
this.runtime.lifecycle.setState("closed");
|
|
8053
|
-
await this.publishLifecycleStopEvent({ state: client._publicState(client._state) });
|
|
8054
|
-
client._resetSeqTrackingState();
|
|
8055
|
-
client._clientLog.debug(`close exit: elapsed=${Date.now() - tStart}ms`);
|
|
8056
8568
|
}, "close");
|
|
8057
8569
|
}
|
|
8058
8570
|
};
|
|
@@ -14849,6 +15361,14 @@ var PROTECTED_HEADERS_METHODS = /* @__PURE__ */ new Set([
|
|
|
14849
15361
|
"message.thought.put",
|
|
14850
15362
|
"group.thought.put"
|
|
14851
15363
|
]);
|
|
15364
|
+
function generateMessageId() {
|
|
15365
|
+
if (typeof crypto.randomUUID === "function") return `m-${crypto.randomUUID().replace(/-/g, "")}`;
|
|
15366
|
+
const bytes = new Uint8Array(16);
|
|
15367
|
+
crypto.getRandomValues(bytes);
|
|
15368
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
15369
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
15370
|
+
return `m-${Array.from(bytes, (value) => value.toString(16).padStart(2, "0")).join("")}`;
|
|
15371
|
+
}
|
|
14852
15372
|
var SIGNED_METHODS = /* @__PURE__ */ new Set([
|
|
14853
15373
|
"message.send",
|
|
14854
15374
|
"message.v2.put_peer_pk",
|
|
@@ -15111,6 +15631,7 @@ var RpcPipeline = class {
|
|
|
15111
15631
|
__publicField(this, "runtime");
|
|
15112
15632
|
__publicField(this, "pullGateStates", /* @__PURE__ */ new Map());
|
|
15113
15633
|
__publicField(this, "inlineRealtimeScopes", /* @__PURE__ */ new Set());
|
|
15634
|
+
__publicField(this, "pullWorkTokens", /* @__PURE__ */ new Set());
|
|
15114
15635
|
__publicField(this, "pullGeneration", 0);
|
|
15115
15636
|
__publicField(this, "pullInvalidationWait", null);
|
|
15116
15637
|
this.runtime = runtime;
|
|
@@ -15318,6 +15839,9 @@ var RpcPipeline = class {
|
|
|
15318
15839
|
delete p._rpc_background;
|
|
15319
15840
|
if (method === "message.send" || method === "group.send") {
|
|
15320
15841
|
this.normalizeOutboundMessagePayload(p, method);
|
|
15842
|
+
if (!Object.prototype.hasOwnProperty.call(p, "message_id") || p.message_id == null) {
|
|
15843
|
+
p.message_id = generateMessageId();
|
|
15844
|
+
}
|
|
15321
15845
|
}
|
|
15322
15846
|
this.normalizeGroupCallIdentifier(method, p);
|
|
15323
15847
|
this.validateOutboundCall(method, p);
|
|
@@ -15622,6 +16146,28 @@ var RpcPipeline = class {
|
|
|
15622
16146
|
const matches = (job) => job !== null && job.namespace === ns;
|
|
15623
16147
|
return matches(state.active) || state.foreground.some(matches) || state.background.some(matches);
|
|
15624
16148
|
}
|
|
16149
|
+
hasAnyPullActivity() {
|
|
16150
|
+
if (this.pullWorkTokens.size > 0) return true;
|
|
16151
|
+
for (const state of this.pullGateStates.values()) {
|
|
16152
|
+
if (state.active || state.foreground.length > 0 || state.background.length > 0) return true;
|
|
16153
|
+
}
|
|
16154
|
+
return false;
|
|
16155
|
+
}
|
|
16156
|
+
reservePullWork() {
|
|
16157
|
+
const token = Symbol("pull-work");
|
|
16158
|
+
this.pullWorkTokens.add(token);
|
|
16159
|
+
let released = false;
|
|
16160
|
+
return () => {
|
|
16161
|
+
if (released) return;
|
|
16162
|
+
released = true;
|
|
16163
|
+
this.pullWorkTokens.delete(token);
|
|
16164
|
+
this.runtime.client._delivery?.onPullWorkSettled?.();
|
|
16165
|
+
};
|
|
16166
|
+
}
|
|
16167
|
+
releasePullWorkToken(token) {
|
|
16168
|
+
if (!this.pullWorkTokens.delete(token)) return;
|
|
16169
|
+
this.runtime.client._delivery?.onPullWorkSettled?.();
|
|
16170
|
+
}
|
|
15625
16171
|
async tryRunInlineRealtime(ns, seq2, operation) {
|
|
15626
16172
|
const normalized = String(ns ?? "").trim();
|
|
15627
16173
|
if (!normalized.startsWith("p2p:") && !normalized.startsWith("group:") || !Number.isSafeInteger(seq2) || seq2 <= 0 || typeof operation !== "function") {
|
|
@@ -15663,7 +16209,8 @@ var RpcPipeline = class {
|
|
|
15663
16209
|
invalidated: false,
|
|
15664
16210
|
cancel: null,
|
|
15665
16211
|
settled: Promise.resolve(),
|
|
15666
|
-
settledResolve: null
|
|
16212
|
+
settledResolve: null,
|
|
16213
|
+
workToken: Symbol("inline-pull-work")
|
|
15667
16214
|
};
|
|
15668
16215
|
this.inlineRealtimeScopes.add(normalized);
|
|
15669
16216
|
try {
|
|
@@ -15725,6 +16272,7 @@ var RpcPipeline = class {
|
|
|
15725
16272
|
if (job.running) {
|
|
15726
16273
|
waits.push(job.settled);
|
|
15727
16274
|
} else {
|
|
16275
|
+
this.releasePullWorkToken(job.workToken);
|
|
15728
16276
|
job.settledResolve?.();
|
|
15729
16277
|
job.settledResolve = null;
|
|
15730
16278
|
}
|
|
@@ -15737,6 +16285,7 @@ var RpcPipeline = class {
|
|
|
15737
16285
|
this.drainPullGate(state);
|
|
15738
16286
|
}
|
|
15739
16287
|
const wait = Promise.all(waits).then(() => void 0);
|
|
16288
|
+
this.runtime.client._delivery?.onPullWorkSettled?.();
|
|
15740
16289
|
let tracked;
|
|
15741
16290
|
tracked = wait.finally(() => {
|
|
15742
16291
|
if (this.pullInvalidationWait === tracked) this.pullInvalidationWait = null;
|
|
@@ -15751,7 +16300,14 @@ var RpcPipeline = class {
|
|
|
15751
16300
|
if (this.pullInvalidationInProgress()) {
|
|
15752
16301
|
throw new Error("pull invalidated");
|
|
15753
16302
|
}
|
|
15754
|
-
if (!key)
|
|
16303
|
+
if (!key) {
|
|
16304
|
+
const releasePullWork = this.reservePullWork();
|
|
16305
|
+
try {
|
|
16306
|
+
return await this.executePullOperation(operation, background);
|
|
16307
|
+
} finally {
|
|
16308
|
+
releasePullWork();
|
|
16309
|
+
}
|
|
16310
|
+
}
|
|
15755
16311
|
const state = this.pullGateState(key);
|
|
15756
16312
|
const namespace = this.pullScopeKey(key);
|
|
15757
16313
|
const candidate = state.byKey.get(key);
|
|
@@ -15765,6 +16321,8 @@ var RpcPipeline = class {
|
|
|
15765
16321
|
}
|
|
15766
16322
|
return await existing.promise;
|
|
15767
16323
|
}
|
|
16324
|
+
const workToken = Symbol("pull-work");
|
|
16325
|
+
this.pullWorkTokens.add(workToken);
|
|
15768
16326
|
let resolve;
|
|
15769
16327
|
let reject;
|
|
15770
16328
|
let settledResolve;
|
|
@@ -15795,7 +16353,8 @@ var RpcPipeline = class {
|
|
|
15795
16353
|
invalidated: false,
|
|
15796
16354
|
cancel: null,
|
|
15797
16355
|
settled,
|
|
15798
|
-
settledResolve
|
|
16356
|
+
settledResolve,
|
|
16357
|
+
workToken
|
|
15799
16358
|
};
|
|
15800
16359
|
(background ? state.background : state.foreground).push(job);
|
|
15801
16360
|
state.byKey.set(key, job);
|
|
@@ -15890,6 +16449,7 @@ var RpcPipeline = class {
|
|
|
15890
16449
|
if (!job.timedOut && !job.invalidated) job.reject(error);
|
|
15891
16450
|
}
|
|
15892
16451
|
).finally(() => {
|
|
16452
|
+
this.pullWorkTokens.delete(job.workToken);
|
|
15893
16453
|
state.lifecycle.set(job.namespace, "idle");
|
|
15894
16454
|
if (state.active === job) state.active = null;
|
|
15895
16455
|
if (state.byKey.get(job.key) === job) state.byKey.delete(job.key);
|
|
@@ -15897,6 +16457,7 @@ var RpcPipeline = class {
|
|
|
15897
16457
|
job.settledResolve?.();
|
|
15898
16458
|
job.settledResolve = null;
|
|
15899
16459
|
if (!job.invalidated) this.runtime.client._delivery?.onPullGateIdle?.(job.namespace);
|
|
16460
|
+
this.runtime.client._delivery?.onPullWorkSettled?.();
|
|
15900
16461
|
});
|
|
15901
16462
|
}
|
|
15902
16463
|
armQueuedPullTimers(_state) {
|
|
@@ -23793,11 +24354,22 @@ var V2E2EECoordinator = class {
|
|
|
23793
24354
|
const fetchKey = this.pendingSenderIKFetchKey(fromAid, senderDeviceId, groupId);
|
|
23794
24355
|
if (!fromAid || client._v2SenderIKFetching.has(fetchKey)) return;
|
|
23795
24356
|
client._v2SenderIKFetching.add(fetchKey);
|
|
23796
|
-
client.
|
|
24357
|
+
const releasePullWork = client._rpcPipeline?.reservePullWork?.() ?? (() => {
|
|
24358
|
+
});
|
|
24359
|
+
const generation = client._delivery.captureInlineGeneration?.();
|
|
24360
|
+
client._safeAsync(this.resolveSenderIKPending(
|
|
24361
|
+
fromAid,
|
|
24362
|
+
senderDeviceId,
|
|
24363
|
+
groupId,
|
|
24364
|
+
fetchKey,
|
|
24365
|
+
generation
|
|
24366
|
+
).finally(releasePullWork));
|
|
23797
24367
|
}
|
|
23798
|
-
async resolveSenderIKPending(fromAid, senderDeviceId, groupId, fetchKey) {
|
|
24368
|
+
async resolveSenderIKPending(fromAid, senderDeviceId, groupId, fetchKey, generation) {
|
|
23799
24369
|
const client = this.client;
|
|
24370
|
+
const generationCurrent = () => generation === void 0 || client._delivery.isInlineGenerationCurrent?.(generation) !== false;
|
|
23800
24371
|
try {
|
|
24372
|
+
if (!generationCurrent()) return;
|
|
23801
24373
|
const session = client._v2Session;
|
|
23802
24374
|
if (session && fromAid) {
|
|
23803
24375
|
try {
|
|
@@ -23828,17 +24400,21 @@ var V2E2EECoordinator = class {
|
|
|
23828
24400
|
await this.getV2SenderPubDer(fromAid, senderDeviceId);
|
|
23829
24401
|
}
|
|
23830
24402
|
}
|
|
24403
|
+
if (!generationCurrent()) return;
|
|
23831
24404
|
const pendingItems = [...client._v2SenderIKPending.entries()].filter(([, entry]) => entry.fromAid === fromAid && entry.senderDeviceId === senderDeviceId && entry.groupId === groupId);
|
|
23832
24405
|
for (const [key, entry] of pendingItems) {
|
|
24406
|
+
if (!generationCurrent()) return;
|
|
23833
24407
|
let plaintext = null;
|
|
23834
24408
|
const retryStatus = {};
|
|
23835
24409
|
try {
|
|
23836
24410
|
plaintext = await client._decryptV2Message(entry.msg, false, true, true, true, retryStatus);
|
|
23837
24411
|
} catch (exc) {
|
|
24412
|
+
if (!generationCurrent()) return;
|
|
23838
24413
|
client._clientLog.warn(`V2 sender IK pending retry raised: key=${key} err=${String(formatE2EEError(exc))}`);
|
|
23839
24414
|
client._v2SenderIKPending.delete(key);
|
|
23840
24415
|
continue;
|
|
23841
24416
|
}
|
|
24417
|
+
if (!generationCurrent()) return;
|
|
23842
24418
|
if (plaintext === null) {
|
|
23843
24419
|
if (retryStatus.deferred) {
|
|
23844
24420
|
client._clientLog.warn(`V2 pending retry still missing key material: key=${key}`);
|
|
@@ -23890,6 +24466,7 @@ var V2E2EECoordinator = class {
|
|
|
23890
24466
|
return client.call("message.send", {
|
|
23891
24467
|
to: toAid,
|
|
23892
24468
|
payload: envelope,
|
|
24469
|
+
message_id: opts?.messageId,
|
|
23893
24470
|
encrypt: false,
|
|
23894
24471
|
_skip_send_result_envelope: true
|
|
23895
24472
|
});
|
|
@@ -23966,7 +24543,8 @@ var V2E2EECoordinator = class {
|
|
|
23966
24543
|
event.event,
|
|
23967
24544
|
client._aid ? `p2p:${client._aid}` : "",
|
|
23968
24545
|
seq2,
|
|
23969
|
-
event.payload
|
|
24546
|
+
event.payload,
|
|
24547
|
+
source
|
|
23970
24548
|
);
|
|
23971
24549
|
} else {
|
|
23972
24550
|
await client._publishAppEvent(event.event, event.payload, source);
|
|
@@ -24025,7 +24603,8 @@ var V2E2EECoordinator = class {
|
|
|
24025
24603
|
"group.message_created",
|
|
24026
24604
|
`group:${groupId}`,
|
|
24027
24605
|
seq2,
|
|
24028
|
-
plaintext
|
|
24606
|
+
plaintext,
|
|
24607
|
+
source
|
|
24029
24608
|
);
|
|
24030
24609
|
} else {
|
|
24031
24610
|
await client._publishAppEvent("group.message_created", plaintext, source);
|
|
@@ -24193,7 +24772,7 @@ var V2E2EECoordinator = class {
|
|
|
24193
24772
|
attachGatewayProximity(v1Msg, msg);
|
|
24194
24773
|
const appEvent = client._delivery.p2pAppEventForMessage(v1Msg);
|
|
24195
24774
|
if (ns) await client._publishPulledMessage(appEvent.event, ns, seq2, appEvent.payload, false);
|
|
24196
|
-
else await client._publishAppEvent(appEvent.event, appEvent.payload);
|
|
24775
|
+
else await client._publishAppEvent(appEvent.event, appEvent.payload, "pull");
|
|
24197
24776
|
decrypted.push(v1Msg);
|
|
24198
24777
|
} else {
|
|
24199
24778
|
client._clientLog.debug(`message.v2.pull skipping V1 envelope seq=${seq2} payload_type=${payloadType || "<none>"} (V1 E2EE removed)`);
|
|
@@ -24226,7 +24805,7 @@ var V2E2EECoordinator = class {
|
|
|
24226
24805
|
await client._publishPulledMessage("message.received", ns, seq2, plaintext, false);
|
|
24227
24806
|
decrypted.push(plaintext);
|
|
24228
24807
|
} else {
|
|
24229
|
-
await client._publishAppEvent("message.received", plaintext);
|
|
24808
|
+
await client._publishAppEvent("message.received", plaintext, "pull");
|
|
24230
24809
|
decrypted.push(plaintext);
|
|
24231
24810
|
}
|
|
24232
24811
|
}
|
|
@@ -24402,7 +24981,8 @@ var V2E2EECoordinator = class {
|
|
|
24402
24981
|
});
|
|
24403
24982
|
return client.call("group.v2.send", withExplicitGroupAid({
|
|
24404
24983
|
group_id: gid,
|
|
24405
|
-
envelope
|
|
24984
|
+
envelope,
|
|
24985
|
+
message_id: opts?.messageId
|
|
24406
24986
|
}, groupAid));
|
|
24407
24987
|
};
|
|
24408
24988
|
try {
|
|
@@ -25838,7 +26418,7 @@ var GroupStateCoordinator = class {
|
|
|
25838
26418
|
if (!isJsonObject(data) || !client._v2Session) return;
|
|
25839
26419
|
const groupId = groupIdFromRecord(data);
|
|
25840
26420
|
if (!groupId) return;
|
|
25841
|
-
|
|
26421
|
+
client._dispatcher.enqueue("group.v2.state_proposed", data);
|
|
25842
26422
|
try {
|
|
25843
26423
|
await client._v2ConfirmPendingProposal(groupId);
|
|
25844
26424
|
} catch (exc) {
|
|
@@ -25850,7 +26430,7 @@ var GroupStateCoordinator = class {
|
|
|
25850
26430
|
if (!isJsonObject(data) || !client._v2Session) return;
|
|
25851
26431
|
const groupId = groupIdFromRecord(data);
|
|
25852
26432
|
if (!groupId) return;
|
|
25853
|
-
|
|
26433
|
+
client._dispatcher.enqueue("group.v2.state_retry_needed", data);
|
|
25854
26434
|
try {
|
|
25855
26435
|
await client._v2AutoProposeState(groupId, { leaderDelay: true });
|
|
25856
26436
|
} catch (exc) {
|
|
@@ -25868,7 +26448,7 @@ var GroupStateCoordinator = class {
|
|
|
25868
26448
|
}
|
|
25869
26449
|
client._v2AutoProposeLastSnapshot?.delete?.(groupId);
|
|
25870
26450
|
}
|
|
25871
|
-
|
|
26451
|
+
client._dispatcher.enqueue("group.v2.state_confirmed", data);
|
|
25872
26452
|
}
|
|
25873
26453
|
async publishV2GroupSecurityLevel(groupId, bootstrap) {
|
|
25874
26454
|
const client = this.client;
|
|
@@ -25879,7 +26459,7 @@ var GroupStateCoordinator = class {
|
|
|
25879
26459
|
const previous = securityLevels.get(gid);
|
|
25880
26460
|
if (previous === level) return;
|
|
25881
26461
|
securityLevels.set(gid, level);
|
|
25882
|
-
|
|
26462
|
+
client._dispatcher.enqueue("group.v2.security_level", {
|
|
25883
26463
|
group_id: gid,
|
|
25884
26464
|
level,
|
|
25885
26465
|
warning: String(bootstrap.e2ee_security_warning ?? ""),
|
|
@@ -25974,7 +26554,7 @@ var GroupStateCoordinator = class {
|
|
|
25974
26554
|
} catch {
|
|
25975
26555
|
}
|
|
25976
26556
|
client._clientLog.warn(`V2 state chain fork detected: group=${gid} local_chain=${localChain.slice(0, 16)}... server_chain=${serverChain.slice(0, 16)}...`);
|
|
25977
|
-
|
|
26557
|
+
client._dispatcher.enqueue("group.v2.fork_detected", {
|
|
25978
26558
|
group_id: gid,
|
|
25979
26559
|
local_chain: localChain,
|
|
25980
26560
|
server_chain: serverChain
|
|
@@ -26508,7 +27088,7 @@ var GroupStateCoordinator = class {
|
|
|
26508
27088
|
}
|
|
26509
27089
|
if (mode !== "open" && mode !== "invite_code" && mode !== "invite_only") {
|
|
26510
27090
|
client._clientLog.warn(`V2 state tamper detected: group=${groupId} pending_extra=${extra.sort().join(",")} mode=${mode}`);
|
|
26511
|
-
|
|
27091
|
+
client._dispatcher.enqueue("group.v2.state_tampered", {
|
|
26512
27092
|
group_id: groupId,
|
|
26513
27093
|
pending_extra: extra.sort(),
|
|
26514
27094
|
mode
|
|
@@ -27458,6 +28038,7 @@ function buildDefaultAgentMd(aid, options = {}) {
|
|
|
27458
28038
|
].join("\n");
|
|
27459
28039
|
}
|
|
27460
28040
|
var HEAD_HTTP_TIMEOUT_MS = 15e3;
|
|
28041
|
+
var AGENT_MD_NEGATIVE_CACHE_TTL_MS = 6e4;
|
|
27461
28042
|
var noopLogger = {
|
|
27462
28043
|
error: () => {
|
|
27463
28044
|
},
|
|
@@ -27798,6 +28379,24 @@ var AgentMdManager = class _AgentMdManager {
|
|
|
27798
28379
|
ttl_days: Number(ttlDays) || 0
|
|
27799
28380
|
};
|
|
27800
28381
|
}
|
|
28382
|
+
const remoteMissingCached = String(before.remote_status ?? "").trim().toLowerCase() === "missing";
|
|
28383
|
+
if (!localFound && !remoteEtagCached && remoteMissingCached && _AgentMdManager.checkedAtFresh(checkedAtCached, ttlDays)) {
|
|
28384
|
+
return {
|
|
28385
|
+
aid: target,
|
|
28386
|
+
local_found: false,
|
|
28387
|
+
remote_found: false,
|
|
28388
|
+
local_etag: "",
|
|
28389
|
+
remote_etag: "",
|
|
28390
|
+
in_sync: false,
|
|
28391
|
+
needs_update: false,
|
|
28392
|
+
last_modified: "",
|
|
28393
|
+
status: 404,
|
|
28394
|
+
cached: true,
|
|
28395
|
+
verify_status: "",
|
|
28396
|
+
verify_error: "",
|
|
28397
|
+
ttl_days: Number(ttlDays) || 0
|
|
28398
|
+
};
|
|
28399
|
+
}
|
|
27801
28400
|
const now = Date.now();
|
|
27802
28401
|
let remote;
|
|
27803
28402
|
try {
|
|
@@ -28287,14 +28886,16 @@ var AgentMdManager = class _AgentMdManager {
|
|
|
28287
28886
|
async _scheduleFetchIfMissing(aid, record, source = "") {
|
|
28288
28887
|
const target = String(aid ?? "").trim();
|
|
28289
28888
|
if (!target || await this._hasLocalContent(target, record)) return;
|
|
28889
|
+
const cached = record ?? await this.loadRecord(target) ?? {};
|
|
28890
|
+
const checkedAt = Number(cached.checked_at ?? 0) || 0;
|
|
28891
|
+
if (String(cached.remote_status ?? "").trim().toLowerCase() === "missing" && checkedAt > 0 && Date.now() - checkedAt <= AGENT_MD_NEGATIVE_CACHE_TTL_MS) return;
|
|
28290
28892
|
if (this._fetchInflight.has(target)) return;
|
|
28291
28893
|
this._fetchInflight.add(target);
|
|
28292
28894
|
try {
|
|
28293
28895
|
await this.download(target);
|
|
28294
28896
|
} catch (err) {
|
|
28295
28897
|
await this.saveRecord(target, {
|
|
28296
|
-
last_error: err instanceof Error ? err.message : String(err)
|
|
28297
|
-
remote_status: "found"
|
|
28898
|
+
last_error: err instanceof Error ? err.message : String(err)
|
|
28298
28899
|
});
|
|
28299
28900
|
this._log.debug(`agent.md auto fetch failed: aid=${target} source=${source || "-"} err=${err instanceof Error ? err.message : String(err)}`);
|
|
28300
28901
|
} finally {
|
|
@@ -28718,7 +29319,6 @@ var _AUNClient = class _AUNClient {
|
|
|
28718
29319
|
__publicField(this, "_reconnectActive", false);
|
|
28719
29320
|
__publicField(this, "_reconnectAbort", null);
|
|
28720
29321
|
__publicField(this, "_reconnectTask", null);
|
|
28721
|
-
__publicField(this, "_reconnectEventDispatchDepth", 0);
|
|
28722
29322
|
__publicField(this, "_serverKicked", false);
|
|
28723
29323
|
// 重连状态追踪(对齐 Python client.py)
|
|
28724
29324
|
__publicField(this, "_nextRetryAt", null);
|
|
@@ -28898,7 +29498,7 @@ var _AUNClient = class _AUNClient {
|
|
|
28898
29498
|
});
|
|
28899
29499
|
for (const evt of ["message.ack", "storage.object_changed", "stream/created", "stream/closed"]) {
|
|
28900
29500
|
this._dispatcher.subscribe(`_raw.${evt}`, (data) => {
|
|
28901
|
-
this._dispatcher.
|
|
29501
|
+
this._dispatcher.enqueue(evt, data);
|
|
28902
29502
|
});
|
|
28903
29503
|
}
|
|
28904
29504
|
this._dispatcher.subscribe("_raw.gateway.disconnect", async (data) => {
|
|
@@ -29985,8 +30585,8 @@ var _AUNClient = class _AUNClient {
|
|
|
29985
30585
|
_markPublishedSeq(ns, seq2) {
|
|
29986
30586
|
this._delivery.markPublishedSeq(ns, seq2);
|
|
29987
30587
|
}
|
|
29988
|
-
async _publishAppEvent(event, payload) {
|
|
29989
|
-
await this._delivery.publishAppEvent(event, payload);
|
|
30588
|
+
async _publishAppEvent(event, payload, source = "", ns = "", batch) {
|
|
30589
|
+
await this._delivery.publishAppEvent(event, payload, source, ns, batch);
|
|
29990
30590
|
}
|
|
29991
30591
|
_echoTimestamp() {
|
|
29992
30592
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -30024,11 +30624,11 @@ var _AUNClient = class _AUNClient {
|
|
|
30024
30624
|
async _drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true) {
|
|
30025
30625
|
await this._delivery.drainOrderedMessages(ns, beforeSeq, pullResponse, persist);
|
|
30026
30626
|
}
|
|
30027
|
-
async _publishOrderedMessage(event, ns, seq2, payload) {
|
|
30028
|
-
return this._delivery.publishOrderedMessage(event, ns, seq2, payload);
|
|
30627
|
+
async _publishOrderedMessage(event, ns, seq2, payload, source = "push", batch) {
|
|
30628
|
+
return this._delivery.publishOrderedMessage(event, ns, seq2, payload, source, batch);
|
|
30029
30629
|
}
|
|
30030
|
-
async _publishPulledMessage(event, ns, seq2, payload, persist = true) {
|
|
30031
|
-
return this._delivery.publishPulledMessage(event, ns, seq2, payload, persist);
|
|
30630
|
+
async _publishPulledMessage(event, ns, seq2, payload, persist = true, source = "pull", batch) {
|
|
30631
|
+
return this._delivery.publishPulledMessage(event, ns, seq2, payload, persist, source, batch);
|
|
30032
30632
|
}
|
|
30033
30633
|
_extractGroupIdFromResult(result) {
|
|
30034
30634
|
const group = isJsonObject(result.group) ? result.group : null;
|
|
@@ -30059,7 +30659,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30059
30659
|
const groupId = d.group_id ?? d.group_aid ?? "";
|
|
30060
30660
|
await this._delivery.handleGroupChangedEventSeq(d, groupId);
|
|
30061
30661
|
} else {
|
|
30062
|
-
|
|
30662
|
+
this._dispatcher.enqueue("group.changed", data);
|
|
30063
30663
|
}
|
|
30064
30664
|
this._clientLog.debug(`_onRawGroupChanged exit: elapsed=${Date.now() - tStart}ms group_id=${groupIdInit}`);
|
|
30065
30665
|
} catch (err) {
|
|
@@ -30132,7 +30732,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30132
30732
|
const ok = await ecdsaVerifyDer(pubKey, sigBytes, signData);
|
|
30133
30733
|
if (!ok) {
|
|
30134
30734
|
this._clientLog.warn(`group event sig verify failed aid=%s method=%s${sigAid} ${method}`);
|
|
30135
|
-
this._dispatcher.
|
|
30735
|
+
this._dispatcher.enqueue("signature.verification_failed", {
|
|
30136
30736
|
aid: sigAid,
|
|
30137
30737
|
method,
|
|
30138
30738
|
error: "ECDSA verification failed"
|
|
@@ -30141,7 +30741,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30141
30741
|
return ok;
|
|
30142
30742
|
} catch (exc) {
|
|
30143
30743
|
this._clientLog.warn(`group event sig verify exception:${String(exc)}`);
|
|
30144
|
-
this._dispatcher.
|
|
30744
|
+
this._dispatcher.enqueue("signature.verification_failed", {
|
|
30145
30745
|
aid: sigAid,
|
|
30146
30746
|
method,
|
|
30147
30747
|
error: String(exc)
|
|
@@ -30359,7 +30959,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30359
30959
|
throw new StateError("connection attempt superseded");
|
|
30360
30960
|
}
|
|
30361
30961
|
} else {
|
|
30362
|
-
|
|
30962
|
+
this._dispatcher.enqueue("state_change", statePayload);
|
|
30363
30963
|
}
|
|
30364
30964
|
this._assertReconnectOwner(reconnectOwner);
|
|
30365
30965
|
this._lifecycle.assertConnectionAttemptOwner(connectionOwner);
|
|
@@ -30676,7 +31276,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30676
31276
|
if (this._sessionParams && identity.access_token) {
|
|
30677
31277
|
this._sessionParams.access_token = identity.access_token;
|
|
30678
31278
|
}
|
|
30679
|
-
|
|
31279
|
+
this._dispatcher.enqueue("token.refreshed", {
|
|
30680
31280
|
aid: identity.aid,
|
|
30681
31281
|
expires_at: identity.access_token_expires_at
|
|
30682
31282
|
});
|
|
@@ -30685,7 +31285,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30685
31285
|
if (exc instanceof AuthError) {
|
|
30686
31286
|
if (authErrorRequiresRelogin(exc)) {
|
|
30687
31287
|
this._clientLog.warn(`token refresh requires relogin, stopping refresh loop and triggering reconnect: ${exc.message}`);
|
|
30688
|
-
|
|
31288
|
+
this._dispatcher.enqueue("token.refresh_exhausted", {
|
|
30689
31289
|
aid: this._identity?.aid ?? null,
|
|
30690
31290
|
consecutive_failures: 1,
|
|
30691
31291
|
last_error: String(exc),
|
|
@@ -30698,7 +31298,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30698
31298
|
this._tokenRefreshFailures++;
|
|
30699
31299
|
if (this._tokenRefreshFailures >= 3) {
|
|
30700
31300
|
this._clientLog.warn(`token refresh failed ${this._tokenRefreshFailures} consecutive times, stopping refresh loop and triggering reconnect`);
|
|
30701
|
-
|
|
31301
|
+
this._dispatcher.enqueue("token.refresh_exhausted", {
|
|
30702
31302
|
aid: this._identity?.aid ?? null,
|
|
30703
31303
|
consecutive_failures: this._tokenRefreshFailures,
|
|
30704
31304
|
last_error: String(exc)
|
|
@@ -30709,7 +31309,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30709
31309
|
}
|
|
30710
31310
|
this._clientLog.warn(`token refresh failed (${this._tokenRefreshFailures}/3), next retry: ${String(exc)}`);
|
|
30711
31311
|
} else {
|
|
30712
|
-
this._dispatcher.
|
|
31312
|
+
this._dispatcher.enqueue("connection.error", { error: formatCaughtError2(exc) });
|
|
30713
31313
|
}
|
|
30714
31314
|
}
|
|
30715
31315
|
scheduleRefresh();
|
|
@@ -30738,7 +31338,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30738
31338
|
this._serverKicked = !retryable;
|
|
30739
31339
|
this._lastDisconnectInfo = { code, reason, detail };
|
|
30740
31340
|
try {
|
|
30741
|
-
|
|
31341
|
+
this._dispatcher.enqueue("gateway.disconnect", { code, reason, detail });
|
|
30742
31342
|
} catch (exc) {
|
|
30743
31343
|
this._clientLog.debug(`publish gateway.disconnect failed: ${exc?.message ?? exc}`);
|
|
30744
31344
|
}
|
|
@@ -30757,7 +31357,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30757
31357
|
} catch (exc) {
|
|
30758
31358
|
this._clientLog.debug(`transport cleanup skipped: ${formatCaughtError2(exc)}`);
|
|
30759
31359
|
}
|
|
30760
|
-
|
|
31360
|
+
this._dispatcher.enqueue("state_change", {
|
|
30761
31361
|
state: this._publicState(this._state),
|
|
30762
31362
|
error
|
|
30763
31363
|
});
|
|
@@ -30793,7 +31393,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30793
31393
|
if (disconnectInfo.code !== void 0 && disconnectInfo.code !== null) {
|
|
30794
31394
|
eventPayload.code = disconnectInfo.code;
|
|
30795
31395
|
}
|
|
30796
|
-
|
|
31396
|
+
this._dispatcher.enqueue("state_change", eventPayload);
|
|
30797
31397
|
if (this._reconnectAbort === reconnectAbort) {
|
|
30798
31398
|
this._reconnectAbort = null;
|
|
30799
31399
|
this._reconnectActive = false;
|
|
@@ -30824,12 +31424,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30824
31424
|
}
|
|
30825
31425
|
async _publishReconnectEvent(owner, event, payload) {
|
|
30826
31426
|
if (!this._ownsReconnect(owner)) return false;
|
|
30827
|
-
this.
|
|
30828
|
-
try {
|
|
30829
|
-
await this._dispatcher.publish(event, payload);
|
|
30830
|
-
} finally {
|
|
30831
|
-
this._reconnectEventDispatchDepth -= 1;
|
|
30832
|
-
}
|
|
31427
|
+
this._dispatcher.enqueue(event, payload);
|
|
30833
31428
|
return this._ownsReconnect(owner);
|
|
30834
31429
|
}
|
|
30835
31430
|
async _cancelReconnectAndWait() {
|
|
@@ -30842,7 +31437,7 @@ var _AUNClient = class _AUNClient {
|
|
|
30842
31437
|
} catch (exc) {
|
|
30843
31438
|
this._clientLog.debug(`reconnect cancellation transport cleanup skipped: ${formatCaughtError2(exc)}`);
|
|
30844
31439
|
}
|
|
30845
|
-
if (task
|
|
31440
|
+
if (task) {
|
|
30846
31441
|
try {
|
|
30847
31442
|
await task;
|
|
30848
31443
|
} catch (exc) {
|
|
@@ -31365,7 +31960,7 @@ var _AUNClient = class _AUNClient {
|
|
|
31365
31960
|
_spk_id: spkId
|
|
31366
31961
|
};
|
|
31367
31962
|
attachV2EnvelopeMetadata2(event, e2eeMeta);
|
|
31368
|
-
|
|
31963
|
+
this._dispatcher.enqueue(undecryptableEvent, event);
|
|
31369
31964
|
} catch {
|
|
31370
31965
|
}
|
|
31371
31966
|
}
|
|
@@ -31406,7 +32001,7 @@ var _AUNClient = class _AUNClient {
|
|
|
31406
32001
|
_suite: String(envelope.suite ?? "")
|
|
31407
32002
|
};
|
|
31408
32003
|
attachV2EnvelopeMetadata2(event, e2eeMeta);
|
|
31409
|
-
|
|
32004
|
+
this._dispatcher.enqueue(undecryptableEvent, event);
|
|
31410
32005
|
} catch {
|
|
31411
32006
|
}
|
|
31412
32007
|
}
|
|
@@ -31442,7 +32037,7 @@ var _AUNClient = class _AUNClient {
|
|
|
31442
32037
|
_suite: String(envelope.suite ?? "")
|
|
31443
32038
|
};
|
|
31444
32039
|
attachV2EnvelopeMetadata2(event, e2eeMeta);
|
|
31445
|
-
|
|
32040
|
+
this._dispatcher.enqueue(undecryptableEvent, event);
|
|
31446
32041
|
} catch {
|
|
31447
32042
|
}
|
|
31448
32043
|
}
|
|
@@ -32017,7 +32612,7 @@ var RegisterFlow = class _RegisterFlow {
|
|
|
32017
32612
|
return new Promise((resolve, reject) => {
|
|
32018
32613
|
let ws;
|
|
32019
32614
|
try {
|
|
32020
|
-
ws =
|
|
32615
|
+
ws = createTransportWebSocket(gatewayUrl);
|
|
32021
32616
|
} catch {
|
|
32022
32617
|
reject(new AuthError(`WebSocket \u8FDE\u63A5\u5931\u8D25: ${gatewayUrl}`));
|
|
32023
32618
|
return;
|
|
@@ -32051,7 +32646,19 @@ var RegisterFlow = class _RegisterFlow {
|
|
|
32051
32646
|
if (!receivedChallenge) {
|
|
32052
32647
|
if (!isJsonObject(msg) || msg.method !== "challenge") return;
|
|
32053
32648
|
receivedChallenge = true;
|
|
32054
|
-
ws.send(JSON.stringify({ jsonrpc: "2.0", id: requestId, method, params: params2 }));
|
|
32649
|
+
const sendResult = ws.send(JSON.stringify({ jsonrpc: "2.0", id: requestId, method, params: params2 }));
|
|
32650
|
+
if (sendResult && typeof sendResult.then === "function") {
|
|
32651
|
+
void Promise.resolve(sendResult).catch((error) => {
|
|
32652
|
+
if (settled) return;
|
|
32653
|
+
settled = true;
|
|
32654
|
+
globalThis.clearTimeout(timeout);
|
|
32655
|
+
try {
|
|
32656
|
+
ws.close();
|
|
32657
|
+
} catch {
|
|
32658
|
+
}
|
|
32659
|
+
reject(error instanceof Error ? error : new AuthError(String(error)));
|
|
32660
|
+
});
|
|
32661
|
+
}
|
|
32055
32662
|
return;
|
|
32056
32663
|
}
|
|
32057
32664
|
if (!isJsonObject(msg) || msg.id !== requestId) return;
|