camou 0.1.0
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/README.md +229 -0
- package/dist/browser/actions.d.ts +4 -0
- package/dist/browser/actions.js +15 -0
- package/dist/browser/actions.js.map +1 -0
- package/dist/browser/manager.d.ts +85 -0
- package/dist/browser/manager.js +300 -0
- package/dist/browser/manager.js.map +1 -0
- package/dist/browser/snapshot.d.ts +17 -0
- package/dist/browser/snapshot.js +93 -0
- package/dist/browser/snapshot.js.map +1 -0
- package/dist/browser/tabs.d.ts +24 -0
- package/dist/browser/tabs.js +8 -0
- package/dist/browser/tabs.js.map +1 -0
- package/dist/camoufox/config.d.ts +67 -0
- package/dist/camoufox/config.js +121 -0
- package/dist/camoufox/config.js.map +1 -0
- package/dist/camoufox/env.d.ts +3 -0
- package/dist/camoufox/env.js +27 -0
- package/dist/camoufox/env.js.map +1 -0
- package/dist/camoufox/installer.d.ts +24 -0
- package/dist/camoufox/installer.js +291 -0
- package/dist/camoufox/installer.js.map +1 -0
- package/dist/camoufox/launcher.d.ts +22 -0
- package/dist/camoufox/launcher.js +105 -0
- package/dist/camoufox/launcher.js.map +1 -0
- package/dist/camoufox/prefs.d.ts +5 -0
- package/dist/camoufox/prefs.js +27 -0
- package/dist/camoufox/prefs.js.map +1 -0
- package/dist/camoufox/presets.d.ts +14 -0
- package/dist/camoufox/presets.js +73 -0
- package/dist/camoufox/presets.js.map +1 -0
- package/dist/camoufox/registry.d.ts +30 -0
- package/dist/camoufox/registry.js +195 -0
- package/dist/camoufox/registry.js.map +1 -0
- package/dist/camoufox/validation.d.ts +4 -0
- package/dist/camoufox/validation.js +103 -0
- package/dist/camoufox/validation.js.map +1 -0
- package/dist/cli/daemon.d.ts +2 -0
- package/dist/cli/daemon.js +59 -0
- package/dist/cli/daemon.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +147 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.d.ts +1 -0
- package/dist/cli/output.js +108 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/program.d.ts +42 -0
- package/dist/cli/program.js +214 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/daemon/daemon.d.ts +12 -0
- package/dist/daemon/daemon.js +36 -0
- package/dist/daemon/daemon.js.map +1 -0
- package/dist/daemon/main.d.ts +2 -0
- package/dist/daemon/main.js +28 -0
- package/dist/daemon/main.js.map +1 -0
- package/dist/daemon/router.d.ts +7 -0
- package/dist/daemon/router.js +43 -0
- package/dist/daemon/router.js.map +1 -0
- package/dist/daemon/runtime.d.ts +11 -0
- package/dist/daemon/runtime.js +54 -0
- package/dist/daemon/runtime.js.map +1 -0
- package/dist/doctor/diagnostics.d.ts +38 -0
- package/dist/doctor/diagnostics.js +152 -0
- package/dist/doctor/diagnostics.js.map +1 -0
- package/dist/ipc/client.d.ts +6 -0
- package/dist/ipc/client.js +63 -0
- package/dist/ipc/client.js.map +1 -0
- package/dist/ipc/protocol.d.ts +775 -0
- package/dist/ipc/protocol.js +128 -0
- package/dist/ipc/protocol.js.map +1 -0
- package/dist/ipc/server.d.ts +10 -0
- package/dist/ipc/server.js +99 -0
- package/dist/ipc/server.js.map +1 -0
- package/dist/state/paths.d.ts +32 -0
- package/dist/state/paths.js +121 -0
- package/dist/state/paths.js.map +1 -0
- package/dist/state/store.d.ts +4 -0
- package/dist/state/store.js +30 -0
- package/dist/state/store.js.map +1 -0
- package/dist/util/errors.d.ts +45 -0
- package/dist/util/errors.js +82 -0
- package/dist/util/errors.js.map +1 -0
- package/dist/util/log.d.ts +19 -0
- package/dist/util/log.js +71 -0
- package/dist/util/log.js.map +1 -0
- package/dist/util/platform.d.ts +12 -0
- package/dist/util/platform.js +44 -0
- package/dist/util/platform.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Camoucli
|
|
2
|
+
|
|
3
|
+
Camoucli is a Node.js-first CLI and local daemon for driving Camoufox through Playwright.
|
|
4
|
+
|
|
5
|
+
The published npm package is `camou`, and the installed command is `camou`.
|
|
6
|
+
|
|
7
|
+
It is built for local agent-style workflows:
|
|
8
|
+
|
|
9
|
+
- keep a browser session alive across CLI invocations
|
|
10
|
+
- preserve login state with persistent profiles
|
|
11
|
+
- target named tabs and sessions
|
|
12
|
+
- work with stable `@eN` refs from text snapshots
|
|
13
|
+
- install and switch Camoufox versions without the Python SDK
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Node.js `>=20`
|
|
18
|
+
- a supported OS for Camoufox releases
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
End users:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g camou
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Contributors / local development:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install
|
|
32
|
+
npm run build
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For local development:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm run dev -- --help
|
|
39
|
+
npm run dev:daemon
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
Install a browser build:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
camou install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`install` runs a quick launch probe after download so it can warn if the installed browser does not work with the current `playwright-core` version.
|
|
51
|
+
`use` runs the same check when you switch versions.
|
|
52
|
+
|
|
53
|
+
Open a page and capture refs:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
camou open https://example.com
|
|
57
|
+
camou snapshot -i
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Use refs in later commands:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
camou click @e1
|
|
64
|
+
camou fill @e2 "hello"
|
|
65
|
+
camou get title
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
When working from this repo without a global install, prefix commands with `npm run dev --`.
|
|
69
|
+
|
|
70
|
+
The daemon auto-starts on demand, so later commands reuse the same session and profile.
|
|
71
|
+
|
|
72
|
+
## What Works Today
|
|
73
|
+
|
|
74
|
+
### Browser management
|
|
75
|
+
|
|
76
|
+
- `camou install [version]`
|
|
77
|
+
- `camou remove [version]`
|
|
78
|
+
- `camou use <version>`
|
|
79
|
+
- `camou versions`
|
|
80
|
+
- `camou presets`
|
|
81
|
+
- `camou version`
|
|
82
|
+
- `camou path`
|
|
83
|
+
- `camou doctor`
|
|
84
|
+
|
|
85
|
+
### Page automation
|
|
86
|
+
|
|
87
|
+
- `camou open <url>`
|
|
88
|
+
- `camou snapshot [-i]`
|
|
89
|
+
- `camou click <selectorOrRef>`
|
|
90
|
+
- `camou fill <selectorOrRef> <text>`
|
|
91
|
+
- `camou press <key>`
|
|
92
|
+
- `camou wait <selectorOrRef>`
|
|
93
|
+
- `camou screenshot [path]`
|
|
94
|
+
- `camou get url`
|
|
95
|
+
- `camou get title`
|
|
96
|
+
- `camou get text <selectorOrRef>`
|
|
97
|
+
|
|
98
|
+
### Session and tab management
|
|
99
|
+
|
|
100
|
+
- `camou session list`
|
|
101
|
+
- `camou session stop [name]`
|
|
102
|
+
- `camou tab list`
|
|
103
|
+
- `camou tab new [url]`
|
|
104
|
+
- `camou tab close [nameOrIndex]`
|
|
105
|
+
|
|
106
|
+
## Common Flags
|
|
107
|
+
|
|
108
|
+
Most browser commands support:
|
|
109
|
+
|
|
110
|
+
- `--session <name>`
|
|
111
|
+
- `--tabname <name>`
|
|
112
|
+
- `--headless`
|
|
113
|
+
- `--browser <version>`
|
|
114
|
+
- `--config <path>`
|
|
115
|
+
- `--config-json <json>`
|
|
116
|
+
- `--prefs <path>`
|
|
117
|
+
- `--prefs-json <json>`
|
|
118
|
+
- `--preset <name>`
|
|
119
|
+
- `--proxy <url>`
|
|
120
|
+
- `--locale <locale>`
|
|
121
|
+
- `--timezone <timezone>`
|
|
122
|
+
- `--width <px>` / `--height <px>`
|
|
123
|
+
- `--json`
|
|
124
|
+
- `--verbose`
|
|
125
|
+
|
|
126
|
+
## Example Flows
|
|
127
|
+
|
|
128
|
+
Use a named session and tab:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
camou open https://github.com --session work --tabname github
|
|
132
|
+
camou snapshot -i --session work --tabname github
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Install and switch versions:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
camou install 135.0.1-beta.24
|
|
139
|
+
camou install 134.0.0-beta.20
|
|
140
|
+
camou versions
|
|
141
|
+
camou use 134.0.0-beta.20
|
|
142
|
+
camou version
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Check the current install inventory and launch compatibility:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
camou doctor --json
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Launch a session with an explicit installed browser version without changing the global default:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
camou open https://example.com --session canary --browser 135.0.1-beta.24
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Save a screenshot to the session artifacts directory:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
camou screenshot --session work --tabname github
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Storage Layout
|
|
164
|
+
|
|
165
|
+
Camoucli uses platform-specific app directories for its own state and profiles.
|
|
166
|
+
|
|
167
|
+
- session profiles live under `profiles/<session>/{user-data,downloads,artifacts}`
|
|
168
|
+
- daemon state and logs live under the platform state/runtime dirs
|
|
169
|
+
|
|
170
|
+
Camoufox binaries are stored in the shared cache layout used by the Python library when possible:
|
|
171
|
+
|
|
172
|
+
- Linux: `~/.cache/camoufox/browsers/official/<version>/`
|
|
173
|
+
- macOS: `~/Library/Caches/camoufox/browsers/official/<version>/`
|
|
174
|
+
- Windows: `%LOCALAPPDATA%\camoufox\Cache\browsers\official\<version>\`
|
|
175
|
+
|
|
176
|
+
This lets Camoucli reuse compatible Camoufox installs from the Python ecosystem and vice versa.
|
|
177
|
+
|
|
178
|
+
## Presets
|
|
179
|
+
|
|
180
|
+
Built-in presets give you a small layer of tested ergonomics on top of raw config and prefs JSON:
|
|
181
|
+
|
|
182
|
+
- `default` - baseline launch with no additional overrides
|
|
183
|
+
- `cache` - enables the Firefox cache/session prefs used by the Python library
|
|
184
|
+
- `low-bandwidth` - blocks images and speculative requests for lighter automation sessions
|
|
185
|
+
- `disable-coop` - relaxes Cross-Origin-Opener-Policy isolation for troublesome embedded flows
|
|
186
|
+
|
|
187
|
+
List them from the CLI:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
camou presets
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Apply one or more presets to a browser command:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
camou open https://example.com --preset cache --preset low-bandwidth
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Compatibility Matrix
|
|
200
|
+
|
|
201
|
+
Current local verification with `playwright-core` `1.51.1`:
|
|
202
|
+
|
|
203
|
+
| Camoufox | Status | Notes |
|
|
204
|
+
| --- | --- | --- |
|
|
205
|
+
| `135.0.1-beta.24` | launches | smoke-tested successfully |
|
|
206
|
+
| `135.0.1-beta.23` | incompatible | `Browser.setContrast` is not supported |
|
|
207
|
+
|
|
208
|
+
## Notes
|
|
209
|
+
|
|
210
|
+
- The CLI is intentionally thin; the daemon owns browser lifecycle and persistent state.
|
|
211
|
+
- `snapshot` creates per-tab `@eN` refs, and refs are cleared after navigation or a new snapshot.
|
|
212
|
+
- Browser installation is explicit; the package does not download Camoufox during `npm install`.
|
|
213
|
+
- `install` and `use` include a quick compatibility hint based on a real headless launch probe of the selected version.
|
|
214
|
+
- `doctor` reports installed versions, a per-version launch compatibility matrix, shared-library diagnostics, and remediation hints.
|
|
215
|
+
- Passing `--json` returns structured machine-readable errors for both top-level CLI failures and daemon responses.
|
|
216
|
+
|
|
217
|
+
## Development
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npm install
|
|
221
|
+
npm run build
|
|
222
|
+
npm test
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Optional targeted integration suite:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
npm run test:integration
|
|
229
|
+
```
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Locator, Page } from 'playwright-core';
|
|
2
|
+
import type { TabRuntime } from './tabs.js';
|
|
3
|
+
export declare function resolveSelectorOrRef(tab: TabRuntime, target: string): string;
|
|
4
|
+
export declare function locatorForTarget(page: Page, tab: TabRuntime, target: string): Locator;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RefNotFoundError } from '../util/errors.js';
|
|
2
|
+
export function resolveSelectorOrRef(tab, target) {
|
|
3
|
+
if (!target.startsWith('@')) {
|
|
4
|
+
return target;
|
|
5
|
+
}
|
|
6
|
+
const selector = tab.refMap.get(target);
|
|
7
|
+
if (!selector) {
|
|
8
|
+
throw new RefNotFoundError(target);
|
|
9
|
+
}
|
|
10
|
+
return selector;
|
|
11
|
+
}
|
|
12
|
+
export function locatorForTarget(page, tab, target) {
|
|
13
|
+
return page.locator(resolveSelectorOrRef(tab, target));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/browser/actions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,MAAM,UAAU,oBAAoB,CAAC,GAAe,EAAE,MAAc;IAClE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAU,EAAE,GAAe,EAAE,MAAc;IAC1E,OAAO,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { LaunchInput } from '../camoufox/config.js';
|
|
2
|
+
import type { CamoucliPaths } from '../state/paths.js';
|
|
3
|
+
import type { Logger } from '../util/log.js';
|
|
4
|
+
interface BrowserManagerOptions {
|
|
5
|
+
paths: CamoucliPaths;
|
|
6
|
+
logger: Logger;
|
|
7
|
+
}
|
|
8
|
+
export declare class BrowserManager {
|
|
9
|
+
private readonly paths;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly sessions;
|
|
12
|
+
private readonly startingSessions;
|
|
13
|
+
constructor(options: BrowserManagerOptions);
|
|
14
|
+
listSessions(): Promise<Array<Record<string, unknown>>>;
|
|
15
|
+
stopSession(sessionName: string): Promise<{
|
|
16
|
+
stopped: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
stopAllSessions(): Promise<void>;
|
|
19
|
+
open(input: LaunchInput & {
|
|
20
|
+
session: string;
|
|
21
|
+
tabName: string;
|
|
22
|
+
url: string;
|
|
23
|
+
}): Promise<Record<string, unknown>>;
|
|
24
|
+
snapshot(input: LaunchInput & {
|
|
25
|
+
session: string;
|
|
26
|
+
tabName: string;
|
|
27
|
+
interactive: boolean;
|
|
28
|
+
}): Promise<Record<string, unknown>>;
|
|
29
|
+
click(input: LaunchInput & {
|
|
30
|
+
session: string;
|
|
31
|
+
tabName: string;
|
|
32
|
+
target: string;
|
|
33
|
+
}): Promise<Record<string, unknown>>;
|
|
34
|
+
fill(input: LaunchInput & {
|
|
35
|
+
session: string;
|
|
36
|
+
tabName: string;
|
|
37
|
+
target: string;
|
|
38
|
+
text: string;
|
|
39
|
+
}): Promise<Record<string, unknown>>;
|
|
40
|
+
press(input: LaunchInput & {
|
|
41
|
+
session: string;
|
|
42
|
+
tabName: string;
|
|
43
|
+
key: string;
|
|
44
|
+
}): Promise<Record<string, unknown>>;
|
|
45
|
+
screenshot(input: LaunchInput & {
|
|
46
|
+
session: string;
|
|
47
|
+
tabName: string;
|
|
48
|
+
path?: string | undefined;
|
|
49
|
+
}): Promise<Record<string, unknown>>;
|
|
50
|
+
getUrl(input: LaunchInput & {
|
|
51
|
+
session: string;
|
|
52
|
+
tabName: string;
|
|
53
|
+
}): Promise<Record<string, unknown>>;
|
|
54
|
+
getTitle(input: LaunchInput & {
|
|
55
|
+
session: string;
|
|
56
|
+
tabName: string;
|
|
57
|
+
}): Promise<Record<string, unknown>>;
|
|
58
|
+
getText(input: LaunchInput & {
|
|
59
|
+
session: string;
|
|
60
|
+
tabName: string;
|
|
61
|
+
target: string;
|
|
62
|
+
}): Promise<Record<string, unknown>>;
|
|
63
|
+
wait(input: LaunchInput & {
|
|
64
|
+
session: string;
|
|
65
|
+
tabName: string;
|
|
66
|
+
target: string;
|
|
67
|
+
timeoutMs?: number | undefined;
|
|
68
|
+
}): Promise<Record<string, unknown>>;
|
|
69
|
+
listTabs(sessionName: string): Promise<Array<Record<string, unknown>>>;
|
|
70
|
+
newTab(input: LaunchInput & {
|
|
71
|
+
session: string;
|
|
72
|
+
tabName: string;
|
|
73
|
+
url?: string | undefined;
|
|
74
|
+
}): Promise<Record<string, unknown>>;
|
|
75
|
+
closeTab(sessionName: string, target: string): Promise<{
|
|
76
|
+
closed: boolean;
|
|
77
|
+
tabName?: string;
|
|
78
|
+
}>;
|
|
79
|
+
private ensureSession;
|
|
80
|
+
private ensureTab;
|
|
81
|
+
private assertSessionCompatible;
|
|
82
|
+
private trackPage;
|
|
83
|
+
private findTab;
|
|
84
|
+
}
|
|
85
|
+
export {};
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { launchPersistentCamoufox } from '../camoufox/launcher.js';
|
|
3
|
+
import { SessionError } from '../util/errors.js';
|
|
4
|
+
import { locatorForTarget } from './actions.js';
|
|
5
|
+
import { clearSnapshotRefs, takeSnapshot } from './snapshot.js';
|
|
6
|
+
import { createTabRuntime } from './tabs.js';
|
|
7
|
+
export class BrowserManager {
|
|
8
|
+
paths;
|
|
9
|
+
logger;
|
|
10
|
+
sessions = new Map();
|
|
11
|
+
startingSessions = new Map();
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.paths = options.paths;
|
|
14
|
+
this.logger = options.logger;
|
|
15
|
+
}
|
|
16
|
+
async listSessions() {
|
|
17
|
+
return Array.from(this.sessions.values()).map((session) => ({
|
|
18
|
+
sessionName: session.name,
|
|
19
|
+
status: session.status,
|
|
20
|
+
browserVersion: session.browserVersion,
|
|
21
|
+
profileDir: session.paths.profileDir,
|
|
22
|
+
downloadsDir: session.paths.downloadsDir,
|
|
23
|
+
artifactsDir: session.paths.artifactsDir,
|
|
24
|
+
headless: session.resolvedConfig.headless,
|
|
25
|
+
tabs: Array.from(session.tabs.values()).map((tab) => ({
|
|
26
|
+
tabName: tab.name,
|
|
27
|
+
url: tab.page.url(),
|
|
28
|
+
})),
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
async stopSession(sessionName) {
|
|
32
|
+
const session = this.sessions.get(sessionName);
|
|
33
|
+
if (!session) {
|
|
34
|
+
return { stopped: false };
|
|
35
|
+
}
|
|
36
|
+
await session.context.close();
|
|
37
|
+
this.sessions.delete(sessionName);
|
|
38
|
+
this.logger.info('Stopped browser session', { sessionName });
|
|
39
|
+
return { stopped: true };
|
|
40
|
+
}
|
|
41
|
+
async stopAllSessions() {
|
|
42
|
+
await Promise.all(Array.from(this.sessions.keys()).map((sessionName) => this.stopSession(sessionName)));
|
|
43
|
+
}
|
|
44
|
+
async open(input) {
|
|
45
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
46
|
+
await tab.page.goto(input.url, { waitUntil: 'domcontentloaded' });
|
|
47
|
+
return {
|
|
48
|
+
sessionName: input.session,
|
|
49
|
+
tabName: tab.name,
|
|
50
|
+
url: tab.page.url(),
|
|
51
|
+
title: await tab.page.title(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async snapshot(input) {
|
|
55
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
56
|
+
const result = await takeSnapshot(tab.page, input.interactive);
|
|
57
|
+
tab.lastSnapshot = result;
|
|
58
|
+
tab.refMap = new Map(Object.entries(result.refs));
|
|
59
|
+
return {
|
|
60
|
+
sessionName: input.session,
|
|
61
|
+
tabName: tab.name,
|
|
62
|
+
interactive: input.interactive,
|
|
63
|
+
count: result.entries.length,
|
|
64
|
+
snapshot: result.text,
|
|
65
|
+
entries: result.entries,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async click(input) {
|
|
69
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
70
|
+
await locatorForTarget(tab.page, tab, input.target).click();
|
|
71
|
+
return {
|
|
72
|
+
sessionName: input.session,
|
|
73
|
+
tabName: tab.name,
|
|
74
|
+
target: input.target,
|
|
75
|
+
url: tab.page.url(),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async fill(input) {
|
|
79
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
80
|
+
await locatorForTarget(tab.page, tab, input.target).fill(input.text);
|
|
81
|
+
return {
|
|
82
|
+
sessionName: input.session,
|
|
83
|
+
tabName: tab.name,
|
|
84
|
+
target: input.target,
|
|
85
|
+
valueLength: input.text.length,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async press(input) {
|
|
89
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
90
|
+
await tab.page.keyboard.press(input.key);
|
|
91
|
+
return {
|
|
92
|
+
sessionName: input.session,
|
|
93
|
+
tabName: tab.name,
|
|
94
|
+
key: input.key,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async screenshot(input) {
|
|
98
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
99
|
+
const session = await this.ensureSession(input.session, input);
|
|
100
|
+
const filePath = input.path ?? path.join(session.paths.artifactsDir, `${tab.name}-${Date.now()}.png`);
|
|
101
|
+
await tab.page.screenshot({ path: filePath, fullPage: true });
|
|
102
|
+
return {
|
|
103
|
+
sessionName: input.session,
|
|
104
|
+
tabName: tab.name,
|
|
105
|
+
path: filePath,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async getUrl(input) {
|
|
109
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
110
|
+
return {
|
|
111
|
+
sessionName: input.session,
|
|
112
|
+
tabName: tab.name,
|
|
113
|
+
url: tab.page.url(),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async getTitle(input) {
|
|
117
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
118
|
+
return {
|
|
119
|
+
sessionName: input.session,
|
|
120
|
+
tabName: tab.name,
|
|
121
|
+
title: await tab.page.title(),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async getText(input) {
|
|
125
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
126
|
+
const text = await locatorForTarget(tab.page, tab, input.target).innerText();
|
|
127
|
+
return {
|
|
128
|
+
sessionName: input.session,
|
|
129
|
+
tabName: tab.name,
|
|
130
|
+
target: input.target,
|
|
131
|
+
text,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
async wait(input) {
|
|
135
|
+
const tab = await this.ensureTab(input.session, input.tabName, input);
|
|
136
|
+
const waitOptions = input.timeoutMs ? { timeout: input.timeoutMs } : undefined;
|
|
137
|
+
await locatorForTarget(tab.page, tab, input.target).waitFor(waitOptions);
|
|
138
|
+
return {
|
|
139
|
+
sessionName: input.session,
|
|
140
|
+
tabName: tab.name,
|
|
141
|
+
target: input.target,
|
|
142
|
+
url: tab.page.url(),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async listTabs(sessionName) {
|
|
146
|
+
const session = await this.ensureSession(sessionName, { headless: false });
|
|
147
|
+
return Promise.all(Array.from(session.tabs.values()).map(async (tab, index) => ({
|
|
148
|
+
index,
|
|
149
|
+
tabName: tab.name,
|
|
150
|
+
url: tab.page.url(),
|
|
151
|
+
title: tab.page.isClosed() ? '' : await tab.page.title(),
|
|
152
|
+
})));
|
|
153
|
+
}
|
|
154
|
+
async newTab(input) {
|
|
155
|
+
const session = await this.ensureSession(input.session, input);
|
|
156
|
+
if (session.tabs.has(input.tabName)) {
|
|
157
|
+
throw new SessionError(`Tab ${input.tabName} already exists in session ${input.session}.`);
|
|
158
|
+
}
|
|
159
|
+
const page = await session.context.newPage();
|
|
160
|
+
const tab = this.trackPage(session, input.tabName, page);
|
|
161
|
+
if (input.url) {
|
|
162
|
+
await page.goto(input.url, { waitUntil: 'domcontentloaded' });
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
sessionName: input.session,
|
|
166
|
+
tabName: tab.name,
|
|
167
|
+
url: page.url(),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async closeTab(sessionName, target) {
|
|
171
|
+
const session = this.sessions.get(sessionName);
|
|
172
|
+
if (!session) {
|
|
173
|
+
return { closed: false };
|
|
174
|
+
}
|
|
175
|
+
const tab = this.findTab(session, target);
|
|
176
|
+
if (!tab) {
|
|
177
|
+
return { closed: false };
|
|
178
|
+
}
|
|
179
|
+
await tab.page.close();
|
|
180
|
+
session.tabs.delete(tab.name);
|
|
181
|
+
return {
|
|
182
|
+
closed: true,
|
|
183
|
+
tabName: tab.name,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async ensureSession(sessionName, input) {
|
|
187
|
+
const existing = this.sessions.get(sessionName);
|
|
188
|
+
if (existing) {
|
|
189
|
+
return existing;
|
|
190
|
+
}
|
|
191
|
+
const inFlight = this.startingSessions.get(sessionName);
|
|
192
|
+
if (inFlight) {
|
|
193
|
+
return inFlight;
|
|
194
|
+
}
|
|
195
|
+
const startPromise = (async () => {
|
|
196
|
+
const launched = await launchPersistentCamoufox(this.paths, sessionName, input, this.logger);
|
|
197
|
+
const session = {
|
|
198
|
+
name: sessionName,
|
|
199
|
+
status: 'running',
|
|
200
|
+
context: launched.context,
|
|
201
|
+
tabs: new Map(),
|
|
202
|
+
browserVersion: launched.browserVersion,
|
|
203
|
+
installPath: launched.installPath,
|
|
204
|
+
paths: launched.sessionPaths,
|
|
205
|
+
resolvedConfig: launched.resolvedConfig,
|
|
206
|
+
launchInput: input,
|
|
207
|
+
startedAt: new Date().toISOString(),
|
|
208
|
+
};
|
|
209
|
+
const pages = session.context.pages();
|
|
210
|
+
if (pages.length === 0) {
|
|
211
|
+
const page = await session.context.newPage();
|
|
212
|
+
this.trackPage(session, 'main', page);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
pages.forEach((page, index) => {
|
|
216
|
+
this.trackPage(session, index === 0 ? 'main' : `restored-${index + 1}`, page);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
session.context.on('close', () => {
|
|
220
|
+
session.status = 'stopped';
|
|
221
|
+
this.sessions.delete(session.name);
|
|
222
|
+
});
|
|
223
|
+
this.sessions.set(sessionName, session);
|
|
224
|
+
this.logger.info('Started browser session', { sessionName, browserVersion: session.browserVersion });
|
|
225
|
+
return session;
|
|
226
|
+
})();
|
|
227
|
+
this.startingSessions.set(sessionName, startPromise);
|
|
228
|
+
try {
|
|
229
|
+
return await startPromise;
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
this.logger.error('Failed to start browser session', { sessionName, error: String(error) });
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
this.startingSessions.delete(sessionName);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async ensureTab(sessionName, tabName, input) {
|
|
240
|
+
const session = await this.ensureSession(sessionName, input);
|
|
241
|
+
const existing = session.tabs.get(tabName);
|
|
242
|
+
if (existing && !existing.page.isClosed()) {
|
|
243
|
+
return existing;
|
|
244
|
+
}
|
|
245
|
+
if (existing?.page.isClosed()) {
|
|
246
|
+
session.tabs.delete(tabName);
|
|
247
|
+
}
|
|
248
|
+
const page = await session.context.newPage();
|
|
249
|
+
return this.trackPage(session, tabName, page);
|
|
250
|
+
}
|
|
251
|
+
assertSessionCompatible(session, input) {
|
|
252
|
+
if (input.configPath || input.configJson || input.prefsPath || input.prefsJson || input.preset?.length) {
|
|
253
|
+
throw new SessionError(`Session ${session.name} is already running. Stop it before changing config, prefs, or presets for that session.`);
|
|
254
|
+
}
|
|
255
|
+
if (input.browser && input.browser !== session.browserVersion) {
|
|
256
|
+
throw new SessionError(`Session ${session.name} is already running with browser ${session.browserVersion}. Use a different session name or stop the existing session first.`);
|
|
257
|
+
}
|
|
258
|
+
if (input.headless !== undefined && input.headless !== session.resolvedConfig.headless) {
|
|
259
|
+
throw new SessionError(`Session ${session.name} is already running with headless=${String(session.resolvedConfig.headless)}. Use a different session name or stop the existing session first.`);
|
|
260
|
+
}
|
|
261
|
+
if (input.proxy && input.proxy !== session.resolvedConfig.proxy?.server) {
|
|
262
|
+
throw new SessionError(`Session ${session.name} is already running with proxy ${session.resolvedConfig.proxy?.server ?? 'none'}. Use a different session name or stop the existing session first.`);
|
|
263
|
+
}
|
|
264
|
+
if (input.locale && input.locale !== session.resolvedConfig.locale) {
|
|
265
|
+
throw new SessionError(`Session ${session.name} is already running with locale ${session.resolvedConfig.locale ?? 'default'}. Use a different session name or stop the existing session first.`);
|
|
266
|
+
}
|
|
267
|
+
if (input.timezone && input.timezone !== session.resolvedConfig.timezoneId) {
|
|
268
|
+
throw new SessionError(`Session ${session.name} is already running with timezone ${session.resolvedConfig.timezoneId ?? 'default'}. Use a different session name or stop the existing session first.`);
|
|
269
|
+
}
|
|
270
|
+
if ((input.width || input.height) && (!session.resolvedConfig.viewport || session.resolvedConfig.viewport.width !== input.width || session.resolvedConfig.viewport.height !== input.height)) {
|
|
271
|
+
throw new SessionError(`Session ${session.name} is already running with a different window size. Use a different session name or stop the existing session first.`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
trackPage(session, tabName, page) {
|
|
275
|
+
const tab = createTabRuntime(tabName, page);
|
|
276
|
+
page.on('framenavigated', (frame) => {
|
|
277
|
+
if (frame === page.mainFrame()) {
|
|
278
|
+
void clearSnapshotRefs(page);
|
|
279
|
+
tab.refMap.clear();
|
|
280
|
+
delete tab.lastSnapshot;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
page.on('close', () => {
|
|
284
|
+
session.tabs.delete(tab.name);
|
|
285
|
+
});
|
|
286
|
+
session.tabs.set(tabName, tab);
|
|
287
|
+
return tab;
|
|
288
|
+
}
|
|
289
|
+
findTab(session, target) {
|
|
290
|
+
if (session.tabs.has(target)) {
|
|
291
|
+
return session.tabs.get(target);
|
|
292
|
+
}
|
|
293
|
+
const numericIndex = Number(target);
|
|
294
|
+
if (Number.isInteger(numericIndex)) {
|
|
295
|
+
return Array.from(session.tabs.values())[numericIndex];
|
|
296
|
+
}
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/browser/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Page } from 'playwright-core';
|
|
2
|
+
export interface SnapshotEntry {
|
|
3
|
+
ref: string;
|
|
4
|
+
selector: string;
|
|
5
|
+
tag: string;
|
|
6
|
+
role?: string | undefined;
|
|
7
|
+
inputType?: string | undefined;
|
|
8
|
+
text: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SnapshotResult {
|
|
11
|
+
interactive: boolean;
|
|
12
|
+
text: string;
|
|
13
|
+
entries: SnapshotEntry[];
|
|
14
|
+
refs: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
export declare function clearSnapshotRefs(page: Page): Promise<void>;
|
|
17
|
+
export declare function takeSnapshot(page: Page, interactiveOnly: boolean): Promise<SnapshotResult>;
|