fix(connect): stable per-tab relay session id — re-attach auto-recovers (#17)
When a tab's chrome.debugger session was torn down and re-established (cross-process navigation, MV3 service-worker restart wiping the in-memory maps, DevTools stealing the debugger), the extension minted a brand-new monotonic `cb-tab-N` for the same tab. The daemon stays bound to the old id and the relay consumes attach/detach events without telling it to rebind, so the session was orphaned permanently → `stale sessionId / tab is gone`, and re-open never recovered. Derive the session id from the STABLE Chrome tabId (`cb-tab-<tabId>`) instead. Any re-attach of the same tab now restores the SAME session the daemon already holds, so eval/snapshot transparently follow the new page after a navigation. Extension 0.4.3 → 0.4.4. Adds a relay unit test for the detach→reattach-same- session recovery contract.
This commit is contained in:
@@ -330,6 +330,45 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reattach_with_same_session_restores_target() {
|
||||
// Issue #17 recovery contract. A tab's chrome.debugger session is torn
|
||||
// down (cross-process nav, SW restart, …) then re-attached. The fix has
|
||||
// the extension reuse the SAME `cb-tab-<tabId>` id across that churn, so
|
||||
// after detach+reattach the relay must expose the NEW target under the
|
||||
// SAME session — which is exactly the session the daemon is still bound
|
||||
// to, so its eval/snapshot auto-follow the new page instead of going stale.
|
||||
let mut s = RelayState::new();
|
||||
s.handle_ext_message(&attached_event("T_old", "cb-tab-42"), "tok");
|
||||
s.handle_ext_message(
|
||||
&json!({
|
||||
"method": "forwardCDPEvent",
|
||||
"params": { "method": "Target.detachedFromTarget", "params": { "sessionId": "cb-tab-42" } }
|
||||
}),
|
||||
"tok",
|
||||
);
|
||||
s.handle_ext_message(&attached_event("T_new", "cb-tab-42"), "tok");
|
||||
|
||||
let route = s.route_client_command(1, &json!({ "id": 1, "method": "Target.getTargets" }));
|
||||
match route {
|
||||
ClientRoute::Local(v) => {
|
||||
let infos = v["result"]["targetInfos"].as_array().unwrap();
|
||||
assert_eq!(infos.len(), 1, "only the new target should remain");
|
||||
assert_eq!(infos[0]["targetId"], "T_new");
|
||||
}
|
||||
_ => panic!("getTargets must be local"),
|
||||
}
|
||||
// The daemon's existing session id still resolves — to the new target.
|
||||
let route = s.route_client_command(
|
||||
1,
|
||||
&json!({ "id": 2, "method": "Target.attachToTarget", "params": { "targetId": "T_new" } }),
|
||||
);
|
||||
assert_eq!(
|
||||
route,
|
||||
ClientRoute::Local(json!({ "id": 2, "result": { "sessionId": "cb-tab-42" } }))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn browser_get_version_is_answered_locally() {
|
||||
// Liveness probe must NOT be forwarded (the extension can't do
|
||||
|
||||
Reference in New Issue
Block a user