@iflyrpa/playwright 1.0.14 → 1.0.15-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3,20 +3,27 @@
3
3
  const fs = require('node:fs');
4
4
  const path = require('node:path');
5
5
  const https = require('node:https');
6
+ const childProcess = require('node:child_process');
7
+ const os = require('node:os');
8
+ const get = require('@electron/get');
9
+ const extract = require('extract-zip');
6
10
  const log = require('loglevel');
7
- const npminstall = require('npminstall');
11
+ const node = require('@sentry/node');
12
+ const livePluginManager = require('live-plugin-manager');
8
13
 
9
14
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
10
15
 
11
16
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
12
17
  const path__default = /*#__PURE__*/_interopDefaultCompat(path);
13
18
  const https__default = /*#__PURE__*/_interopDefaultCompat(https);
19
+ const childProcess__default = /*#__PURE__*/_interopDefaultCompat(childProcess);
20
+ const os__default = /*#__PURE__*/_interopDefaultCompat(os);
21
+ const extract__default = /*#__PURE__*/_interopDefaultCompat(extract);
14
22
  const log__default = /*#__PURE__*/_interopDefaultCompat(log);
15
- const npminstall__default = /*#__PURE__*/_interopDefaultCompat(npminstall);
16
23
 
17
24
  const name = "@iflyrpa/playwright";
18
25
  const type = "module";
19
- const version$1 = "1.0.14";
26
+ const version$1 = "1.0.15-beta.1";
20
27
  const main = "./dist/index.cjs";
21
28
  const module$1 = "./dist/index.mjs";
22
29
  const types = "./dist/index.d.ts";
@@ -31,14 +38,20 @@ const files = [
31
38
  "dist"
32
39
  ];
33
40
  const dependencies = {
34
- loglevel: "^1.9.2",
35
- npminstall: "^7.12.0"
41
+ "@electron/get": "^2.0.0",
42
+ "@sentry/node": "^5.5.0",
43
+ "extract-zip": "^2.0.1",
44
+ "live-plugin-manager": "^1.0.0",
45
+ loglevel: "^1.9.2"
46
+ };
47
+ const peerDependencies = {
48
+ playwright: "^1.46.1"
36
49
  };
37
50
  const devDependencies = {
38
51
  esno: "^4.7.0",
52
+ playwright: "^1.46.1",
39
53
  typescript: "^5.5.2",
40
- unbuild: "^2.0.0",
41
- playwright: "^1.46.1"
54
+ unbuild: "^2.0.0"
42
55
  };
