@push.rocks/smartpuppeteer 2.0.7 → 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/index.d.ts +2 -0
- package/dist_ts/index.js +3 -1
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.d.ts +105 -0
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.js +2468 -0
- package/dist_ts/smartpuppeteer.classes.smartpuppeteer.d.ts +2 -0
- package/dist_ts/smartpuppeteer.classes.smartpuppeteer.js +41 -10
- package/dist_ts/smartpuppeteer.interfaces.livebrowser.d.ts +215 -0
- package/dist_ts/smartpuppeteer.interfaces.livebrowser.js +2 -0
- package/dist_ts/smartpuppeteer.plugins.d.ts +3 -2
- package/dist_ts/smartpuppeteer.plugins.js +4 -3
- package/package.json +8 -6
- package/readme.hints.md +15 -1
- package/readme.md +128 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +2 -0
- package/ts/smartpuppeteer.classes.livebrowsersession.ts +2975 -0
- package/ts/smartpuppeteer.classes.smartpuppeteer.ts +46 -10
- package/ts/smartpuppeteer.interfaces.livebrowser.ts +267 -0
- package/ts/smartpuppeteer.plugins.ts +3 -2
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -18
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as plugins from './smartpuppeteer.plugins.js';
|
|
2
2
|
export interface IEnvAwareOptions {
|
|
3
3
|
forceNoSandbox?: boolean;
|
|
4
|
+
requireSandbox?: boolean;
|
|
4
5
|
usePipe?: boolean;
|
|
6
|
+
launchOptions?: plugins.puppeteer.LaunchOptions;
|
|
5
7
|
}
|
|
6
8
|
export declare const resolveBrowserExecutablePath: (candidateNamesArg?: string[]) => string | undefined;
|
|
7
9
|
export declare const getEnvAwareBrowserInstance: (optionsArg?: IEnvAwareOptions) => Promise<plugins.puppeteer.Browser>;
|
|
@@ -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,34 +23,59 @@ 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
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
if (options.forceNoSandbox && options.requireSandbox) {
|
|
30
|
+
throw new Error('forceNoSandbox and requireSandbox are mutually exclusive');
|
|
31
|
+
}
|
|
32
|
+
const launchOptions = options.launchOptions ?? {};
|
|
33
|
+
let chromeArgs = [...(launchOptions.args ?? [])];
|
|
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') {
|
|
46
|
+
for (const sandboxArg of ['--no-sandbox', '--disable-setuid-sandbox']) {
|
|
47
|
+
if (!chromeArgs.includes(sandboxArg)) {
|
|
48
|
+
chromeArgs.push(sandboxArg);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
27
51
|
console.warn('********************************************************');
|
|
28
52
|
console.warn('WARNING: Launching browser without sandbox. This can be insecure!');
|
|
29
53
|
console.warn('********************************************************');
|
|
30
54
|
}
|
|
31
|
-
// Automatically choose an executable
|
|
32
|
-
const
|
|
55
|
+
// Automatically choose an executable only when the caller did not select one.
|
|
56
|
+
const callerSelectedBrowser = launchOptions.browser !== undefined
|
|
57
|
+
|| launchOptions.channel !== undefined
|
|
58
|
+
|| launchOptions.executablePath !== undefined;
|
|
59
|
+
const execPath = callerSelectedBrowser ? undefined : resolveBrowserExecutablePath();
|
|
33
60
|
const executablePathOptions = execPath ? { executablePath: execPath } : {};
|
|
34
61
|
console.log('Launching puppeteer browser with arguments:');
|
|
35
62
|
console.log(chromeArgs);
|
|
36
63
|
if (execPath) {
|
|
37
64
|
console.log(`Using executable: ${execPath}`);
|
|
38
65
|
}
|
|
66
|
+
else if (callerSelectedBrowser) {
|
|
67
|
+
console.log('Using browser selection from caller launch options.');
|
|
68
|
+
}
|
|
39
69
|
else {
|
|
40
70
|
console.log('No specific browser executable found; falling back to Puppeteer default.');
|
|
41
71
|
}
|
|
42
72
|
const headlessBrowser = await plugins.puppeteer.launch({
|
|
43
|
-
args: chromeArgs,
|
|
44
|
-
pipe: options.usePipe ?? true,
|
|
45
73
|
headless: true,
|
|
74
|
+
...launchOptions,
|
|
75
|
+
args: chromeArgs,
|
|
76
|
+
pipe: options.usePipe ?? launchOptions.pipe ?? true,
|
|
46
77
|
...executablePathOptions,
|
|
47
78
|
});
|
|
48
79
|
return headlessBrowser;
|
|
49
80
|
};
|
|
50
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIuY2xhc3Nlcy5zbWFydHB1cHBldGVlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLmNsYXNzZXMuc21hcnRwdXBwZXRlZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSw2QkFBNkIsQ0FBQztBQVN2RCxNQUFNLHlCQUF5QixHQUFHO0lBQ2hDLHVCQUF1QjtJQUN2QixrQ0FBa0M7SUFDbEMsMEJBQTBCO0lBQzFCLGNBQWM7Q0FDZixDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sNEJBQTRCLEdBQUcsQ0FDMUMsb0JBQThCO0lBQzVCLGVBQWU7SUFDZixVQUFVO0lBQ1Ysa0JBQWtCO0NBQ25CLEVBQ21CLEVBQUU7SUFDdEIsS0FBSyxNQUFNLGFBQWEsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO1FBQzlDLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDbEUsT0FBTyxFQUFFLElBQUk7U0FDZCxDQUFDLENBQUM7UUFDSCxJQUFJLGNBQWMsRUFBRSxDQUFDO1lBQ25CLE9BQU8sY0FBYyxDQUFDO1FBQ3hCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQUcsS0FBSyxFQUM3QyxhQUErQixFQUFFLEVBQ0csRUFBRTtJQUN0QyxNQUFNLE9BQU8sR0FBcUI7UUFDaEMsY0FBYyxFQUFFLEtBQUs7UUFDckIsY0FBYyxFQUFFLEtBQUs7UUFDckIsR0FBRyxVQUFVO0tBQ2QsQ0FBQztJQUVGLElBQUksT0FBTyxDQUFDLGNBQWMsSUFBSSxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDckQsTUFBTSxJQUFJLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFFRCxN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
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { IEnvAwareOptions } from './smartpuppeteer.classes.smartpuppeteer.js';
|
|
2
|
+
export type TLiveBrowserStatus = 'stopped' | 'starting' | 'running' | 'stopping';
|
|
3
|
+
export type TLiveBrowserImageFormat = 'jpeg' | 'png';
|
|
4
|
+
export type TLiveBrowserTabStatus = 'open' | 'crashed';
|
|
5
|
+
export type TLiveBrowserWaitUntil = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
|
|
6
|
+
export interface ILiveBrowserViewport {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
deviceScaleFactor: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ILiveBrowserScreencastOptions {
|
|
12
|
+
format?: TLiveBrowserImageFormat;
|
|
13
|
+
quality?: number;
|
|
14
|
+
maxWidth?: number;
|
|
15
|
+
maxHeight?: number;
|
|
16
|
+
everyNthFrame?: number;
|
|
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
|
+
}
|
|
40
|
+
export type TLiveBrowserLaunchOptions = Omit<NonNullable<IEnvAwareOptions['launchOptions']>, 'signal'>;
|
|
41
|
+
export interface ILiveBrowserSessionOptions extends Omit<IEnvAwareOptions, 'launchOptions'> {
|
|
42
|
+
launchOptions?: TLiveBrowserLaunchOptions;
|
|
43
|
+
viewport?: ILiveBrowserViewport;
|
|
44
|
+
screencast?: ILiveBrowserScreencastOptions;
|
|
45
|
+
security?: ILiveBrowserSecurityOptions;
|
|
46
|
+
allowEvaluation?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface ILiveBrowserTabState {
|
|
49
|
+
id: string;
|
|
50
|
+
url: string;
|
|
51
|
+
title: string;
|
|
52
|
+
active: boolean;
|
|
53
|
+
status: TLiveBrowserTabStatus;
|
|
54
|
+
generation: number;
|
|
55
|
+
appliedViewportRevision: number;
|
|
56
|
+
streaming: boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface ILiveBrowserError {
|
|
59
|
+
code: string;
|
|
60
|
+
message: string;
|
|
61
|
+
fatal: boolean;
|
|
62
|
+
tabId?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface ILiveBrowserState {
|
|
65
|
+
status: TLiveBrowserStatus;
|
|
66
|
+
activeTabId: string | null;
|
|
67
|
+
viewportRevision: number;
|
|
68
|
+
viewport: ILiveBrowserViewport;
|
|
69
|
+
tabs: ILiveBrowserTabState[];
|
|
70
|
+
lastError?: ILiveBrowserError;
|
|
71
|
+
}
|
|
72
|
+
export interface ILiveBrowserScreencastMetadata {
|
|
73
|
+
offsetTop: number;
|
|
74
|
+
pageScaleFactor: number;
|
|
75
|
+
deviceWidth: number;
|
|
76
|
+
deviceHeight: number;
|
|
77
|
+
scrollOffsetX: number;
|
|
78
|
+
scrollOffsetY: number;
|
|
79
|
+
timestamp?: number;
|
|
80
|
+
}
|
|
81
|
+
export interface ILiveBrowserFrame {
|
|
82
|
+
tabId: string;
|
|
83
|
+
sequence: number;
|
|
84
|
+
generation: number;
|
|
85
|
+
viewportRevision: number;
|
|
86
|
+
viewport: ILiveBrowserViewport;
|
|
87
|
+
format: TLiveBrowserImageFormat;
|
|
88
|
+
mimeType: 'image/jpeg' | 'image/png';
|
|
89
|
+
width: number;
|
|
90
|
+
height: number;
|
|
91
|
+
metadata: ILiveBrowserScreencastMetadata;
|
|
92
|
+
data: Uint8Array;
|
|
93
|
+
}
|
|
94
|
+
export interface ILiveBrowserSnapshot {
|
|
95
|
+
tabId: string;
|
|
96
|
+
viewportRevision: number;
|
|
97
|
+
viewport: ILiveBrowserViewport;
|
|
98
|
+
format: TLiveBrowserImageFormat;
|
|
99
|
+
mimeType: 'image/jpeg' | 'image/png';
|
|
100
|
+
width: number;
|
|
101
|
+
height: number;
|
|
102
|
+
data: Uint8Array;
|
|
103
|
+
}
|
|
104
|
+
export interface ILiveBrowserStateEvent {
|
|
105
|
+
type: 'state';
|
|
106
|
+
state: ILiveBrowserState;
|
|
107
|
+
}
|
|
108
|
+
export interface ILiveBrowserFrameEvent {
|
|
109
|
+
type: 'frame';
|
|
110
|
+
frame: ILiveBrowserFrame;
|
|
111
|
+
}
|
|
112
|
+
export interface ILiveBrowserErrorEvent {
|
|
113
|
+
type: 'error';
|
|
114
|
+
error: ILiveBrowserError;
|
|
115
|
+
}
|
|
116
|
+
export type TLiveBrowserEvent = ILiveBrowserStateEvent | ILiveBrowserFrameEvent | ILiveBrowserErrorEvent;
|
|
117
|
+
export type TLiveBrowserEventListener = (event: TLiveBrowserEvent) => void;
|
|
118
|
+
export interface ILiveBrowserFrameAcknowledgement {
|
|
119
|
+
accepted: boolean;
|
|
120
|
+
}
|
|
121
|
+
export interface ILiveBrowserFrameAcknowledgementRequest {
|
|
122
|
+
tabId: string;
|
|
123
|
+
sequence: number;
|
|
124
|
+
generation: number;
|
|
125
|
+
viewportRevision: number;
|
|
126
|
+
}
|
|
127
|
+
export interface ILiveBrowserCreateTabOptions {
|
|
128
|
+
url?: string;
|
|
129
|
+
activate?: boolean;
|
|
130
|
+
timeoutMs?: number;
|
|
131
|
+
waitUntil?: TLiveBrowserWaitUntil;
|
|
132
|
+
}
|
|
133
|
+
export interface ILiveBrowserNavigationOptions {
|
|
134
|
+
tabId?: string;
|
|
135
|
+
timeoutMs?: number;
|
|
136
|
+
waitUntil?: TLiveBrowserWaitUntil;
|
|
137
|
+
}
|
|
138
|
+
export interface ILiveBrowserNavigateOptions extends ILiveBrowserNavigationOptions {
|
|
139
|
+
url: string;
|
|
140
|
+
}
|
|
141
|
+
export interface ILiveBrowserModifierState {
|
|
142
|
+
alt?: boolean;
|
|
143
|
+
control?: boolean;
|
|
144
|
+
meta?: boolean;
|
|
145
|
+
shift?: boolean;
|
|
146
|
+
}
|
|
147
|
+
export interface ILiveBrowserInputBase {
|
|
148
|
+
tabId: string;
|
|
149
|
+
generation: number;
|
|
150
|
+
viewportRevision: number;
|
|
151
|
+
}
|
|
152
|
+
export interface ILiveBrowserMouseInput extends ILiveBrowserInputBase {
|
|
153
|
+
type: 'move' | 'down' | 'up';
|
|
154
|
+
x: number;
|
|
155
|
+
y: number;
|
|
156
|
+
button?: 'none' | 'left' | 'middle' | 'right' | 'back' | 'forward';
|
|
157
|
+
buttons?: number;
|
|
158
|
+
clickCount?: number;
|
|
159
|
+
modifiers?: ILiveBrowserModifierState;
|
|
160
|
+
}
|
|
161
|
+
export interface ILiveBrowserWheelInput extends ILiveBrowserInputBase {
|
|
162
|
+
x: number;
|
|
163
|
+
y: number;
|
|
164
|
+
deltaX: number;
|
|
165
|
+
deltaY: number;
|
|
166
|
+
modifiers?: ILiveBrowserModifierState;
|
|
167
|
+
}
|
|
168
|
+
export interface ILiveBrowserKeyInput extends ILiveBrowserInputBase {
|
|
169
|
+
type: 'down' | 'up';
|
|
170
|
+
key: string;
|
|
171
|
+
code?: string;
|
|
172
|
+
text?: string;
|
|
173
|
+
unmodifiedText?: string;
|
|
174
|
+
windowsVirtualKeyCode?: number;
|
|
175
|
+
nativeVirtualKeyCode?: number;
|
|
176
|
+
autoRepeat?: boolean;
|
|
177
|
+
isKeypad?: boolean;
|
|
178
|
+
location?: number;
|
|
179
|
+
modifiers?: ILiveBrowserModifierState;
|
|
180
|
+
}
|
|
181
|
+
export interface ILiveBrowserInsertTextInput extends ILiveBrowserInputBase {
|
|
182
|
+
text: string;
|
|
183
|
+
}
|
|
184
|
+
export interface ILiveBrowserSemanticActionBase extends ILiveBrowserInputBase {
|
|
185
|
+
selector: string;
|
|
186
|
+
timeoutMs?: number;
|
|
187
|
+
}
|
|
188
|
+
export interface ILiveBrowserClickOptions extends ILiveBrowserSemanticActionBase {
|
|
189
|
+
button?: 'left' | 'middle' | 'right';
|
|
190
|
+
clickCount?: number;
|
|
191
|
+
}
|
|
192
|
+
export interface ILiveBrowserFillOptions extends ILiveBrowserSemanticActionBase {
|
|
193
|
+
text: string;
|
|
194
|
+
}
|
|
195
|
+
export interface ILiveBrowserPressOptions extends ILiveBrowserSemanticActionBase {
|
|
196
|
+
key: string;
|
|
197
|
+
}
|
|
198
|
+
export interface ILiveBrowserSnapshotOptions {
|
|
199
|
+
tabId?: string;
|
|
200
|
+
format?: TLiveBrowserImageFormat;
|
|
201
|
+
quality?: number;
|
|
202
|
+
}
|
|
203
|
+
export interface ILiveBrowserObserveOptions {
|
|
204
|
+
tabId?: string;
|
|
205
|
+
maxCharacters?: number;
|
|
206
|
+
}
|
|
207
|
+
export interface ILiveBrowserObservation {
|
|
208
|
+
tabId: string;
|
|
209
|
+
url: string;
|
|
210
|
+
title: string;
|
|
211
|
+
tab: ILiveBrowserTabState;
|
|
212
|
+
state: ILiveBrowserState;
|
|
213
|
+
text: string;
|
|
214
|
+
truncated: boolean;
|
|
215
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIuaW50ZXJmYWNlcy5saXZlYnJvd3Nlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLmludGVyZmFjZXMubGl2ZWJyb3dzZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
1
2
|
import * as os from 'os';
|
|
2
|
-
export { os };
|
|
3
|
+
export { Buffer, os };
|
|
3
4
|
import * as smartdelay from '@push.rocks/smartdelay';
|
|
4
5
|
import * as smartshell from '@push.rocks/smartshell';
|
|
5
6
|
export { smartdelay, smartshell };
|
|
6
|
-
import puppeteer from 'puppeteer';
|
|
7
|
+
import * as puppeteer from 'puppeteer';
|
|
7
8
|
import treeKill from 'tree-kill';
|
|
8
9
|
export { puppeteer, treeKill };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// node native scope
|
|
2
|
+
import { Buffer } from 'node:buffer';
|
|
2
3
|
import * as os from 'os';
|
|
3
|
-
export { os };
|
|
4
|
+
export { Buffer, os };
|
|
4
5
|
// @pushrocks scope
|
|
5
6
|
import * as smartdelay from '@push.rocks/smartdelay';
|
|
6
7
|
import * as smartshell from '@push.rocks/smartshell';
|
|
7
8
|
export { smartdelay, smartshell };
|
|
8
9
|
// third party scope
|
|
9
|
-
import puppeteer from 'puppeteer';
|
|
10
|
+
import * as puppeteer from 'puppeteer';
|
|
10
11
|
import treeKill from 'tree-kill';
|
|
11
12
|
export { puppeteer, treeKill };
|
|
12
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIucGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLnBsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFekIsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQztBQUV0QixtQkFBbUI7QUFDbkIsT0FBTyxLQUFLLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRCxPQUFPLEtBQUssVUFBVSxNQUFNLHdCQUF3QixDQUFDO0FBRXJELE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLENBQUM7QUFFbEMsb0JBQW9CO0FBQ3BCLE9BQU8sS0FBSyxTQUFTLE1BQU0sV0FBVyxDQUFDO0FBQ3ZDLE9BQU8sUUFBUSxNQUFNLFdBQVcsQ0FBQztBQUVqQyxPQUFPLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxDQUFDIn0=
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartpuppeteer",
|
|
3
|
-
"version": "2.0
|
|
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",
|
|
@@ -8,22 +8,24 @@
|
|
|
8
8
|
"type": "module",
|
|
9
9
|
"author": "Task Venture Capital GmbH <hello@task.vc>",
|
|
10
10
|
"license": "MIT",
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=22.12.0"
|
|
13
|
+
},
|
|
11
14
|
"devDependencies": {
|
|
12
15
|
"@git.zone/tsbuild": "^4.4.2",
|
|
13
|
-
"@git.zone/tsrun": "^2.0.
|
|
14
|
-
"@git.zone/tstest": "^
|
|
15
|
-
"@types/node": "^
|
|
16
|
+
"@git.zone/tsrun": "^2.0.6",
|
|
17
|
+
"@git.zone/tstest": "^4.0.0",
|
|
18
|
+
"@types/node": "^26.2.0"
|
|
16
19
|
},
|
|
17
20
|
"dependencies": {
|
|
18
21
|
"@push.rocks/smartdelay": "^3.0.1",
|
|
19
22
|
"@push.rocks/smartshell": "^3.5.0",
|
|
20
|
-
"puppeteer": "^
|
|
23
|
+
"puppeteer": "^25.4.0",
|
|
21
24
|
"tree-kill": "^1.2.2"
|
|
22
25
|
},
|
|
23
26
|
"files": [
|
|
24
27
|
"ts/**/*",
|
|
25
28
|
"ts_web/**/*",
|
|
26
|
-
"dist/**/*",
|
|
27
29
|
"dist_*/**/*",
|
|
28
30
|
"dist_ts/**/*",
|
|
29
31
|
"dist_ts_web/**/*",
|
package/readme.hints.md
CHANGED
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
# Implementation Hints
|
|
2
|
+
|
|
3
|
+
- `getEnvAwareBrowserInstance()` is the only Chromium launch path. Merge caller arguments before adding environment-required sandbox arguments, retain the pipe default, and do not run executable discovery when the caller selected a browser, channel, or executable.
|
|
4
|
+
- `LiveBrowserSession` uses the browser's default context so all tabs and popups share one profile. Omitting both `launchOptions.userDataDir` and a `--user-data-dir` argument intentionally relies on Puppeteer's ephemeral profile lifecycle.
|
|
5
|
+
- CDP is private to the live runtime. Public contracts contain transport-neutral values and `Uint8Array` image data, never `CDPSession`, raw CDP frame IDs, or base64 image strings.
|
|
6
|
+
- Every published screencast frame has one private sequence-to-CDP acknowledgement entry. Public acknowledgement requires matching tab ID, sequence, generation, and viewport revision. Pending frames are bounded; drops and all stream invalidation paths must retire and acknowledge entries before detaching the CDP session.
|
|
7
|
+
- Activation, viewport changes, navigation, tab closure, snapshots, observations, semantic actions, and shutdown share one bounded operation scheduler. Raw input and frame acknowledgement remain direct, but must validate active tab, generation, and viewport revision. Repeated internal navigation/load state updates are coalesced per tab, and shutdown cancels queued work.
|
|
8
|
+
- Retain the scheduler-owned launch `AbortController` for the full browser lifetime. Shutdown aborts both the active operation and Chromium itself so a non-signal-aware Puppeteer command or disabled protocol timeout cannot retain the browser ahead of queued cleanup.
|
|
9
|
+
- Viewport revision starts at 1 and advances only after `Page.setViewport()` succeeds. Stop and flush the active screencast before applying a viewport or navigation mutation, then restart it with a new generation.
|
|
10
|
+
- Track the applied viewport revision on every tab. Before an inactive tab is captured, observed, activated, or acted upon, apply the current global viewport and report metadata from that exact viewport. Full-page capture is outside the initial live-runtime scope.
|
|
11
|
+
- Canonicalize the configured viewport once. `viewport` wins over `launchOptions.defaultViewport`, `null` uses 800x600, and every Puppeteer viewport explicitly disables mobile, landscape, and touch emulation. The operation scheduler owns `LaunchOptions.signal`; never accept a caller signal for `LiveBrowserSession`.
|
|
12
|
+
- New-page registration and navigation are transactional: validate before creating a page where possible and restore page, listener, tab-map, active-tab, viewport, and screencast ownership on failure. Keep listeners attached during `page.close()` so a failed close remains observed and recoverable.
|
|
13
|
+
- Browser disconnect is runtime-fatal. Page crash or current CDP-session loss is tab-scoped: activate another usable tab, trying all candidates, or stop cleanly when none remains.
|
|
14
|
+
- Every popup is either registered, closed, or escalated to browser-wide shutdown. Queue saturation and startup-time popup events must never leave an untracked live page.
|
|
15
|
+
- Verify Puppeteer behavior against the installed Puppeteer 25 declarations and implementation. Do not add a direct `devtools-protocol` dependency; Puppeteer's public protocol typing is sufficient for private CDP calls.
|
package/readme.md
CHANGED
|
@@ -14,6 +14,8 @@ Install `@push.rocks/smartpuppeteer` with pnpm:
|
|
|
14
14
|
pnpm add @push.rocks/smartpuppeteer
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
Puppeteer 25 requires Node.js 22.12.0 or newer.
|
|
18
|
+
|
|
17
19
|
## Usage
|
|
18
20
|
`@push.rocks/smartpuppeteer` simplifies interaction with Puppeteer, providing easier ways to launch Puppeteer instances considering environment constraints, such as running in a CI pipeline or as root, which necessitates certain flags for Chrome.
|
|
19
21
|
|
|
@@ -28,7 +30,11 @@ import { getEnvAwareBrowserInstance, IncognitoBrowser, puppeteer } from '@push.r
|
|
|
28
30
|
// Usually, you would initialize the browser instance at the start of your script or application logic
|
|
29
31
|
const initializeBrowser = async () => {
|
|
30
32
|
const browser = await getEnvAwareBrowserInstance({
|
|
31
|
-
|
|
33
|
+
launchOptions: {
|
|
34
|
+
headless: true,
|
|
35
|
+
defaultViewport: { width: 1280, height: 720 },
|
|
36
|
+
args: ['--lang=en-US'],
|
|
37
|
+
},
|
|
32
38
|
});
|
|
33
39
|
return browser;
|
|
34
40
|
};
|
|
@@ -36,6 +42,10 @@ const initializeBrowser = async () => {
|
|
|
36
42
|
|
|
37
43
|
`getEnvAwareBrowserInstance()` checks `google-chrome`, `chromium`, and `chromium-browser` in that order. Missing candidates are skipped safely. When none resolve, Puppeteer chooses its default executable.
|
|
38
44
|
|
|
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
|
+
|
|
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
|
+
|
|
39
49
|
Use `resolveBrowserExecutablePath()` directly when you need to inspect the selected executable or provide your own ordered candidate list:
|
|
40
50
|
|
|
41
51
|
```typescript
|
|
@@ -89,6 +99,123 @@ useIncognitoBrowser()
|
|
|
89
99
|
### Advanced Configuration
|
|
90
100
|
`@push.rocks/smartpuppeteer` allows further customization for launching the Puppeteer browser, such as disabling the sandbox environment (not recommended for production).
|
|
91
101
|
|
|
102
|
+
### Live Browser Sessions
|
|
103
|
+
|
|
104
|
+
`LiveBrowserSession` provides a transport-neutral runtime for remote browser and agent adapters. It owns one Chromium process and one default-context profile. All tabs and popups therefore share cookies, local storage, cache, and other profile state. Puppeteer creates an ephemeral profile when neither `launchOptions.userDataDir` nor a `--user-data-dir` argument is supplied. Either explicit form persists potentially sensitive authentication and browsing data, must not be shared concurrently between Chromium processes, and must be protected by the caller.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import {
|
|
108
|
+
LiveBrowserSession,
|
|
109
|
+
type ILiveBrowserFrame,
|
|
110
|
+
} from '@push.rocks/smartpuppeteer';
|
|
111
|
+
|
|
112
|
+
const session = new LiveBrowserSession({
|
|
113
|
+
viewport: {
|
|
114
|
+
width: 1280,
|
|
115
|
+
height: 720,
|
|
116
|
+
deviceScaleFactor: 1,
|
|
117
|
+
},
|
|
118
|
+
screencast: {
|
|
119
|
+
format: 'jpeg',
|
|
120
|
+
quality: 80,
|
|
121
|
+
maxWidth: 1280,
|
|
122
|
+
maxHeight: 720,
|
|
123
|
+
},
|
|
124
|
+
launchOptions: {
|
|
125
|
+
headless: true,
|
|
126
|
+
// userDataDir: '/explicit/profile/path',
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const unsubscribe = session.onEvent((event) => {
|
|
131
|
+
if (event.type !== 'frame') {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const frame: ILiveBrowserFrame = event.frame;
|
|
135
|
+
console.log(frame.mimeType, frame.data.byteLength);
|
|
136
|
+
void session.acknowledgeFrame({
|
|
137
|
+
tabId: frame.tabId,
|
|
138
|
+
sequence: frame.sequence,
|
|
139
|
+
generation: frame.generation,
|
|
140
|
+
viewportRevision: frame.viewportRevision,
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await session.start();
|
|
145
|
+
try {
|
|
146
|
+
const state = session.getState();
|
|
147
|
+
const tabId = state.activeTabId!;
|
|
148
|
+
|
|
149
|
+
await session.navigate({
|
|
150
|
+
tabId,
|
|
151
|
+
url: 'data:text/html,<title>Live session</title><button>Continue</button>',
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const observation = await session.observe({ tabId });
|
|
155
|
+
console.log(observation.text);
|
|
156
|
+
|
|
157
|
+
const currentState = session.getState();
|
|
158
|
+
const currentTab = currentState.tabs.find((tab) => tab.id === tabId)!;
|
|
159
|
+
await session.click({
|
|
160
|
+
tabId,
|
|
161
|
+
generation: currentTab.generation,
|
|
162
|
+
viewportRevision: currentState.viewportRevision,
|
|
163
|
+
selector: 'button',
|
|
164
|
+
});
|
|
165
|
+
} finally {
|
|
166
|
+
unsubscribe();
|
|
167
|
+
await session.stop();
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Only the active tab is streamed. Frames carry a session-monotonic sequence, tab/CDP generation, viewport revision, viewport, MIME type, encoded dimensions, screencast metadata, and binary `Uint8Array` data. Every delivered frame must be acknowledged with all four identity fields. A delivered frame remains pending until it is acknowledged, dropped, or retired by the runtime; mismatched, duplicate, stale, retired, or operationally failed acknowledgements return `{ accepted: false }`. Operational acknowledgement failures also emit an `error` event whose code is `frame_acknowledgement_failed`. The runtime bounds pending frames and CDP-acknowledges an oldest frame when it must be dropped. Tab switches, navigation, resize, page cleanup, disconnect, and shutdown retire pending frames and acknowledge them while their CDP session remains available.
|
|
172
|
+
|
|
173
|
+
The live API includes:
|
|
174
|
+
|
|
175
|
+
- Lifecycle and state: `start()`, `stop()`, `onEvent()`, and `getState()`
|
|
176
|
+
- Tabs and navigation: `createTab()`, `activateTab()`, `closeTab()`, `navigate()`, `back()`, `forward()`, and `reload()`
|
|
177
|
+
- Viewport and raw input: `setViewport()`, `dispatchMouse()`, `dispatchWheel()`, `dispatchKey()`, and `insertText()`
|
|
178
|
+
- Agent-oriented actions: `click()`, `fill()`, and `press()` with bounded selectors and timeouts
|
|
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`
|
|
181
|
+
|
|
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.
|
|
183
|
+
|
|
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.
|
|
218
|
+
|
|
92
219
|
### Handling Browser Events
|
|
93
220
|
It's important to handle browser events, such as disconnections, which might occur due to various reasons:
|
|
94
221
|
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/index.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
export * from './smartpuppeteer.classes.smartpuppeteer.js';
|
|
4
4
|
export * from './smartpuppeteer.classes.incognitobrowser.js';
|
|
5
|
+
export * from './smartpuppeteer.interfaces.livebrowser.js';
|
|
6
|
+
export * from './smartpuppeteer.classes.livebrowsersession.js';
|
|
5
7
|
|
|
6
8
|
// direct exports
|
|
7
9
|
import { puppeteer } from './smartpuppeteer.plugins.js';
|