@push.rocks/smartpuppeteer 2.1.0 → 2.2.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.d.ts +23 -15
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.js +619 -57
- package/dist_ts/smartpuppeteer.classes.smartpuppeteer.d.ts +1 -0
- package/dist_ts/smartpuppeteer.classes.smartpuppeteer.js +23 -4
- package/dist_ts/smartpuppeteer.interfaces.livebrowser.d.ts +24 -0
- package/package.json +2 -2
- package/readme.md +37 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/smartpuppeteer.classes.livebrowsersession.ts +726 -49
- package/ts/smartpuppeteer.classes.smartpuppeteer.ts +27 -4
- package/ts/smartpuppeteer.interfaces.livebrowser.ts +32 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import * as plugins from './smartpuppeteer.plugins.js';
|
|
2
|
+
const sandboxDisablingArguments = [
|
|
3
|
+
'--disable-gpu-sandbox',
|
|
4
|
+
'--disable-seccomp-filter-sandbox',
|
|
5
|
+
'--disable-setuid-sandbox',
|
|
6
|
+
'--no-sandbox',
|
|
7
|
+
];
|
|
2
8
|
export const resolveBrowserExecutablePath = (candidateNamesArg = [
|
|
3
9
|
'google-chrome',
|
|
4
10
|
'chromium',
|
|
@@ -17,13 +23,26 @@ export const resolveBrowserExecutablePath = (candidateNamesArg = [
|
|
|
17
23
|
export const getEnvAwareBrowserInstance = async (optionsArg = {}) => {
|
|
18
24
|
const options = {
|
|
19
25
|
forceNoSandbox: false,
|
|
26
|
+
requireSandbox: false,
|
|
20
27
|
...optionsArg,
|
|
21
28
|
};
|
|
29
|
+
if (options.forceNoSandbox && options.requireSandbox) {
|
|
30
|
+
throw new Error('forceNoSandbox and requireSandbox are mutually exclusive');
|
|
31
|
+
}
|
|
22
32
|
const launchOptions = options.launchOptions ?? {};
|
|
23
33
|
let chromeArgs = [...(launchOptions.args ?? [])];
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
if (options.requireSandbox) {
|
|
35
|
+
const forbiddenArgument = chromeArgs.find((argument) => (sandboxDisablingArguments.includes(argument.split('=', 1)[0])));
|
|
36
|
+
if (forbiddenArgument) {
|
|
37
|
+
throw new Error(`Sandbox-required browser launch rejects argument: ${forbiddenArgument}`);
|
|
38
|
+
}
|
|
39
|
+
if (process.platform === 'linux' && process.getuid?.() === 0) {
|
|
40
|
+
throw new Error('Sandbox-required Chromium cannot be launched as root');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (process.env.CI
|
|
44
|
+
|| options.forceNoSandbox
|
|
45
|
+
|| plugins.os.userInfo().username === 'root') {
|
|
27
46
|
for (const sandboxArg of ['--no-sandbox', '--disable-setuid-sandbox']) {
|
|
28
47
|
if (!chromeArgs.includes(sandboxArg)) {
|
|
29
48
|
chromeArgs.push(sandboxArg);
|
|
@@ -59,4 +78,4 @@ export const getEnvAwareBrowserInstance = async (optionsArg = {}) => {
|
|
|
59
78
|
});
|
|
60
79
|
return headlessBrowser;
|
|
61
80
|
};
|
|
62
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIuY2xhc3Nlcy5zbWFydHB1cHBldGVlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLmNsYXNzZXMuc21hcnRwdXBwZXRlZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSw2QkFBNkIsQ0FBQztBQVN2RCxNQUFNLHlCQUF5QixHQUFHO0lBQ2hDLHVCQUF1QjtJQUN2QixrQ0FBa0M7SUFDbEMsMEJBQTBCO0lBQzFCLGNBQWM7Q0FDZixDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sNEJBQTRCLEdBQUcsQ0FDMUMsb0JBQThCO0lBQzVCLGVBQWU7SUFDZixVQUFVO0lBQ1Ysa0JBQWtCO0NBQ25CLEVBQ21CLEVBQUU7SUFDdEIsS0FBSyxNQUFNLGFBQWEsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO1FBQzlDLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDbEUsT0FBTyxFQUFFLElBQUk7U0FDZCxDQUFDLENBQUM7UUFDSCxJQUFJLGNBQWMsRUFBRSxDQUFDO1lBQ25CLE9BQU8sY0FBYyxDQUFDO1FBQ3hCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQUcsS0FBSyxFQUM3QyxhQUErQixFQUFFLEVBQ0csRUFBRTtJQUN0QyxNQUFNLE9BQU8sR0FBcUI7UUFDaEMsY0FBYyxFQUFFLEtBQUs7UUFDckIsY0FBYyxFQUFFLEtBQUs7UUFDckIsR0FBRyxVQUFVO0tBQ2QsQ0FBQztJQUVGLElBQUksT0FBTyxDQUFDLGNBQWMsSUFBSSxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDckQsTUFBTSxJQUFJLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFFRCxN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
|
|
@@ -15,11 +15,35 @@ export interface ILiveBrowserScreencastOptions {
|
|
|
15
15
|
maxHeight?: number;
|
|
16
16
|
everyNthFrame?: number;
|
|
17
17
|
}
|
|
18
|
+
export interface ILiveBrowserSecurityOptions {
|
|
19
|
+
denyDownloads?: boolean;
|
|
20
|
+
denyFileChoosers?: boolean;
|
|
21
|
+
denyPermissions?: boolean;
|
|
22
|
+
httpNavigationOnly?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface ILiveBrowserOperationOptions {
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}
|
|
27
|
+
export type TLiveBrowserJsonValue = null | boolean | number | string | TLiveBrowserJsonValue[] | {
|
|
28
|
+
[key: string]: TLiveBrowserJsonValue;
|
|
29
|
+
};
|
|
30
|
+
export interface ILiveBrowserEvaluateOptions {
|
|
31
|
+
tabId?: string;
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
maxOutputBytes?: number;
|
|
34
|
+
maxDepth?: number;
|
|
35
|
+
maxNodes?: number;
|
|
36
|
+
maxStringBytes?: number;
|
|
37
|
+
maxArrayLength?: number;
|
|
38
|
+
maxObjectKeys?: number;
|
|
39
|
+
}
|
|
18
40
|
export type TLiveBrowserLaunchOptions = Omit<NonNullable<IEnvAwareOptions['launchOptions']>, 'signal'>;
|
|
19
41
|
export interface ILiveBrowserSessionOptions extends Omit<IEnvAwareOptions, 'launchOptions'> {
|
|
20
42
|
launchOptions?: TLiveBrowserLaunchOptions;
|
|
21
43
|
viewport?: ILiveBrowserViewport;
|
|
22
44
|
screencast?: ILiveBrowserScreencastOptions;
|
|
45
|
+
security?: ILiveBrowserSecurityOptions;
|
|
46
|
+
allowEvaluation?: boolean;
|
|
23
47
|
}
|
|
24
48
|
export interface ILiveBrowserTabState {
|
|
25
49
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartpuppeteer",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Provides simplified access to Puppeteer for automation and testing purposes.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@git.zone/tsbuild": "^4.4.2",
|
|
16
16
|
"@git.zone/tsrun": "^2.0.6",
|
|
17
17
|
"@git.zone/tstest": "^4.0.0",
|
|
18
|
-
"@types/node": "^26.
|
|
18
|
+
"@types/node": "^26.2.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@push.rocks/smartdelay": "^3.0.1",
|
package/readme.md
CHANGED
|
@@ -44,6 +44,8 @@ const initializeBrowser = async () => {
|
|
|
44
44
|
|
|
45
45
|
Caller `launchOptions` are passed to Puppeteer. Caller arguments are retained when the environment requires `--no-sandbox` and `--disable-setuid-sandbox`, and the required arguments are added without duplication. This no-sandbox behavior remains limited to root users, CI environments, or callers that explicitly set `forceNoSandbox`; disabling Chromium's sandbox reduces process isolation. The existing pipe transport remains enabled by default; set `usePipe: false` to request Puppeteer's WebSocket transport. Executable discovery is skipped when `launchOptions.browser`, `launchOptions.channel`, or `launchOptions.executablePath` is present.
|
|
46
46
|
|
|
47
|
+
Set `requireSandbox: true` when a caller must fail closed instead of accepting the environment-aware no-sandbox behavior. This rejects `forceNoSandbox`, known sandbox-disabling Chromium arguments, and Linux launches as root. It also prevents `CI` from adding no-sandbox arguments. This option prevents SmartPuppeteer from disabling Chromium's sandbox; a successful process launch is still not an independent verification of Chromium's internal sandbox state.
|
|
48
|
+
|
|
47
49
|
Use `resolveBrowserExecutablePath()` directly when you need to inspect the selected executable or provide your own ordered candidate list:
|
|
48
50
|
|
|
49
51
|
```typescript
|
|
@@ -175,10 +177,44 @@ The live API includes:
|
|
|
175
177
|
- Viewport and raw input: `setViewport()`, `dispatchMouse()`, `dispatchWheel()`, `dispatchKey()`, and `insertText()`
|
|
176
178
|
- Agent-oriented actions: `click()`, `fill()`, and `press()` with bounded selectors and timeouts
|
|
177
179
|
- Capture and observation: `captureSnapshot()` returns viewport-only JPEG or PNG bytes; `observe()` returns bounded URL, title, tab state, and textual accessibility content without image bytes
|
|
180
|
+
- Optional evaluation: `evaluate()` returns bounded JSON values when the session explicitly sets `allowEvaluation: true`
|
|
178
181
|
|
|
179
182
|
Coordinate, keyboard, text, and semantic input messages include `tabId`, `generation`, and `viewportRevision`. This rejects input derived from an old stream generation, resize, or tab state. Snapshot, observation, and semantic operations are serialized with lifecycle mutations; inactive tabs receive the current session viewport before use. `viewport` takes precedence over `launchOptions.defaultViewport`; `null` falls back to 800x600. The runtime canonicalizes every page to a desktop, non-touch viewport because mobile emulation flags are outside the public viewport contract. Viewport dimensions, device scale factor, and physical pixel area are bounded, and full-page snapshots are intentionally unsupported. CDP sessions and CDP frame identifiers remain private implementation details. `LiveBrowserSession` owns launch cancellation, so callers cannot supply `launchOptions.signal`. It supports only Chromium over CDP and rejects Firefox or WebDriver BiDi launch selections.
|
|
180
183
|
|
|
181
|
-
`
|
|
184
|
+
`start()`, tab and navigation methods, `setViewport()`, `captureSnapshot()`, `observe()`, semantic actions, and `evaluate()` accept a trailing `{ signal }` operation argument. A pre-aborted operation is never admitted. An operation aborted while queued is removed immediately. An active operation receives cancellation when its Puppeteer or CDP primitive supports it; otherwise its promise rejects only after the underlying work settles, and it continues to occupy the serialized queue until then. Cancellation therefore does not promise that an already-started browser side effect did not occur. `stop()`, frame acknowledgement, event/state access, and direct raw input are intentionally not caller-cancellable.
|
|
185
|
+
|
|
186
|
+
Optional browser guards can be enabled when composing a higher-level runtime:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const guardedSession = new LiveBrowserSession({
|
|
190
|
+
requireSandbox: true,
|
|
191
|
+
security: {
|
|
192
|
+
denyDownloads: true,
|
|
193
|
+
denyFileChoosers: true,
|
|
194
|
+
denyPermissions: true,
|
|
195
|
+
httpNavigationOnly: true,
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`denyDownloads` installs a default-context download denial at launch. `denyPermissions` applies an empty browser-wide permission grant before the first page is exposed, causing unlisted permissions to be denied. `denyFileChoosers` installs persistent CDP cancellation on each registered page. `httpNavigationOnly` limits URLs passed to `createTab()` and `navigate()` to `http:` and `https:`; it does not inspect or rewrite renderer-initiated navigation.
|
|
201
|
+
|
|
202
|
+
Evaluation is disabled by default. Once enabled, it accepts a JavaScript expression, runs it in a dedicated main-frame isolated world, awaits its result, and returns only JSON-compatible values:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const evaluationSession = new LiveBrowserSession({ allowEvaluation: true });
|
|
206
|
+
await evaluationSession.start();
|
|
207
|
+
const result = await evaluationSession.evaluate(
|
|
208
|
+
`({ title: document.title, links: document.links.length })`,
|
|
209
|
+
{ timeoutMs: 2000, maxOutputBytes: 65536 },
|
|
210
|
+
);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The default evaluation limits are a 5-second timeout, 256 KiB transferred output, depth 16, 10,000 total nodes, 64 KiB per string or key, 1,000 array entries, and 1,000 object keys. Hard ceilings are 30 seconds, 1 MiB output, depth 32, 50,000 nodes, 256 KiB per string or key, and 10,000 array entries or object keys. Expressions are limited to 256 KiB of UTF-8 source. Results reject non-finite numbers, `undefined`, bigint, symbols, functions, sparse or extended arrays, accessors, non-plain objects, cycles, and repeated object references. Output is normalized and measured inside the renderer before bounded JSON text is transferred, then measured again before host parsing.
|
|
214
|
+
|
|
215
|
+
`evaluate()` is trusted-caller code execution, not a JavaScript sandbox. An expression can mutate or navigate the page, initiate network activity, consume renderer resources, or crash the renderer. User-started asynchronous work can outlive a returned result, timeout, or caller cancellation; a higher-level runtime that requires strict quiescence must stop or quarantine the browser. Keep evaluation disabled unless a higher-level policy explicitly authorizes it.
|
|
216
|
+
|
|
217
|
+
`LiveBrowserSession` remains a browser runtime, not a complete security policy layer. The optional guards do not authenticate callers, authorize actions, enforce network egress, own profile-directory cleanup, isolate operating-system resources, or contain a compromised Chromium process. Adapters must apply those controls before invoking it. `stop()` rejects active and queued operations and aborts Chromium independently of Puppeteer operation timeouts. Closing the final usable tab also stops the session. Browser-wide loss stops the runtime without automatic relaunch. Page or CDP loss is tab-scoped: another usable tab becomes active when possible, otherwise the runtime stops. Popup registration queue saturation emits `popup_registration_capacity_exceeded` and stops the session rather than leaving an untracked page.
|
|
182
218
|
|
|
183
219
|
### Handling Browser Events
|
|
184
220
|
It's important to handle browser events, such as disconnections, which might occur due to various reasons:
|