github-router 0.3.35 → 0.3.36
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/dist/browser-bridge/index.js +62 -10
- package/dist/main.js +435 -297
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
|
@@ -3639,6 +3639,64 @@ function discoveryPath() {
|
|
|
3639
3639
|
return path.join(homedir(), ".local", "share", "github-router", "browser-mcp", "bridge.json");
|
|
3640
3640
|
}
|
|
3641
3641
|
|
|
3642
|
+
//#endregion
|
|
3643
|
+
//#region src/browser-bridge/pending.ts
|
|
3644
|
+
const pendingMap = /* @__PURE__ */ new Map();
|
|
3645
|
+
/**
|
|
3646
|
+
* Register a pending request. The TTL timer ensures the entry is removed
|
|
3647
|
+
* even when the extension hangs (MV3 SW dormancy, tab crash, navigation
|
|
3648
|
+
* interrupt) and the WS client stays connected — which would otherwise
|
|
3649
|
+
* leave the entry in the Map for the lifetime of a long proxy session.
|
|
3650
|
+
*
|
|
3651
|
+
* On TTL expiry the caller receives a structured timeout error so the
|
|
3652
|
+
* dispatcher can surface a meaningful message rather than hanging.
|
|
3653
|
+
*
|
|
3654
|
+
* @param id Request ID (must match the extension's response).
|
|
3655
|
+
* @param client WS client to send the response back on.
|
|
3656
|
+
* @param ttlMs How long to wait before forcibly resolving with an error.
|
|
3657
|
+
* @param sendResp Callback that encodes and writes BridgeResponse to `client`.
|
|
3658
|
+
*/
|
|
3659
|
+
function pendingAdd(id, client, ttlMs, sendResp) {
|
|
3660
|
+
const ttlTimer = setTimeout(() => {
|
|
3661
|
+
if (!pendingMap.has(id)) return;
|
|
3662
|
+
pendingMap.delete(id);
|
|
3663
|
+
sendResp({
|
|
3664
|
+
id,
|
|
3665
|
+
ok: false,
|
|
3666
|
+
error: `bridge timeout after ${ttlMs}ms`,
|
|
3667
|
+
code: "timeout"
|
|
3668
|
+
});
|
|
3669
|
+
}, ttlMs);
|
|
3670
|
+
pendingMap.set(id, {
|
|
3671
|
+
resolve: sendResp,
|
|
3672
|
+
client,
|
|
3673
|
+
ttlTimer
|
|
3674
|
+
});
|
|
3675
|
+
}
|
|
3676
|
+
/**
|
|
3677
|
+
* Resolve a pending request with the browser's response and cancel the
|
|
3678
|
+
* TTL timer. No-ops if the id is unknown (double-resolve from a
|
|
3679
|
+
* misbehaving extension is harmless).
|
|
3680
|
+
*/
|
|
3681
|
+
function pendingResolve(id, msg) {
|
|
3682
|
+
const entry = pendingMap.get(id);
|
|
3683
|
+
if (!entry) return;
|
|
3684
|
+
clearTimeout(entry.ttlTimer);
|
|
3685
|
+
pendingMap.delete(id);
|
|
3686
|
+
entry.resolve(msg);
|
|
3687
|
+
}
|
|
3688
|
+
/**
|
|
3689
|
+
* Drop all pending entries belonging to a specific WS client and cancel
|
|
3690
|
+
* their TTL timers. Called from the WS "close" handler so we don't leak
|
|
3691
|
+
* entries when the dispatcher disconnects mid-flight.
|
|
3692
|
+
*/
|
|
3693
|
+
function pendingDropClient(client) {
|
|
3694
|
+
for (const [id, entry] of pendingMap) if (entry.client === client) {
|
|
3695
|
+
clearTimeout(entry.ttlTimer);
|
|
3696
|
+
pendingMap.delete(id);
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3699
|
+
|
|
3642
3700
|
//#endregion
|
|
3643
3701
|
//#region src/browser-bridge/index.ts
|
|
3644
3702
|
try {
|
|
@@ -3646,6 +3704,7 @@ try {
|
|
|
3646
3704
|
} catch {}
|
|
3647
3705
|
const HEARTBEAT_MS = 5e3;
|
|
3648
3706
|
const HEARTBEAT_MISS_LIMIT = 3;
|
|
3707
|
+
const PENDING_TTL_MS = 3e5;
|
|
3649
3708
|
function writeDiscoveryFile(payload) {
|
|
3650
3709
|
const file = discoveryPath();
|
|
3651
3710
|
mkdirSync(path.dirname(file), { recursive: true });
|
|
@@ -3726,7 +3785,6 @@ httpServer.on("upgrade", (req, socket, head) => {
|
|
|
3726
3785
|
handleWsConnection(ws);
|
|
3727
3786
|
});
|
|
3728
3787
|
});
|
|
3729
|
-
const pending = /* @__PURE__ */ new Map();
|
|
3730
3788
|
function handleWsConnection(ws) {
|
|
3731
3789
|
let alive = true;
|
|
3732
3790
|
let misses = 0;
|
|
@@ -3765,15 +3823,12 @@ function handleWsConnection(ws) {
|
|
|
3765
3823
|
return;
|
|
3766
3824
|
}
|
|
3767
3825
|
if (typeof msg.id !== "string" || typeof msg.tool !== "string") return;
|
|
3768
|
-
|
|
3769
|
-
resolve: (resp) => ws.send(JSON.stringify(resp)),
|
|
3770
|
-
client: ws
|
|
3771
|
-
});
|
|
3826
|
+
pendingAdd(msg.id, ws, PENDING_TTL_MS, (resp) => ws.send(JSON.stringify(resp)));
|
|
3772
3827
|
sendToBrowser(msg);
|
|
3773
3828
|
});
|
|
3774
3829
|
ws.on("close", () => {
|
|
3775
3830
|
clearInterval(heartbeat);
|
|
3776
|
-
|
|
3831
|
+
pendingDropClient(ws);
|
|
3777
3832
|
});
|
|
3778
3833
|
}
|
|
3779
3834
|
let lastBrowserContactMs = 0;
|
|
@@ -3784,10 +3839,7 @@ fromBrowserListeners.push((msg) => {
|
|
|
3784
3839
|
lastBrowserContactMs = Date.now();
|
|
3785
3840
|
const r = msg;
|
|
3786
3841
|
if (typeof r.id !== "string") return;
|
|
3787
|
-
|
|
3788
|
-
if (!p) return;
|
|
3789
|
-
pending.delete(r.id);
|
|
3790
|
-
p.resolve(r);
|
|
3842
|
+
pendingResolve(r.id, r);
|
|
3791
3843
|
});
|
|
3792
3844
|
httpServer.listen(0, "127.0.0.1", () => {
|
|
3793
3845
|
const addr = httpServer.address();
|