1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! Shared routing preamble + named-tab dispatch for the page-evaluating CLI
//! commands (`eval`, `fetch`, `storage`).
//!
//! These commands all accept the unified `<browser>[/<tab>]` positional plus a
//! mutually-exclusive `--target <regex>` and fan out into the *same three
//! routing paths*, picked by `(tab_name, target)`:
//!
//! 1. **named-tab** (`<browser>/<tab>`, no `--target`) — resolve `<tab>` in the
//! `tabs` table via the engine-agnostic [`TabBackend`] and run the op under
//! [`with_named_tab_recovery`], so a tab that dies between resolve and op is
//! recovered once. Requires a registered browser. See [`run_named_tab`].
//! 2. **bare browser** (no `--target`) — the per-command default. This arm
//! *differs per command* (scratch tab for `eval`/`storage`, origin-bound
//! attach for `fetch`, plus an external-endpoint fallback), so it stays in
//! each command rather than here.
//! 3. **target-regex** (`--target <regex>`) — legacy [`PageSession::attach`]
//! against a user tab matching the URL regex. Also per-command (it differs
//! in await-promise flags / timeouts), so it stays in each command.
//!
//! The genuinely shared pieces — the preamble (parse, mutual-exclusion check,
//! browser resolution, registry handle, BiDi lock) and the named-tab arm — live
//! here so the three commands cannot drift on them. The per-command variation
//! (the JS expression, the await-promise flag, the timeout, and the
//! bare-browser arm) is supplied by the caller.
//!
//! [`PageSession::attach`]: crate::session::PageSession::attach
//! [`TabBackend`]: crate::session::backend::TabBackend
use Future;
use ;
use crate;
use crate;
use cratestrip_tab;
use crateCommandTrace;
use crate;
use crate;
use cratewith_named_tab_recovery;
/// Outcome of the shared routing preamble. Holds everything the per-command
/// dispatch needs: the resolved browser, the open [`Registry`] handle, the held
/// BiDi lock guard (RAII — released when this struct drops), and the parsed
/// `(tab_name, browser_only)` from the positional.
///
/// The `_bidi_lock` field is never read directly; it exists to keep the lock
/// held for the lifetime of the route and releases after the command finishes
/// its dispatch.
/// Run the shared preamble: parse the `<browser>[/<tab>]` positional, enforce
/// the `<tab>` / `--target` mutual exclusion (in ONE place with ONE message),
/// resolve the browser, record `trace.browser`/`trace.engine`, open the
/// registry, and acquire the BiDi lock if applicable.
///
/// `browser` is the raw positional/env value; `target` is `--target`. Returns a
/// [`Route`] the caller dispatches on via `(route.tab_name, target)`.
pub async
/// The named-tab routing arm, identical across `eval`/`fetch`/`storage`:
/// resolve the registered browser name, open its [`TabBackend`], and run the
/// caller's `op` against the named tab under [`with_named_tab_recovery`] (which
/// recovers once if the tab dies between resolve and op).
///
/// `name` is the tab name; `op` evaluates the command-specific JS — the JS
/// expression, await-promise flag, and timeout all live inside the closure, so
/// they are the per-command variation point. `no_external_msg` is the `bail!`
/// text used when the source is not a registered browser; it is passed in
/// because the existing commands phrase it slightly differently and this is a
/// behavior-preserving refactor.
///
/// The caller is responsible for `trace.route("named-tab")` /
/// `trace.tab_name(...)` so the trace contract stays visible at the call site.
pub async