@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.
@@ -2,9 +2,18 @@ import * as plugins from './smartpuppeteer.plugins.js';
2
2
 
3
3
  export interface IEnvAwareOptions {
4
4
  forceNoSandbox?: boolean;
5
+ requireSandbox?: boolean;
5
6
  usePipe?: boolean;
7
+ launchOptions?: plugins.puppeteer.LaunchOptions;
6
8
  }
7
9
 
10
+ const sandboxDisablingArguments = [
11
+ '--disable-gpu-sandbox',
12
+ '--disable-seccomp-filter-sandbox',
13
+ '--disable-setuid-sandbox',
14
+ '--no-sandbox',
15
+ ];
16
+
8
17
  export const resolveBrowserExecutablePath = (
9
18
  candidateNamesArg: string[] = [
10
19
  'google-chrome',
@@ -28,23 +37,47 @@ export const getEnvAwareBrowserInstance = async (
28
37
  ): Promise<plugins.puppeteer.Browser> => {
29
38
  const options: IEnvAwareOptions = {
30
39
  forceNoSandbox: false,
40
+ requireSandbox: false,
31
41
  ...optionsArg,
32
42
  };
33
43
 
34
- let chromeArgs: string[] = [];
35
- if (
36
- process.env.CI ||
37
- options.forceNoSandbox ||
38
- plugins.os.userInfo().username === 'root'
44
+ if (options.forceNoSandbox && options.requireSandbox) {
45
+ throw new Error('forceNoSandbox and requireSandbox are mutually exclusive');
46
+ }
47
+
48
+ const launchOptions = options.launchOptions ?? {};
49
+ let chromeArgs: string[] = [...(launchOptions.args ?? [])];
50
+ if (options.requireSandbox) {
51
+ const forbiddenArgument = chromeArgs.find((argument) => (
52
+ sandboxDisablingArguments.includes(argument.split('=', 1)[0]!)
53
+ ));
54
+ if (forbiddenArgument) {
55
+ throw new Error(`Sandbox-required browser launch rejects argument: ${forbiddenArgument}`);
56
+ }
57
+ if (process.platform === 'linux' && process.getuid?.() === 0) {
58
+ throw new Error('Sandbox-required Chromium cannot be launched as root');
59
+ }
60
+ } else if (
61
+ process.env.CI
62
+ || options.forceNoSandbox
63
+ || plugins.os.userInfo().username === 'root'
39
64
  ) {
40
- chromeArgs = chromeArgs.concat(['--no-sandbox', '--disable-setuid-sandbox']);
65
+ for (const sandboxArg of ['--no-sandbox', '--disable-setuid-sandbox']) {
66
+ if (!chromeArgs.includes(sandboxArg)) {
67
+ chromeArgs.push(sandboxArg);
68
+ }
69
+ }
41
70
  console.warn('********************************************************');
42
71
  console.warn('WARNING: Launching browser without sandbox. This can be insecure!');
43
72
  console.warn('********************************************************');
44
73
  }
45
74
 
46
- // Automatically choose an executable if available: prefer google-chrome, then chromium, then chromium-browser.
47
- const execPath = resolveBrowserExecutablePath();
75
+ // Automatically choose an executable only when the caller did not select one.
76
+ const callerSelectedBrowser =
77
+ launchOptions.browser !== undefined
78
+ || launchOptions.channel !== undefined
79
+ || launchOptions.executablePath !== undefined;
80
+ const execPath = callerSelectedBrowser ? undefined : resolveBrowserExecutablePath();
48
81
 
49
82
  const executablePathOptions = execPath ? { executablePath: execPath } : {};
50
83
 
@@ -52,14 +85,17 @@ export const getEnvAwareBrowserInstance = async (
52
85
  console.log(chromeArgs);
53
86
  if (execPath) {
54
87
  console.log(`Using executable: ${execPath}`);
88
+ } else if (callerSelectedBrowser) {
89
+ console.log('Using browser selection from caller launch options.');
55
90
  } else {
56
91
  console.log('No specific browser executable found; falling back to Puppeteer default.');
57
92
  }
58
93
 
59
94
  const headlessBrowser = await plugins.puppeteer.launch({
60
- args: chromeArgs,
61
- pipe: options.usePipe ?? true,
62
95
  headless: true,
96
+ ...launchOptions,
97
+ args: chromeArgs,
98
+ pipe: options.usePipe ?? launchOptions.pipe ?? true,
63
99
  ...executablePathOptions,
64
100
  });
65
101
 
@@ -0,0 +1,267 @@
1
+ import type { IEnvAwareOptions } from './smartpuppeteer.classes.smartpuppeteer.js';
2
+
3
+ export type TLiveBrowserStatus = 'stopped' | 'starting' | 'running' | 'stopping';
4
+ export type TLiveBrowserImageFormat = 'jpeg' | 'png';
5
+ export type TLiveBrowserTabStatus = 'open' | 'crashed';
6
+ export type TLiveBrowserWaitUntil =
7
+ | 'load'
8
+ | 'domcontentloaded'
9
+ | 'networkidle0'
10
+ | 'networkidle2';
11
+
12
+ export interface ILiveBrowserViewport {
13
+ width: number;
14
+ height: number;
15
+ deviceScaleFactor: number;
16
+ }
17
+
18
+ export interface ILiveBrowserScreencastOptions {
19
+ format?: TLiveBrowserImageFormat;
20
+ quality?: number;
21
+ maxWidth?: number;
22
+ maxHeight?: number;
23
+ everyNthFrame?: number;
24
+ }
25
+
26
+ export interface ILiveBrowserSecurityOptions {
27
+ denyDownloads?: boolean;
28
+ denyFileChoosers?: boolean;
29
+ denyPermissions?: boolean;
30
+ httpNavigationOnly?: boolean;
31
+ }
32
+
33
+ export interface ILiveBrowserOperationOptions {
34
+ signal?: AbortSignal;
35
+ }
36
+
37
+ export type TLiveBrowserJsonValue =
38
+ | null
39
+ | boolean
40
+ | number
41
+ | string
42
+ | TLiveBrowserJsonValue[]
43
+ | { [key: string]: TLiveBrowserJsonValue };
44
+
45
+ export interface ILiveBrowserEvaluateOptions {
46
+ tabId?: string;
47
+ timeoutMs?: number;
48
+ maxOutputBytes?: number;
49
+ maxDepth?: number;
50
+ maxNodes?: number;
51
+ maxStringBytes?: number;
52
+ maxArrayLength?: number;
53
+ maxObjectKeys?: number;
54
+ }
55
+
56
+ export type TLiveBrowserLaunchOptions = Omit<
57
+ NonNullable<IEnvAwareOptions['launchOptions']>,
58
+ 'signal'
59
+ >;
60
+
61
+ export interface ILiveBrowserSessionOptions extends Omit<IEnvAwareOptions, 'launchOptions'> {
62
+ launchOptions?: TLiveBrowserLaunchOptions;
63
+ viewport?: ILiveBrowserViewport;
64
+ screencast?: ILiveBrowserScreencastOptions;
65
+ security?: ILiveBrowserSecurityOptions;
66
+ allowEvaluation?: boolean;
67
+ }
68
+
69
+ export interface ILiveBrowserTabState {
70
+ id: string;
71
+ url: string;
72
+ title: string;
73
+ active: boolean;
74
+ status: TLiveBrowserTabStatus;
75
+ generation: number;
76
+ appliedViewportRevision: number;
77
+ streaming: boolean;
78
+ }
79
+
80
+ export interface ILiveBrowserError {
81
+ code: string;
82
+ message: string;
83
+ fatal: boolean;
84
+ tabId?: string;
85
+ }
86
+
87
+ export interface ILiveBrowserState {
88
+ status: TLiveBrowserStatus;
89
+ activeTabId: string | null;
90
+ viewportRevision: number;
91
+ viewport: ILiveBrowserViewport;
92
+ tabs: ILiveBrowserTabState[];
93
+ lastError?: ILiveBrowserError;
94
+ }
95
+
96
+ export interface ILiveBrowserScreencastMetadata {
97
+ offsetTop: number;
98
+ pageScaleFactor: number;
99
+ deviceWidth: number;
100
+ deviceHeight: number;
101
+ scrollOffsetX: number;
102
+ scrollOffsetY: number;
103
+ timestamp?: number;
104
+ }
105
+
106
+ export interface ILiveBrowserFrame {
107
+ tabId: string;
108
+ sequence: number;
109
+ generation: number;
110
+ viewportRevision: number;
111
+ viewport: ILiveBrowserViewport;
112
+ format: TLiveBrowserImageFormat;
113
+ mimeType: 'image/jpeg' | 'image/png';
114
+ width: number;
115
+ height: number;
116
+ metadata: ILiveBrowserScreencastMetadata;
117
+ data: Uint8Array;
118
+ }
119
+
120
+ export interface ILiveBrowserSnapshot {
121
+ tabId: string;
122
+ viewportRevision: number;
123
+ viewport: ILiveBrowserViewport;
124
+ format: TLiveBrowserImageFormat;
125
+ mimeType: 'image/jpeg' | 'image/png';
126
+ width: number;
127
+ height: number;
128
+ data: Uint8Array;
129
+ }
130
+
131
+ export interface ILiveBrowserStateEvent {
132
+ type: 'state';
133
+ state: ILiveBrowserState;
134
+ }
135
+
136
+ export interface ILiveBrowserFrameEvent {
137
+ type: 'frame';
138
+ frame: ILiveBrowserFrame;
139
+ }
140
+
141
+ export interface ILiveBrowserErrorEvent {
142
+ type: 'error';
143
+ error: ILiveBrowserError;
144
+ }
145
+
146
+ export type TLiveBrowserEvent =
147
+ | ILiveBrowserStateEvent
148
+ | ILiveBrowserFrameEvent
149
+ | ILiveBrowserErrorEvent;
150
+
151
+ export type TLiveBrowserEventListener = (event: TLiveBrowserEvent) => void;
152
+
153
+ export interface ILiveBrowserFrameAcknowledgement {
154
+ accepted: boolean;
155
+ }
156
+
157
+ export interface ILiveBrowserFrameAcknowledgementRequest {
158
+ tabId: string;
159
+ sequence: number;
160
+ generation: number;
161
+ viewportRevision: number;
162
+ }
163
+
164
+ export interface ILiveBrowserCreateTabOptions {
165
+ url?: string;
166
+ activate?: boolean;
167
+ timeoutMs?: number;
168
+ waitUntil?: TLiveBrowserWaitUntil;
169
+ }
170
+
171
+ export interface ILiveBrowserNavigationOptions {
172
+ tabId?: string;
173
+ timeoutMs?: number;
174
+ waitUntil?: TLiveBrowserWaitUntil;
175
+ }
176
+
177
+ export interface ILiveBrowserNavigateOptions extends ILiveBrowserNavigationOptions {
178
+ url: string;
179
+ }
180
+
181
+ export interface ILiveBrowserModifierState {
182
+ alt?: boolean;
183
+ control?: boolean;
184
+ meta?: boolean;
185
+ shift?: boolean;
186
+ }
187
+
188
+ export interface ILiveBrowserInputBase {
189
+ tabId: string;
190
+ generation: number;
191
+ viewportRevision: number;
192
+ }
193
+
194
+ export interface ILiveBrowserMouseInput extends ILiveBrowserInputBase {
195
+ type: 'move' | 'down' | 'up';
196
+ x: number;
197
+ y: number;
198
+ button?: 'none' | 'left' | 'middle' | 'right' | 'back' | 'forward';
199
+ buttons?: number;
200
+ clickCount?: number;
201
+ modifiers?: ILiveBrowserModifierState;
202
+ }
203
+
204
+ export interface ILiveBrowserWheelInput extends ILiveBrowserInputBase {
205
+ x: number;
206
+ y: number;
207
+ deltaX: number;
208
+ deltaY: number;
209
+ modifiers?: ILiveBrowserModifierState;
210
+ }
211
+
212
+ export interface ILiveBrowserKeyInput extends ILiveBrowserInputBase {
213
+ type: 'down' | 'up';
214
+ key: string;
215
+ code?: string;
216
+ text?: string;
217
+ unmodifiedText?: string;
218
+ windowsVirtualKeyCode?: number;
219
+ nativeVirtualKeyCode?: number;
220
+ autoRepeat?: boolean;
221
+ isKeypad?: boolean;
222
+ location?: number;
223
+ modifiers?: ILiveBrowserModifierState;
224
+ }
225
+
226
+ export interface ILiveBrowserInsertTextInput extends ILiveBrowserInputBase {
227
+ text: string;
228
+ }
229
+
230
+ export interface ILiveBrowserSemanticActionBase extends ILiveBrowserInputBase {
231
+ selector: string;
232
+ timeoutMs?: number;
233
+ }
234
+
235
+ export interface ILiveBrowserClickOptions extends ILiveBrowserSemanticActionBase {
236
+ button?: 'left' | 'middle' | 'right';
237
+ clickCount?: number;
238
+ }
239
+
240
+ export interface ILiveBrowserFillOptions extends ILiveBrowserSemanticActionBase {
241
+ text: string;
242
+ }
243
+
244
+ export interface ILiveBrowserPressOptions extends ILiveBrowserSemanticActionBase {
245
+ key: string;
246
+ }
247
+
248
+ export interface ILiveBrowserSnapshotOptions {
249
+ tabId?: string;
250
+ format?: TLiveBrowserImageFormat;
251
+ quality?: number;
252
+ }
253
+
254
+ export interface ILiveBrowserObserveOptions {
255
+ tabId?: string;
256
+ maxCharacters?: number;
257
+ }
258
+
259
+ export interface ILiveBrowserObservation {
260
+ tabId: string;
261
+ url: string;
262
+ title: string;
263
+ tab: ILiveBrowserTabState;
264
+ state: ILiveBrowserState;
265
+ text: string;
266
+ truncated: boolean;
267
+ }
@@ -1,7 +1,8 @@
1
1
  // node native scope
2
+ import { Buffer } from 'node:buffer';
2
3
  import * as os from 'os';
3
4
 
4
- export { os };
5
+ export { Buffer, os };
5
6
 
6
7
  // @pushrocks scope
7
8
  import * as smartdelay from '@push.rocks/smartdelay';
@@ -10,7 +11,7 @@ import * as smartshell from '@push.rocks/smartshell';
10
11
  export { smartdelay, smartshell };
11
12
 
12
13
  // third party scope
13
- import puppeteer from 'puppeteer';
14
+ import * as puppeteer from 'puppeteer';
14
15
  import treeKill from 'tree-kill';
15
16
 
16
17
  export { puppeteer, treeKill };
package/dist/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import puppeteer from 'puppeteer';
2
- export declare const getEnvAwareBrowserInstance: () => Promise<puppeteer.Browser>;
3
- export { puppeteer };
package/dist/index.js DELETED
@@ -1,18 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const puppeteer_1 = __importDefault(require("puppeteer"));
7
- exports.puppeteer = puppeteer_1.default;
8
- exports.getEnvAwareBrowserInstance = async () => {
9
- let chromeArgs = [];
10
- if (process.env.CI) {
11
- chromeArgs = chromeArgs.concat(['--no-sandbox', '--disable-setuid-sandbox']);
12
- }
13
- const headlessBrowser = await puppeteer_1.default.launch({
14
- args: chromeArgs
15
- });
16
- return headlessBrowser;
17
- };
18
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDBEQUFrQztBQWF6QixvQkFiRixtQkFBUyxDQWFFO0FBWEwsUUFBQSwwQkFBMEIsR0FBRyxLQUFLLElBQWdDLEVBQUU7SUFDL0UsSUFBSSxVQUFVLEdBQWEsRUFBRSxDQUFDO0lBQzlCLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUU7UUFDbEIsVUFBVSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxjQUFjLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxDQUFDO0tBQzlFO0lBQ0QsTUFBTSxlQUFlLEdBQUcsTUFBTSxtQkFBUyxDQUFDLE1BQU0sQ0FBQztRQUM3QyxJQUFJLEVBQUUsVUFBVTtLQUNqQixDQUFDLENBQUM7SUFDSCxPQUFPLGVBQWUsQ0FBQztBQUN6QixDQUFDLENBQUMifQ==