43
56
  const packageJson = {
44
57
  name: name,
@@ -52,6 +65,7 @@ const packageJson = {
52
65
  license: license,
53
66
  files: files,
54
67
  dependencies: dependencies,
68
+ peerDependencies: peerDependencies,
55
69
  devDependencies: devDependencies
56
70
  };
57
71
 
@@ -253,7 +267,7 @@ const xiaohongshuPublishAction = async (props) => {
253
267
  await page.getByRole("textbox").click();
254
268
  const fileChooser = await fileChooserPromise;
255
269
  await fileChooser.setFiles(images);
256
- const titleInstance = page.locator(".titleInput input");
270
+ const titleInstance = page.locator(".input.titleInput input");
257
271
  await titleInstance.click();
258
272
  await titleInstance.fill(params.title);
259
273
  const descInstance = page.locator("#post-textarea");
@@ -336,6 +350,117 @@ const xiaohongshuPublishAction = async (props) => {
336
350
  return response;
337
351
  };
338
352
 
353
+ var __defProp$4 = Object.defineProperty;
354
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
355
+ var __publicField$4 = (obj, key, value) => {
356
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
357
+ return value;
358
+ };
359
+ const ELECTRON_MIRROR = "http://npmmirror.com/mirrors/electron/";
360
+ class ElectronInstall {
361
+ constructor(rootDir, version, logger) {
362
+ this.rootDir = rootDir;
363
+ this.version = version;
364
+ this.logger = logger;
365
+ __publicField$4(this, "electronPath");
366
+ __publicField$4(this, "platformPath");
367
+ this.platformPath = this.getPlatformPath();
368
+ this.electronPath = path__default.join(rootDir, this.platformPath);
369
+ }
370
+ isInstalled() {
371
+ try {
372
+ if (fs__default.readFileSync(path__default.join(this.rootDir, "version"), "utf-8").replace(/^v/, "") !== this.version) {
373
+ return false;
374
+ }
375
+ } catch (ignored) {
376
+ return false;
377
+ }
378
+ const electronPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path__default.join(this.rootDir, this.platformPath);
379
+ return fs__default.existsSync(electronPath);
380
+ }
381
+ getPlatformPath() {
382
+ const platform = process.env.npm_config_platform || os__default.platform();
383
+ switch (platform) {
384
+ case "mas":
385
+ case "darwin":
386
+ return "Electron.app/Contents/MacOS/Electron";
387
+ case "freebsd":
388
+ case "openbsd":
389
+ case "linux":
390
+ return "electron";
391
+ case "win32":
392
+ return "electron.exe";
393
+ default:
394
+ throw new Error(
395
+ `Electron builds are not available on platform: ${platform}`
396
+ );
397
+ }
398
+ }
399
+ async install() {
400
+ const installed = this.isInstalled();
401
+ this.logger.info(`electron@${this.version} \u662F\u5426\u5DF2\u5B89\u88C5\uFF1A${installed}`);
402
+ if (installed)
403
+ return this.electronPath;
404
+ const platform = process.env.npm_config_platform || process.platform;
405
+ let arch = process.env.npm_config_arch || process.arch;
406
+ if (platform === "darwin" && process.platform === "darwin" && arch === "x64" && process.env.npm_config_arch === void 0) {
407
+ try {
408
+ const output = childProcess__default.execSync(
409
+ "sysctl -in sysctl.proc_translated"
410
+ );
411
+ if (output.toString().trim() === "1") {
412
+ arch = "arm64";
413
+ }
414
+ } catch {
415
+ }
416
+ }
417
+ try {
418
+ this.logger.info(`electron@${this.version} \u5F00\u59CB\u4E0B\u8F7D\u8D44\u6E90`);
419
+ const zipPath = await get.downloadArtifact({
420
+ version: this.version,
421
+ artifactName: "electron",
422
+ force: process.env.force_no_cache === "true",
423
+ cacheRoot: process.env.electron_config_cache,
424
+ checksums: void 0,
425
+ mirrorOptions: { mirror: ELECTRON_MIRROR },
426
+ // 使用国内镜像下载
427
+ platform,
428
+ arch
429
+ });
430
+ this.logger.info(`electron@${this.version} \u5F00\u59CB\u89E3\u538B\u8D44\u6E90`);
431
+ process.noAsar = true;
432
+ await extract__default(zipPath, { dir: this.rootDir });
433
+ this.logger.info(`electron@${this.version} \u4E0B\u8F7D\u6210\u529F`);
434
+ return this.electronPath;
435
+ } catch (error) {
436
+ this.logger.error(`electron@${this.version} \u4E0B\u8F7D\u5931\u8D25`, error);
437
+ throw error;
438
+ }
439
+ }
440
+ }
441
+
442
+ var __defProp$3 = Object.defineProperty;
443
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
444
+ var __publicField$3 = (obj, key, value) => {
445
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
446
+ return value;
447
+ };
448
+ class SentryInstance {
449
+ constructor(dsn) {
450
+ __publicField$3(this, "sentry");
451
+ if (!dsn)
452
+ return;
453
+ this.sentry = new node.NodeClient({
454
+ dsn,
455
+ defaultIntegrations: false
456
+ });
457
+ }
458
+ captureException(error) {
459
+ this.sentry?.captureException(error);
460
+ }
461
+ }
462
+ const sentry = new SentryInstance(process.env.RPA_SENTRY_DSN);
463
+
339
464
  var __defProp$2 = Object.defineProperty;
340
465
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
341
466
  var __publicField$2 = (obj, key, value) => {
@@ -354,7 +479,7 @@ const _Logger = class _Logger {
354
479
  log__default.methodFactory = (methodName) => {
355
480
  return (message) => {
356
481
  this.stream.write(
357
- `[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
482
+ `[${( new Date()).toLocaleString()}] ${methodName.toUpperCase()}: ${message}
358
483
  `
359
484
  );
360
485
  };
@@ -380,12 +505,14 @@ const _Logger = class _Logger {
380
505
  warn(...msg) {
381
506
  log__default.warn(...msg);
382
507
  }
383
- error(prefix, error) {
384
- log__default.error(prefix);
385
- if (error instanceof Error) {
386
- log__default.error(`${error.message}
387
- Error stack: ${error.stack}`);
508
+ // error 级别的日志上报 sentry
509
+ error(prefix, err) {
510
+ const error = err || prefix;
511
+ if (err instanceof Error) {
512
+ err.message = `${prefix}\uFF1A${err.message}`;
388
513
  }
514
+ log__default.error(error);
515
+ sentry.captureException(error);
389
516
  }
390
517
  close() {
391
518
  this.stream.end();
@@ -410,23 +537,17 @@ const generateFile = async (dir) => {
410
537
  }
411
538
  return filePath;
412
539
  };
413
- const createElectronApp = async (cachePath, playwright) => {
540
+ const launchElectronApp = async (cachePath, playwright, electronPath) => {
414
541
  const logger = Logger.getInstance(cachePath);
415
542
  try {
416
- const executablePath = path__default.join(
417
- cachePath,
418
- "node_modules",
419
- ".bin",
420
- "electron"
421
- );
422
543
  const mainPath = await generateFile(cachePath);
423
544
  const electronApp = await playwright._electron.launch({
424
- executablePath,
545
+ executablePath: electronPath,
425
546
  // 获取 Electron 可执行文件的路径
426
547
  args: [mainPath],
427
548
  cwd: cachePath
428
549
  });
429
- logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
550
+ logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${electronPath} ${mainPath}`);
430
551
  return electronApp;
431
552
  } catch (error) {
432
553
  logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
@@ -441,8 +562,13 @@ var __publicField$1 = (obj, key, value) => {
441
562
  return value;
442
563
  };
443
564
  const NPM_REGISTRY = "https://registry.npmmirror.com/";
444
- class PackageManager {
565
+ class PackageManager extends livePluginManager.PluginManager {
445
566
  constructor(params) {
567
+ super({
568
+ cwd: params.cacheDir,
569
+ pluginsPath: path__default.join(params.cacheDir, "node_modules"),
570
+ npmRegistryUrl: NPM_REGISTRY
571
+ });
446
572
  __publicField$1(this, "cacheDir");
447
573
  // 依赖安装目录
448
574
  __publicField$1(this, "forceUpdate");
@@ -484,7 +610,6 @@ class PackageManager {
484
610
  try {
485
611
  return require(path__default.join(pluginDir, module));
486
612
  } catch (error) {
487
- this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
488
613
  return null;
489
614
  }
490
615
  }
@@ -493,27 +618,29 @@ class PackageManager {
493
618
  return this.getPlugin(module);
494
619
  }
495
620
  // 安装依赖
496
- install(name, version) {
497
- return npminstall__default({
498
- root: this.cacheDir,
499
- pkgs: [{ name, version }],
500
- registry: NPM_REGISTRY
501
- });
621
+ async installPackage(name, version) {
622
+ try {
623
+ this.logger.info(`${name} \u5F00\u59CB\u5B89\u88C5`);
624
+ await this.install(name, version);
625
+ this.logger.info(`${name} \u5B89\u88C5\u6210\u529F`);
626
+ } catch (error) {
627
+ this.logger.error(`${name} \u5B89\u88C5\u5931\u8D25`, error);
628
+ }
502
629
  }
503
630
  async init(name, version) {
504
631
  const plugin = this.getPlugin(path__default.join(name, "package.json"));
505
632
  this.logger.info(`${name} \u662F\u5426\u5DF2\u5B89\u88C5\uFF1A${!!plugin}`);
506
633
  try {
507
634
  if (!plugin) {
508
- await this.install(name, version);
635
+ await this.installPackage(name, version);
509
636
  } else if (this.forceUpdate) {
510
637
  const pkInfo = await this.getPluginInfo(name);
511
638
  if (!pkInfo)
512
639
  return;
513
640
  const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
514
641
  if (hasNewVersion) {
515
- this.logger.info(`${name} \u68C0\u67E5\u5230\u65B0\u7248\u672C ${pkInfo.version}\uFF0C\u66F4\u65B0\u4F9D\u8D56`);
516
- await this.install(name, pkInfo.version);
642
+ this.logger.info(`${name} \u68C0\u67E5\u5230\u65B0\u7248\u672C ${pkInfo.version}`);
643
+ await this.installPackage(name, pkInfo.version);
517
644
  }
518
645
  }
519
646
  this.logger.info(`${name} package manager init done!`);
@@ -530,6 +657,7 @@ var __publicField = (obj, key, value) => {
530
657
  return value;
531
658
  };
532
659
  const PLAYWRIGHT_VERSION = "1.46.1";
660
+ const PLAYWRIGHT_NAME = "playwright-core";
533
661
  const ELECTRON_VERSION = "22.3.27";
534
662
  class LocalAutomateTask {
535
663
  constructor({ cachePath, debug }) {
@@ -539,6 +667,10 @@ class LocalAutomateTask {
539
667
  __publicField(this, "playwrightPackage");
540
668
  __publicField(this, "electronPackage");
541
669
  __publicField(this, "_electronApp", null);
670
+ /**
671
+ * 应用是否已关闭
672
+ */
673
+ __publicField(this, "isClosed", false);
542
674
  this.cachePath = cachePath;
543
675
  this.debug = debug || false;
544
676
  this.logger = Logger.getInstance(cachePath);
@@ -551,37 +683,40 @@ class LocalAutomateTask {
551
683
  */
552
684
  installPlaywright() {
553
685
  const playwrightPackageManager = new PackageManager({
554
- packageName: "playwright",
686
+ packageName: PLAYWRIGHT_NAME,
555
687
  packageVersion: PLAYWRIGHT_VERSION,
556
688
  cacheDir: this.cachePath,
557
689
  forceUpdate: false
558
690
  });
559
- return playwrightPackageManager.getPluginAfterInit("playwright");
691
+ return playwrightPackageManager.getPluginAfterInit(PLAYWRIGHT_NAME);
560
692
  }
561
693
  /**
562
694
  * 安装 electron
563
695
  * @returns
564
696
  */
565
697
  installElectron() {
566
- const playwrightPackageManager = new PackageManager({
567
- packageName: "electron",
568
- packageVersion: ELECTRON_VERSION,
569
- cacheDir: this.cachePath,
570
- forceUpdate: false
571
- });
572
- return playwrightPackageManager.getPluginAfterInit("electron");
698
+ const electronInstall = new ElectronInstall(
699
+ path__default.join(this.cachePath, "electron"),
700
+ ELECTRON_VERSION,
701
+ this.logger
702
+ );
703
+ return electronInstall.install();
573
704
  }
574
705
  /**
575
706
  * 启动 Electron
576
707
  * @returns
577
708
  */
578
- async getElectronApp() {
709
+ async launchApp() {
579
710
  if (!this._electronApp) {
580
- const [playwright] = await Promise.all([
711
+ const [playwright, electronPath] = await Promise.all([
581
712
  this.playwrightPackage,
582
713
  this.electronPackage
583
714
  ]);
584
- this._electronApp = await createElectronApp(this.cachePath, playwright);
715
+ this._electronApp = await launchElectronApp(
716
+ this.cachePath,
717
+ playwright,
718
+ electronPath
719
+ );
585
720
  }
586
721
  return this._electronApp;
587
722
  }
@@ -610,16 +745,20 @@ class LocalAutomateTask {
610
745
  * @returns
611
746
  */
612
747
  async close() {
613
- this.logger.close();
748
+ this.logger.info("\u5173\u95ED\u5E94\u7528");
614
749
  this.clearTmpPath();
615
- const electronApp = await this.getElectronApp();
616
- return electronApp.close();
750
+ this.logger.close();
751
+ await this._electronApp?.close();
752
+ this.isClosed = true;
753
+ this._electronApp = null;
617
754
  }
618
755
  /**
619
756
  * 小红书自动化发布
620
757
  */
621
758
  async xiaohongshuPublish(params) {
622
- const electronApp = await this.getElectronApp();
759
+ this.logger.info("\u5F00\u59CB\u5C0F\u7EA2\u4E66\u53D1\u5E03");
760
+ const electronApp = await this.launchApp();
761
+ this.logger.info("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u4E13\u7528\u5BA2\u6237\u7AEF\u5DF2\u542F\u52A8");
623
762
  const commonCookies = {
624
763
  path: "/",
625
764
  sameSite: "lax",
@@ -659,6 +798,7 @@ class LocalAutomateTask {
659
798
  { pageParams }
660
799
  )
661
800
  ]);
801
+ this.logger.info("\u5DF2\u6253\u5F00\u5C0F\u7EA2\u4E66\u53D1\u5E03\u9875\u9762");
662
802
  try {
663
803
  const res = await xiaohongshuPublishAction({
664
804
  page,
@@ -666,6 +806,7 @@ class LocalAutomateTask {
666
806
  tmpCachePath: this.getTmpPath(),
667
807
  debug: !!this.debug
668
808
  });
809
+ this.logger.info(`\u5C0F\u7EA2\u4E66\u53D1\u5E03\u6210\u529F\uFF1A${res}`);
669
810
  return res;
670
811
  } catch (error) {
671
812
  this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
@@ -675,14 +816,17 @@ class LocalAutomateTask {
675
816
  }
676
817
  const RpaTask = (params) => {
677
818
  const logger = Logger.getInstance(params.cachePath);
678
- const packageManager = new PackageManager({
679
- packageName: packageJson.name,
680
- cacheDir: params.cachePath
681
- });
682
- const localPackge = packageManager.getPlugin(packageJson.name);
683
- if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
684
- logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
685
- return new localPackge.LocalAutomateTask(params);
819
+ if (params.forceUpdate) {
820
+ logger.info("\u5C1D\u8BD5\u4F7F\u7528\u8FDC\u7A0B\u6700\u65B0\u7248\u672C");
821
+ const packageManager = new PackageManager({
822
+ packageName: packageJson.name,
823
+ cacheDir: params.cachePath
824
+ });
825
+ const localPackge = packageManager.getPlugin(packageJson.name);
826
+ if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
827
+ logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
828
+ return new localPackge.LocalAutomateTask(params);
829
+ }
686
830
  }
687
831
  return new LocalAutomateTask(params);
688
832
  };
package/dist/index.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ElectronApplication } from 'playwright';
2
+
1
3
  interface CookiesSetDetails {
2
4
  /**
3
5
  * The URL to associate the cookie with. The promise will be rejected if the URL is
@@ -84,6 +86,7 @@ interface XiaohonshuPublishParams
84
86
  interface TaskParams {
85
87
  debug?: boolean;
86
88
  cachePath: string;
89
+ forceUpdate?: boolean;
87
90
  }
88
91
  declare class LocalAutomateTask implements TaskParams {
89
92
  private logger;
@@ -92,6 +95,10 @@ declare class LocalAutomateTask implements TaskParams {
92
95
  private playwrightPackage;
93
96
  private electronPackage;
94
97
  private _electronApp;
98
+ /**
99
+ * 应用是否已关闭
100
+ */
101
+ isClosed: boolean;
95
102
  constructor({ cachePath, debug }: TaskParams);
96
103
  /**
97
104
  * 安装 playwright
@@ -107,7 +114,7 @@ declare class LocalAutomateTask implements TaskParams {
107
114
  * 启动 Electron
108
115
  * @returns
109
116
  */
110
- private getElectronApp;
117
+ launchApp(): Promise<ElectronApplication>;
111
118
  /**
112
119
  * 临时文件目录
113
120
  * @returns
package/dist/index.d.mts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ElectronApplication } from 'playwright';
2
+
1
3
  interface CookiesSetDetails {
2
4
  /**
3
5
  * The URL to associate the cookie with. The promise will be rejected if the URL is
@@ -84,6 +86,7 @@ interface XiaohonshuPublishParams
84
86
  interface TaskParams {
85
87
  debug?: boolean;
86
88
  cachePath: string;
89
+ forceUpdate?: boolean;
87
90
  }
88
91
  declare class LocalAutomateTask implements TaskParams {
89
92
  private logger;
@@ -92,6 +95,10 @@ declare class LocalAutomateTask implements TaskParams {
92
95
  private playwrightPackage;
93
96
  private electronPackage;
94
97
  private _electronApp;
98
+ /**
99
+ * 应用是否已关闭
100
+ */
101
+ isClosed: boolean;
95
102
  constructor({ cachePath, debug }: TaskParams);
96
103
  /**
97
104
  * 安装 playwright
@@ -107,7 +114,7 @@ declare class LocalAutomateTask implements TaskParams {
107
114
  * 启动 Electron
108
115
  * @returns
109
116
  */
110
- private getElectronApp;
117
+ launchApp(): Promise<ElectronApplication>;
111
118
  /**
112
119
  * 临时文件目录
113
120
  * @returns
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ElectronApplication } from 'playwright';
2
+
1
3
  interface CookiesSetDetails {
2
4
  /**
3
5
  * The URL to associate the cookie with. The promise will be rejected if the URL is
@@ -84,6 +86,7 @@ interface XiaohonshuPublishParams
84
86
  interface TaskParams {
85
87
  debug?: boolean;
86
88
  cachePath: string;
89
+ forceUpdate?: boolean;
87
90
  }
88
91
  declare class LocalAutomateTask implements TaskParams {
89
92
  private logger;
@@ -92,6 +95,10 @@ declare class LocalAutomateTask implements TaskParams {
92
95
  private playwrightPackage;
93
96
  private electronPackage;
94
97
  private _electronApp;
98
+ /**
99
+ * 应用是否已关闭
100
+ */
101
+ isClosed: boolean;
95
102
  constructor({ cachePath, debug }: TaskParams);
96
103
  /**
97
104
  * 安装 playwright
@@ -107,7 +114,7 @@ declare class LocalAutomateTask implements TaskParams {
107
114
  * 启动 Electron
108
115
  * @returns
109
116
  */
110
- private getElectronApp;
117
+ launchApp(): Promise<ElectronApplication>;
111
118
  /**
112
119
  * 临时文件目录
113
120
  * @returns
package/dist/index.mjs CHANGED
@@ -1,12 +1,17 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import https from 'node:https';
4
+ import childProcess from 'node:child_process';
5
+ import os from 'node:os';
6
+ import { downloadArtifact } from '@electron/get';
7
+ import extract from 'extract-zip';
4
8
  import log from 'loglevel';
5
- import npminstall from 'npminstall';
9
+ import { NodeClient } from '@sentry/node';
10
+ import { PluginManager } from 'live-plugin-manager';
6
11
 
7
12
  const name = "@iflyrpa/playwright";
8
13
  const type = "module";
9
- const version$1 = "1.0.14";
14
+ const version$1 = "1.0.15-beta.1";
10
15
  const main = "./dist/index.cjs";
11
16
  const module = "./dist/index.mjs";
12
17
  const types = "./dist/index.d.ts";
@@ -21,14 +26,20 @@ const files = [
21
26
  "dist"
22
27
  ];
23
28
  const dependencies = {
24
- loglevel: "^1.9.2",
25
- npminstall: "^7.12.0"
29
+ "@electron/get": "^2.0.0",
30
+ "@sentry/node": "^5.5.0",
31
+ "extract-zip": "^2.0.1",
32
+ "live-plugin-manager": "^1.0.0",
33
+ loglevel: "^1.9.2"
34
+ };
35
+ const peerDependencies = {
36
+ playwright: "^1.46.1"
26
37
  };
27
38
  const devDependencies = {
28
39
  esno: "^4.7.0",
40
+ playwright: "^1.46.1",
29
41
  typescript: "^5.5.2",
30
- unbuild: "^2.0.0",
31
- playwright: "^1.46.1"
42
+ unbuild: "^2.0.0"
32
43
  };
33
44
  const packageJson = {
34
45
  name: name,
@@ -42,6 +53,7 @@ const packageJson = {
42
53
  license: license,
43
54
  files: files,
44
55
  dependencies: dependencies,
56
+ peerDependencies: peerDependencies,
45
57
  devDependencies: devDependencies
46
58
  };
47
59
 
@@ -243,7 +255,7 @@ const xiaohongshuPublishAction = async (props) => {
243
255
  await page.getByRole("textbox").click();
244
256
  const fileChooser = await fileChooserPromise;
245
257
  await fileChooser.setFiles(images);
246
- const titleInstance = page.locator(".titleInput input");
258
+ const titleInstance = page.locator(".input.titleInput input");
247
259
  await titleInstance.click();
248
260
  await titleInstance.fill(params.title);
249
261
  const descInstance = page.locator("#post-textarea");
@@ -326,6 +338,117 @@ const xiaohongshuPublishAction = async (props) => {
326
338
  return response;
327
339
  };
328
340
 
341
+ var __defProp$4 = Object.defineProperty;
342
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
343
+ var __publicField$4 = (obj, key, value) => {
344
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
345
+ return value;
346
+ };
347
+ const ELECTRON_MIRROR = "http://npmmirror.com/mirrors/electron/";
348
+ class ElectronInstall {
349
+ constructor(rootDir, version, logger) {
350
+ this.rootDir = rootDir;
351
+ this.version = version;
352
+ this.logger = logger;
353
+ __publicField$4(this, "electronPath");
354
+ __publicField$4(this, "platformPath");
355
+ this.platformPath = this.getPlatformPath();
356
+ this.electronPath = path.join(rootDir, this.platformPath);
357
+ }
358
+ isInstalled() {
359
+ try {
360
+ if (fs.readFileSync(path.join(this.rootDir, "version"), "utf-8").replace(/^v/, "") !== this.version) {
361
+ return false;
362
+ }
363
+ } catch (ignored) {
364
+ return false;
365
+ }
366
+ const electronPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(this.rootDir, this.platformPath);
367
+ return fs.existsSync(electronPath);
368
+ }
369
+ getPlatformPath() {
370
+ const platform = process.env.npm_config_platform || os.platform();
371
+ switch (platform) {
372
+ case "mas":
373
+ case "darwin":
374
+ return "Electron.app/Contents/MacOS/Electron";
375
+ case "freebsd":
376
+ case "openbsd":
377
+ case "linux":
378
+ return "electron";
379
+ case "win32":
380
+ return "electron.exe";
381
+ default:
382
+ throw new Error(
383
+ `Electron builds are not available on platform: ${platform}`
384
+ );
385
+ }
386
+ }
387
+ async install() {
388
+ const installed = this.isInstalled();
389
+ this.logger.info(`electron@${this.version} \u662F\u5426\u5DF2\u5B89\u88C5\uFF1A${installed}`);
390
+ if (installed)
391
+ return this.electronPath;
392
+ const platform = process.env.npm_config_platform || process.platform;
393
+ let arch = process.env.npm_config_arch || process.arch;
394
+ if (platform === "darwin" && process.platform === "darwin" && arch === "x64" && process.env.npm_config_arch === void 0) {
395
+ try {
396
+ const output = childProcess.execSync(
397
+ "sysctl -in sysctl.proc_translated"
398
+ );
399
+ if (output.toString().trim() === "1") {
400
+ arch = "arm64";
401
+ }
402
+ } catch {
403
+ }
404
+ }
405
+ try {
406
+ this.logger.info(`electron@${this.version} \u5F00\u59CB\u4E0B\u8F7D\u8D44\u6E90`);
407
+ const zipPath = await downloadArtifact({
408
+ version: this.version,
409
+ artifactName: "electron",
410
+ force: process.env.force_no_cache === "true",
411
+ cacheRoot: process.env.electron_config_cache,
412
+ checksums: void 0,
413
+ mirrorOptions: { mirror: ELECTRON_MIRROR },
414
+ // 使用国内镜像下载
415
+ platform,
416
+ arch
417
+ });
418
+ this.logger.info(`electron@${this.version} \u5F00\u59CB\u89E3\u538B\u8D44\u6E90`);
419
+ process.noAsar = true;
420
+ await extract(zipPath, { dir: this.rootDir });
421
+ this.logger.info(`electron@${this.version} \u4E0B\u8F7D\u6210\u529F`);
422
+ return this.electronPath;
423
+ } catch (error) {
424
+ this.logger.error(`electron@${this.version} \u4E0B\u8F7D\u5931\u8D25`, error);
425
+ throw error;
426
+ }
427
+ }
428
+ }
429
+
430
+ var __defProp$3 = Object.defineProperty;
431
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
432
+ var __publicField$3 = (obj, key, value) => {
433
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
434
+ return value;
435
+ };
436
+ class SentryInstance {
437
+ constructor(dsn) {
438
+ __publicField$3(this, "sentry");
439
+ if (!dsn)
440
+ return;
441
+ this.sentry = new NodeClient({
442
+ dsn,
443
+ defaultIntegrations: false
444
+ });
445
+ }
446
+ captureException(error) {
447
+ this.sentry?.captureException(error);
448
+ }
449
+ }
450
+ const sentry = new SentryInstance(process.env.RPA_SENTRY_DSN);
451
+
329
452
  var __defProp$2 = Object.defineProperty;
330
453
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
331
454
  var __publicField$2 = (obj, key, value) => {
@@ -344,7 +467,7 @@ const _Logger = class _Logger {
344
467
  log.methodFactory = (methodName) => {
345
468
  return (message) => {
346
469
  this.stream.write(
347
- `[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
470
+ `[${( new Date()).toLocaleString()}] ${methodName.toUpperCase()}: ${message}
348
471
  `
349
472
  );
350
473
  };
@@ -370,12 +493,14 @@ const _Logger = class _Logger {
370
493
  warn(...msg) {
371
494
  log.warn(...msg);
372
495
  }
373
- error(prefix, error) {
374
- log.error(prefix);
375
- if (error instanceof Error) {
376
- log.error(`${error.message}
377
- Error stack: ${error.stack}`);
496
+ // error 级别的日志上报 sentry
497
+ error(prefix, err) {
498
+ const error = err || prefix;
499
+ if (err instanceof Error) {
500
+ err.message = `${prefix}\uFF1A${err.message}`;
378
501
  }
502
+ log.error(error);
503
+ sentry.captureException(error);
379
504
  }
380
505
  close() {
381
506
  this.stream.end();
@@ -400,23 +525,17 @@ const generateFile = async (dir) => {
400
525
  }
401
526
  return filePath;
402
527
  };
403
- const createElectronApp = async (cachePath, playwright) => {
528
+ const launchElectronApp = async (cachePath, playwright, electronPath) => {
404
529
  const logger = Logger.getInstance(cachePath);
405
530
  try {
406
- const executablePath = path.join(
407
- cachePath,
408
- "node_modules",
409
- ".bin",
410
- "electron"
411
- );
412
531
  const mainPath = await generateFile(cachePath);
413
532
  const electronApp = await playwright._electron.launch({
414
- executablePath,
533
+ executablePath: electronPath,
415
534
  // 获取 Electron 可执行文件的路径
416
535
  args: [mainPath],
417
536
  cwd: cachePath
418
537
  });
419
- logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
538
+ logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${electronPath} ${mainPath}`);
420
539
  return electronApp;
421
540
  } catch (error) {
422
541
  logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
@@ -431,8 +550,13 @@ var __publicField$1 = (obj, key, value) => {
431
550
  return value;
432
551
  };
433
552
  const NPM_REGISTRY = "https://registry.npmmirror.com/";
434
- class PackageManager {
553
+ class PackageManager extends PluginManager {
435
554
  constructor(params) {
555
+ super({
556
+ cwd: params.cacheDir,
557
+ pluginsPath: path.join(params.cacheDir, "node_modules"),
558
+ npmRegistryUrl: NPM_REGISTRY
559
+ });
436
560
  __publicField$1(this, "cacheDir");
437
561
  // 依赖安装目录
438
562
  __publicField$1(this, "forceUpdate");
@@ -474,7 +598,6 @@ class PackageManager {
474
598
  try {
475
599
  return require(path.join(pluginDir, module));
476
600
  } catch (error) {
477
- this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
478
601
  return null;
479
602
  }
480
603
  }
@@ -483,27 +606,29 @@ class PackageManager {
483
606
  return this.getPlugin(module);
484
607
  }
485
608
  // 安装依赖
486
- install(name, version) {
487
- return npminstall({
488
- root: this.cacheDir,
489
- pkgs: [{ name, version }],
490
- registry: NPM_REGISTRY
491
- });
609
+ async installPackage(name, version) {
610
+ try {
611
+ this.logger.info(`${name} \u5F00\u59CB\u5B89\u88C5`);
612
+ await this.install(name, version);
613
+ this.logger.info(`${name} \u5B89\u88C5\u6210\u529F`);
614
+ } catch (error) {
615
+ this.logger.error(`${name} \u5B89\u88C5\u5931\u8D25`, error);
616
+ }
492
617
  }
493
618
  async init(name, version) {
494
619
  const plugin = this.getPlugin(path.join(name, "package.json"));
495
620
  this.logger.info(`${name} \u662F\u5426\u5DF2\u5B89\u88C5\uFF1A${!!plugin}`);
496
621
  try {
497
622
  if (!plugin) {
498
- await this.install(name, version);
623
+ await this.installPackage(name, version);
499
624
  } else if (this.forceUpdate) {
500
625
  const pkInfo = await this.getPluginInfo(name);
501
626
  if (!pkInfo)
502
627
  return;
503
628
  const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
504
629
  if (hasNewVersion) {
505
- this.logger.info(`${name} \u68C0\u67E5\u5230\u65B0\u7248\u672C ${pkInfo.version}\uFF0C\u66F4\u65B0\u4F9D\u8D56`);
506
- await this.install(name, pkInfo.version);
630
+ this.logger.info(`${name} \u68C0\u67E5\u5230\u65B0\u7248\u672C ${pkInfo.version}`);
631
+ await this.installPackage(name, pkInfo.version);
507
632
  }
508
633
  }
509
634
  this.logger.info(`${name} package manager init done!`);
@@ -520,6 +645,7 @@ var __publicField = (obj, key, value) => {
520
645
  return value;
521
646
  };
522
647
  const PLAYWRIGHT_VERSION = "1.46.1";
648
+ const PLAYWRIGHT_NAME = "playwright-core";
523
649
  const ELECTRON_VERSION = "22.3.27";
524
650
  class LocalAutomateTask {
525
651
  constructor({ cachePath, debug }) {
@@ -529,6 +655,10 @@ class LocalAutomateTask {
529
655
  __publicField(this, "playwrightPackage");
530
656
  __publicField(this, "electronPackage");
531
657
  __publicField(this, "_electronApp", null);
658
+ /**
659
+ * 应用是否已关闭
660
+ */
661
+ __publicField(this, "isClosed", false);
532
662
  this.cachePath = cachePath;
533
663
  this.debug = debug || false;
534
664
  this.logger = Logger.getInstance(cachePath);
@@ -541,37 +671,40 @@ class LocalAutomateTask {
541
671
  */
542
672
  installPlaywright() {
543
673
  const playwrightPackageManager = new PackageManager({
544
- packageName: "playwright",
674
+ packageName: PLAYWRIGHT_NAME,
545
675
  packageVersion: PLAYWRIGHT_VERSION,
546
676
  cacheDir: this.cachePath,
547
677
  forceUpdate: false
548
678
  });
549
- return playwrightPackageManager.getPluginAfterInit("playwright");
679
+ return playwrightPackageManager.getPluginAfterInit(PLAYWRIGHT_NAME);
550
680
  }
551
681
  /**
552
682
  * 安装 electron
553
683
  * @returns
554
684
  */
555
685
  installElectron() {
556
- const playwrightPackageManager = new PackageManager({
557
- packageName: "electron",
558
- packageVersion: ELECTRON_VERSION,
559
- cacheDir: this.cachePath,
560
- forceUpdate: false
561
- });
562
- return playwrightPackageManager.getPluginAfterInit("electron");
686
+ const electronInstall = new ElectronInstall(
687
+ path.join(this.cachePath, "electron"),
688
+ ELECTRON_VERSION,
689
+ this.logger
690
+ );
691
+ return electronInstall.install();
563
692
  }
564
693
  /**
565
694
  * 启动 Electron
566
695
  * @returns
567
696
  */
568
- async getElectronApp() {
697
+ async launchApp() {
569
698
  if (!this._electronApp) {
570
- const [playwright] = await Promise.all([
699
+ const [playwright, electronPath] = await Promise.all([
571
700
  this.playwrightPackage,
572
701
  this.electronPackage
573
702
  ]);
574
- this._electronApp = await createElectronApp(this.cachePath, playwright);
703
+ this._electronApp = await launchElectronApp(
704
+ this.cachePath,
705
+ playwright,
706
+ electronPath
707
+ );
575
708
  }
576
709
  return this._electronApp;
577
710
  }
@@ -600,16 +733,20 @@ class LocalAutomateTask {
600
733
  * @returns
601
734
  */
602
735
  async close() {
603
- this.logger.close();
736
+ this.logger.info("\u5173\u95ED\u5E94\u7528");
604
737
  this.clearTmpPath();
605
- const electronApp = await this.getElectronApp();
606
- return electronApp.close();
738
+ this.logger.close();
739
+ await this._electronApp?.close();
740
+ this.isClosed = true;
741
+ this._electronApp = null;
607
742
  }
608
743
  /**
609
744
  * 小红书自动化发布
610
745
  */
611
746
  async xiaohongshuPublish(params) {
612
- const electronApp = await this.getElectronApp();
747
+ this.logger.info("\u5F00\u59CB\u5C0F\u7EA2\u4E66\u53D1\u5E03");
748
+ const electronApp = await this.launchApp();
749
+ this.logger.info("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u4E13\u7528\u5BA2\u6237\u7AEF\u5DF2\u542F\u52A8");
613
750
  const commonCookies = {
614
751
  path: "/",
615
752
  sameSite: "lax",
@@ -649,6 +786,7 @@ class LocalAutomateTask {
649
786
  { pageParams }
650
787
  )
651
788
  ]);
789
+ this.logger.info("\u5DF2\u6253\u5F00\u5C0F\u7EA2\u4E66\u53D1\u5E03\u9875\u9762");
652
790
  try {
653
791
  const res = await xiaohongshuPublishAction({
654
792
  page,
@@ -656,6 +794,7 @@ class LocalAutomateTask {
656
794
  tmpCachePath: this.getTmpPath(),
657
795
  debug: !!this.debug
658
796
  });
797
+ this.logger.info(`\u5C0F\u7EA2\u4E66\u53D1\u5E03\u6210\u529F\uFF1A${res}`);
659
798
  return res;
660
799
  } catch (error) {
661
800
  this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
@@ -665,14 +804,17 @@ class LocalAutomateTask {
665
804
  }
666
805
  const RpaTask = (params) => {
667
806
  const logger = Logger.getInstance(params.cachePath);
668
- const packageManager = new PackageManager({
669
- packageName: packageJson.name,
670
- cacheDir: params.cachePath
671
- });
672
- const localPackge = packageManager.getPlugin(packageJson.name);
673
- if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
674
- logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
675
- return new localPackge.LocalAutomateTask(params);
807
+ if (params.forceUpdate) {
808
+ logger.info("\u5C1D\u8BD5\u4F7F\u7528\u8FDC\u7A0B\u6700\u65B0\u7248\u672C");
809
+ const packageManager = new PackageManager({
810
+ packageName: packageJson.name,
811
+ cacheDir: params.cachePath
812
+ });
813
+ const localPackge = packageManager.getPlugin(packageJson.name);
814
+ if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
815
+ logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
816
+ return new localPackge.LocalAutomateTask(params);
817
+ }
676
818
  }
677
819
  return new LocalAutomateTask(params);
678
820
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iflyrpa/playwright",
3
3
  "type": "module",
4
- "version": "1.0.14",
4
+ "version": "1.0.15-beta.1",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
@@ -14,13 +14,19 @@
14
14
  "license": "ISC",
15
15
  "files": ["dist"],
16
16
  "dependencies": {
17
- "loglevel": "^1.9.2",
18
- "npminstall": "^7.12.0"
17
+ "@electron/get": "^2.0.0",
18
+ "@sentry/node": "^5.5.0",
19
+ "extract-zip": "^2.0.1",
20
+ "live-plugin-manager": "^1.0.0",
21
+ "loglevel": "^1.9.2"
22
+ },
23
+ "peerDependencies": {
24
+ "playwright": "^1.46.1"
19
25
  },
20
26
  "devDependencies": {
21
27
  "esno": "^4.7.0",
28
+ "playwright": "^1.46.1",
22
29
  "typescript": "^5.5.2",
23
- "unbuild": "^2.0.0",
24
- "playwright": "^1.46.1"
30
+ "unbuild": "^2.0.0"
25
31
  }
26
32
  }