@push.rocks/smartpuppeteer 2.0.6 → 2.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.
@@ -2,5 +2,7 @@ import * as plugins from './smartpuppeteer.plugins.js';
2
2
  export interface IEnvAwareOptions {
3
3
  forceNoSandbox?: boolean;
4
4
  usePipe?: boolean;
5
+ launchOptions?: plugins.puppeteer.LaunchOptions;
5
6
  }
7
+ export declare const resolveBrowserExecutablePath: (candidateNamesArg?: string[]) => string | undefined;
6
8
  export declare const getEnvAwareBrowserInstance: (optionsArg?: IEnvAwareOptions) => Promise<plugins.puppeteer.Browser>;
@@ -1,37 +1,62 @@
1
1
  import * as plugins from './smartpuppeteer.plugins.js';
2
+ export const resolveBrowserExecutablePath = (candidateNamesArg = [
3
+ 'google-chrome',
4
+ 'chromium',
5
+ 'chromium-browser',
6
+ ]) => {
7
+ for (const candidateName of candidateNamesArg) {
8
+ const executablePath = plugins.smartshell.which.sync(candidateName, {
9
+ nothrow: true,
10
+ });
11
+ if (executablePath) {
12
+ return executablePath;
13
+ }
14
+ }
15
+ return undefined;
16
+ };
2
17
  export const getEnvAwareBrowserInstance = async (optionsArg = {}) => {
3
18
  const options = {
4
19
  forceNoSandbox: false,
5
20
  ...optionsArg,
6
21
  };
7
- let chromeArgs = [];
22
+ const launchOptions = options.launchOptions ?? {};
23
+ let chromeArgs = [...(launchOptions.args ?? [])];
8
24
  if (process.env.CI ||
9
25
  options.forceNoSandbox ||
10
26
  plugins.os.userInfo().username === 'root') {
11
- chromeArgs = chromeArgs.concat(['--no-sandbox', '--disable-setuid-sandbox']);
27
+ for (const sandboxArg of ['--no-sandbox', '--disable-setuid-sandbox']) {
28
+ if (!chromeArgs.includes(sandboxArg)) {
29
+ chromeArgs.push(sandboxArg);
30
+ }
31
+ }
12
32
  console.warn('********************************************************');
13
33
  console.warn('WARNING: Launching browser without sandbox. This can be insecure!');
14
34
  console.warn('********************************************************');
15
35
  }
16
- // Automatically choose an executable if available: prefer google-chrome, then chromium, then chromium-browser.
17
- const execPath = plugins.smartshell.which.sync('google-chrome') ||
18
- plugins.smartshell.which.sync('chromium') ||
19
- plugins.smartshell.which.sync('chromium-browser');
36
+ // Automatically choose an executable only when the caller did not select one.
37
+ const callerSelectedBrowser = launchOptions.browser !== undefined
38
+ || launchOptions.channel !== undefined
39
+ || launchOptions.executablePath !== undefined;
40
+ const execPath = callerSelectedBrowser ? undefined : resolveBrowserExecutablePath();
20
41
  const executablePathOptions = execPath ? { executablePath: execPath } : {};
21
42
  console.log('Launching puppeteer browser with arguments:');
22
43
  console.log(chromeArgs);
23
44
  if (execPath) {
24
45
  console.log(`Using executable: ${execPath}`);
25
46
  }
47
+ else if (callerSelectedBrowser) {
48
+ console.log('Using browser selection from caller launch options.');
49
+ }
26
50
  else {
27
51
  console.log('No specific browser executable found; falling back to Puppeteer default.');
28
52
  }
29
53
  const headlessBrowser = await plugins.puppeteer.launch({
30
- args: chromeArgs,
31
- pipe: options.usePipe ?? true,
32
54
  headless: true,
55
+ ...launchOptions,
56
+ args: chromeArgs,
57
+ pipe: options.usePipe ?? launchOptions.pipe ?? true,
33
58
  ...executablePathOptions,
34
59
  });
35
60
  return headlessBrowser;
36
61
  };
