@push.rocks/smartpuppeteer 2.0.7 → 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,6 +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
  }
6
7
  export declare const resolveBrowserExecutablePath: (candidateNamesArg?: string[]) => string | undefined;
7
8
  export declare const getEnvAwareBrowserInstance: (optionsArg?: IEnvAwareOptions) => Promise<plugins.puppeteer.Browser>;
@@ -19,32 +19,44 @@ export const getEnvAwareBrowserInstance = async (optionsArg = {}) => {
19
19
  forceNoSandbox: false,
20
20
  ...optionsArg,
21
21
  };
22
- let chromeArgs = [];
22
+ const launchOptions = options.launchOptions ?? {};
23
+ let chromeArgs = [...(launchOptions.args ?? [])];
23
24
  if (process.env.CI ||
24
25
  options.forceNoSandbox ||
25
26
  plugins.os.userInfo().username === 'root') {
26
- 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
+ }
27
32
  console.warn('********************************************************');
28
33
  console.warn('WARNING: Launching browser without sandbox. This can be insecure!');
29
34
  console.warn('********************************************************');
30
35
  }
31
- // Automatically choose an executable if available: prefer google-chrome, then chromium, then chromium-browser.
32
- const execPath = resolveBrowserExecutablePath();
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();
33
41
  const executablePathOptions = execPath ? { executablePath: execPath } : {};
34
42
  console.log('Launching puppeteer browser with arguments:');
35
43
  console.log(chromeArgs);
36
44
  if (execPath) {
37
45
  console.log(`Using executable: ${execPath}`);
38
46
  }
47
+ else if (callerSelectedBrowser) {
48
+ console.log('Using browser selection from caller launch options.');
49
+ }
39
50
  else {
40
51
  console.log('No specific browser executable found; falling back to Puppeteer default.');
41
52
  }
42
53
  const headlessBrowser = await plugins.puppeteer.launch({
43
- args: chromeArgs,
44
- pipe: options.usePipe ?? true,
45
54
  headless: true,
55
+ ...launchOptions,
56
+ args: chromeArgs,
57
+ pipe: options.usePipe ?? launchOptions.pipe ?? true,
46
58
  ...executablePathOptions,
47
59
  });
48
60
  return headlessBrowser;
49
61
  };
50
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIuY2xhc3Nlcy5zbWFydHB1cHBldGVlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLmNsYXNzZXMuc21hcnRwdXBwZXRlZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSw2QkFBNkIsQ0FBQztBQU92RCxNQUFNLENBQUMsTUFBTSw0QkFBNEIsR0FBRyxDQUMxQyxvQkFBOEI7SUFDNUIsZUFBZTtJQUNmLFVBQVU7SUFDVixrQkFBa0I7Q0FDbkIsRUFDbUIsRUFBRTtJQUN0QixLQUFLLE1BQU0sYUFBYSxJQUFJLGlCQUFpQixFQUFFLENBQUM7UUFDOUMsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUNsRSxPQUFPLEVBQUUsSUFBSTtTQUNkLENBQUMsQ0FBQztRQUNILElBQUksY0FBYyxFQUFFLENBQUM7WUFDbkIsT0FBTyxjQUFjLENBQUM7UUFDeEIsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLEVBQzdDLGFBQStCLEVBQUUsRUFDRyxFQUFFO0lBQ3RDLE1BQU0sT0FBTyxHQUFxQjtRQUNoQyxjQUFjLEVBQUUsS0FBSztRQUNyQixHQUFHLFVBQVU7S0FDZCxDQUFDO0lBRUYsSUFBSSxVQUFVLEdBQWEsRUFBRSxDQUFDO0lBQzlCLElBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1FBQ2QsT0FBTyxDQUFDLGNBQWM7UUFDdEIsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEtBQUssTUFBTSxFQUN6QyxDQUFDO1FBQ0QsVUFBVSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxjQUFjLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxDQUFDO1FBQzdFLE9BQU8sQ0FBQyxJQUFJLENBQUMsMERBQTBELENBQUMsQ0FBQztRQUN6RSxPQUFPLENBQUMsSUFBSSxDQUFDLG1FQUFtRSxDQUFDLENBQUM7UUFDbEYsT0FBTyxDQUFDLElBQUksQ0FBQywwREFBMEQsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFFRCwrR0FBK0c7SUFDL0csTUFBTSxRQUFRLEdBQUcsNEJBQTRCLEVBQUUsQ0FBQztJQUVoRCxNQUFNLHFCQUFxQixHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxjQUFjLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUUzRSxPQUFPLENBQUMsR0FBRyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7SUFDM0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QixJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQ2IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUMvQyxDQUFDO1NBQU0sQ0FBQztRQUNOLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEVBQTBFLENBQUMsQ0FBQztJQUMxRixDQUFDO0lBRUQsTUFBTSxlQUFlLEdBQUcsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQztRQUNyRCxJQUFJLEVBQUUsVUFBVTtRQUNoQixJQUFJLEVBQUUsT0FBTyxDQUFDLE9BQU8sSUFBSSxJQUFJO1FBQzdCLFFBQVEsRUFBRSxJQUFJO1FBQ2QsR0FBRyxxQkFBcUI7S0FDekIsQ0FBQyxDQUFDO0lBRUgsT0FBTyxlQUFlLENBQUM7QUFDekIsQ0FBQyxDQUFDIn0=
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.7",
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,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.5",
14
- "@git.zone/tstest": "^3.6.7",
15
- "@types/node": "^25.9.5"
16
+ "@git.zone/tsrun": "^2.0.6",
17
+ "@git.zone/tstest": "^4.0.0",
18
+ "@types/node": "^26.1.2"
16
19
  },
17
20
  "dependencies": {
18
21
  "@push.rocks/smartdelay": "^3.0.1",
19
22
  "@push.rocks/smartshell": "^3.5.0",
20
- "puppeteer": "^24.42.0",
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
- 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
  };
@@ -36,6 +42,8 @@ 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
+
39
47
  Use `resolveBrowserExecutablePath()` directly when you need to inspect the selected executable or provide your own ordered candidate list:
40
48
 
41
49
  ```typescript
@@ -89,6 +97,89 @@ useIncognitoBrowser()
89
97
  ### Advanced Configuration
90
98
  `@push.rocks/smartpuppeteer` allows further customization for launching the Puppeteer browser, such as disabling the sandbox environment (not recommended for production).
91
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
+
92
183
  ### Handling Browser Events
93
184
  It's important to handle browser events, such as disconnections, which might occur due to various reasons:
94
185
 
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartpuppeteer',
6
- version: '2.0.7',
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';