@iflyrpa/playwright 1.0.9 → 1.0.10-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
@@ -1,20 +1,21 @@
1
1
  'use strict';
2
2
 
3
- const path = require('node:path');
4
3
  const fs = require('node:fs');
4
+ const path = require('node:path');
5
5
  const https = require('node:https');
6
- const electron = require('electron');
6
+ const log = require('loglevel');
7
7
  const node_child_process = require('node:child_process');
8
8
 
9
9
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
10
10
 
11
- const path__default = /*#__PURE__*/_interopDefaultCompat(path);
12
11
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
12
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
13
13
  const https__default = /*#__PURE__*/_interopDefaultCompat(https);
14
+ const log__default = /*#__PURE__*/_interopDefaultCompat(log);
14
15
 
15
16
  const name = "@iflyrpa/playwright";
16
17
  const type = "module";
17
- const version$1 = "1.0.9";
18
+ const version$1 = "1.0.10-beta.1";
18
19
  const description = "";
19
20
  const main = "./dist/index.cjs";
20
21
  const module$1 = "./dist/index.mjs";
@@ -32,6 +33,7 @@ const files = [
32
33
  "dist"
33
34
  ];
34
35
  const dependencies = {
36
+ loglevel: "^1.9.2",
35
37
  playwright: "^1.46.1"
36
38
  };