37
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIuY2xhc3Nlcy5zbWFydHB1cHBldGVlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLmNsYXNzZXMuc21hcnRwdXBwZXRlZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSw2QkFBNkIsQ0FBQztBQU92RCxNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLEVBQzdDLGFBQStCLEVBQUUsRUFDRyxFQUFFO0lBQ3RDLE1BQU0sT0FBTyxHQUFxQjtRQUNoQyxjQUFjLEVBQUUsS0FBSztRQUNyQixHQUFHLFVBQVU7S0FDZCxDQUFDO0lBRUYsSUFBSSxVQUFVLEdBQWEsRUFBRSxDQUFDO0lBQzlCLElBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1FBQ2QsT0FBTyxDQUFDLGNBQWM7UUFDdEIsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEtBQUssTUFBTSxFQUN6QyxDQUFDO1FBQ0QsVUFBVSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxjQUFjLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxDQUFDO1FBQzdFLE9BQU8sQ0FBQyxJQUFJLENBQUMsMERBQTBELENBQUMsQ0FBQztRQUN6RSxPQUFPLENBQUMsSUFBSSxDQUFDLG1FQUFtRSxDQUFDLENBQUM7UUFDbEYsT0FBTyxDQUFDLElBQUksQ0FBQywwREFBMEQsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFFRCwrR0FBK0c7SUFDL0csTUFBTSxRQUFRLEdBQ1osT0FBTyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQztRQUM5QyxPQUFPLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQ3pDLE9BQU8sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBRXBELE1BQU0scUJBQXFCLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBRTNFLE9BQU8sQ0FBQyxHQUFHLENBQUMsNkNBQTZDLENBQUMsQ0FBQztJQUMzRCxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3hCLElBQUksUUFBUSxFQUFFLENBQUM7UUFDYixPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLENBQUM7U0FBTSxDQUFDO1FBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQywwRUFBMEUsQ0FBQyxDQUFDO0lBQzFGLENBQUM7SUFFRCxNQUFNLGVBQWUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQ3JELElBQUksRUFBRSxVQUFVO1FBQ2hCLElBQUksRUFBRSxPQUFPLENBQUMsT0FBTyxJQUFJLElBQUk7UUFDN0IsUUFBUSxFQUFFLElBQUk7UUFDZCxHQUFHLHFCQUFxQjtLQUN6QixDQUFDLENBQUM7SUFFSCxPQUFPLGVBQWUsQ0FBQztBQUN6QixDQUFDLENBQUMifQ==
62
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIuY2xhc3Nlcy5zbWFydHB1cHBldGVlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLmNsYXNzZXMuc21hcnRwdXBwZXRlZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSw2QkFBNkIsQ0FBQztBQVF2RCxNQUFNLENBQUMsTUFBTSw0QkFBNEIsR0FBRyxDQUMxQyxvQkFBOEI7SUFDNUIsZUFBZTtJQUNmLFVBQVU7SUFDVixrQkFBa0I7Q0FDbkIsRUFDbUIsRUFBRTtJQUN0QixLQUFLLE1BQU0sYUFBYSxJQUFJLGlCQUFpQixFQUFFLENBQUM7UUFDOUMsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUNsRSxPQUFPLEVBQUUsSUFBSTtTQUNkLENBQUMsQ0FBQztRQUNILElBQUksY0FBYyxFQUFFLENBQUM7WUFDbkIsT0FBTyxjQUFjLENBQUM7UUFDeEIsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLEVBQzdDLGFBQStCLEVBQUUsRUFDRyxFQUFFO0lBQ3RDLE1BQU0sT0FBTyxHQUFxQjtRQUNoQyxjQUFjLEVBQUUsS0FBSztRQUNyQixHQUFHLFVBQVU7S0FDZCxDQUFDO0lBRUYsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsSUFBSSxFQUFFLENBQUM7SUFDbEQsSUFBSSxVQUFVLEdBQWEsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzNELElBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1FBQ2QsT0FBTyxDQUFDLGNBQWM7UUFDdEIsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEtBQUssTUFBTSxFQUN6QyxDQUFDO1FBQ0QsS0FBSyxNQUFNLFVBQVUsSUFBSSxDQUFDLGNBQWMsRUFBRSwwQkFBMEIsQ0FBQyxFQUFFLENBQUM7WUFDdEUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztnQkFDckMsVUFBVSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUM5QixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sQ0FBQyxJQUFJLENBQUMsMERBQTBELENBQUMsQ0FBQztRQUN6RSxPQUFPLENBQUMsSUFBSSxDQUFDLG1FQUFtRSxDQUFDLENBQUM7UUFDbEYsT0FBTyxDQUFDLElBQUksQ0FBQywwREFBMEQsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFFRCw4RUFBOEU7SUFDOUUsTUFBTSxxQkFBcUIsR0FDekIsYUFBYSxDQUFDLE9BQU8sS0FBSyxTQUFTO1dBQ2hDLGFBQWEsQ0FBQyxPQUFPLEtBQUssU0FBUztXQUNuQyxhQUFhLENBQUMsY0FBYyxLQUFLLFNBQVMsQ0FBQztJQUNoRCxNQUFNLFFBQVEsR0FBRyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyw0QkFBNEIsRUFBRSxDQUFDO0lBRXBGLE1BQU0scUJBQXFCLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBRTNFLE9BQU8sQ0FBQyxHQUFHLENBQUMsNkNBQTZDLENBQUMsQ0FBQztJQUMzRCxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3hCLElBQUksUUFBUSxFQUFFLENBQUM7UUFDYixPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLENBQUM7U0FBTSxJQUFJLHFCQUFxQixFQUFFLENBQUM7UUFDakMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxREFBcUQsQ0FBQyxDQUFDO0lBQ3JFLENBQUM7U0FBTSxDQUFDO1FBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQywwRUFBMEUsQ0FBQyxDQUFDO0lBQzFGLENBQUM7SUFFRCxNQUFNLGVBQWUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQ3JELFFBQVEsRUFBRSxJQUFJO1FBQ2QsR0FBRyxhQUFhO1FBQ2hCLElBQUksRUFBRSxVQUFVO1FBQ2hCLElBQUksRUFBRSxPQUFPLENBQUMsT0FBTyxJQUFJLGFBQWEsQ0FBQyxJQUFJLElBQUksSUFBSTtRQUNuRCxHQUFHLHFCQUFxQjtLQUN6QixDQUFDLENBQUM7SUFFSCxPQUFPLGVBQWUsQ0FBQztBQUN6QixDQUFDLENBQUMifQ==
@@ -0,0 +1,191 @@
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 type TLiveBrowserLaunchOptions = Omit<NonNullable<IEnvAwareOptions['launchOptions']>, 'signal'>;
19
+ export interface ILiveBrowserSessionOptions extends Omit<IEnvAwareOptions, 'launchOptions'> {
20
+ launchOptions?: TLiveBrowserLaunchOptions;
21
+ viewport?: ILiveBrowserViewport;
22
+ screencast?: ILiveBrowserScreencastOptions;
23
+ }
24
+ export interface ILiveBrowserTabState {
25
+ id: string;
26
+ url: string;
27
+ title: string;
28
+ active: boolean;
29
+ status: TLiveBrowserTabStatus;
30
+ generation: number;
31
+ appliedViewportRevision: number;
32
+ streaming: boolean;
33
+ }
34
+ export interface ILiveBrowserError {
35
+ code: string;
36
+ message: string;
37
+ fatal: boolean;
38
+ tabId?: string;
39
+ }
40
+ export interface ILiveBrowserState {
41
+ status: TLiveBrowserStatus;
42
+ activeTabId: string | null;
43
+ viewportRevision: number;
44
+ viewport: ILiveBrowserViewport;
45
+ tabs: ILiveBrowserTabState[];
46
+ lastError?: ILiveBrowserError;
47
+ }
48
+ export interface ILiveBrowserScreencastMetadata {
49
+ offsetTop: number;
50
+ pageScaleFactor: number;
51
+ deviceWidth: number;
52
+ deviceHeight: number;
53
+ scrollOffsetX: number;
54
+ scrollOffsetY: number;
55
+ timestamp?: number;
56
+ }
57
+ export interface ILiveBrowserFrame {
58
+ tabId: string;
59
+ sequence: number;
60
+ generation: number;
61
+ viewportRevision: number;
62
+ viewport: ILiveBrowserViewport;
63
+ format: TLiveBrowserImageFormat;
64
+ mimeType: 'image/jpeg' | 'image/png';
65
+ width: number;
66
+ height: number;
67
+ metadata: ILiveBrowserScreencastMetadata;
68
+ data: Uint8Array;
69
+ }
70
+ export interface ILiveBrowserSnapshot {
71
+ tabId: string;
72
+ viewportRevision: number;
73
+ viewport: ILiveBrowserViewport;
74
+ format: TLiveBrowserImageFormat;
75
+ mimeType: 'image/jpeg' | 'image/png';
76
+ width: number;
77
+ height: number;
78
+ data: Uint8Array;
79
+ }
80
+ export interface ILiveBrowserStateEvent {
81
+ type: 'state';
82
+ state: ILiveBrowserState;
83
+ }
84
+ export interface ILiveBrowserFrameEvent {
85
+ type: 'frame';
86
+ frame: ILiveBrowserFrame;
87
+ }
88
+ export interface ILiveBrowserErrorEvent {
89
+ type: 'error';
90
+ error: ILiveBrowserError;
91
+ }
92
+ export type TLiveBrowserEvent = ILiveBrowserStateEvent | ILiveBrowserFrameEvent | ILiveBrowserErrorEvent;
93
+ export type TLiveBrowserEventListener = (event: TLiveBrowserEvent) => void;
94
+ export interface ILiveBrowserFrameAcknowledgement {
95
+ accepted: boolean;
96
+ }
97
+ export interface ILiveBrowserFrameAcknowledgementRequest {
98
+ tabId: string;
99
+ sequence: number;
100
+ generation: number;
101
+ viewportRevision: number;
102
+ }
103
+ export interface ILiveBrowserCreateTabOptions {
104
+ url?: string;
105
+ activate?: boolean;
106
+ timeoutMs?: number;
107
+ waitUntil?: TLiveBrowserWaitUntil;
108
+ }
109
+ export interface ILiveBrowserNavigationOptions {
110
+ tabId?: string;
111
+ timeoutMs?: number;
112
+ waitUntil?: TLiveBrowserWaitUntil;
113
+ }
114
+ export interface ILiveBrowserNavigateOptions extends ILiveBrowserNavigationOptions {
115
+ url: string;
116
+ }
117
+ export interface ILiveBrowserModifierState {
118
+ alt?: boolean;
119
+ control?: boolean;
120
+ meta?: boolean;
121
+ shift?: boolean;
122
+ }
123
+ export interface ILiveBrowserInputBase {
124
+ tabId: string;
125
+ generation: number;
126
+ viewportRevision: number;
127
+ }
128
+ export interface ILiveBrowserMouseInput extends ILiveBrowserInputBase {
129
+ type: 'move' | 'down' | 'up';
130
+ x: number;
131
+ y: number;
132
+ button?: 'none' | 'left' | 'middle' | 'right' | 'back' | 'forward';
133
+ buttons?: number;
134
+ clickCount?: number;
135
+ modifiers?: ILiveBrowserModifierState;
136
+ }
137
+ export interface ILiveBrowserWheelInput extends ILiveBrowserInputBase {
138
+ x: number;
139
+ y: number;
140
+ deltaX: number;
141
+ deltaY: number;
142
+ modifiers?: ILiveBrowserModifierState;
143
+ }
144
+ export interface ILiveBrowserKeyInput extends ILiveBrowserInputBase {
145
+ type: 'down' | 'up';
146
+ key: string;
147
+ code?: string;
148
+ text?: string;
149
+ unmodifiedText?: string;
150
+ windowsVirtualKeyCode?: number;
151
+ nativeVirtualKeyCode?: number;
152
+ autoRepeat?: boolean;
153
+ isKeypad?: boolean;
154
+ location?: number;
155
+ modifiers?: ILiveBrowserModifierState;
156
+ }
157
+ export interface ILiveBrowserInsertTextInput extends ILiveBrowserInputBase {
158
+ text: string;
159
+ }
160
+ export interface ILiveBrowserSemanticActionBase extends ILiveBrowserInputBase {
161
+ selector: string;
162
+ timeoutMs?: number;
163
+ }
164
+ export interface ILiveBrowserClickOptions extends ILiveBrowserSemanticActionBase {
165
+ button?: 'left' | 'middle' | 'right';
166
+ clickCount?: number;
167
+ }
168
+ export interface ILiveBrowserFillOptions extends ILiveBrowserSemanticActionBase {
169
+ text: string;
170
+ }
171
+ export interface ILiveBrowserPressOptions extends ILiveBrowserSemanticActionBase {
172
+ key: string;
173
+ }
174
+ export interface ILiveBrowserSnapshotOptions {
175
+ tabId?: string;
176
+ format?: TLiveBrowserImageFormat;
177
+ quality?: number;
178
+ }
179
+ export interface ILiveBrowserObserveOptions {
180
+ tabId?: string;
181
+ maxCharacters?: number;
182
+ }
183
+ export interface ILiveBrowserObservation {
184
+ tabId: string;
185
+ url: string;
186
+ title: string;
187
+ tab: ILiveBrowserTabState;
188
+ state: ILiveBrowserState;
189
+ text: string;
190
+ truncated: boolean;
191
+ }
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIucGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLnBsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBRXpCLE9BQU8sRUFBRSxFQUFFLEVBQUUsQ0FBQztBQUVkLG1CQUFtQjtBQUNuQixPQUFPLEtBQUssVUFBVSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sS0FBSyxVQUFVLE1BQU0sd0JBQXdCLENBQUM7QUFFckQsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsQ0FBQztBQUVsQyxvQkFBb0I7QUFDcEIsT0FBTyxTQUFTLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sUUFBUSxNQUFNLFdBQVcsQ0FBQztBQUVqQyxPQUFPLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxDQUFDIn0=
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.6",
3
+ "version": "2.1.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,28 +8,24 @@
8
8
  "type": "module",
