@iflyrpa/playwright 1.0.7 → 1.0.9
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 +221 -71
- package/dist/index.d.cts +6 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +218 -66
- package/package.json +2 -12
package/dist/index.cjs
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const semver = require('semver');
|
|
4
3
|
const path = require('node:path');
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const https = require('node:https');
|
|
7
6
|
const electron = require('electron');
|
|
8
|
-
const
|
|
9
|
-
const spawn = require('cross-spawn');
|
|
7
|
+
const node_child_process = require('node:child_process');
|
|
10
8
|
|
|
11
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
12
10
|
|
|
13
|
-
const semver__default = /*#__PURE__*/_interopDefaultCompat(semver);
|
|
14
11
|
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
15
|
-
const axios__default = /*#__PURE__*/_interopDefaultCompat(axios);
|
|
16
12
|
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
17
|
-
const
|
|
13
|
+
const https__default = /*#__PURE__*/_interopDefaultCompat(https);
|
|
18
14
|
|
|
19
15
|
const name = "@iflyrpa/playwright";
|
|
20
16
|
const type = "module";
|
|
21
|
-
const version$1 = "1.0.
|
|
17
|
+
const version$1 = "1.0.9";
|
|
22
18
|
const description = "";
|
|
23
19
|
const main = "./dist/index.cjs";
|
|
24
20
|
const module$1 = "./dist/index.mjs";
|
|
@@ -36,23 +32,13 @@ const files = [
|
|
|
36
32
|
"dist"
|
|
37
33
|
];
|
|
38
34
|
const dependencies = {
|
|
39
|
-
|
|
40
|
-
"cross-spawn": "^7.0.3",
|
|
41
|
-
deepmerge: "^4.3.1",
|
|
42
|
-
"fs-extra": "^11.2.0",
|
|
43
|
-
playwright: "^1.46.1",
|
|
44
|
-
semver: "^7.6.3"
|
|
35
|
+
playwright: "^1.46.1"
|
|
45
36
|
};
|
|
46
37
|
const peerDependencies = {
|
|
47
38
|
electron: "*"
|
|
48
39
|
};
|
|
49
40
|
const devDependencies = {
|
|
50
|
-
"@types/cross-spawn": "^6.0.6",
|
|
51
|
-
"@types/fs-extra": "^11.0.4",
|
|
52
|
-
"@types/semver": "^7.5.8",
|
|
53
|
-
bumpp: "^9.5.2",
|
|
54
41
|
esno: "^4.7.0",
|
|
55
|
-
"ts-node": "^10.9.2",
|
|
56
42
|
typescript: "^5.5.2",
|
|
57
43
|
unbuild: "^2.0.0"
|
|
58
44
|
};
|
|
@@ -74,25 +60,159 @@ const packageJson = {
|
|
|
74
60
|
devDependencies: devDependencies
|
|
75
61
|
};
|
|
76
62
|
|
|
77
|
-
async function downloadImage(url,
|
|
78
|
-
|
|
79
|
-
url,
|
|
80
|
-
method: "GET",
|
|
81
|
-
responseType: "stream"
|
|
82
|
-
// 重要:设置响应类型为 'stream'
|
|
83
|
-
});
|
|
84
|
-
await fs__default.ensureFile(path2);
|
|
85
|
-
const writer = fs__default.createWriteStream(path2);
|
|
86
|
-
response.data.pipe(writer);
|
|
63
|
+
async function downloadImage(url, savePath) {
|
|
64
|
+
await ensureFile(savePath);
|
|
87
65
|
return new Promise((resolve, reject) => {
|
|
88
|
-
|
|
89
|
-
|
|
66
|
+
https__default.get(url, (response) => {
|
|
67
|
+
if (response.statusCode === 200) {
|
|
68
|
+
const fileStream = fs__default.createWriteStream(savePath);
|
|
69
|
+
response.pipe(fileStream);
|
|
70
|
+
fileStream.on("finish", () => {
|
|
71
|
+
fileStream.close();
|
|
72
|
+
console.log("\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u6587\u4EF6\u5DF2\u4FDD\u5B58\u81F3:", savePath);
|
|
73
|
+
resolve(savePath);
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
console.log("\u56FE\u7247\u4E0B\u8F7D\u5931\u8D25:", response.statusCode);
|
|
77
|
+
response.resume();
|
|
78
|
+
reject();
|
|
79
|
+
}
|
|
80
|
+
}).on("error", (error) => {
|
|
81
|
+
console.error("\u8BF7\u6C42\u56FE\u7247\u65F6\u53D1\u751F\u9519\u8BEF:", error.message);
|
|
82
|
+
reject();
|
|
83
|
+
});
|
|
90
84
|
});
|
|
91
85
|
}
|
|
92
86
|
function getFilenameFromUrl(imageUrl) {
|
|
93
87
|
const parsedUrl = new URL(imageUrl);
|
|
94
88
|
return path__default.basename(parsedUrl.pathname);
|
|
95
89
|
}
|
|
90
|
+
function pathExists(path2) {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
fs__default.stat(path2, (err) => {
|
|
93
|
+
resolve(!err);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function ensureFile(filePath) {
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
const dirPath = path__default.dirname(filePath);
|
|
100
|
+
fs__default.stat(dirPath, (err, stats) => {
|
|
101
|
+
if (err) {
|
|
102
|
+
if (err.code === "ENOENT") {
|
|
103
|
+
fs__default.mkdir(dirPath, { recursive: true }, (err2) => {
|
|
104
|
+
if (err2) {
|
|
105
|
+
return reject(err2);
|
|
106
|
+
}
|
|
107
|
+
createFile();
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
return reject(err);
|
|
111
|
+
}
|
|
112
|
+
} else if (stats.isDirectory()) {
|
|
113
|
+
checkFile();
|
|
114
|
+
} else {
|
|
115
|
+
reject(new Error(`${dirPath} is not a directory`));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
function checkFile() {
|
|
119
|
+
fs__default.stat(filePath, (err, stats) => {
|
|
120
|
+
if (err) {
|
|
121
|
+
if (err.code === "ENOENT") {
|
|
122
|
+
createFile();
|
|
123
|
+
} else {
|
|
124
|
+
reject(err);
|
|
125
|
+
}
|
|
126
|
+
} else if (stats.isFile()) {
|
|
127
|
+
resolve();
|
|
128
|
+
} else {
|
|
129
|
+
reject(new Error(`${filePath} is not a file`));
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function createFile() {
|
|
134
|
+
fs__default.writeFile(filePath, "", (err) => {
|
|
135
|
+
if (err) {
|
|
136
|
+
reject(err);
|
|
137
|
+
} else {
|
|
138
|
+
resolve();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function ensureFileSync(filePath) {
|
|
145
|
+
const dirPath = path__default.dirname(filePath);
|
|
146
|
+
try {
|
|
147
|
+
if (!fs__default.existsSync(dirPath)) {
|
|
148
|
+
fs__default.mkdirSync(dirPath, { recursive: true });
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
if (err instanceof Error) {
|
|
152
|
+
throw new Error(`Error creating directory: ${err.message}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
if (!fs__default.existsSync(filePath)) {
|
|
157
|
+
fs__default.writeFileSync(filePath, "");
|
|
158
|
+
}
|
|
159
|
+
} catch (err) {
|
|
160
|
+
if (err instanceof Error) {
|
|
161
|
+
throw new Error(`Error creating file: ${err.message}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function writeFile(filePath, data) {
|
|
166
|
+
return new Promise((resolve, reject) => {
|
|
167
|
+
fs__default.writeFile(filePath, data, (err) => {
|
|
168
|
+
if (err) {
|
|
169
|
+
console.error("Error writing file:", err);
|
|
170
|
+
reject();
|
|
171
|
+
} else {
|
|
172
|
+
console.log("File written successfully");
|
|
173
|
+
resolve();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function compareVersions(v1, v2) {
|
|
179
|
+
const parts1 = v1.split(".").map(Number);
|
|
180
|
+
const parts2 = v2.split(".").map(Number);
|
|
181
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
182
|
+
const num1 = i < parts1.length ? parts1[i] : 0;
|
|
183
|
+
const num2 = i < parts2.length ? parts2[i] : 0;
|
|
184
|
+
if (num1 > num2)
|
|
185
|
+
return 1;
|
|
186
|
+
if (num1 < num2)
|
|
187
|
+
return -1;
|
|
188
|
+
}
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
const semver = {
|
|
192
|
+
gt: (v1, v2) => compareVersions(v1, v2) === 1
|
|
193
|
+
};
|
|
194
|
+
function fetchJSON(url) {
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
https__default.get(url, (res) => {
|
|
197
|
+
let data = "";
|
|
198
|
+
res.on("data", (chunk) => {
|
|
199
|
+
data += chunk;
|
|
200
|
+
});
|
|
201
|
+
res.on("end", () => {
|
|
202
|
+
try {
|
|
203
|
+
const parsedData = JSON.parse(data);
|
|
204
|
+
resolve(parsedData);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
if (e instanceof Error) {
|
|
207
|
+
reject(new Error(`Error parsing JSON: ${e.message}`));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}).on("error", (err) => {
|
|
212
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
}
|
|
96
216
|
|
|
97
217
|
const visibleRangeTexts = {
|
|
98
218
|
public: "\u516C\u5F00",
|
|
@@ -103,9 +223,9 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
103
223
|
const selectAddress = async (selector, address) => {
|
|
104
224
|
const instance = typeof selector === "string" ? page.locator(selector) : selector;
|
|
105
225
|
await instance.click();
|
|
106
|
-
await instance.fill(address);
|
|
226
|
+
await instance.locator("input").fill(address);
|
|
107
227
|
const poperInstance = page.locator(
|
|
108
|
-
|
|
228
|
+
'.d-popover:not([style*="display: none"]) .d-options .d-grid-item'
|
|
109
229
|
);
|
|
110
230
|
await poperInstance.first().waitFor();
|
|
111
231
|
await poperInstance.first().click();
|
|
@@ -116,8 +236,12 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
116
236
|
await instance.fill(date);
|
|
117
237
|
await instance.blur();
|
|
118
238
|
};
|
|
119
|
-
await page.waitForSelector("#CreatorPlatform", { state: "visible" })
|
|
120
|
-
|
|
239
|
+
await page.waitForSelector("#CreatorPlatform", { state: "visible" }).catch(() => {
|
|
240
|
+
throw new Error("\u767B\u5F55\u5931\u8D25");
|
|
241
|
+
});
|
|
242
|
+
await page.locator("#content-area .menu-container .publish-video a").click().catch(() => {
|
|
243
|
+
throw new Error("\u672A\u627E\u5230\u53D1\u5E03\u7B14\u8BB0\u6309\u94AE");
|
|
244
|
+
});
|
|
121
245
|
await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click();
|
|
122
246
|
const images = await Promise.all(
|
|
123
247
|
params.banners.map((url) => {
|
|
@@ -140,7 +264,7 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
140
264
|
await page.mouse.wheel(0, 500);
|
|
141
265
|
if (params.address) {
|
|
142
266
|
await selectAddress(
|
|
143
|
-
".media-extension .address-input
|
|
267
|
+
page.locator(".media-extension .address-input").filter({ hasText: "\u6DFB\u52A0\u5730\u70B9" }),
|
|
144
268
|
params.address
|
|
145
269
|
);
|
|
146
270
|
}
|
|
@@ -167,7 +291,7 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
167
291
|
const hasCustomContent = shootingDate || shootingLocation;
|
|
168
292
|
if (shootingLocation) {
|
|
169
293
|
await selectAddress(
|
|
170
|
-
selfShootingPopup.locator(".address-input
|
|
294
|
+
selfShootingPopup.locator(".address-input"),
|
|
171
295
|
shootingLocation
|
|
172
296
|
);
|
|
173
297
|
}
|
|
@@ -221,14 +345,15 @@ app.on("window-all-closed", (e) => e.preventDefault());
|
|
|
221
345
|
`;
|
|
222
346
|
const generateFile = async (dir) => {
|
|
223
347
|
const filePath = path__default.join(dir, "src", "main.js");
|
|
224
|
-
const
|
|
225
|
-
if (!
|
|
226
|
-
await
|
|
227
|
-
await
|
|
348
|
+
const isPathExists = await pathExists(filePath);
|
|
349
|
+
if (!isPathExists) {
|
|
350
|
+
await ensureFile(filePath);
|
|
351
|
+
await writeFile(filePath, template);
|
|
228
352
|
}
|
|
229
353
|
return filePath;
|
|
230
354
|
};
|
|
231
|
-
const createElectronApp = async (cachePath) => {
|
|
355
|
+
const createElectronApp = async (cachePath, playwrightPackage) => {
|
|
356
|
+
const playwright = await playwrightPackage;
|
|
232
357
|
const mainPath = await generateFile(cachePath);
|
|
233
358
|
const electronApp = await playwright._electron.launch({
|
|
234
359
|
executablePath: electron.app.getPath("exe"),
|
|
@@ -245,21 +370,22 @@ var __publicField$1 = (obj, key, value) => {
|
|
|
245
370
|
return value;
|
|
246
371
|
};
|
|
247
372
|
class PackageManager {
|
|
248
|
-
|
|
249
|
-
constructor(packageName, cacheDir) {
|
|
373
|
+
constructor(params) {
|
|
250
374
|
__publicField$1(this, "cacheDir");
|
|
251
375
|
// 依赖安装目录
|
|
252
|
-
__publicField$1(this, "
|
|
253
|
-
|
|
254
|
-
this
|
|
255
|
-
this.
|
|
376
|
+
__publicField$1(this, "forceUpdate");
|
|
377
|
+
// 是否强制更新
|
|
378
|
+
__publicField$1(this, "initPromise");
|
|
379
|
+
this.cacheDir = params.cacheDir;
|
|
380
|
+
this.forceUpdate = params.forceUpdate || true;
|
|
381
|
+
this.initPromise = this.init(params.packageName, params.packageVersion);
|
|
256
382
|
}
|
|
257
383
|
// 在子线程执行 npm 命令
|
|
258
384
|
execCommand(cmd, modules, where = this.cacheDir) {
|
|
259
385
|
return new Promise((resolve) => {
|
|
260
386
|
const args = [cmd].concat(modules).concat("--color=always").concat("--save");
|
|
261
387
|
try {
|
|
262
|
-
const npm =
|
|
388
|
+
const npm = node_child_process.spawn("npm", args, { cwd: where });
|
|
263
389
|
let output = "";
|
|
264
390
|
npm.stdout?.on("data", (data) => {
|
|
265
391
|
output += data;
|
|
@@ -284,7 +410,7 @@ class PackageManager {
|
|
|
284
410
|
});
|
|
285
411
|
}
|
|
286
412
|
// 构建 package.json 文件,有了该文件后,依赖可以安装在该目录下,避免污染全局环境
|
|
287
|
-
|
|
413
|
+
initCacheProject() {
|
|
288
414
|
const packagePath = path__default.join(this.cacheDir, "package.json");
|
|
289
415
|
if (!fs__default.existsSync(packagePath)) {
|
|
290
416
|
const pkg = {
|
|
@@ -292,18 +418,16 @@ class PackageManager {
|
|
|
292
418
|
description: "rpa-plugins",
|
|
293
419
|
license: "MIT"
|
|
294
420
|
};
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
fs__default.writeFile(packagePath, JSON.stringify(pkg), "utf8")
|
|
298
|
-
]);
|
|
421
|
+
ensureFileSync(packagePath);
|
|
422
|
+
fs__default.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
|
|
299
423
|
}
|
|
300
424
|
}
|
|
301
425
|
// 获取依赖信息
|
|
302
426
|
async getPluginInfo(module) {
|
|
303
|
-
const res = await
|
|
427
|
+
const res = await fetchJSON(
|
|
304
428
|
`https://registry.npmjs.com/-/v1/search?text=${module}`
|
|
305
429
|
);
|
|
306
|
-
const packages = res.
|
|
430
|
+
const packages = res.objects;
|
|
307
431
|
return packages.find((it) => it.package.name === module)?.package;
|
|
308
432
|
}
|
|
309
433
|
// 查询本地安装的依赖
|
|
@@ -315,26 +439,31 @@ class PackageManager {
|
|
|
315
439
|
return null;
|
|
316
440
|
}
|
|
317
441
|
}
|
|
442
|
+
async getPluginAfterInit(module) {
|
|
443
|
+
await this.initPromise;
|
|
444
|
+
return this.getPlugin(module);
|
|
445
|
+
}
|
|
318
446
|
// 安装依赖
|
|
319
|
-
install(module) {
|
|
320
|
-
|
|
447
|
+
install(module, version) {
|
|
448
|
+
const moduleName = version ? `${module}@${version}` : module;
|
|
449
|
+
return this.execCommand("install", [moduleName]);
|
|
321
450
|
}
|
|
322
451
|
// 更新依赖
|
|
323
452
|
update(module) {
|
|
324
453
|
return this.execCommand("update", [module]);
|
|
325
454
|
}
|
|
326
|
-
async init() {
|
|
327
|
-
|
|
328
|
-
const plugin = this.getPlugin(path__default.join(
|
|
455
|
+
async init(name, version) {
|
|
456
|
+
this.initCacheProject();
|
|
457
|
+
const plugin = this.getPlugin(path__default.join(name, "package.json"));
|
|
329
458
|
if (!plugin) {
|
|
330
|
-
await this.install(
|
|
331
|
-
} else {
|
|
332
|
-
const pkInfo = await this.getPluginInfo(
|
|
459
|
+
await this.install(name, version);
|
|
460
|
+
} else if (this.forceUpdate) {
|
|
461
|
+
const pkInfo = await this.getPluginInfo(name);
|
|
333
462
|
if (!pkInfo)
|
|
334
|
-
|
|
335
|
-
const hasNewVersion =
|
|
463
|
+
return;
|
|
464
|
+
const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
|
|
336
465
|
if (hasNewVersion) {
|
|
337
|
-
await this.install(
|
|
466
|
+
await this.install(name, pkInfo.version);
|
|
338
467
|
}
|
|
339
468
|
}
|
|
340
469
|
console.log("Package manager init done!");
|
|
@@ -347,14 +476,32 @@ var __publicField = (obj, key, value) => {
|
|
|
347
476
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
348
477
|
return value;
|
|
349
478
|
};
|
|
479
|
+
const PLAYWRIGHT_VERSION = "1.46.1";
|
|
350
480
|
class LocalAutomateTask {
|
|
351
481
|
constructor(params) {
|
|
352
482
|
__publicField(this, "cachePath");
|
|
353
483
|
__publicField(this, "debug");
|
|
354
484
|
__publicField(this, "appWhenReady");
|
|
485
|
+
__publicField(this, "playwrightPackage");
|
|
355
486
|
this.cachePath = params.cachePath;
|
|
356
487
|
this.debug = params.debug || false;
|
|
357
|
-
this.
|
|
488
|
+
this.playwrightPackage = this.installPlaywright();
|
|
489
|
+
this.appWhenReady = createElectronApp(
|
|
490
|
+
params.cachePath,
|
|
491
|
+
this.playwrightPackage
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* 安装 playwright
|
|
496
|
+
* @returns
|
|
497
|
+
*/
|
|
498
|
+
installPlaywright() {
|
|
499
|
+
const playwrightPackageManager = new PackageManager({
|
|
500
|
+
packageName: "playwright",
|
|
501
|
+
packageVersion: PLAYWRIGHT_VERSION,
|
|
502
|
+
cacheDir: this.cachePath
|
|
503
|
+
});
|
|
504
|
+
return playwrightPackageManager.getPluginAfterInit("playwright");
|
|
358
505
|
}
|
|
359
506
|
/**
|
|
360
507
|
* 关闭 playwright 启动的 electron 客户端
|
|
@@ -418,9 +565,12 @@ class LocalAutomateTask {
|
|
|
418
565
|
}
|
|
419
566
|
}
|
|
420
567
|
const RpaTask = (params) => {
|
|
421
|
-
const packageManager = new PackageManager(
|
|
568
|
+
const packageManager = new PackageManager({
|
|
569
|
+
packageName: packageJson.name,
|
|
570
|
+
cacheDir: params.cachePath
|
|
571
|
+
});
|
|
422
572
|
const localPackge = packageManager.getPlugin(packageJson.name);
|
|
423
|
-
if (localPackge?.LocalAutomateTask && localPackge?.version &&
|
|
573
|
+
if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
|
|
424
574
|
return new localPackge.LocalAutomateTask(params);
|
|
425
575
|
}
|
|
426
576
|
return new LocalAutomateTask(params);
|
package/dist/index.d.cts
CHANGED
|
@@ -47,7 +47,13 @@ declare class LocalAutomateTask implements TaskParams {
|
|
|
47
47
|
cachePath: string;
|
|
48
48
|
debug: boolean;
|
|
49
49
|
appWhenReady: Promise<ElectronApplication>;
|
|
50
|
+
playwrightPackage: Promise<unknown>;
|
|
50
51
|
constructor(params: TaskParams);
|
|
52
|
+
/**
|
|
53
|
+
* 安装 playwright
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
installPlaywright(): Promise<any>;
|
|
51
57
|
/**
|
|
52
58
|
* 关闭 playwright 启动的 electron 客户端
|
|
53
59
|
* @returns
|
package/dist/index.d.mts
CHANGED
|
@@ -47,7 +47,13 @@ declare class LocalAutomateTask implements TaskParams {
|
|
|
47
47
|
cachePath: string;
|
|
48
48
|
debug: boolean;
|
|
49
49
|
appWhenReady: Promise<ElectronApplication>;
|
|
50
|
+
playwrightPackage: Promise<unknown>;
|
|
50
51
|
constructor(params: TaskParams);
|
|
52
|
+
/**
|
|
53
|
+
* 安装 playwright
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
installPlaywright(): Promise<any>;
|
|
51
57
|
/**
|
|
52
58
|
* 关闭 playwright 启动的 electron 客户端
|
|
53
59
|
* @returns
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,13 @@ declare class LocalAutomateTask implements TaskParams {
|
|
|
47
47
|
cachePath: string;
|
|
48
48
|
debug: boolean;
|
|
49
49
|
appWhenReady: Promise<ElectronApplication>;
|
|
50
|
+
playwrightPackage: Promise<unknown>;
|
|
50
51
|
constructor(params: TaskParams);
|
|
52
|
+
/**
|
|
53
|
+
* 安装 playwright
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
installPlaywright(): Promise<any>;
|
|
51
57
|
/**
|
|
52
58
|
* 关闭 playwright 启动的 electron 客户端
|
|
53
59
|
* @returns
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import semver from 'semver';
|
|
2
1
|
import path from 'node:path';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import https from 'node:https';
|
|
5
4
|
import { app } from 'electron';
|
|
6
|
-
import {
|
|
7
|
-
import spawn from 'cross-spawn';
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
8
6
|
|
|
9
7
|
const name = "@iflyrpa/playwright";
|
|
10
8
|
const type = "module";
|
|
11
|
-
const version$1 = "1.0.
|
|
9
|
+
const version$1 = "1.0.9";
|
|
12
10
|
const description = "";
|
|
13
11
|
const main = "./dist/index.cjs";
|
|
14
12
|
const module = "./dist/index.mjs";
|
|
@@ -26,23 +24,13 @@ const files = [
|
|
|
26
24
|
"dist"
|
|
27
25
|
];
|
|
28
26
|
const dependencies = {
|
|
29
|
-
|
|
30
|
-
"cross-spawn": "^7.0.3",
|
|
31
|
-
deepmerge: "^4.3.1",
|
|
32
|
-
"fs-extra": "^11.2.0",
|
|
33
|
-
playwright: "^1.46.1",
|
|
34
|
-
semver: "^7.6.3"
|
|
27
|
+
playwright: "^1.46.1"
|
|
35
28
|
};
|
|
36
29
|
const peerDependencies = {
|
|
37
30
|
electron: "*"
|
|
38
31
|
};
|
|
39
32
|
const devDependencies = {
|
|
40
|
-
"@types/cross-spawn": "^6.0.6",
|
|
41
|
-
"@types/fs-extra": "^11.0.4",
|
|
42
|
-
"@types/semver": "^7.5.8",
|
|
43
|
-
bumpp: "^9.5.2",
|
|
44
33
|
esno: "^4.7.0",
|
|
45
|
-
"ts-node": "^10.9.2",
|
|
46
34
|
typescript: "^5.5.2",
|
|
47
35
|
unbuild: "^2.0.0"
|
|
48
36
|
};
|
|
@@ -64,25 +52,159 @@ const packageJson = {
|
|
|
64
52
|
devDependencies: devDependencies
|
|
65
53
|
};
|
|
66
54
|
|
|
67
|
-
async function downloadImage(url,
|
|
68
|
-
|
|
69
|
-
url,
|
|
70
|
-
method: "GET",
|
|
71
|
-
responseType: "stream"
|
|
72
|
-
// 重要:设置响应类型为 'stream'
|
|
73
|
-
});
|
|
74
|
-
await fs.ensureFile(path2);
|
|
75
|
-
const writer = fs.createWriteStream(path2);
|
|
76
|
-
response.data.pipe(writer);
|
|
55
|
+
async function downloadImage(url, savePath) {
|
|
56
|
+
await ensureFile(savePath);
|
|
77
57
|
return new Promise((resolve, reject) => {
|
|
78
|
-
|
|
79
|
-
|
|
58
|
+
https.get(url, (response) => {
|
|
59
|
+
if (response.statusCode === 200) {
|
|
60
|
+
const fileStream = fs.createWriteStream(savePath);
|
|
61
|
+
response.pipe(fileStream);
|
|
62
|
+
fileStream.on("finish", () => {
|
|
63
|
+
fileStream.close();
|
|
64
|
+
console.log("\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u6587\u4EF6\u5DF2\u4FDD\u5B58\u81F3:", savePath);
|
|
65
|
+
resolve(savePath);
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
console.log("\u56FE\u7247\u4E0B\u8F7D\u5931\u8D25:", response.statusCode);
|
|
69
|
+
response.resume();
|
|
70
|
+
reject();
|
|
71
|
+
}
|
|
72
|
+
}).on("error", (error) => {
|
|
73
|
+
console.error("\u8BF7\u6C42\u56FE\u7247\u65F6\u53D1\u751F\u9519\u8BEF:", error.message);
|
|
74
|
+
reject();
|
|
75
|
+
});
|
|
80
76
|
});
|
|
81
77
|
}
|
|
82
78
|
function getFilenameFromUrl(imageUrl) {
|
|
83
79
|
const parsedUrl = new URL(imageUrl);
|
|
84
80
|
return path.basename(parsedUrl.pathname);
|
|
85
81
|
}
|
|
82
|
+
function pathExists(path2) {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
fs.stat(path2, (err) => {
|
|
85
|
+
resolve(!err);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function ensureFile(filePath) {
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
const dirPath = path.dirname(filePath);
|
|
92
|
+
fs.stat(dirPath, (err, stats) => {
|
|
93
|
+
if (err) {
|
|
94
|
+
if (err.code === "ENOENT") {
|
|
95
|
+
fs.mkdir(dirPath, { recursive: true }, (err2) => {
|
|
96
|
+
if (err2) {
|
|
97
|
+
return reject(err2);
|
|
98
|
+
}
|
|
99
|
+
createFile();
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
return reject(err);
|
|
103
|
+
}
|
|
104
|
+
} else if (stats.isDirectory()) {
|
|
105
|
+
checkFile();
|
|
106
|
+
} else {
|
|
107
|
+
reject(new Error(`${dirPath} is not a directory`));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
function checkFile() {
|
|
111
|
+
fs.stat(filePath, (err, stats) => {
|
|
112
|
+
if (err) {
|
|
113
|
+
if (err.code === "ENOENT") {
|
|
114
|
+
createFile();
|
|
115
|
+
} else {
|
|
116
|
+
reject(err);
|
|
117
|
+
}
|
|
118
|
+
} else if (stats.isFile()) {
|
|
119
|
+
resolve();
|
|
120
|
+
} else {
|
|
121
|
+
reject(new Error(`${filePath} is not a file`));
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function createFile() {
|
|
126
|
+
fs.writeFile(filePath, "", (err) => {
|
|
127
|
+
if (err) {
|
|
128
|
+
reject(err);
|
|
129
|
+
} else {
|
|
130
|
+
resolve();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function ensureFileSync(filePath) {
|
|
137
|
+
const dirPath = path.dirname(filePath);
|
|
138
|
+
try {
|
|
139
|
+
if (!fs.existsSync(dirPath)) {
|
|
140
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
141
|
+
}
|
|
142
|
+
} catch (err) {
|
|
143
|
+
if (err instanceof Error) {
|
|
144
|
+
throw new Error(`Error creating directory: ${err.message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
if (!fs.existsSync(filePath)) {
|
|
149
|
+
fs.writeFileSync(filePath, "");
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
if (err instanceof Error) {
|
|
153
|
+
throw new Error(`Error creating file: ${err.message}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function writeFile(filePath, data) {
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
fs.writeFile(filePath, data, (err) => {
|
|
160
|
+
if (err) {
|
|
161
|
+
console.error("Error writing file:", err);
|
|
162
|
+
reject();
|
|
163
|
+
} else {
|
|
164
|
+
console.log("File written successfully");
|
|
165
|
+
resolve();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function compareVersions(v1, v2) {
|
|
171
|
+
const parts1 = v1.split(".").map(Number);
|
|
172
|
+
const parts2 = v2.split(".").map(Number);
|
|
173
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
174
|
+
const num1 = i < parts1.length ? parts1[i] : 0;
|
|
175
|
+
const num2 = i < parts2.length ? parts2[i] : 0;
|
|
176
|
+
if (num1 > num2)
|
|
177
|
+
return 1;
|
|
178
|
+
if (num1 < num2)
|
|
179
|
+
return -1;
|
|
180
|
+
}
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
const semver = {
|
|
184
|
+
gt: (v1, v2) => compareVersions(v1, v2) === 1
|
|
185
|
+
};
|
|
186
|
+
function fetchJSON(url) {
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
https.get(url, (res) => {
|
|
189
|
+
let data = "";
|
|
190
|
+
res.on("data", (chunk) => {
|
|
191
|
+
data += chunk;
|
|
192
|
+
});
|
|
193
|
+
res.on("end", () => {
|
|
194
|
+
try {
|
|
195
|
+
const parsedData = JSON.parse(data);
|
|
196
|
+
resolve(parsedData);
|
|
197
|
+
} catch (e) {
|
|
198
|
+
if (e instanceof Error) {
|
|
199
|
+
reject(new Error(`Error parsing JSON: ${e.message}`));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}).on("error", (err) => {
|
|
204
|
+
reject(new Error(`Request failed: ${err.message}`));
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
}
|
|
86
208
|
|
|
87
209
|
const visibleRangeTexts = {
|
|
88
210
|
public: "\u516C\u5F00",
|
|
@@ -93,9 +215,9 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
93
215
|
const selectAddress = async (selector, address) => {
|
|
94
216
|
const instance = typeof selector === "string" ? page.locator(selector) : selector;
|
|
95
217
|
await instance.click();
|
|
96
|
-
await instance.fill(address);
|
|
218
|
+
await instance.locator("input").fill(address);
|
|
97
219
|
const poperInstance = page.locator(
|
|
98
|
-
|
|
220
|
+
'.d-popover:not([style*="display: none"]) .d-options .d-grid-item'
|
|
99
221
|
);
|
|
100
222
|
await poperInstance.first().waitFor();
|
|
101
223
|
await poperInstance.first().click();
|
|
@@ -106,8 +228,12 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
106
228
|
await instance.fill(date);
|
|
107
229
|
await instance.blur();
|
|
108
230
|
};
|
|
109
|
-
await page.waitForSelector("#CreatorPlatform", { state: "visible" })
|
|
110
|
-
|
|
231
|
+
await page.waitForSelector("#CreatorPlatform", { state: "visible" }).catch(() => {
|
|
232
|
+
throw new Error("\u767B\u5F55\u5931\u8D25");
|
|
233
|
+
});
|
|
234
|
+
await page.locator("#content-area .menu-container .publish-video a").click().catch(() => {
|
|
235
|
+
throw new Error("\u672A\u627E\u5230\u53D1\u5E03\u7B14\u8BB0\u6309\u94AE");
|
|
236
|
+
});
|
|
111
237
|
await page.locator(".creator-container .header .title").filter({ hasText: /^上传图文$/ }).click();
|
|
112
238
|
const images = await Promise.all(
|
|
113
239
|
params.banners.map((url) => {
|
|
@@ -130,7 +256,7 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
130
256
|
await page.mouse.wheel(0, 500);
|
|
131
257
|
if (params.address) {
|
|
132
258
|
await selectAddress(
|
|
133
|
-
".media-extension .address-input
|
|
259
|
+
page.locator(".media-extension .address-input").filter({ hasText: "\u6DFB\u52A0\u5730\u70B9" }),
|
|
134
260
|
params.address
|
|
135
261
|
);
|
|
136
262
|
}
|
|
@@ -157,7 +283,7 @@ const xiaohongshuPublishAction = async (props) => {
|
|
|
157
283
|
const hasCustomContent = shootingDate || shootingLocation;
|
|
158
284
|
if (shootingLocation) {
|
|
159
285
|
await selectAddress(
|
|
160
|
-
selfShootingPopup.locator(".address-input
|
|
286
|
+
selfShootingPopup.locator(".address-input"),
|
|
161
287
|
shootingLocation
|
|
162
288
|
);
|
|
163
289
|
}
|
|
@@ -211,16 +337,17 @@ app.on("window-all-closed", (e) => e.preventDefault());
|
|
|
211
337
|
`;
|
|
212
338
|
const generateFile = async (dir) => {
|
|
213
339
|
const filePath = path.join(dir, "src", "main.js");
|
|
214
|
-
const
|
|
215
|
-
if (!
|
|
216
|
-
await
|
|
217
|
-
await
|
|
340
|
+
const isPathExists = await pathExists(filePath);
|
|
341
|
+
if (!isPathExists) {
|
|
342
|
+
await ensureFile(filePath);
|
|
343
|
+
await writeFile(filePath, template);
|
|
218
344
|
}
|
|
219
345
|
return filePath;
|
|
220
346
|
};
|
|
221
|
-
const createElectronApp = async (cachePath) => {
|
|
347
|
+
const createElectronApp = async (cachePath, playwrightPackage) => {
|
|
348
|
+
const playwright = await playwrightPackage;
|
|
222
349
|
const mainPath = await generateFile(cachePath);
|
|
223
|
-
const electronApp = await _electron.launch({
|
|
350
|
+
const electronApp = await playwright._electron.launch({
|
|
224
351
|
executablePath: app.getPath("exe"),
|
|
225
352
|
// 获取 Electron 可执行文件的路径
|
|
226
353
|
args: [mainPath]
|
|
@@ -235,14 +362,15 @@ var __publicField$1 = (obj, key, value) => {
|
|
|
235
362
|
return value;
|
|
236
363
|
};
|
|
237
364
|
class PackageManager {
|
|
238
|
-
|
|
239
|
-
constructor(packageName, cacheDir) {
|
|
365
|
+
constructor(params) {
|
|
240
366
|
__publicField$1(this, "cacheDir");
|
|
241
367
|
// 依赖安装目录
|
|
242
|
-
__publicField$1(this, "
|
|
243
|
-
|
|
244
|
-
this
|
|
245
|
-
this.
|
|
368
|
+
__publicField$1(this, "forceUpdate");
|
|
369
|
+
// 是否强制更新
|
|
370
|
+
__publicField$1(this, "initPromise");
|
|
371
|
+
this.cacheDir = params.cacheDir;
|
|
372
|
+
this.forceUpdate = params.forceUpdate || true;
|
|
373
|
+
this.initPromise = this.init(params.packageName, params.packageVersion);
|
|
246
374
|
}
|
|
247
375
|
// 在子线程执行 npm 命令
|
|
248
376
|
execCommand(cmd, modules, where = this.cacheDir) {
|
|
@@ -274,7 +402,7 @@ class PackageManager {
|
|
|
274
402
|
});
|
|
275
403
|
}
|
|
276
404
|
// 构建 package.json 文件,有了该文件后,依赖可以安装在该目录下,避免污染全局环境
|
|
277
|
-
|
|
405
|
+
initCacheProject() {
|
|
278
406
|
const packagePath = path.join(this.cacheDir, "package.json");
|
|
279
407
|
if (!fs.existsSync(packagePath)) {
|
|
280
408
|
const pkg = {
|
|
@@ -282,18 +410,16 @@ class PackageManager {
|
|
|
282
410
|
description: "rpa-plugins",
|
|
283
411
|
license: "MIT"
|
|
284
412
|
};
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
fs.writeFile(packagePath, JSON.stringify(pkg), "utf8")
|
|
288
|
-
]);
|
|
413
|
+
ensureFileSync(packagePath);
|
|
414
|
+
fs.writeFileSync(packagePath, JSON.stringify(pkg), "utf8");
|
|
289
415
|
}
|
|
290
416
|
}
|
|
291
417
|
// 获取依赖信息
|
|
292
418
|
async getPluginInfo(module) {
|
|
293
|
-
const res = await
|
|
419
|
+
const res = await fetchJSON(
|
|
294
420
|
`https://registry.npmjs.com/-/v1/search?text=${module}`
|
|
295
421
|
);
|
|
296
|
-
const packages = res.
|
|
422
|
+
const packages = res.objects;
|
|
297
423
|
return packages.find((it) => it.package.name === module)?.package;
|
|
298
424
|
}
|
|
299
425
|
// 查询本地安装的依赖
|
|
@@ -305,26 +431,31 @@ class PackageManager {
|
|
|
305
431
|
return null;
|
|
306
432
|
}
|
|
307
433
|
}
|
|
434
|
+
async getPluginAfterInit(module) {
|
|
435
|
+
await this.initPromise;
|
|
436
|
+
return this.getPlugin(module);
|
|
437
|
+
}
|
|
308
438
|
// 安装依赖
|
|
309
|
-
install(module) {
|
|
310
|
-
|
|
439
|
+
install(module, version) {
|
|
440
|
+
const moduleName = version ? `${module}@${version}` : module;
|
|
441
|
+
return this.execCommand("install", [moduleName]);
|
|
311
442
|
}
|
|
312
443
|
// 更新依赖
|
|
313
444
|
update(module) {
|
|
314
445
|
return this.execCommand("update", [module]);
|
|
315
446
|
}
|
|
316
|
-
async init() {
|
|
317
|
-
|
|
318
|
-
const plugin = this.getPlugin(path.join(
|
|
447
|
+
async init(name, version) {
|
|
448
|
+
this.initCacheProject();
|
|
449
|
+
const plugin = this.getPlugin(path.join(name, "package.json"));
|
|
319
450
|
if (!plugin) {
|
|
320
|
-
await this.install(
|
|
321
|
-
} else {
|
|
322
|
-
const pkInfo = await this.getPluginInfo(
|
|
451
|
+
await this.install(name, version);
|
|
452
|
+
} else if (this.forceUpdate) {
|
|
453
|
+
const pkInfo = await this.getPluginInfo(name);
|
|
323
454
|
if (!pkInfo)
|
|
324
|
-
|
|
455
|
+
return;
|
|
325
456
|
const hasNewVersion = semver.gt(pkInfo.version, plugin.version);
|
|
326
457
|
if (hasNewVersion) {
|
|
327
|
-
await this.install(
|
|
458
|
+
await this.install(name, pkInfo.version);
|
|
328
459
|
}
|
|
329
460
|
}
|
|
330
461
|
console.log("Package manager init done!");
|
|
@@ -337,14 +468,32 @@ var __publicField = (obj, key, value) => {
|
|
|
337
468
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
338
469
|
return value;
|
|
339
470
|
};
|
|
471
|
+
const PLAYWRIGHT_VERSION = "1.46.1";
|
|
340
472
|
class LocalAutomateTask {
|
|
341
473
|
constructor(params) {
|
|
342
474
|
__publicField(this, "cachePath");
|
|
343
475
|
__publicField(this, "debug");
|
|
344
476
|
__publicField(this, "appWhenReady");
|
|
477
|
+
__publicField(this, "playwrightPackage");
|
|
345
478
|
this.cachePath = params.cachePath;
|
|
346
479
|
this.debug = params.debug || false;
|
|
347
|
-
this.
|
|
480
|
+
this.playwrightPackage = this.installPlaywright();
|
|
481
|
+
this.appWhenReady = createElectronApp(
|
|
482
|
+
params.cachePath,
|
|
483
|
+
this.playwrightPackage
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* 安装 playwright
|
|
488
|
+
* @returns
|
|
489
|
+
*/
|
|
490
|
+
installPlaywright() {
|
|
491
|
+
const playwrightPackageManager = new PackageManager({
|
|
492
|
+
packageName: "playwright",
|
|
493
|
+
packageVersion: PLAYWRIGHT_VERSION,
|
|
494
|
+
cacheDir: this.cachePath
|
|
495
|
+
});
|
|
496
|
+
return playwrightPackageManager.getPluginAfterInit("playwright");
|
|
348
497
|
}
|
|
349
498
|
/**
|
|
350
499
|
* 关闭 playwright 启动的 electron 客户端
|
|
@@ -408,7 +557,10 @@ class LocalAutomateTask {
|
|
|
408
557
|
}
|
|
409
558
|
}
|
|
410
559
|
const RpaTask = (params) => {
|
|
411
|
-
const packageManager = new PackageManager(
|
|
560
|
+
const packageManager = new PackageManager({
|
|
561
|
+
packageName: packageJson.name,
|
|
562
|
+
cacheDir: params.cachePath
|
|
563
|
+
});
|
|
412
564
|
const localPackge = packageManager.getPlugin(packageJson.name);
|
|
413
565
|
if (localPackge?.LocalAutomateTask && localPackge?.version && semver.gt(localPackge.version, packageJson.version)) {
|
|
414
566
|
return new localPackge.LocalAutomateTask(params);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iflyrpa/playwright",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.9",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -16,23 +16,13 @@
|
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"files": ["dist"],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"
|
|
20
|
-
"cross-spawn": "^7.0.3",
|
|
21
|
-
"deepmerge": "^4.3.1",
|
|
22
|
-
"fs-extra": "^11.2.0",
|
|
23
|
-
"playwright": "^1.46.1",
|
|
24
|
-
"semver": "^7.6.3"
|
|
19
|
+
"playwright": "^1.46.1"
|
|
25
20
|
},
|
|
26
21
|
"peerDependencies": {
|
|
27
22
|
"electron": "*"
|
|
28
23
|
},
|
|
29
24
|
"devDependencies": {
|
|
30
|
-
"@types/cross-spawn": "^6.0.6",
|
|
31
|
-
"@types/fs-extra": "^11.0.4",
|
|
32
|
-
"@types/semver": "^7.5.8",
|
|
33
|
-
"bumpp": "^9.5.2",
|
|
34
25
|
"esno": "^4.7.0",
|
|
35
|
-
"ts-node": "^10.9.2",
|
|
36
26
|
"typescript": "^5.5.2",
|
|
37
27
|
"unbuild": "^2.0.0"
|
|
38
28
|
}
|