assistsx-js 0.2.3 → 0.2.4
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/README.md +14 -51
- package/dist/index.cjs +679 -145
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2001 -611
- package/dist/index.d.ts +2001 -611
- package/dist/index.global.js +2 -2
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +672 -145
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/assistsx-async.ts +33 -0
- package/src/assistsx.ts +33 -0
- package/src/call-method.ts +1 -0
- package/src/db/db-call-method.ts +11 -0
- package/src/db/db.ts +254 -0
- package/src/global.d.ts +8 -0
- package/src/index.ts +5 -0
- package/src/log/log-call-method.ts +3 -0
- package/src/log/log.ts +108 -23
- package/src/plugin-info.ts +70 -0
- package/src/screenshot/screenshot-call-method.ts +16 -0
- package/src/screenshot/screenshot.ts +200 -0
- package/src/window-flags.ts +21 -0
- package/dist/step-DnFA4DEb.d.mts +0 -1196
- package/dist/step-DnFA4DEb.d.ts +0 -1196
- package/dist/step-flow/index.cjs +0 -4367
- package/dist/step-flow/index.cjs.map +0 -1
- package/dist/step-flow/index.d.mts +0 -83
- package/dist/step-flow/index.d.ts +0 -83
- package/dist/step-flow/index.js +0 -4331
- package/dist/step-flow/index.js.map +0 -1
- package/src/step-flow/index.ts +0 -5
- package/src/step-flow/types.ts +0 -41
package/src/log/log.ts
CHANGED
|
@@ -10,6 +10,44 @@ const pendingCallbacks: Map<string, (data: string) => void> = new Map();
|
|
|
10
10
|
const streamHandlers: Map<string, (data: string) => void> = new Map();
|
|
11
11
|
const subscriptionIdToCallbackId: Map<string, string> = new Map();
|
|
12
12
|
|
|
13
|
+
/** 日志文件定位:dirPath 为绝对路径目录,fileName 不含 .txt 后缀;均未传时默认 log-default.txt */
|
|
14
|
+
export interface LogTarget {
|
|
15
|
+
dirPath?: string;
|
|
16
|
+
fileName?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface LogCallOptions extends LogTarget {
|
|
20
|
+
/** 超时时间(秒),默认 30 */
|
|
21
|
+
timeout?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function buildLogArguments(
|
|
25
|
+
target?: LogTarget,
|
|
26
|
+
extra?: Record<string, unknown>
|
|
27
|
+
): Record<string, unknown> | undefined {
|
|
28
|
+
const args: Record<string, unknown> = { ...extra };
|
|
29
|
+
if (target?.dirPath !== undefined) {
|
|
30
|
+
args.dirPath = target.dirPath;
|
|
31
|
+
}
|
|
32
|
+
if (target?.fileName !== undefined) {
|
|
33
|
+
args.fileName = target.fileName;
|
|
34
|
+
}
|
|
35
|
+
return Object.keys(args).length > 0 ? args : undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function resolveTimeout(
|
|
39
|
+
timeoutOrOptions?: number | LogCallOptions,
|
|
40
|
+
fallback = 30
|
|
41
|
+
): { timeout: number; target?: LogTarget } {
|
|
42
|
+
if (typeof timeoutOrOptions === "number") {
|
|
43
|
+
return { timeout: timeoutOrOptions };
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
timeout: timeoutOrOptions?.timeout ?? fallback,
|
|
47
|
+
target: timeoutOrOptions,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
13
51
|
if (typeof window !== "undefined" && !window.assistsxLogCallback) {
|
|
14
52
|
window.assistsxLogCallback = (data: string) => {
|
|
15
53
|
try {
|
|
@@ -49,7 +87,7 @@ export const logUpdateListeners: Array<
|
|
|
49
87
|
> = [];
|
|
50
88
|
|
|
51
89
|
/**
|
|
52
|
-
* Base64 解码后的 CallResponse,data 含 stream / text
|
|
90
|
+
* Base64 解码后的 CallResponse,data 含 stream / text / logFilePath
|
|
53
91
|
*/
|
|
54
92
|
export interface LogUpdateEvent {
|
|
55
93
|
code: number;
|
|
@@ -61,15 +99,17 @@ export interface LogUpdateEvent {
|
|
|
61
99
|
export interface LogUpdateData {
|
|
62
100
|
stream: LogStreamType;
|
|
63
101
|
text: string;
|
|
102
|
+
logFilePath?: string;
|
|
64
103
|
}
|
|
65
104
|
|
|
66
105
|
export interface LogSubscribeUpdatePayload {
|
|
67
106
|
text: string;
|
|
68
107
|
stream: string;
|
|
69
108
|
subscriptionId: string;
|
|
109
|
+
logFilePath?: string;
|
|
70
110
|
}
|
|
71
111
|
|
|
72
|
-
export interface LogUploadOptions {
|
|
112
|
+
export interface LogUploadOptions extends LogTarget {
|
|
73
113
|
baseUrl?: string;
|
|
74
114
|
/** PNG(默认)| JPEG | JPG | WEBP */
|
|
75
115
|
format?: "PNG" | "JPEG" | "JPG" | "WEBP" | string;
|
|
@@ -150,10 +190,13 @@ export class Log {
|
|
|
150
190
|
}
|
|
151
191
|
|
|
152
192
|
/** 读取当前日志全文 */
|
|
153
|
-
async readAllText(
|
|
193
|
+
async readAllText(
|
|
194
|
+
timeoutOrOptions?: number | LogCallOptions
|
|
195
|
+
): Promise<string> {
|
|
196
|
+
const { timeout, target } = resolveTimeout(timeoutOrOptions);
|
|
154
197
|
const res = await this.asyncCall(
|
|
155
198
|
LogCallMethod.readAllText,
|
|
156
|
-
|
|
199
|
+
buildLogArguments(target),
|
|
157
200
|
timeout
|
|
158
201
|
);
|
|
159
202
|
const d = res.getDataOrNull() as { text?: string } | null;
|
|
@@ -174,21 +217,42 @@ export class Log {
|
|
|
174
217
|
return d?.baseUrl ?? "";
|
|
175
218
|
}
|
|
176
219
|
|
|
220
|
+
/**
|
|
221
|
+
* 解析日志文件绝对路径(不创建文件)。
|
|
222
|
+
* AssistsX 插件环境下会经原生拦截追加 log-{packageName} 子目录。
|
|
223
|
+
*/
|
|
224
|
+
async resolveLogPath(
|
|
225
|
+
targetOrOptions?: LogTarget | LogCallOptions
|
|
226
|
+
): Promise<string> {
|
|
227
|
+
const { timeout, target } = resolveTimeout(targetOrOptions);
|
|
228
|
+
const res = await this.asyncCall(
|
|
229
|
+
LogCallMethod.resolveLogPath,
|
|
230
|
+
buildLogArguments(target),
|
|
231
|
+
timeout
|
|
232
|
+
);
|
|
233
|
+
const d = res.getDataOrNull() as { logFilePath?: string } | null;
|
|
234
|
+
return d?.logFilePath ?? "";
|
|
235
|
+
}
|
|
236
|
+
|
|
177
237
|
/** 清空日志 */
|
|
178
|
-
async clear(
|
|
238
|
+
async clear(timeoutOrOptions?: number | LogCallOptions): Promise<boolean> {
|
|
239
|
+
const { timeout, target } = resolveTimeout(timeoutOrOptions);
|
|
179
240
|
const res = await this.asyncCall(
|
|
180
241
|
LogCallMethod.clear,
|
|
181
|
-
|
|
242
|
+
buildLogArguments(target),
|
|
182
243
|
timeout
|
|
183
244
|
);
|
|
184
245
|
return res.isSuccess();
|
|
185
246
|
}
|
|
186
247
|
|
|
187
248
|
/** 从文件重新加载到内存 Flow */
|
|
188
|
-
async refreshFromFile(
|
|
249
|
+
async refreshFromFile(
|
|
250
|
+
timeoutOrOptions?: number | LogCallOptions
|
|
251
|
+
): Promise<boolean> {
|
|
252
|
+
const { timeout, target } = resolveTimeout(timeoutOrOptions);
|
|
189
253
|
const res = await this.asyncCall(
|
|
190
254
|
LogCallMethod.refreshFromFile,
|
|
191
|
-
|
|
255
|
+
buildLogArguments(target),
|
|
192
256
|
timeout
|
|
193
257
|
);
|
|
194
258
|
return res.isSuccess();
|
|
@@ -197,17 +261,25 @@ export class Log {
|
|
|
197
261
|
/** 追加一行 */
|
|
198
262
|
async appendLine(
|
|
199
263
|
line: string,
|
|
200
|
-
|
|
264
|
+
maxLengthOrOptions?:
|
|
265
|
+
| number
|
|
266
|
+
| (LogTarget & { maxLength?: number; timeout?: number }),
|
|
201
267
|
timeout?: number
|
|
202
268
|
): Promise<boolean> {
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
|
|
269
|
+
let options: (LogTarget & { maxLength?: number; timeout?: number }) | undefined;
|
|
270
|
+
if (typeof maxLengthOrOptions === "number") {
|
|
271
|
+
options = { maxLength: maxLengthOrOptions, timeout };
|
|
272
|
+
} else {
|
|
273
|
+
options = maxLengthOrOptions;
|
|
274
|
+
}
|
|
275
|
+
const args = buildLogArguments(options, { line }) ?? { line };
|
|
276
|
+
if (options?.maxLength !== undefined) {
|
|
277
|
+
args.maxLength = options.maxLength;
|
|
206
278
|
}
|
|
207
279
|
const res = await this.asyncCall(
|
|
208
280
|
LogCallMethod.appendLine,
|
|
209
281
|
args,
|
|
210
|
-
timeout
|
|
282
|
+
options?.timeout
|
|
211
283
|
);
|
|
212
284
|
return res.isSuccess();
|
|
213
285
|
}
|
|
@@ -215,11 +287,13 @@ export class Log {
|
|
|
215
287
|
/** 追加带时间戳的条目 */
|
|
216
288
|
async appendTimestampedEntry(
|
|
217
289
|
message: string,
|
|
218
|
-
|
|
290
|
+
timeoutOrOptions?: number | LogCallOptions
|
|
219
291
|
): Promise<boolean> {
|
|
292
|
+
const { timeout, target } = resolveTimeout(timeoutOrOptions);
|
|
293
|
+
const args = buildLogArguments(target, { message }) ?? { message };
|
|
220
294
|
const res = await this.asyncCall(
|
|
221
295
|
LogCallMethod.appendTimestampedEntry,
|
|
222
|
-
|
|
296
|
+
args,
|
|
223
297
|
timeout
|
|
224
298
|
);
|
|
225
299
|
return res.isSuccess();
|
|
@@ -231,28 +305,30 @@ export class Log {
|
|
|
231
305
|
*/
|
|
232
306
|
async append(
|
|
233
307
|
text: string,
|
|
234
|
-
options?: {
|
|
308
|
+
options?: LogTarget & {
|
|
235
309
|
/** @default true */
|
|
236
310
|
timestamped?: boolean;
|
|
237
311
|
maxLength?: number;
|
|
238
312
|
timeout?: number;
|
|
239
313
|
}
|
|
240
314
|
): Promise<boolean> {
|
|
241
|
-
const { timestamped = true, maxLength, timeout } = options ?? {};
|
|
315
|
+
const { timestamped = true, maxLength, timeout, ...target } = options ?? {};
|
|
242
316
|
if (timestamped) {
|
|
243
|
-
return this.appendTimestampedEntry(text, timeout);
|
|
317
|
+
return this.appendTimestampedEntry(text, { ...target, timeout });
|
|
244
318
|
}
|
|
245
|
-
return this.appendLine(text, maxLength, timeout);
|
|
319
|
+
return this.appendLine(text, { ...target, maxLength, timeout });
|
|
246
320
|
}
|
|
247
321
|
|
|
248
322
|
/** 替换全部内容 */
|
|
249
323
|
async replaceAll(
|
|
250
324
|
content: string,
|
|
251
|
-
|
|
325
|
+
timeoutOrOptions?: number | LogCallOptions
|
|
252
326
|
): Promise<boolean> {
|
|
327
|
+
const { timeout, target } = resolveTimeout(timeoutOrOptions);
|
|
328
|
+
const args = buildLogArguments(target, { content }) ?? { content };
|
|
253
329
|
const res = await this.asyncCall(
|
|
254
330
|
LogCallMethod.replaceAll,
|
|
255
|
-
|
|
331
|
+
args,
|
|
256
332
|
timeout
|
|
257
333
|
);
|
|
258
334
|
return res.isSuccess();
|
|
@@ -265,7 +341,7 @@ export class Log {
|
|
|
265
341
|
async subscribe(
|
|
266
342
|
stream: LogStreamType,
|
|
267
343
|
onUpdate: (payload: LogSubscribeUpdatePayload) => void,
|
|
268
|
-
options?:
|
|
344
|
+
options?: LogCallOptions
|
|
269
345
|
): Promise<{
|
|
270
346
|
subscriptionId: string;
|
|
271
347
|
dispose: () => Promise<void>;
|
|
@@ -273,6 +349,7 @@ export class Log {
|
|
|
273
349
|
const self = this;
|
|
274
350
|
const callbackId = generateUUID();
|
|
275
351
|
const timeoutSec = options?.timeout ?? 30;
|
|
352
|
+
const subscribeArgs = buildLogArguments(options, { stream }) ?? { stream };
|
|
276
353
|
|
|
277
354
|
return new Promise((resolve, reject) => {
|
|
278
355
|
let settled = false;
|
|
@@ -293,6 +370,7 @@ export class Log {
|
|
|
293
370
|
subscriptionId?: string;
|
|
294
371
|
stream?: string;
|
|
295
372
|
text?: string;
|
|
373
|
+
logFilePath?: string;
|
|
296
374
|
};
|
|
297
375
|
};
|
|
298
376
|
try {
|
|
@@ -338,6 +416,7 @@ export class Log {
|
|
|
338
416
|
text: data.text ?? "",
|
|
339
417
|
stream: data.stream ?? stream,
|
|
340
418
|
subscriptionId: data.subscriptionId,
|
|
419
|
+
logFilePath: data.logFilePath,
|
|
341
420
|
});
|
|
342
421
|
}
|
|
343
422
|
});
|
|
@@ -346,7 +425,7 @@ export class Log {
|
|
|
346
425
|
this.getBridge().call(
|
|
347
426
|
JSON.stringify({
|
|
348
427
|
method: LogCallMethod.subscribe,
|
|
349
|
-
arguments:
|
|
428
|
+
arguments: subscribeArgs,
|
|
350
429
|
callbackId,
|
|
351
430
|
})
|
|
352
431
|
);
|
|
@@ -397,6 +476,12 @@ export class Log {
|
|
|
397
476
|
if (args.uploadKey !== undefined) {
|
|
398
477
|
payload.uploadKey = args.uploadKey;
|
|
399
478
|
}
|
|
479
|
+
if (args.dirPath !== undefined) {
|
|
480
|
+
payload.dirPath = args.dirPath;
|
|
481
|
+
}
|
|
482
|
+
if (args.fileName !== undefined) {
|
|
483
|
+
payload.fileName = args.fileName;
|
|
484
|
+
}
|
|
400
485
|
const uuid = generateUUID();
|
|
401
486
|
const params = {
|
|
402
487
|
method: LogCallMethod.uploadLogs,
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AssistsX 当前运行插件信息(由宿主拦截 getCurrentPlugin 返回)
|
|
3
|
+
*/
|
|
4
|
+
export class PluginInfo {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
packageName: string;
|
|
8
|
+
versionName: string;
|
|
9
|
+
versionCode: number;
|
|
10
|
+
description: string;
|
|
11
|
+
path: string;
|
|
12
|
+
index: string;
|
|
13
|
+
port: number;
|
|
14
|
+
needScreenCapture: boolean;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
id: string = "",
|
|
18
|
+
name: string = "",
|
|
19
|
+
packageName: string = "",
|
|
20
|
+
versionName: string = "",
|
|
21
|
+
versionCode: number = 0,
|
|
22
|
+
description: string = "",
|
|
23
|
+
path: string = "",
|
|
24
|
+
index: string = "",
|
|
25
|
+
port: number = 0,
|
|
26
|
+
needScreenCapture: boolean = false
|
|
27
|
+
) {
|
|
28
|
+
this.id = id;
|
|
29
|
+
this.name = name;
|
|
30
|
+
this.packageName = packageName;
|
|
31
|
+
this.versionName = versionName;
|
|
32
|
+
this.versionCode = versionCode;
|
|
33
|
+
this.description = description;
|
|
34
|
+
this.path = path;
|
|
35
|
+
this.index = index;
|
|
36
|
+
this.port = port;
|
|
37
|
+
this.needScreenCapture = needScreenCapture;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static fromJSON(data: unknown): PluginInfo {
|
|
41
|
+
const record = (data ?? {}) as Record<string, unknown>;
|
|
42
|
+
return new PluginInfo(
|
|
43
|
+
String(record.id ?? ""),
|
|
44
|
+
String(record.name ?? ""),
|
|
45
|
+
String(record.packageName ?? ""),
|
|
46
|
+
String(record.versionName ?? ""),
|
|
47
|
+
Number(record.versionCode ?? 0),
|
|
48
|
+
String(record.description ?? ""),
|
|
49
|
+
String(record.path ?? ""),
|
|
50
|
+
String(record.index ?? ""),
|
|
51
|
+
Number(record.port ?? 0),
|
|
52
|
+
Boolean(record.needScreenCapture ?? false)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
toJSON(): Record<string, unknown> {
|
|
57
|
+
return {
|
|
58
|
+
id: this.id,
|
|
59
|
+
name: this.name,
|
|
60
|
+
packageName: this.packageName,
|
|
61
|
+
versionName: this.versionName,
|
|
62
|
+
versionCode: this.versionCode,
|
|
63
|
+
description: this.description,
|
|
64
|
+
path: this.path,
|
|
65
|
+
index: this.index,
|
|
66
|
+
port: this.port,
|
|
67
|
+
needScreenCapture: this.needScreenCapture,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 截图相关的 JavascriptInterface 方法常量
|
|
3
|
+
*/
|
|
4
|
+
export const ScreenshotCallMethod = {
|
|
5
|
+
/** 截取全屏并返回 Base64 */
|
|
6
|
+
takeScreenshotBase64: "takeScreenshotBase64",
|
|
7
|
+
|
|
8
|
+
/** 截取指定节点区域并返回 Base64,需传 node.nodeId */
|
|
9
|
+
takeNodeScreenshotBase64: "takeNodeScreenshotBase64",
|
|
10
|
+
|
|
11
|
+
/** 批量截取节点区域并返回 Base64 数组,nodes 为空时返回全屏 */
|
|
12
|
+
takeScreenshotNodesBase64: "takeScreenshotNodesBase64",
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
export type ScreenshotCallMethodType =
|
|
16
|
+
(typeof ScreenshotCallMethod)[keyof typeof ScreenshotCallMethod];
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 截图专用 Bridge:assistsxScreenshot
|
|
3
|
+
* 直接返回 Base64 / data URL,无需经过文件保存
|
|
4
|
+
*/
|
|
5
|
+
import { CallResponse } from "../call-response";
|
|
6
|
+
import { Node } from "../node";
|
|
7
|
+
import { decodeBase64UTF8, generateUUID } from "../utils";
|
|
8
|
+
import { ScreenshotCallMethod } from "./screenshot-call-method";
|
|
9
|
+
|
|
10
|
+
export type ScreenshotImageFormat = "PNG" | "JPEG" | "JPG" | "WEBP";
|
|
11
|
+
|
|
12
|
+
/** takeScreenshotBase64 / takeNodeScreenshotBase64 返回数据 */
|
|
13
|
+
export interface ScreenshotBase64Data {
|
|
14
|
+
base64: string;
|
|
15
|
+
dataUrl: string;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TakeScreenshotBase64Options {
|
|
20
|
+
overlayHiddenScreenshotDelayMillis?: number;
|
|
21
|
+
format?: ScreenshotImageFormat;
|
|
22
|
+
withDataUrlPrefix?: boolean;
|
|
23
|
+
timeout?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TakeScreenshotNodesBase64Options extends TakeScreenshotBase64Options {}
|
|
27
|
+
|
|
28
|
+
// 回调函数存储对象
|
|
29
|
+
const callbacks: Map<string, (data: string) => void> = new Map();
|
|
30
|
+
|
|
31
|
+
// 初始化全局回调函数
|
|
32
|
+
if (typeof window !== "undefined" && !window.assistsxScreenshotCallback) {
|
|
33
|
+
window.assistsxScreenshotCallback = (data: string) => {
|
|
34
|
+
let callbackId: string | undefined;
|
|
35
|
+
try {
|
|
36
|
+
const json = decodeBase64UTF8(data);
|
|
37
|
+
const response = JSON.parse(json);
|
|
38
|
+
callbackId = response.callbackId;
|
|
39
|
+
if (callbackId) {
|
|
40
|
+
const callback = callbacks.get(callbackId);
|
|
41
|
+
if (callback) {
|
|
42
|
+
callback(json);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.error("Screenshot callback error:", e);
|
|
47
|
+
} finally {
|
|
48
|
+
if (callbackId) {
|
|
49
|
+
callbacks.delete(callbackId);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function createNodeStub(nodeId: string): Node {
|
|
56
|
+
return { nodeId } as Node;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function parseScreenshotBase64Data(data: unknown): ScreenshotBase64Data | null {
|
|
60
|
+
if (!data || typeof data !== "object") {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const record = data as Record<string, unknown>;
|
|
64
|
+
const base64 = typeof record.base64 === "string" ? record.base64 : "";
|
|
65
|
+
const mimeType = typeof record.mimeType === "string" ? record.mimeType : "image/png";
|
|
66
|
+
const dataUrl =
|
|
67
|
+
typeof record.dataUrl === "string"
|
|
68
|
+
? record.dataUrl
|
|
69
|
+
: `data:${mimeType};base64,${base64}`;
|
|
70
|
+
if (!base64) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return { base64, dataUrl, mimeType };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class Screenshot {
|
|
77
|
+
/**
|
|
78
|
+
* 执行异步调用
|
|
79
|
+
*/
|
|
80
|
+
private async asyncCall(
|
|
81
|
+
method: string,
|
|
82
|
+
{
|
|
83
|
+
args,
|
|
84
|
+
node,
|
|
85
|
+
nodes,
|
|
86
|
+
timeout = 30,
|
|
87
|
+
}: {
|
|
88
|
+
args?: Record<string, unknown>;
|
|
89
|
+
node?: Node;
|
|
90
|
+
nodes?: Node[];
|
|
91
|
+
timeout?: number;
|
|
92
|
+
} = {}
|
|
93
|
+
): Promise<CallResponse> {
|
|
94
|
+
const uuid = generateUUID();
|
|
95
|
+
const params = {
|
|
96
|
+
method,
|
|
97
|
+
arguments: args ? args : undefined,
|
|
98
|
+
node: node ? node : undefined,
|
|
99
|
+
nodes: nodes ? nodes : undefined,
|
|
100
|
+
callbackId: uuid,
|
|
101
|
+
};
|
|
102
|
+
const promise = new Promise<string>((resolve) => {
|
|
103
|
+
callbacks.set(uuid, (data: string) => {
|
|
104
|
+
resolve(data);
|
|
105
|
+
});
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
callbacks.delete(uuid);
|
|
108
|
+
resolve(JSON.stringify(new CallResponse(0, null, uuid)));
|
|
109
|
+
}, timeout * 1000);
|
|
110
|
+
});
|
|
111
|
+
window.assistsxScreenshot.call(JSON.stringify(params));
|
|
112
|
+
const promiseResult = await promise;
|
|
113
|
+
if (typeof promiseResult === "string") {
|
|
114
|
+
const responseData = JSON.parse(promiseResult);
|
|
115
|
+
return new CallResponse(
|
|
116
|
+
responseData.code,
|
|
117
|
+
responseData.data,
|
|
118
|
+
responseData.callbackId
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
throw new Error("Screenshot call failed");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private buildScreenshotArgs(
|
|
125
|
+
options: TakeScreenshotBase64Options = {}
|
|
126
|
+
): Record<string, unknown> {
|
|
127
|
+
const {
|
|
128
|
+
overlayHiddenScreenshotDelayMillis = 250,
|
|
129
|
+
format = "PNG",
|
|
130
|
+
withDataUrlPrefix = true,
|
|
131
|
+
} = options;
|
|
132
|
+
return {
|
|
133
|
+
overlayHiddenScreenshotDelayMillis,
|
|
134
|
+
format,
|
|
135
|
+
withDataUrlPrefix,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 截取全屏并返回 Base64
|
|
141
|
+
*/
|
|
142
|
+
async takeScreenshotBase64(
|
|
143
|
+
options: TakeScreenshotBase64Options = {}
|
|
144
|
+
): Promise<ScreenshotBase64Data | null> {
|
|
145
|
+
const { timeout = 30, ...rest } = options;
|
|
146
|
+
const response = await this.asyncCall(ScreenshotCallMethod.takeScreenshotBase64, {
|
|
147
|
+
args: this.buildScreenshotArgs(rest),
|
|
148
|
+
timeout,
|
|
149
|
+
});
|
|
150
|
+
if (!response.isSuccess()) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
return parseScreenshotBase64Data(response.getDataOrNull());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 截取指定节点区域并返回 Base64
|
|
158
|
+
*/
|
|
159
|
+
async takeNodeScreenshotBase64(
|
|
160
|
+
nodeId: string,
|
|
161
|
+
options: TakeScreenshotBase64Options = {}
|
|
162
|
+
): Promise<ScreenshotBase64Data | null> {
|
|
163
|
+
if (!nodeId) {
|
|
164
|
+
throw new Error("nodeId is required");
|
|
165
|
+
}
|
|
166
|
+
const { timeout = 30, ...rest } = options;
|
|
167
|
+
const response = await this.asyncCall(ScreenshotCallMethod.takeNodeScreenshotBase64, {
|
|
168
|
+
args: this.buildScreenshotArgs(rest),
|
|
169
|
+
node: createNodeStub(nodeId),
|
|
170
|
+
timeout,
|
|
171
|
+
});
|
|
172
|
+
if (!response.isSuccess()) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return parseScreenshotBase64Data(response.getDataOrNull());
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 批量截取节点区域;nodeIds 为空时返回全屏截图
|
|
180
|
+
*/
|
|
181
|
+
async takeScreenshotNodesBase64(
|
|
182
|
+
nodeIds: string[] = [],
|
|
183
|
+
options: TakeScreenshotNodesBase64Options = {}
|
|
184
|
+
): Promise<string[]> {
|
|
185
|
+
const { timeout = 30, ...rest } = options;
|
|
186
|
+
const nodes = nodeIds.map((nodeId) => createNodeStub(nodeId));
|
|
187
|
+
const response = await this.asyncCall(ScreenshotCallMethod.takeScreenshotNodesBase64, {
|
|
188
|
+
args: this.buildScreenshotArgs(rest),
|
|
189
|
+
nodes,
|
|
190
|
+
timeout,
|
|
191
|
+
});
|
|
192
|
+
if (!response.isSuccess()) {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
const data = response.getDataOrNull() as { images?: string[] } | null;
|
|
196
|
+
return Array.isArray(data?.images) ? data.images : [];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export const screenshot = new Screenshot();
|
package/src/window-flags.ts
CHANGED
|
@@ -90,6 +90,27 @@ export class WindowFlags {
|
|
|
90
90
|
return flags & ~flag;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/** 输入框获取焦点时使用的悬浮窗 flag 组合(不含 FLAG_NOT_FOCUSABLE) */
|
|
94
|
+
static getOverlayInputFocusFlagList(): number[] {
|
|
95
|
+
return [
|
|
96
|
+
WindowFlags.FLAG_WATCH_OUTSIDE_TOUCH,
|
|
97
|
+
WindowFlags.FLAG_NOT_TOUCH_MODAL,
|
|
98
|
+
WindowFlags.FLAG_LAYOUT_NO_LIMITS,
|
|
99
|
+
WindowFlags.FLAG_LAYOUT_IN_SCREEN,
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** 输入框失去焦点时使用的悬浮窗 flag 组合(含 FLAG_NOT_FOCUSABLE) */
|
|
104
|
+
static getOverlayInputBlurFlagList(): number[] {
|
|
105
|
+
return [
|
|
106
|
+
WindowFlags.FLAG_WATCH_OUTSIDE_TOUCH,
|
|
107
|
+
WindowFlags.FLAG_NOT_TOUCH_MODAL,
|
|
108
|
+
WindowFlags.FLAG_LAYOUT_NO_LIMITS,
|
|
109
|
+
WindowFlags.FLAG_NOT_FOCUSABLE,
|
|
110
|
+
WindowFlags.FLAG_LAYOUT_IN_SCREEN,
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
93
114
|
/**
|
|
94
115
|
* 获取所有标志位的描述信息
|
|
95
116
|
* @returns 标志位描述对象数组
|