9
9
  "author": "Task Venture Capital GmbH <hello@task.vc>",
10
10
  "license": "MIT",
11
- "scripts": {
12
- "test": "tstest test/",
13
- "format": "gitzone format",
14
- "build": "tsbuild --web",
15
- "buildDocs": "tsdoc"
11
+ "engines": {
12
+ "node": ">=22.12.0"
16
13
  },
17
14
  "devDependencies": {
18
- "@git.zone/tsbuild": "^4.4.0",
19
- "@git.zone/tsrun": "^2.0.3",
20
- "@git.zone/tstest": "^3.6.3",
21
- "@types/node": "^25.6.0"
15
+ "@git.zone/tsbuild": "^4.4.2",
16
+ "@git.zone/tsrun": "^2.0.6",
17
+ "@git.zone/tstest": "^4.0.0",
18
+ "@types/node": "^26.1.2"
22
19
  },
23
20
  "dependencies": {
24
21
  "@push.rocks/smartdelay": "^3.0.1",
25
- "@push.rocks/smartshell": "^3.3.8",
26
- "puppeteer": "^24.42.0",
22
+ "@push.rocks/smartshell": "^3.5.0",
23
+ "puppeteer": "^25.4.0",
27
24
  "tree-kill": "^1.2.2"
28
25
  },
29
26
  "files": [
30
27
  "ts/**/*",
31
28
  "ts_web/**/*",
32
- "dist/**/*",
33
29
  "dist_*/**/*",
34
30
  "dist_ts/**/*",
35
31
  "dist_ts_web/**/*",
@@ -56,5 +52,11 @@
56
52
  "repository": {
57
53
  "type": "git",
58
54
  "url": "https://code.foss.global/push.rocks/smartpuppeteer.git"
55
+ },
56
+ "scripts": {
57
+ "test": "tstest test/",
58
+ "format": "gitzone format",
59
+ "build": "tsbuild --web",
60
+ "buildDocs": "tsdoc"
59
61
  }
60
- }
62
+ }
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
@@ -1,19 +1,21 @@
1
1
  # @push.rocks/smartpuppeteer