37
39
  const peerDependencies = {
@@ -219,7 +221,7 @@ const visibleRangeTexts = {
219
221
  private: "\u79C1\u5BC6"
220
222
  };
221
223
  const xiaohongshuPublishAction = async (props) => {
222
- const { page, cachePath, params } = props;
224
+ const { page, tmpCachePath, params } = props;
223
225
  const selectAddress = async (selector, address) => {
224
226
  const instance = typeof selector === "string" ? page.locator(selector) : selector;
225
227
  await instance.click();
@@ -242,11 +244,13 @@ const xiaohongshuPublishAction = async (props) => {
242
244
  await page.locator("#content-area .menu-container .publish-video a").click().catch(() => {
243
245
  throw new Error("\u672A\u627E\u5230\u53D1\u5E03\u7B14\u8BB0\u6309\u94AE");
244
246
  });
245
- await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click();
247
+ await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click().catch(() => {
248
+ throw new Error("\u672A\u627E\u5230\u4E0A\u4F20\u56FE\u6587\u6309\u94AE");
249
+ });
246
250
  const images = await Promise.all(
247
251
  params.banners.map((url) => {
248
252
  const fileName = getFilenameFromUrl(url);
249
- return downloadImage(url, path__default.join(cachePath, "image-tmp", fileName));
253
+ return downloadImage(url, path__default.join(tmpCachePath, fileName));
250
254
  })
251
255
  );
252
256
  const fileChooserPromise = page.waitForEvent("filechooser");
@@ -336,6 +340,64 @@ const xiaohongshuPublishAction = async (props) => {
336
340
  return response;
337
341
  };
338
342
 
343
+ var __defProp$2 = Object.defineProperty;
344
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
345
+ var __publicField$2 = (obj, key, value) => {
346
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
347
+ return value;
348
+ };
349
+ const _Logger = class _Logger {
350
+ constructor(cachePath) {
351
+ __publicField$2(this, "stream");
352
+ if (_Logger.instance) {
353
+ return _Logger.instance;
354
+ }
355
+ const logFile = path__default.join(cachePath, "rpa.log");
356
+ this.stream = fs__default.createWriteStream(logFile, { flags: "a" });
357
+ log__default.setLevel("debug");
358
+ log__default.methodFactory = (methodName) => {
359
+ return (message) => {
360
+ this.stream.write(
361
+ `[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
362
+ `
363
+ );
364
+ };
365
+ };
366
+ log__default.setLevel(log__default.getLevel());
367
+ _Logger.instance = this;
368
+ }
369
+ static getInstance(cachePath) {
370
+ if (!_Logger.instance) {
371
+ _Logger.instance = new _Logger(cachePath);
372
+ }
373
+ return _Logger.instance;
374
+ }
375
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
376
+ debug(...msg) {
377
+ log__default.debug(...msg);
378
+ }
379
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
380
+ info(...msg) {
381
+ log__default.info(...msg);
382
+ }
383
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
384
+ warn(...msg) {
385
+ log__default.warn(...msg);
386
+ }
387
+ error(prefix, error) {
388
+ log__default.error(prefix);
389
+ if (error instanceof Error) {
390
+ log__default.error(`${error.message}
391
+ Error stack: ${error.stack}`);
392
+ }
393
+ }
394
+ close() {
395
+ this.stream.end();
396
+ }
397
+ };
398
+ __publicField$2(_Logger, "instance", null);
399
+ let Logger = _Logger;
400
+
339
401
  const template = `
340
402
  const { app } = require("electron");
341
403
 
@@ -353,14 +415,27 @@ const generateFile = async (dir) => {
353
415
  return filePath;
354
416
  };
355
417
  const createElectronApp = async (cachePath, playwrightPackage) => {
356
- const playwright = await playwrightPackage;
357
- const mainPath = await generateFile(cachePath);
358
- const electronApp = await playwright._electron.launch({
359
- executablePath: electron.app.getPath("exe"),
360
- // 获取 Electron 可执行文件的路径
361
- args: [mainPath]
362
- });
363
- return electronApp;
418
+ const logger = Logger.getInstance(cachePath);
419
+ try {
420
+ const executablePath = path__default.join(
421
+ cachePath,
422
+ "node_modules",
423
+ ".bin",
424
+ "electron"
425
+ );
426
+ const playwright = await playwrightPackage;
427
+ const mainPath = await generateFile(cachePath);
428
+ const electronApp = await playwright._electron.launch({
429
+ executablePath,
430
+ // 获取 Electron 可执行文件的路径
431
+ args: [mainPath],
432
+ cwd: cachePath
433
+ });
434
+ logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
435
+ return electronApp;
436
+ } catch (error) {
437
+ logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
438
+ }
364
439
  };
365
440
 
366
441
  var __defProp$1 = Object.defineProperty;
@@ -376,8 +451,11 @@ class PackageManager {
376
451
  __publicField$1(this, "forceUpdate");
377
452
  // 是否强制更新
378
453
  __publicField$1(this, "initPromise");
454
+ __publicField$1(this, "logger");
455
+ this.logger = Logger.getInstance(params.cacheDir);
379
456
  this.cacheDir = params.cacheDir;
380
457
  this.forceUpdate = params.forceUpdate || true;
458
+ this.initCacheProject();
381
459
  this.initPromise = this.init(params.packageName, params.packageVersion);
382
460
  }
383
461
  // 在子线程执行 npm 命令
@@ -385,7 +463,8 @@ class PackageManager {
385
463
  return new Promise((resolve) => {
386
464
  const args = [cmd].concat(modules).concat("--color=always").concat("--save");
387
465
  try {
388
- const npm = node_child_process.spawn("npm", args, { cwd: where });
466
+ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
467
+ const npm = node_child_process.spawn(npmCmd, args, { cwd: where });
389
468
  let output = "";
390
469
  npm.stdout?.on("data", (data) => {
391
470
  output += data;
@@ -401,11 +480,10 @@ class PackageManager {
401
480
  }
402
481
  });
403
482
  npm.on("error", (err) => {
404
- console.error("NPM is not installed");
405
- console.error(err);
483
+ this.logger.error("npm run error", err);
406
484
  });
407
485
  } catch (error) {
408
- console.error(error);
486
+ this.logger.error(`npm ${args.join(" ")}: `, error);
409
487
  }
410
488
  });
411
489
  }
@@ -413,10 +491,12 @@ class PackageManager {
413
491
  initCacheProject() {
414
492
  const packagePath = path__default.join(this.cacheDir, "package.json");
415
493
  if (!fs__default.existsSync(packagePath)) {
494
+ this.logger.info("package.json \u4E0D\u5B58\u5728\uFF0C\u6DFB\u52A0\u8BE5\u6587\u4EF6");
416
495
  const pkg = {
417
496
  name: "rpa-plugins",
418
497
  description: "rpa-plugins",
419
- license: "MIT"
498
+ license: "MIT",
499
+ main: "./src/main.js"
420
500
  };
421
501
  ensureFileSync(packagePath);
422
502
  fs__default.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
@@ -436,6 +516,7 @@ class PackageManager {
436
516
  try {
437
517
  return require(path__default.join(pluginDir, module));
438
518
  } catch (error) {
519
+ this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
439
520
  return null;
440
521
  }
441
522
  }
@@ -453,20 +534,23 @@ class PackageManager {
453
534
  return this.execCommand("update", [module]);
454
535
  }
455
536
  async init(name, version) {
456
- this.initCacheProject();
457
537
  const plugin = this.getPlugin(path__default.join(name, "package.json"));
458
- if (!plugin) {
459
- await this.install(name, version);
460
- } else if (this.forceUpdate) {
461
- const pkInfo = await this.getPluginInfo(name);
462
- if (!pkInfo)
463
- return;
464
- const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
465
- if (hasNewVersion) {
466
- await this.install(name, pkInfo.version);
538
+ try {
539
+ if (!plugin) {
540
+ await this.install(name, version);
541
+ } else if (this.forceUpdate) {
542
+ const pkInfo = await this.getPluginInfo(name);
543
+ if (!pkInfo)
544
+ return;
545
+ const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
546
+ if (hasNewVersion) {
547
+ await this.install(name, pkInfo.version);
548
+ }
467
549
  }
550
+ this.logger.info(`${name} package manager init done!`);
551
+ } catch (error) {
552
+ this.logger.error(`${name} package manager init error`, error);
468
553
  }
469
- console.log("Package manager init done!");
470
554
  }
471
555
  }
472
556
 
@@ -478,18 +562,16 @@ var __publicField = (obj, key, value) => {
478
562
  };
479
563
  const PLAYWRIGHT_VERSION = "1.46.1";
480
564
  class LocalAutomateTask {
481
- constructor(params) {
565
+ constructor({ cachePath, debug }) {
482
566
  __publicField(this, "cachePath");
483
567
  __publicField(this, "debug");
484
- __publicField(this, "appWhenReady");
485
568
  __publicField(this, "playwrightPackage");
486
- this.cachePath = params.cachePath;
487
- this.debug = params.debug || false;
569
+ __publicField(this, "logger");
570
+ __publicField(this, "_electronApp", null);
571
+ this.cachePath = cachePath;
572
+ this.debug = debug || false;
573
+ this.logger = Logger.getInstance(cachePath);
488
574
  this.playwrightPackage = this.installPlaywright();
489
- this.appWhenReady = createElectronApp(
490
- params.cachePath,
491
- this.playwrightPackage
492
- );
493
575
  }
494
576
  /**
495
577
  * 安装 playwright
@@ -503,19 +585,54 @@ class LocalAutomateTask {
503
585
  });
504
586
  return playwrightPackageManager.getPluginAfterInit("playwright");
505
587
  }
588
+ /**
589
+ * 启动 Electron
590
+ * @returns
591
+ */
592
+ async getElectronApp() {
593
+ if (!this._electronApp) {
594
+ this._electronApp = await createElectronApp(
595
+ this.cachePath,
596
+ this.playwrightPackage
597
+ );
598
+ }
599
+ return this._electronApp;
600
+ }
601
+ /**
602
+ * 临时文件目录
603
+ * @returns
604
+ */
605
+ getTmpPath() {
606
+ return path__default.join(this.cachePath, "tmp");
607
+ }
608
+ /**
609
+ * 清空临时文件
610
+ */
611
+ clearTmpPath() {
612
+ const tmpPath = this.getTmpPath();
613
+ return fs__default.rm(tmpPath, { recursive: true, force: true }, (err) => {
614
+ if (err) {
615
+ this.logger.error("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u5931\u8D25\uFF0C", err);
616
+ } else {
617
+ this.logger.info("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u6210\u529F");
618
+ }
619
+ });
620
+ }
506
621
  /**
507
622
  * 关闭 playwright 启动的 electron 客户端
508
623
  * @returns
509
624
  */
510
625
  async close() {
511
- const electronApp = await this.appWhenReady;
626
+ this.logger.close();
627
+ this.clearTmpPath();
628
+ const electronApp = await this.getElectronApp();
512
629
  return electronApp.close();
513
630
  }
514
631
  /**
515
632
  * 小红书自动化发布
516
633
  */
517
634
  async xiaohongshuPublish(params) {
518
- const electronApp = await this.appWhenReady;
635
+ const electronApp = await this.getElectronApp();
519
636
  const commonCookies = {
520
637
  path: "/",
521
638
  sameSite: "lax",
@@ -555,23 +672,32 @@ class LocalAutomateTask {
555
672
  { pageParams }
556
673
  )
557
674
  ]);
558
- const res = await xiaohongshuPublishAction({
559
- page,
560
- params,
561
- cachePath: this.cachePath,
562
- debug: !!this.debug
563
- });
564
- return res;
675
+ try {
676
+ const res = await xiaohongshuPublishAction({
677
+ page,
678
+ params,
679
+ tmpCachePath: this.getTmpPath(),
680
+ debug: !!this.debug
681
+ });
682
+ return res;
683
+ } catch (error) {
684
+ this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
685
+ throw error;
686
+ }
565
687
  }
566
688
  }
567
689
  const RpaTask = (params) => {
568
- const packageManager = new PackageManager({
569
- packageName: packageJson.name,
570
- cacheDir: params.cachePath
571
- });
572
- const localPackge = packageManager.getPlugin(packageJson.name);
573
- if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
574
- return new localPackge.LocalAutomateTask(params);
690
+ const logger = Logger.getInstance(params.cachePath);
691
+ if (params.forceUpdate) {
692
+ const packageManager = new PackageManager({
693
+ packageName: packageJson.name,
694
+ cacheDir: params.cachePath
695
+ });
696
+ const localPackge = packageManager.getPlugin(packageJson.name);
697
+ if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
698
+ logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
699
+ return new localPackge.LocalAutomateTask(params);
700
+ }
575
701
  }
576
702
  return new LocalAutomateTask(params);
577
703
  };
package/dist/index.d.cts CHANGED
@@ -1,6 +1,17 @@
1
- import { ElectronApplication } from 'playwright';
2
1
  import { CookiesSetDetails } from 'electron';
3
2
 
3
+ declare class Logger {
4
+ static instance: Logger | null;
5
+ private stream;
6
+ constructor(cachePath: string);
7
+ static getInstance(cachePath: string): Logger;
8
+ debug(...msg: any[]): void;
9
+ info(...msg: any[]): void;
10
+ warn(...msg: any[]): void;
11
+ error(prefix: string, error: unknown): void;
12
+ close(): void;
13
+ }
14
+
4
15
  type CookieMap = CookiesSetDetails[];
5
16
 
6
17
  interface FictionalRendition {
@@ -42,18 +53,34 @@ interface XiaohonshuPublishParams
42
53
  interface TaskParams {
43
54
  debug?: boolean;
44
55
  cachePath: string;
56
+ forceUpdate?: boolean;
45
57
  }
46
58
  declare class LocalAutomateTask implements TaskParams {
47
59
  cachePath: string;
48
60
  debug: boolean;
49
- appWhenReady: Promise<ElectronApplication>;
50
61
  playwrightPackage: Promise<unknown>;
51
- constructor(params: TaskParams);
62
+ logger: Logger;
63
+ private _electronApp;
64
+ constructor({ cachePath, debug }: TaskParams);
52
65
  /**
53
66
  * 安装 playwright
54
67
  * @returns
55
68
  */
56
- installPlaywright(): Promise<any>;
69
+ private installPlaywright;
70
+ /**
71
+ * 启动 Electron
72
+ * @returns
73
+ */
74
+ private getElectronApp;
75
+ /**
76
+ * 临时文件目录
77
+ * @returns
78
+ */
79
+ private getTmpPath;
80
+ /**
81
+ * 清空临时文件
82
+ */
83
+ private clearTmpPath;
57
84
  /**
58
85
  * 关闭 playwright 启动的 electron 客户端
59
86
  * @returns
package/dist/index.d.mts CHANGED
@@ -1,6 +1,17 @@
1
- import { ElectronApplication } from 'playwright';
2
1
  import { CookiesSetDetails } from 'electron';
3
2
 
3
+ declare class Logger {
4
+ static instance: Logger | null;
5
+ private stream;
6
+ constructor(cachePath: string);
7
+ static getInstance(cachePath: string): Logger;
8
+ debug(...msg: any[]): void;
9
+ info(...msg: any[]): void;
10
+ warn(...msg: any[]): void;
11
+ error(prefix: string, error: unknown): void;
12
+ close(): void;
13
+ }
14
+
4
15
  type CookieMap = CookiesSetDetails[];
5
16
 
6
17
  interface FictionalRendition {
@@ -42,18 +53,34 @@ interface XiaohonshuPublishParams
42
53
  interface TaskParams {
43
54
  debug?: boolean;
44
55
  cachePath: string;
56
+ forceUpdate?: boolean;
45
57
  }
46
58
  declare class LocalAutomateTask implements TaskParams {
47
59
  cachePath: string;
48
60
  debug: boolean;
49
- appWhenReady: Promise<ElectronApplication>;
50
61
  playwrightPackage: Promise<unknown>;
51
- constructor(params: TaskParams);
62
+ logger: Logger;
63
+ private _electronApp;
64
+ constructor({ cachePath, debug }: TaskParams);
52
65
  /**
53
66
  * 安装 playwright
54
67
  * @returns
55
68
  */
56
- installPlaywright(): Promise<any>;
69
+ private installPlaywright;
70
+ /**
71
+ * 启动 Electron
72
+ * @returns
73
+ */
74
+ private getElectronApp;
75
+ /**
76
+ * 临时文件目录
77
+ * @returns
78
+ */
79
+ private getTmpPath;
80
+ /**
81
+ * 清空临时文件
82
+ */
83
+ private clearTmpPath;
57
84
  /**
58
85
  * 关闭 playwright 启动的 electron 客户端
59
86
  * @returns
package/dist/index.d.ts CHANGED
@@ -1,6 +1,17 @@
1
- import { ElectronApplication } from 'playwright';
2
1
  import { CookiesSetDetails } from 'electron';
3
2
 
3
+ declare class Logger {
4
+ static instance: Logger | null;
5
+ private stream;
6
+ constructor(cachePath: string);
7
+ static getInstance(cachePath: string): Logger;
8
+ debug(...msg: any[]): void;
9
+ info(...msg: any[]): void;
10
+ warn(...msg: any[]): void;
11
+ error(prefix: string, error: unknown): void;
12
+ close(): void;
13
+ }
14
+
4
15
  type CookieMap = CookiesSetDetails[];
5
16
 
6
17
  interface FictionalRendition {
@@ -42,18 +53,34 @@ interface XiaohonshuPublishParams
42
53
  interface TaskParams {
43
54
  debug?: boolean;
44
55
  cachePath: string;
56
+ forceUpdate?: boolean;
45
57
  }
46
58
  declare class LocalAutomateTask implements TaskParams {
47
59
  cachePath: string;
48
60
  debug: boolean;
49
- appWhenReady: Promise<ElectronApplication>;
50
61
  playwrightPackage: Promise<unknown>;
51
- constructor(params: TaskParams);
62
+ logger: Logger;
63
+ private _electronApp;
64
+ constructor({ cachePath, debug }: TaskParams);
52
65
  /**
53
66
  * 安装 playwright
54
67
  * @returns
55
68
  */
56
- installPlaywright(): Promise<any>;
69
+ private installPlaywright;
70
+ /**
71
+ * 启动 Electron
72
+ * @returns
73
+ */
74
+ private getElectronApp;
75
+ /**
76
+ * 临时文件目录
77
+ * @returns
78
+ */
79
+ private getTmpPath;
80
+ /**
81
+ * 清空临时文件
82
+ */
83
+ private clearTmpPath;
57
84
  /**
58
85
  * 关闭 playwright 启动的 electron 客户端
59
86
  * @returns
package/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
- import path from 'node:path';
2
1
  import fs from 'node:fs';
2
+ import path from 'node:path';
3
3
  import https from 'node:https';
4
- import { app } from 'electron';
4
+ import log from 'loglevel';
5
5
  import { spawn } from 'node:child_process';
6
6
 
7
7
  const name = "@iflyrpa/playwright";
8
8
  const type = "module";
9
- const version$1 = "1.0.9";
9
+ const version$1 = "1.0.10-beta.1";
10
10
  const description = "";
11
11
  const main = "./dist/index.cjs";
12
12
  const module = "./dist/index.mjs";
@@ -24,6 +24,7 @@ const files = [
24
24
  "dist"
25
25
  ];
26
26
  const dependencies = {
27
+ loglevel: "^1.9.2",
27
28
  playwright: "^1.46.1"
28
29
  };
29
30
  const peerDependencies = {
@@ -211,7 +212,7 @@ const visibleRangeTexts = {
211
212
  private: "\u79C1\u5BC6"
212
213
  };
213
214
  const xiaohongshuPublishAction = async (props) => {
214
- const { page, cachePath, params } = props;
215
+ const { page, tmpCachePath, params } = props;
215
216
  const selectAddress = async (selector, address) => {
216
217
  const instance = typeof selector === "string" ? page.locator(selector) : selector;
217
218
  await instance.click();
@@ -234,11 +235,13 @@ const xiaohongshuPublishAction = async (props) => {
234
235
  await page.locator("#content-area .menu-container .publish-video a").click().catch(() => {
235
236
  throw new Error("\u672A\u627E\u5230\u53D1\u5E03\u7B14\u8BB0\u6309\u94AE");
236
237
  });
237
- await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click();
238
+ await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click().catch(() => {
239
+ throw new Error("\u672A\u627E\u5230\u4E0A\u4F20\u56FE\u6587\u6309\u94AE");
240
+ });
238
241
  const images = await Promise.all(
239
242
  params.banners.map((url) => {
240
243
  const fileName = getFilenameFromUrl(url);
241
- return downloadImage(url, path.join(cachePath, "image-tmp", fileName));
244
+ return downloadImage(url, path.join(tmpCachePath, fileName));
242
245
  })
243
246
  );
244
247
  const fileChooserPromise = page.waitForEvent("filechooser");
@@ -328,6 +331,64 @@ const xiaohongshuPublishAction = async (props) => {
328
331
  return response;
329
332
  };
330
333
 
334
+ var __defProp$2 = Object.defineProperty;
335
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
336
+ var __publicField$2 = (obj, key, value) => {
337
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
338
+ return value;
339
+ };
340
+ const _Logger = class _Logger {
341
+ constructor(cachePath) {
342
+ __publicField$2(this, "stream");
343
+ if (_Logger.instance) {
344
+ return _Logger.instance;
345
+ }
346
+ const logFile = path.join(cachePath, "rpa.log");
347
+ this.stream = fs.createWriteStream(logFile, { flags: "a" });
348
+ log.setLevel("debug");
349
+ log.methodFactory = (methodName) => {
350
+ return (message) => {
351
+ this.stream.write(
352
+ `[${( new Date()).toISOString()}] ${methodName.toUpperCase()}: ${message}
353
+ `
354
+ );
355
+ };
356
+ };
357
+ log.setLevel(log.getLevel());
358
+ _Logger.instance = this;
359
+ }
360
+ static getInstance(cachePath) {
361
+ if (!_Logger.instance) {
362
+ _Logger.instance = new _Logger(cachePath);
363
+ }
364
+ return _Logger.instance;
365
+ }
366
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
367
+ debug(...msg) {
368
+ log.debug(...msg);
369
+ }
370
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
371
+ info(...msg) {
372
+ log.info(...msg);
373
+ }
374
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
375
+ warn(...msg) {
376
+ log.warn(...msg);
377
+ }
378
+ error(prefix, error) {
379
+ log.error(prefix);
380
+ if (error instanceof Error) {
381
+ log.error(`${error.message}
382
+ Error stack: ${error.stack}`);
383
+ }
384
+ }
385
+ close() {
386
+ this.stream.end();
387
+ }
388
+ };
389
+ __publicField$2(_Logger, "instance", null);
390
+ let Logger = _Logger;
391
+
331
392
  const template = `
332
393
  const { app } = require("electron");
333
394
 
@@ -345,14 +406,27 @@ const generateFile = async (dir) => {
345
406
  return filePath;
346
407
  };
347
408
  const createElectronApp = async (cachePath, playwrightPackage) => {
348
- const playwright = await playwrightPackage;
349
- const mainPath = await generateFile(cachePath);
350
- const electronApp = await playwright._electron.launch({
351
- executablePath: app.getPath("exe"),
352
- // 获取 Electron 可执行文件的路径
353
- args: [mainPath]
354
- });
355
- return electronApp;
409
+ const logger = Logger.getInstance(cachePath);
410
+ try {
411
+ const executablePath = path.join(
412
+ cachePath,
413
+ "node_modules",
414
+ ".bin",
415
+ "electron"
416
+ );
417
+ const playwright = await playwrightPackage;
418
+ const mainPath = await generateFile(cachePath);
419
+ const electronApp = await playwright._electron.launch({
420
+ executablePath,
421
+ // 获取 Electron 可执行文件的路径
422
+ args: [mainPath],
423
+ cwd: cachePath
424
+ });
425
+ logger.info(`electron \u542F\u52A8\u6210\u529F\uFF1A${executablePath} ${mainPath}`);
426
+ return electronApp;
427
+ } catch (error) {
428
+ logger.error("electron \u542F\u52A8\u5931\u8D25\uFF1A", error);
429
+ }
356
430
  };
357
431
 
358
432
  var __defProp$1 = Object.defineProperty;
@@ -368,8 +442,11 @@ class PackageManager {
368
442
  __publicField$1(this, "forceUpdate");
369
443
  // 是否强制更新
370
444
  __publicField$1(this, "initPromise");
445
+ __publicField$1(this, "logger");
446
+ this.logger = Logger.getInstance(params.cacheDir);
371
447
  this.cacheDir = params.cacheDir;
372
448
  this.forceUpdate = params.forceUpdate || true;
449
+ this.initCacheProject();
373
450
  this.initPromise = this.init(params.packageName, params.packageVersion);
374
451
  }
375
452
  // 在子线程执行 npm 命令
@@ -377,7 +454,8 @@ class PackageManager {
377
454
  return new Promise((resolve) => {
378
455
  const args = [cmd].concat(modules).concat("--color=always").concat("--save");
379
456
  try {
380
- const npm = spawn("npm", args, { cwd: where });
457
+ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
458
+ const npm = spawn(npmCmd, args, { cwd: where });
381
459
  let output = "";
382
460
  npm.stdout?.on("data", (data) => {
383
461
  output += data;
@@ -393,11 +471,10 @@ class PackageManager {
393
471
  }
394
472
  });
395
473
  npm.on("error", (err) => {
396
- console.error("NPM is not installed");
397
- console.error(err);
474
+ this.logger.error("npm run error", err);
398
475
  });
399
476
  } catch (error) {
400
- console.error(error);
477
+ this.logger.error(`npm ${args.join(" ")}: `, error);
401
478
  }
402
479
  });
403
480
  }
@@ -405,10 +482,12 @@ class PackageManager {
405
482
  initCacheProject() {
406
483
  const packagePath = path.join(this.cacheDir, "package.json");
407
484
  if (!fs.existsSync(packagePath)) {
485
+ this.logger.info("package.json \u4E0D\u5B58\u5728\uFF0C\u6DFB\u52A0\u8BE5\u6587\u4EF6");
408
486
  const pkg = {
409
487
  name: "rpa-plugins",
410
488
  description: "rpa-plugins",
411
- license: "MIT"
489
+ license: "MIT",
490
+ main: "./src/main.js"
412
491
  };
413
492
  ensureFileSync(packagePath);
414
493
  fs.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
@@ -428,6 +507,7 @@ class PackageManager {
428
507
  try {
429
508
  return require(path.join(pluginDir, module));
430
509
  } catch (error) {
510
+ this.logger.warn(`${module}\u672C\u5730\u4F9D\u8D56\u4E0D\u5B58\u5728\uFF0C${pluginDir}`);
431
511
  return null;
432
512
  }
433
513
  }
@@ -445,20 +525,23 @@ class PackageManager {
445
525
  return this.execCommand("update", [module]);
446
526
  }
447
527
  async init(name, version) {
448
- this.initCacheProject();
449
528
  const plugin = this.getPlugin(path.join(name, "package.json"));
450
- if (!plugin) {
451
- await this.install(name, version);
452
- } else if (this.forceUpdate) {
453
- const pkInfo = await this.getPluginInfo(name);
454
- if (!pkInfo)
455
- return;
456
- const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
457
- if (hasNewVersion) {
458
- await this.install(name, pkInfo.version);
529
+ try {
530
+ if (!plugin) {
531
+ await this.install(name, version);
532
+ } else if (this.forceUpdate) {
533
+ const pkInfo = await this.getPluginInfo(name);
534
+ if (!pkInfo)
535
+ return;
536
+ const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
537
+ if (hasNewVersion) {
538
+ await this.install(name, pkInfo.version);
539
+ }
459
540
  }
541
+ this.logger.info(`${name} package manager init done!`);
542
+ } catch (error) {
543
+ this.logger.error(`${name} package manager init error`, error);
460
544
  }
461
- console.log("Package manager init done!");
462
545
  }
463
546
  }
464
547
 
@@ -470,18 +553,16 @@ var __publicField = (obj, key, value) => {
470
553
  };
471
554
  const PLAYWRIGHT_VERSION = "1.46.1";
472
555
  class LocalAutomateTask {
473
- constructor(params) {
556
+ constructor({ cachePath, debug }) {
474
557
  __publicField(this, "cachePath");
475
558
  __publicField(this, "debug");
476
- __publicField(this, "appWhenReady");
477
559
  __publicField(this, "playwrightPackage");
478
- this.cachePath = params.cachePath;
479
- this.debug = params.debug || false;
560
+ __publicField(this, "logger");
561
+ __publicField(this, "_electronApp", null);
562
+ this.cachePath = cachePath;
563
+ this.debug = debug || false;
564
+ this.logger = Logger.getInstance(cachePath);
480
565
  this.playwrightPackage = this.installPlaywright();
481
- this.appWhenReady = createElectronApp(
482
- params.cachePath,
483
- this.playwrightPackage
484
- );
485
566
  }
486
567
  /**
487
568
  * 安装 playwright
@@ -495,19 +576,54 @@ class LocalAutomateTask {
495
576
  });
496
577
  return playwrightPackageManager.getPluginAfterInit("playwright");
497
578
  }
579
+ /**
580
+ * 启动 Electron
581
+ * @returns
582
+ */
583
+ async getElectronApp() {
584
+ if (!this._electronApp) {
585
+ this._electronApp = await createElectronApp(
586
+ this.cachePath,
587
+ this.playwrightPackage
588
+ );
589
+ }
590
+ return this._electronApp;
591
+ }
592
+ /**
593
+ * 临时文件目录
594
+ * @returns
595
+ */
596
+ getTmpPath() {
597
+ return path.join(this.cachePath, "tmp");
598
+ }
599
+ /**
600
+ * 清空临时文件
601
+ */
602
+ clearTmpPath() {
603
+ const tmpPath = this.getTmpPath();
604
+ return fs.rm(tmpPath, { recursive: true, force: true }, (err) => {
605
+ if (err) {
606
+ this.logger.error("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u5931\u8D25\uFF0C", err);
607
+ } else {
608
+ this.logger.info("\u5220\u9664\u4E34\u65F6\u6587\u4EF6\u6210\u529F");
609
+ }
610
+ });
611
+ }
498
612
  /**
499
613
  * 关闭 playwright 启动的 electron 客户端
500
614
  * @returns
501
615
  */
502
616
  async close() {
503
- const electronApp = await this.appWhenReady;
617
+ this.logger.close();
618
+ this.clearTmpPath();
619
+ const electronApp = await this.getElectronApp();
504
620
  return electronApp.close();
505
621
  }
506
622
  /**
507
623
  * 小红书自动化发布
508
624
  */
509
625
  async xiaohongshuPublish(params) {
510
- const electronApp = await this.appWhenReady;
626
+ const electronApp = await this.getElectronApp();
511
627
  const commonCookies = {
512
628
  path: "/",
513
629
  sameSite: "lax",
@@ -547,23 +663,32 @@ class LocalAutomateTask {
547
663
  { pageParams }
548
664
  )
549
665
  ]);
550
- const res = await xiaohongshuPublishAction({
551
- page,
552
- params,
553
- cachePath: this.cachePath,
554
- debug: !!this.debug
555
- });
556
- return res;
666
+ try {
667
+ const res = await xiaohongshuPublishAction({
668
+ page,
669
+ params,
670
+ tmpCachePath: this.getTmpPath(),
671
+ debug: !!this.debug
672
+ });
673
+ return res;
674
+ } catch (error) {
675
+ this.logger.error("\u5C0F\u7EA2\u4E66\u53D1\u5E03\u5931\u8D25", error);
676
+ throw error;
677
+ }
557
678
  }
558
679
  }
559
680
  const RpaTask = (params) => {
560
- const packageManager = new PackageManager({
561
- packageName: packageJson.name,
562
- cacheDir: params.cachePath
563
- });
564
- const localPackge = packageManager.getPlugin(packageJson.name);
565
- if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
566
- return new localPackge.LocalAutomateTask(params);
681
+ const logger = Logger.getInstance(params.cachePath);
682
+ if (params.forceUpdate) {
683
+ const packageManager = new PackageManager({
684
+ packageName: packageJson.name,
685
+ cacheDir: params.cachePath
686
+ });
687
+ const localPackge = packageManager.getPlugin(packageJson.name);
688
+ if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
689
+ logger.info(`\u4F7F\u7528\u8FDC\u7A0B\u7684\u65B0\u7248\u672C\uFF0C\u7248\u672C\u53F7\u4E3A\uFF1A${localPackge.version}`);
690
+ return new localPackge.LocalAutomateTask(params);
691
+ }
567
692
  }
568
693
  return new LocalAutomateTask(params);
569
694
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iflyrpa/playwright",
3
3
  "type": "module",
4
- "version": "1.0.9",
4
+ "version": "1.0.10-beta.1",
5
5
  "description": "",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.mjs",
@@ -16,6 +16,7 @@
16
16
  "license": "ISC",
17
17
  "files": ["dist"],
18
18
  "dependencies": {
19
+ "loglevel": "^1.9.2",
19
20
  "playwright": "^1.46.1"
20
21
  },
21
22
  "peerDependencies": {