@skrillex1224/playwright-toolkit 3.0.15 → 3.0.16
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/browser.d.ts +6 -0
- package/dist/browser.js +421 -163
- package/dist/browser.js.map +4 -4
- package/dist/index.cjs +1021 -497
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +1021 -497
- package/dist/index.js.map +4 -4
- package/index.d.ts +49 -9
- package/package.json +9 -1
- package/scripts/postinstall.js +203 -0
package/index.d.ts
CHANGED
|
@@ -18,14 +18,29 @@ export interface StatusType {
|
|
|
18
18
|
Failed: 'FAILED';
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export interface ModeType {
|
|
22
|
+
Default: 'default';
|
|
23
|
+
Cloak: 'cloak';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ToolkitModeStatic {
|
|
27
|
+
default: 'default';
|
|
28
|
+
cloak: 'cloak';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type ToolkitMode = 'default' | 'cloak';
|
|
32
|
+
|
|
21
33
|
export interface ConstantsModule {
|
|
22
34
|
Code: CodeType;
|
|
23
35
|
Status: StatusType;
|
|
36
|
+
Mode: ModeType;
|
|
37
|
+
mode: ToolkitModeStatic;
|
|
24
38
|
PresetOfLiveViewKey: string;
|
|
25
39
|
Device: {
|
|
26
40
|
Desktop: 'desktop';
|
|
27
41
|
Mobile: 'mobile';
|
|
28
42
|
};
|
|
43
|
+
normalizeMode(value?: unknown, fallback?: ToolkitMode): ToolkitMode;
|
|
29
44
|
normalizeDevice(value?: unknown, fallback?: RuntimeDevice): RuntimeDevice;
|
|
30
45
|
ActorInfo: Record<string, ActorInfoItem>;
|
|
31
46
|
}
|
|
@@ -33,7 +48,7 @@ export interface ConstantsModule {
|
|
|
33
48
|
export type RuntimeDevice = 'desktop' | 'mobile';
|
|
34
49
|
|
|
35
50
|
export interface ActorShareInfo {
|
|
36
|
-
mode: 'dom' | 'response';
|
|
51
|
+
mode: 'dom' | 'response' | 'custom';
|
|
37
52
|
prefix: string;
|
|
38
53
|
xurl: Array<string | string[]>;
|
|
39
54
|
}
|
|
@@ -400,9 +415,9 @@ export interface CrawlerBaseOptions {
|
|
|
400
415
|
requestHandlerTimeoutSecs: number;
|
|
401
416
|
navigationTimeoutSecs: number;
|
|
402
417
|
headless: boolean;
|
|
403
|
-
browserPoolOptions: {
|
|
404
|
-
useFingerprints
|
|
405
|
-
fingerprintOptions
|
|
418
|
+
browserPoolOptions: Record<string, any> & {
|
|
419
|
+
useFingerprints?: boolean;
|
|
420
|
+
fingerprintOptions?: {
|
|
406
421
|
fingerprintGeneratorOptions: Record<string, any>;
|
|
407
422
|
};
|
|
408
423
|
};
|
|
@@ -417,10 +432,6 @@ export interface CrawlerNavigationHook {
|
|
|
417
432
|
(crawlingContext: any, gotoOptions: Record<string, any>): Promise<void> | void;
|
|
418
433
|
}
|
|
419
434
|
|
|
420
|
-
export interface LaunchHooks {
|
|
421
|
-
modifyPageOptions?: (pageOptions: Record<string, any>, context: { pageId: string; browserController: any }) => Promise<void> | void;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
435
|
export interface GetPlaywrightCrawlerOptionsInput {
|
|
425
436
|
customArgs?: string[];
|
|
426
437
|
proxyConfiguration?: ProxyConfiguration;
|
|
@@ -432,7 +443,6 @@ export interface GetPlaywrightCrawlerOptionsInput {
|
|
|
432
443
|
isRunningOnApify?: boolean;
|
|
433
444
|
launcher?: any;
|
|
434
445
|
runtimeState?: RuntimeEnvState | null;
|
|
435
|
-
hooks?: LaunchHooks;
|
|
436
446
|
preNavigationHooks?: CrawlerNavigationHook[];
|
|
437
447
|
postNavigationHooks?: CrawlerNavigationHook[];
|
|
438
448
|
}
|
|
@@ -446,6 +456,25 @@ export interface LaunchModule {
|
|
|
446
456
|
getPlaywrightCrawlerOptions(options?: GetPlaywrightCrawlerOptionsInput): PlaywrightCrawlerOptions;
|
|
447
457
|
}
|
|
448
458
|
|
|
459
|
+
export interface CloakGetPlaywrightCrawlerOptionsInput extends GetPlaywrightCrawlerOptionsInput {
|
|
460
|
+
cloakOptions?: Record<string, any>;
|
|
461
|
+
humanizeOptions?: boolean | Record<string, any>;
|
|
462
|
+
crawlerBaseOptions?: Partial<CrawlerBaseOptions>;
|
|
463
|
+
browserPoolOptions?: Record<string, any>;
|
|
464
|
+
launchContext?: Record<string, any>;
|
|
465
|
+
recommendedGotoOptions?: Record<string, any>;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export interface CloakPlaywrightCrawlerOptions extends PlaywrightCrawlerOptions {
|
|
469
|
+
cleanup?: () => Promise<void>;
|
|
470
|
+
closeActiveBrowsers?: () => Promise<void>;
|
|
471
|
+
forceTerminateActiveProcesses?: () => Promise<void>;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export interface CloakLaunchModule {
|
|
475
|
+
getPlaywrightCrawlerOptions(options?: CloakGetPlaywrightCrawlerOptionsInput): Promise<CloakPlaywrightCrawlerOptions>;
|
|
476
|
+
}
|
|
477
|
+
|
|
449
478
|
// =============================================================================
|
|
450
479
|
// LiveView
|
|
451
480
|
// =============================================================================
|
|
@@ -659,6 +688,8 @@ export interface ShareScreenCaptureOptions {
|
|
|
659
688
|
restore?: boolean;
|
|
660
689
|
/** 最大截图高度 (默认: 8000px) */
|
|
661
690
|
maxHeight?: number;
|
|
691
|
+
/** 截图水印合成模式;默认取当前 toolkit mode,`cloak` 时走兼容分支。 */
|
|
692
|
+
mode?: 'default' | 'cloak';
|
|
662
693
|
/** 返回 base64 字符串的最大字节数,默认 5MiB。 */
|
|
663
694
|
maxBytes?: number;
|
|
664
695
|
/** maxBytes 的别名。 */
|
|
@@ -845,6 +876,10 @@ export interface PlaywrightToolKit {
|
|
|
845
876
|
};
|
|
846
877
|
}
|
|
847
878
|
|
|
879
|
+
export interface CloakPlaywrightToolKit extends PlaywrightToolKit {
|
|
880
|
+
Launch: CloakLaunchModule;
|
|
881
|
+
}
|
|
882
|
+
|
|
848
883
|
/** Browser/Extension version of the toolkit */
|
|
849
884
|
export interface BrowserPlaywrightToolKit {
|
|
850
885
|
Logger: LoggerModule;
|
|
@@ -859,3 +894,8 @@ export interface BrowserPlaywrightToolKit {
|
|
|
859
894
|
}
|
|
860
895
|
|
|
861
896
|
export declare function usePlaywrightToolKit(): PlaywrightToolKit;
|
|
897
|
+
export declare function usePlaywrightToolKit(mode: 'default'): PlaywrightToolKit;
|
|
898
|
+
export declare function usePlaywrightToolKit(mode: 'cloak'): CloakPlaywrightToolKit;
|
|
899
|
+
export declare namespace usePlaywrightToolKit {
|
|
900
|
+
const Mode: ToolkitModeStatic;
|
|
901
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skrillex1224/playwright-toolkit",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.16",
|
|
4
4
|
"description": "一个在 Apify/Crawlee Actor 中启用实时截图视图的实用工具库。",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -22,12 +22,14 @@
|
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "node build.js",
|
|
25
|
+
"postinstall": "node ./scripts/postinstall.js",
|
|
25
26
|
"release": "npm run build && npm version patch && npm publish --registry https://registry.npmjs.org --access public --userconfig ../.npmrc",
|
|
26
27
|
"prepublishOnly": "npm run build",
|
|
27
28
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
28
29
|
},
|
|
29
30
|
"files": [
|
|
30
31
|
"dist/",
|
|
32
|
+
"scripts/",
|
|
31
33
|
"browser.d.ts",
|
|
32
34
|
"index.d.ts",
|
|
33
35
|
"README.md"
|
|
@@ -59,10 +61,16 @@
|
|
|
59
61
|
},
|
|
60
62
|
"peerDependencies": {
|
|
61
63
|
"apify": "*",
|
|
64
|
+
"cloakbrowser": "*",
|
|
62
65
|
"crawlee": "*",
|
|
63
66
|
"ghost-cursor-playwright": "*",
|
|
64
67
|
"playwright": "*"
|
|
65
68
|
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"cloakbrowser": {
|
|
71
|
+
"optional": true
|
|
72
|
+
}
|
|
73
|
+
},
|
|
66
74
|
"devDependencies": {
|
|
67
75
|
"esbuild": "^0.24.2"
|
|
68
76
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const PACKAGE_ROOT = path.resolve(SCRIPT_DIR, '..');
|
|
9
|
+
const PREFIX = '[playwright-toolkit:postinstall]';
|
|
10
|
+
const SKIP_ENV = 'PLAYWRIGHT_TOOLKIT_SKIP_CLOAK_POSTINSTALL';
|
|
11
|
+
|
|
12
|
+
const log = (message) => console.log(`${PREFIX} ${message}`);
|
|
13
|
+
const warn = (message) => console.warn(`${PREFIX} ${message}`);
|
|
14
|
+
|
|
15
|
+
const isTruthy = (value) => /^(1|true|yes|on)$/i.test(String(value || '').trim());
|
|
16
|
+
|
|
17
|
+
const readTrimmedFile = (filePath) => {
|
|
18
|
+
try {
|
|
19
|
+
return fs.readFileSync(filePath, 'utf8').trim();
|
|
20
|
+
} catch {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const isBinaryReady = (binaryPath) => {
|
|
26
|
+
if (!binaryPath || !fs.existsSync(binaryPath)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (process.platform === 'win32') {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
fs.accessSync(binaryPath, fs.constants.X_OK);
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function* walkParentDirs(startDir) {
|
|
43
|
+
let currentDir = path.resolve(startDir);
|
|
44
|
+
while (true) {
|
|
45
|
+
yield currentDir;
|
|
46
|
+
|
|
47
|
+
const parentDir = path.dirname(currentDir);
|
|
48
|
+
if (parentDir === currentDir) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
currentDir = parentDir;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const findPackageRoot = (startDir, packageName) => {
|
|
57
|
+
for (const currentDir of walkParentDirs(startDir)) {
|
|
58
|
+
const packageJsonPath = path.join(currentDir, 'package.json');
|
|
59
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
65
|
+
if (packageJson?.name === packageName) {
|
|
66
|
+
return currentDir;
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
// Ignore invalid JSON and keep walking.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const findInstalledCloakRoot = async () => {
|
|
77
|
+
try {
|
|
78
|
+
const resolvedEntryUrl = await import.meta.resolve('cloakbrowser');
|
|
79
|
+
const resolvedEntryPath = fileURLToPath(resolvedEntryUrl);
|
|
80
|
+
const packageRoot = findPackageRoot(path.dirname(resolvedEntryPath), 'cloakbrowser');
|
|
81
|
+
if (packageRoot) {
|
|
82
|
+
return packageRoot;
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
// Fall back to filesystem lookup.
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const searchRoots = [
|
|
89
|
+
process.env.INIT_CWD,
|
|
90
|
+
process.cwd(),
|
|
91
|
+
process.env.npm_config_local_prefix,
|
|
92
|
+
PACKAGE_ROOT,
|
|
93
|
+
SCRIPT_DIR,
|
|
94
|
+
].filter(Boolean);
|
|
95
|
+
|
|
96
|
+
for (const searchRoot of new Set(searchRoots)) {
|
|
97
|
+
for (const currentDir of walkParentDirs(searchRoot)) {
|
|
98
|
+
const packageJsonPath = path.join(currentDir, 'node_modules', 'cloakbrowser', 'package.json');
|
|
99
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
100
|
+
return path.dirname(packageJsonPath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return null;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const clearStaleVersionMarkers = ({ cacheDir, expectedVersion, platformTag }) => {
|
|
109
|
+
let clearedMarkers = 0;
|
|
110
|
+
|
|
111
|
+
for (const markerName of [`latest_version_${platformTag}`, 'latest_version']) {
|
|
112
|
+
const markerPath = path.join(cacheDir, markerName);
|
|
113
|
+
const markerVersion = readTrimmedFile(markerPath);
|
|
114
|
+
|
|
115
|
+
if (!markerVersion || markerVersion === expectedVersion) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fs.rmSync(markerPath, { force: true });
|
|
120
|
+
clearedMarkers += 1;
|
|
121
|
+
log(`Removed stale ${markerName}=${markerVersion} to keep cloakbrowser pinned to ${expectedVersion}.`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return clearedMarkers;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const main = async () => {
|
|
128
|
+
if (isTruthy(process.env[SKIP_ENV])) {
|
|
129
|
+
log(`Skipped because ${SKIP_ENV} is set.`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const cloakRoot = await findInstalledCloakRoot();
|
|
134
|
+
if (!cloakRoot) {
|
|
135
|
+
log('cloakbrowser is not installed; skipping binary preinstall.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const [cloakModule, cloakConfig] = await Promise.all([
|
|
140
|
+
import(pathToFileURL(path.join(cloakRoot, 'dist', 'index.js')).href),
|
|
141
|
+
import(pathToFileURL(path.join(cloakRoot, 'dist', 'config.js')).href),
|
|
142
|
+
]);
|
|
143
|
+
|
|
144
|
+
const localBinaryOverride = cloakConfig.getLocalBinaryOverride?.();
|
|
145
|
+
if (localBinaryOverride) {
|
|
146
|
+
if (!fs.existsSync(localBinaryOverride)) {
|
|
147
|
+
throw new Error(`CLOAKBROWSER_BINARY_PATH points to a missing file: ${localBinaryOverride}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
log(`Using CLOAKBROWSER_BINARY_PATH=${localBinaryOverride}; skipping managed binary install.`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
cloakConfig.checkPlatformAvailable?.();
|
|
156
|
+
} catch (error) {
|
|
157
|
+
warn(`${error?.message || String(error)} Skipping managed binary install.`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const expectedVersion = cloakConfig.getChromiumVersion();
|
|
162
|
+
const platformTag = cloakConfig.getPlatformTag();
|
|
163
|
+
const cacheDir = cloakConfig.getCacheDir();
|
|
164
|
+
const expectedBinaryPath = cloakConfig.getBinaryPath(expectedVersion);
|
|
165
|
+
|
|
166
|
+
process.env.CLOAKBROWSER_AUTO_UPDATE = 'false';
|
|
167
|
+
|
|
168
|
+
const clearedMarkers = clearStaleVersionMarkers({
|
|
169
|
+
cacheDir,
|
|
170
|
+
expectedVersion,
|
|
171
|
+
platformTag,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (isBinaryReady(expectedBinaryPath)) {
|
|
175
|
+
const suffix = clearedMarkers > 0 ? ' Cleared stale version markers.' : '';
|
|
176
|
+
log(`cloakbrowser ${expectedVersion} already available at ${expectedBinaryPath}.${suffix}`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
log(`Installing cloakbrowser ${expectedVersion} for ${platformTag}...`);
|
|
181
|
+
const resolvedBinaryPath = await cloakModule.ensureBinary();
|
|
182
|
+
|
|
183
|
+
if (!isBinaryReady(expectedBinaryPath)) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Expected cloakbrowser binary at ${expectedBinaryPath}, but it is still missing after ensureBinary() returned ${resolvedBinaryPath}.`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (path.resolve(resolvedBinaryPath) !== path.resolve(expectedBinaryPath)) {
|
|
190
|
+
warn(
|
|
191
|
+
`ensureBinary() returned ${resolvedBinaryPath}, expected ${expectedBinaryPath}. `
|
|
192
|
+
+ 'The package-pinned binary is installed and stale version markers were cleared.',
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
log(`cloakbrowser ${expectedVersion} ready at ${expectedBinaryPath}.`);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
main().catch((error) => {
|
|
200
|
+
const message = error?.stack || error?.message || String(error);
|
|
201
|
+
console.error(`${PREFIX} ${message}`);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
});
|