2
- simplified access to puppeteer
3
2
 
4
- ## Install
5
- To install `@push.rocks/smartpuppeteer` in your project, run the following command using npm:
3
+ Simplified access to Puppeteer with environment-aware browser startup helpers.
6
4
 
7
- ```sh
8
- npm install @push.rocks/smartpuppeteer --save
9
- ```
5
+ ## Issue Reporting and Security
6
+
7
+ For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
10
8
 
11
- Or using yarn:
9
+ ## Install
10
+
11
+ Install `@push.rocks/smartpuppeteer` with pnpm:
12
12
 
13
13
  ```sh
14
- yarn add @push.rocks/smartpuppeteer
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,12 +30,31 @@ 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
- forceNoSandbox: true, // A flag useful for certain environments; use it with caution
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
  };
35
41
  ```
36
42
 
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.
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
+ Use `resolveBrowserExecutablePath()` directly when you need to inspect the selected executable or provide your own ordered candidate list:
48
+
49
+ ```typescript
50
+ import { resolveBrowserExecutablePath } from '@push.rocks/smartpuppeteer';
51
+
52
+ const executablePath: string | undefined = resolveBrowserExecutablePath([
53
+ 'chromium',
54
+ 'chromium-browser',
55
+ ]);
56
+ ```
57
+
37
58
  ### Opening a Page and Navigating
38
59
  After obtaining a browser instance, you commonly want to open a page and navigate to a URL:
39
60
 
@@ -76,6 +97,89 @@ useIncognitoBrowser()
76
97
  ### Advanced Configuration
77
98
  `@push.rocks/smartpuppeteer` allows further customization for launching the Puppeteer browser, such as disabling the sandbox environment (not recommended for production).
78
99
 
100
+ ### Live Browser Sessions
101
+
102
+ `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.
103
+
104
+ ```typescript
105
+ import {
106
+ LiveBrowserSession,
107
+ type ILiveBrowserFrame,
108
+ } from '@push.rocks/smartpuppeteer';
109
+
110
+ const session = new LiveBrowserSession({
111
+ viewport: {
112
+ width: 1280,
113
+ height: 720,
114
+ deviceScaleFactor: 1,
115
+ },
116
+ screencast: {
117
+ format: 'jpeg',
118
+ quality: 80,
119
+ maxWidth: 1280,
120
+ maxHeight: 720,
121
+ },
122
+ launchOptions: {
123
+ headless: true,
124
+ // userDataDir: '/explicit/profile/path',
125
+ },
126
+ });
127
+
128
+ const unsubscribe = session.onEvent((event) => {
129
+ if (event.type !== 'frame') {
130
+ return;
131
+ }
132
+ const frame: ILiveBrowserFrame = event.frame;
133
+ console.log(frame.mimeType, frame.data.byteLength);
134
+ void session.acknowledgeFrame({
135
+ tabId: frame.tabId,
136
+ sequence: frame.sequence,
137
+ generation: frame.generation,
138
+ viewportRevision: frame.viewportRevision,
139
+ });
140
+ });
141
+
142
+ await session.start();
143
+ try {
144
+ const state = session.getState();
145
+ const tabId = state.activeTabId!;
146
+
147
+ await session.navigate({
148
+ tabId,
149
+ url: 'data:text/html,<title>Live session</title><button>Continue</button>',
150
+ });
151
+
152
+ const observation = await session.observe({ tabId });
153
+ console.log(observation.text);
154
+
155
+ const currentState = session.getState();
156
+ const currentTab = currentState.tabs.find((tab) => tab.id === tabId)!;
157
+ await session.click({
158
+ tabId,
159
+ generation: currentTab.generation,
160
+ viewportRevision: currentState.viewportRevision,
161
+ selector: 'button',
162
+ });
163
+ } finally {
164
+ unsubscribe();
165
+ await session.stop();
166
+ }
167
+ ```
168
+
169
+ 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.
170
+
171
+ The live API includes:
172
+
173
+ - Lifecycle and state: `start()`, `stop()`, `onEvent()`, and `getState()`
174
+ - Tabs and navigation: `createTab()`, `activateTab()`, `closeTab()`, `navigate()`, `back()`, `forward()`, and `reload()`
175
+ - Viewport and raw input: `setViewport()`, `dispatchMouse()`, `dispatchWheel()`, `dispatchKey()`, and `insertText()`
176
+ - Agent-oriented actions: `click()`, `fill()`, and `press()` with bounded selectors and timeouts
177
+ - 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
178
+
179
+ 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
+
181
+ `LiveBrowserSession` is a browser runtime, not a security policy layer. It does not authenticate callers, authorize actions, restrict URLs, or enforce network/egress policy. 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
+
79
183
  ### Handling Browser Events
80
184
  It's important to handle browser events, such as disconnections, which might occur due to various reasons:
81
185
 
@@ -115,19 +219,21 @@ incognitoBrowser.start()
115
219
 
116
220
  ## License and Legal Information
117
221
 
118
- This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
222
+ This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file.
119
223
 
120
224
  **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
121
225
 
122
226
  ### Trademarks
123
227
 
124
- This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
228
+ This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
229
+
230
+ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
125
231
 
126
232
  ### Company Information
127
233
 
128
- Task Venture Capital GmbH
129
- Registered at District court Bremen HRB 35230 HB, Germany
234
+ Task Venture Capital GmbH<br>
235
+ Registered at District Court Bremen HRB 35230 HB, Germany
130
236
 
131
- For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
237
+ For any legal inquiries or further information, please contact us via email at hello@task.vc.
132
238
 
133
239
  By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartpuppeteer',
6
- version: '2.0.6',
6
+ version: '2.1.0',
7
7
  description: 'Provides simplified access to Puppeteer for automation and testing purposes.'
8
8
  }
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';