@mearl/client 2.8.0 → 2.8.2
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 +1 -0
- package/dist/check.d.ts +51 -0
- package/dist/check.js +64 -3
- package/dist/cli.js +13 -4
- package/dist/commands.d.ts +16 -4
- package/dist/commands.js +19 -2
- package/dist/generated-browser-action-protocol.d.ts +8 -1
- package/package.json +2 -2
package/README.md
CHANGED
package/dist/check.d.ts
CHANGED
|
@@ -1,4 +1,50 @@
|
|
|
1
|
+
import type { CloudConnectorInfo } from '@mearl/cloud-types';
|
|
1
2
|
import { type UnifiedClientOptions, type UnifiedInvokeOptions } from './unified.js';
|
|
3
|
+
export interface UnifiedCheckVersions {
|
|
4
|
+
nativeHost?: string;
|
|
5
|
+
extension?: string | null;
|
|
6
|
+
browser?: string | null;
|
|
7
|
+
}
|
|
8
|
+
interface BrowserInfo {
|
|
9
|
+
browserId: string;
|
|
10
|
+
extensionVersion?: string;
|
|
11
|
+
name: string;
|
|
12
|
+
nativeHostVersion?: string;
|
|
13
|
+
originalBrowserId?: string;
|
|
14
|
+
originalName?: string;
|
|
15
|
+
status: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
provider?: 'local' | 'agentbay';
|
|
18
|
+
transport?: 'extension' | 'cdp';
|
|
19
|
+
}
|
|
20
|
+
interface CheckItem {
|
|
21
|
+
status: 'ok' | 'warning' | 'error';
|
|
22
|
+
label: string;
|
|
23
|
+
details?: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface ExtensionInstallationInfo {
|
|
26
|
+
extensionId: string;
|
|
27
|
+
setupManagedPath: string | null;
|
|
28
|
+
}
|
|
29
|
+
export interface UnifiedCheckBrowserResult extends BrowserInfo {
|
|
30
|
+
agentbayAccessUrl?: string;
|
|
31
|
+
check?: {
|
|
32
|
+
errors?: string[];
|
|
33
|
+
label: string;
|
|
34
|
+
status: CheckItem['status'];
|
|
35
|
+
warnings?: string[];
|
|
36
|
+
};
|
|
37
|
+
extensionInstallation?: ExtensionInstallationInfo;
|
|
38
|
+
selected: boolean;
|
|
39
|
+
versions?: UnifiedCheckVersions;
|
|
40
|
+
}
|
|
41
|
+
export interface UnifiedCheckResult {
|
|
42
|
+
browsers: UnifiedCheckBrowserResult[];
|
|
43
|
+
clientVersion: string;
|
|
44
|
+
connectors: CloudConnectorInfo[];
|
|
45
|
+
environment: CheckItem[];
|
|
46
|
+
ok: boolean;
|
|
47
|
+
}
|
|
2
48
|
interface CheckClient {
|
|
3
49
|
invoke(action: string, data?: Record<string, any>, options?: UnifiedInvokeOptions): Promise<any>;
|
|
4
50
|
disconnect(): void;
|
|
@@ -12,11 +58,16 @@ export interface UnifiedCheckOptions {
|
|
|
12
58
|
connector?: string;
|
|
13
59
|
local?: boolean;
|
|
14
60
|
transport?: 'cdp';
|
|
61
|
+
json?: boolean;
|
|
15
62
|
}
|
|
16
63
|
export interface UnifiedCheckDependencies {
|
|
17
64
|
createClient?: (options: UnifiedClientOptions) => CheckClient;
|
|
65
|
+
writeJson?: (json: string) => void;
|
|
18
66
|
writeLine?: (line: string) => void;
|
|
19
67
|
}
|
|
20
68
|
export declare function parseCheckTimeout(value: string | undefined): number | null;
|
|
69
|
+
export declare function runUnifiedCheck(options: UnifiedCheckOptions & {
|
|
70
|
+
json: true;
|
|
71
|
+
}, dependencies?: UnifiedCheckDependencies): Promise<UnifiedCheckResult>;
|
|
21
72
|
export declare function runUnifiedCheck(options: UnifiedCheckOptions, dependencies?: UnifiedCheckDependencies): Promise<boolean>;
|
|
22
73
|
export {};
|
package/dist/check.js
CHANGED
|
@@ -73,6 +73,7 @@ export function parseCheckTimeout(value) {
|
|
|
73
73
|
export async function runUnifiedCheck(options, dependencies = {}) {
|
|
74
74
|
const timeoutSec = options.timeoutSec ?? 5;
|
|
75
75
|
const writeLine = dependencies.writeLine ?? (line => console.error(line));
|
|
76
|
+
const writeJson = dependencies.writeJson ?? (json => process.stdout.write(`${json}\n`));
|
|
76
77
|
const createClient = dependencies.createClient ??
|
|
77
78
|
((clientOptions) => new UnifiedClient(clientOptions));
|
|
78
79
|
const client = createClient({
|
|
@@ -194,11 +195,28 @@ export async function runUnifiedCheck(options, dependencies = {}) {
|
|
|
194
195
|
browser: browser.browserId,
|
|
195
196
|
...(options.transport ? { transport: options.transport } : {}),
|
|
196
197
|
}));
|
|
198
|
+
const publicVersions = {
|
|
199
|
+
...(versions.nativeHost ? { nativeHost: versions.nativeHost } : {}),
|
|
200
|
+
...(versions.extension !== undefined ? { extension: versions.extension } : {}),
|
|
201
|
+
...(versions.browser !== undefined ? { browser: versions.browser } : {}),
|
|
202
|
+
};
|
|
197
203
|
const details = [
|
|
198
204
|
versions.nativeHost ? `native-host v${versions.nativeHost}` : null,
|
|
199
205
|
versions.extension ? `extension v${versions.extension}` : null,
|
|
200
206
|
versions.browser ? `Chrome ${versions.browser}` : null,
|
|
201
207
|
].filter((value) => value !== null);
|
|
208
|
+
let extensionInstallation;
|
|
209
|
+
if (options.local &&
|
|
210
|
+
browser.transport === 'extension' &&
|
|
211
|
+
typeof versions.extensionId === 'string' &&
|
|
212
|
+
typeof versions.extension === 'string' &&
|
|
213
|
+
(typeof versions.setupManagedPath === 'string' || versions.setupManagedPath === null)) {
|
|
214
|
+
extensionInstallation = {
|
|
215
|
+
extensionId: versions.extensionId,
|
|
216
|
+
setupManagedPath: versions.setupManagedPath,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
let agentbayAccessUrl;
|
|
202
220
|
let accessUrlWarning;
|
|
203
221
|
if (browser.provider === 'agentbay' && options.browser) {
|
|
204
222
|
try {
|
|
@@ -209,6 +227,7 @@ export async function runUnifiedCheck(options, dependencies = {}) {
|
|
|
209
227
|
if (!access.agentbayAccessUrl) {
|
|
210
228
|
throw new Error('AgentBay did not return a browser access URL');
|
|
211
229
|
}
|
|
230
|
+
agentbayAccessUrl = access.agentbayAccessUrl;
|
|
212
231
|
details.push(`AgentBay access URL (temporary, sensitive): ${access.agentbayAccessUrl}`);
|
|
213
232
|
}
|
|
214
233
|
catch (error) {
|
|
@@ -217,7 +236,9 @@ export async function runUnifiedCheck(options, dependencies = {}) {
|
|
|
217
236
|
}
|
|
218
237
|
}
|
|
219
238
|
browserChecks.push({
|
|
239
|
+
...(agentbayAccessUrl ? { agentbayAccessUrl } : {}),
|
|
220
240
|
browser,
|
|
241
|
+
...(extensionInstallation ? { extensionInstallation } : {}),
|
|
221
242
|
item: {
|
|
222
243
|
status: accessUrlWarning ? 'warning' : 'ok',
|
|
223
244
|
label: accessUrlWarning
|
|
@@ -225,12 +246,17 @@ export async function runUnifiedCheck(options, dependencies = {}) {
|
|
|
225
246
|
: 'Browser command path',
|
|
226
247
|
details,
|
|
227
248
|
},
|
|
249
|
+
versions: publicVersions,
|
|
250
|
+
...(accessUrlWarning ? { warnings: [accessUrlWarning] } : {}),
|
|
228
251
|
});
|
|
229
252
|
}
|
|
230
253
|
catch (error) {
|
|
231
254
|
const message = formatError(error);
|
|
232
255
|
browserChecks.push({
|
|
233
256
|
browser,
|
|
257
|
+
...(message.includes('Unknown action')
|
|
258
|
+
? { warnings: ['Update @mearl/native-host for complete diagnostics.'] }
|
|
259
|
+
: { errors: [message] }),
|
|
234
260
|
item: message.includes('Unknown action')
|
|
235
261
|
? {
|
|
236
262
|
status: 'warning',
|
|
@@ -245,6 +271,44 @@ export async function runUnifiedCheck(options, dependencies = {}) {
|
|
|
245
271
|
});
|
|
246
272
|
}
|
|
247
273
|
}));
|
|
274
|
+
const hasError = environment.some(item => item.status === 'error') ||
|
|
275
|
+
browserChecks.some(check => check.item.status === 'error');
|
|
276
|
+
const listedBrowsers = browserList?.browsers ?? [];
|
|
277
|
+
if (options.json) {
|
|
278
|
+
const result = {
|
|
279
|
+
browsers: listedBrowsers.map(browser => {
|
|
280
|
+
const check = browserChecks.find(item => item.browser.browserId === browser.browserId);
|
|
281
|
+
const browserIdentity = { ...browser };
|
|
282
|
+
delete browserIdentity.extensionVersion;
|
|
283
|
+
delete browserIdentity.nativeHostVersion;
|
|
284
|
+
return {
|
|
285
|
+
...browserIdentity,
|
|
286
|
+
selected: targets.some(target => target.browserId === browser.browserId),
|
|
287
|
+
...(check?.agentbayAccessUrl ? { agentbayAccessUrl: check.agentbayAccessUrl } : {}),
|
|
288
|
+
...(check?.item
|
|
289
|
+
? {
|
|
290
|
+
check: {
|
|
291
|
+
label: check.item.label,
|
|
292
|
+
status: check.item.status,
|
|
293
|
+
...(check.errors ? { errors: check.errors } : {}),
|
|
294
|
+
...(check.warnings ? { warnings: check.warnings } : {}),
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
: {}),
|
|
298
|
+
...(check?.extensionInstallation
|
|
299
|
+
? { extensionInstallation: check.extensionInstallation }
|
|
300
|
+
: {}),
|
|
301
|
+
...(check?.versions ? { versions: check.versions } : {}),
|
|
302
|
+
};
|
|
303
|
+
}),
|
|
304
|
+
clientVersion: options.clientVersion,
|
|
305
|
+
connectors,
|
|
306
|
+
environment,
|
|
307
|
+
ok: !hasError,
|
|
308
|
+
};
|
|
309
|
+
writeJson(JSON.stringify(result, null, 2));
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
248
312
|
writeLine('');
|
|
249
313
|
printSection(writeLine, 'Environment', environment);
|
|
250
314
|
if (connectors.length > 0) {
|
|
@@ -253,7 +317,6 @@ export async function runUnifiedCheck(options, dependencies = {}) {
|
|
|
253
317
|
writeLine(formatConnector(connector));
|
|
254
318
|
writeLine('');
|
|
255
319
|
}
|
|
256
|
-
const listedBrowsers = browserList?.browsers ?? [];
|
|
257
320
|
if (listedBrowsers.length > 0) {
|
|
258
321
|
writeLine('Browsers');
|
|
259
322
|
for (const browser of listedBrowsers) {
|
|
@@ -271,8 +334,6 @@ export async function runUnifiedCheck(options, dependencies = {}) {
|
|
|
271
334
|
}
|
|
272
335
|
writeLine('');
|
|
273
336
|
}
|
|
274
|
-
const hasError = environment.some(item => item.status === 'error') ||
|
|
275
|
-
browserChecks.some(check => check.item.status === 'error');
|
|
276
337
|
if (hasError) {
|
|
277
338
|
writeLine('⚠️ Mearl checks failed. See the browser or source details above.');
|
|
278
339
|
return false;
|
package/dist/cli.js
CHANGED
|
@@ -81,6 +81,7 @@ function printUsage(commandName, version) {
|
|
|
81
81
|
' --payload-file <path> 从文件读取整个 JSON 参数',
|
|
82
82
|
' --timeout <seconds> 超时时间(默认按 action 推导)',
|
|
83
83
|
' --compact 输出紧凑格式 JSON',
|
|
84
|
+
' --json check 输出机器可读 JSON',
|
|
84
85
|
' --output <path> 保存输出或截图',
|
|
85
86
|
' --browser <id|名称> 指定 browser_list 返回的浏览器',
|
|
86
87
|
' --connector <id|名称> 限制到一台远端 connector',
|
|
@@ -192,7 +193,7 @@ function validateOptions(args) {
|
|
|
192
193
|
'--connector',
|
|
193
194
|
'--server',
|
|
194
195
|
]);
|
|
195
|
-
const flags = new Set(['--compact', '--local', '--cdp', '--help', '-h']);
|
|
196
|
+
const flags = new Set(['--compact', '--json', '--local', '--cdp', '--help', '-h']);
|
|
196
197
|
for (let index = 1; index < args.length; index += 1) {
|
|
197
198
|
const arg = args[index];
|
|
198
199
|
if (optionsWithValues.has(arg)) {
|
|
@@ -222,6 +223,9 @@ function resolveServer(args) {
|
|
|
222
223
|
function parseArgs(args) {
|
|
223
224
|
validateOptions(args);
|
|
224
225
|
const action = args[0];
|
|
226
|
+
const json = args.includes('--json');
|
|
227
|
+
if (json && action !== 'check')
|
|
228
|
+
throw new Error('--json 仅适用于 check');
|
|
225
229
|
const payload = parsePayload(args);
|
|
226
230
|
const fallbackTimeout = resolveActionTimeoutSec(action, payload, 60);
|
|
227
231
|
const forceCdp = args.includes('--cdp');
|
|
@@ -235,6 +239,7 @@ function parseArgs(args) {
|
|
|
235
239
|
timeoutSec: parsePositiveTimeout(optionValue(args, '--timeout'), fallbackTimeout),
|
|
236
240
|
compact: args.includes('--compact'),
|
|
237
241
|
forceCdp,
|
|
242
|
+
json,
|
|
238
243
|
local,
|
|
239
244
|
...(optionValue(args, '--output') ? { outputPath: optionValue(args, '--output') } : {}),
|
|
240
245
|
...(optionValue(args, '--browser') ? { browser: optionValue(args, '--browser') } : {}),
|
|
@@ -312,7 +317,7 @@ export async function runMearlCli(args, options = {}) {
|
|
|
312
317
|
console.error('--timeout 必须是正整数秒');
|
|
313
318
|
return 2;
|
|
314
319
|
}
|
|
315
|
-
const
|
|
320
|
+
const checkOptions = {
|
|
316
321
|
clientVersion,
|
|
317
322
|
timeoutSec,
|
|
318
323
|
...(parsed.serverUrl ? { serverUrl: parsed.serverUrl } : {}),
|
|
@@ -321,8 +326,12 @@ export async function runMearlCli(args, options = {}) {
|
|
|
321
326
|
...(parsed.connector ? { connector: parsed.connector } : {}),
|
|
322
327
|
...(parsed.local ? { local: true } : {}),
|
|
323
328
|
...(parsed.forceCdp ? { transport: 'cdp' } : {}),
|
|
324
|
-
}
|
|
325
|
-
|
|
329
|
+
};
|
|
330
|
+
if (parsed.json) {
|
|
331
|
+
const result = await runUnifiedCheck({ ...checkOptions, json: true });
|
|
332
|
+
return result.ok ? 0 : 1;
|
|
333
|
+
}
|
|
334
|
+
return (await runUnifiedCheck(checkOptions)) ? 0 : 1;
|
|
326
335
|
}
|
|
327
336
|
if (parsed.action === 'page_selected_element' && parsed.outputPath) {
|
|
328
337
|
parsed.payload = { ...parsed.payload, includeScreenshot: true };
|
package/dist/commands.d.ts
CHANGED
|
@@ -501,9 +501,17 @@ export declare const COMMANDS: readonly [{
|
|
|
501
501
|
}, {
|
|
502
502
|
readonly name: "appProfile";
|
|
503
503
|
readonly type: "string";
|
|
504
|
-
readonly description: "开 tab 即进入 App 容器模拟态(客户端 UA + JSBridge 托管 + iframe
|
|
504
|
+
readonly description: "开 tab 即进入 App 容器模拟态(客户端 UA + JSBridge 托管 + iframe 容器栈 + 自适应系统标题栏,首屏即容器态)。系统栏由 iframe 外层统一渲染,并根据页面协议与桥调用切换普通、沉浸或隐藏状态;档案名同 set_app_profile,如 \"fliggy\"";
|
|
505
|
+
}, {
|
|
506
|
+
readonly name: "os";
|
|
507
|
+
readonly type: "\"ios\" | \"android\"";
|
|
508
|
+
readonly description: "与 appProfile 配合;容器系统,默认 ios";
|
|
509
|
+
}, {
|
|
510
|
+
readonly name: "simulateSystemBars";
|
|
511
|
+
readonly type: "boolean";
|
|
512
|
+
readonly description: "与 appProfile 配合;是否模拟顶部状态/导航栏与底部手势栏,默认 true";
|
|
505
513
|
}];
|
|
506
|
-
readonly examples: ["tab_open --payload '{\"url\":\"https://example.com\"}'", "tab_open --payload '{\"url\":\"https://example.com/page\",\"reuse\":\"prefer\",\"match\":{\"ignoreSearch\":true}}'", "tab_open --payload '{\"url\":\"https://m.example.com\",\"emulation\":{\"preset\":\"iphone-15-pro\"}}'", "tab_open --payload '{\"url\":\"https://market.m.taobao.com/app/trip/rx-home/pages/home\",\"appProfile\":\"fliggy\"}'", "tab_open --payload '{\"url\":\"https://example.com\",\"group\":\"验证任务\"}'"];
|
|
514
|
+
readonly examples: ["tab_open --payload '{\"url\":\"https://example.com\"}'", "tab_open --payload '{\"url\":\"https://example.com/page\",\"reuse\":\"prefer\",\"match\":{\"ignoreSearch\":true}}'", "tab_open --payload '{\"url\":\"https://m.example.com\",\"emulation\":{\"preset\":\"iphone-15-pro\"}}'", "tab_open --payload '{\"url\":\"https://market.m.taobao.com/app/trip/rx-home/pages/home\",\"appProfile\":\"fliggy\"}'", "tab_open --payload '{\"url\":\"https://example.com\",\"appProfile\":\"fliggy\",\"os\":\"android\"}'", "tab_open --payload '{\"url\":\"https://example.com\",\"group\":\"验证任务\"}'"];
|
|
507
515
|
}, {
|
|
508
516
|
readonly name: "tab_close";
|
|
509
517
|
readonly description: "关闭指定标签页";
|
|
@@ -930,7 +938,7 @@ export declare const COMMANDS: readonly [{
|
|
|
930
938
|
readonly examples: ["set_device_emulation --payload '{\"enabled\":true,\"preset\":\"iphone-15-pro\"}'", "set_device_emulation --payload '{\"enabled\":true,\"preset\":\"pixel-8\",\"orientation\":\"landscape\"}'", "set_device_emulation --payload '{\"enabled\":false}'"];
|
|
931
939
|
}, {
|
|
932
940
|
readonly name: "set_app_profile";
|
|
933
|
-
readonly description: "把目标 tab 切换为 App 容器模拟态(客户端 UA + JSBridge 托管 + 页面跳转 iframe 容器栈 + scheme
|
|
941
|
+
readonly description: "把目标 tab 切换为 App 容器模拟态(客户端 UA + JSBridge 托管 + 页面跳转 iframe 容器栈 + scheme 唤端映射 + 自适应系统标题栏),系统栏由 iframe 外层统一渲染,并根据页面协议与桥调用切换普通、沉浸或隐藏状态;用于桌面浏览器近似实机验证 App 内 H5,需保持调试控制才持续生效";
|
|
934
942
|
readonly params: [{
|
|
935
943
|
readonly name: "enabled";
|
|
936
944
|
readonly type: "boolean";
|
|
@@ -952,6 +960,10 @@ export declare const COMMANDS: readonly [{
|
|
|
952
960
|
readonly name: "deviceModel";
|
|
953
961
|
readonly type: "string";
|
|
954
962
|
readonly description: "Android 机型名(拼入 UA 与 __DEVICE_MODEL__)";
|
|
963
|
+
}, {
|
|
964
|
+
readonly name: "simulateSystemBars";
|
|
965
|
+
readonly type: "boolean";
|
|
966
|
+
readonly description: "是否模拟顶部状态/导航栏与底部手势栏,默认 true";
|
|
955
967
|
}, {
|
|
956
968
|
readonly name: "emulation";
|
|
957
969
|
readonly type: "object";
|
|
@@ -966,7 +978,7 @@ export declare const COMMANDS: readonly [{
|
|
|
966
978
|
readonly required: true;
|
|
967
979
|
readonly description: "目标标签页 ID";
|
|
968
980
|
}];
|
|
969
|
-
readonly examples: ["set_app_profile --payload '{\"enabled\":true,\"profile\":\"fliggy\"}'", "set_app_profile --payload '{\"enabled\":true,\"profile\":\"alipay\",\"os\":\"android\",\"deviceModel\":\"Pixel 8 Pro\"}'", "set_app_profile --payload '{\"enabled\":false}'"];
|
|
981
|
+
readonly examples: ["set_app_profile --payload '{\"enabled\":true,\"profile\":\"fliggy\"}'", "set_app_profile --payload '{\"enabled\":true,\"profile\":\"fliggy\",\"simulateSystemBars\":false}'", "set_app_profile --payload '{\"enabled\":true,\"profile\":\"alipay\",\"os\":\"android\",\"deviceModel\":\"Pixel 8 Pro\"}'", "set_app_profile --payload '{\"enabled\":false}'"];
|
|
970
982
|
}, {
|
|
971
983
|
readonly name: "set_timezone";
|
|
972
984
|
readonly description: "覆盖目标 tab 的时区,传空字符串恢复浏览器默认时区";
|
package/dist/commands.js
CHANGED
|
@@ -408,7 +408,17 @@ export const COMMANDS = [
|
|
|
408
408
|
{
|
|
409
409
|
name: 'appProfile',
|
|
410
410
|
type: 'string',
|
|
411
|
-
description: '开 tab 即进入 App 容器模拟态(客户端 UA + JSBridge 托管 + iframe
|
|
411
|
+
description: '开 tab 即进入 App 容器模拟态(客户端 UA + JSBridge 托管 + iframe 容器栈 + 自适应系统标题栏,首屏即容器态)。系统栏由 iframe 外层统一渲染,并根据页面协议与桥调用切换普通、沉浸或隐藏状态;档案名同 set_app_profile,如 "fliggy"',
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
name: 'os',
|
|
415
|
+
type: '"ios" | "android"',
|
|
416
|
+
description: '与 appProfile 配合;容器系统,默认 ios',
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
name: 'simulateSystemBars',
|
|
420
|
+
type: 'boolean',
|
|
421
|
+
description: '与 appProfile 配合;是否模拟顶部状态/导航栏与底部手势栏,默认 true',
|
|
412
422
|
},
|
|
413
423
|
],
|
|
414
424
|
examples: [
|
|
@@ -416,6 +426,7 @@ export const COMMANDS = [
|
|
|
416
426
|
`tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,
|
|
417
427
|
`tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-15-pro"}}'`,
|
|
418
428
|
`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy"}'`,
|
|
429
|
+
`tab_open --payload '{"url":"https://example.com","appProfile":"fliggy","os":"android"}'`,
|
|
419
430
|
`tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`,
|
|
420
431
|
],
|
|
421
432
|
},
|
|
@@ -834,7 +845,7 @@ export const COMMANDS = [
|
|
|
834
845
|
},
|
|
835
846
|
{
|
|
836
847
|
name: 'set_app_profile',
|
|
837
|
-
description: '把目标 tab 切换为 App 容器模拟态(客户端 UA + JSBridge 托管 + 页面跳转 iframe 容器栈 + scheme
|
|
848
|
+
description: '把目标 tab 切换为 App 容器模拟态(客户端 UA + JSBridge 托管 + 页面跳转 iframe 容器栈 + scheme 唤端映射 + 自适应系统标题栏),系统栏由 iframe 外层统一渲染,并根据页面协议与桥调用切换普通、沉浸或隐藏状态;用于桌面浏览器近似实机验证 App 内 H5,需保持调试控制才持续生效',
|
|
838
849
|
params: [
|
|
839
850
|
{ name: 'enabled', type: 'boolean', required: true, description: 'true=启用,false=清除' },
|
|
840
851
|
{
|
|
@@ -849,6 +860,11 @@ export const COMMANDS = [
|
|
|
849
860
|
type: 'string',
|
|
850
861
|
description: 'Android 机型名(拼入 UA 与 __DEVICE_MODEL__)',
|
|
851
862
|
},
|
|
863
|
+
{
|
|
864
|
+
name: 'simulateSystemBars',
|
|
865
|
+
type: 'boolean',
|
|
866
|
+
description: '是否模拟顶部状态/导航栏与底部手势栏,默认 true',
|
|
867
|
+
},
|
|
852
868
|
{
|
|
853
869
|
name: 'emulation',
|
|
854
870
|
type: 'object',
|
|
@@ -859,6 +875,7 @@ export const COMMANDS = [
|
|
|
859
875
|
],
|
|
860
876
|
examples: [
|
|
861
877
|
`set_app_profile --payload '{"enabled":true,"profile":"fliggy"}'`,
|
|
878
|
+
`set_app_profile --payload '{"enabled":true,"profile":"fliggy","simulateSystemBars":false}'`,
|
|
862
879
|
`set_app_profile --payload '{"enabled":true,"profile":"alipay","os":"android","deviceModel":"Pixel 8 Pro"}'`,
|
|
863
880
|
`set_app_profile --payload '{"enabled":false}'`,
|
|
864
881
|
],
|
|
@@ -289,9 +289,14 @@ export interface TabOpenParams {
|
|
|
289
289
|
group?: string;
|
|
290
290
|
/**
|
|
291
291
|
* 客户端容器模拟档案名(如 'fliggy')。打开后即按该 App 的 WebView 环境渲染:
|
|
292
|
-
* 移动视口 + 容器 UA + JSBridge
|
|
292
|
+
* 移动视口 + 容器 UA + JSBridge 托管 + 自适应系统标题栏。系统栏由 iframe 外层统一渲染,
|
|
293
|
+
* 并根据页面协议与桥调用切换普通、沉浸或隐藏状态。可用档案见 APP_PROFILE_NAMES。
|
|
293
294
|
*/
|
|
294
295
|
appProfile?: AppProfileName;
|
|
296
|
+
/** 与 appProfile 配合使用;容器系统,默认 ios */
|
|
297
|
+
os?: 'ios' | 'android';
|
|
298
|
+
/** 与 appProfile 配合使用;是否模拟顶部状态/导航栏与底部手势栏,默认 true */
|
|
299
|
+
simulateSystemBars?: boolean;
|
|
295
300
|
}
|
|
296
301
|
/**
|
|
297
302
|
* 客户端容器模拟可用档案名。
|
|
@@ -312,6 +317,8 @@ export interface SetAppProfileParams {
|
|
|
312
317
|
os?: 'ios' | 'android';
|
|
313
318
|
appVersion?: string;
|
|
314
319
|
deviceModel?: string;
|
|
320
|
+
/** 是否模拟顶部状态/导航栏与底部手势栏,默认 true */
|
|
321
|
+
simulateSystemBars?: boolean;
|
|
315
322
|
/** 覆盖档案推荐的设备模拟参数(视口/UA 默认取档案值) */
|
|
316
323
|
emulation?: BrowserEmulationOptions;
|
|
317
324
|
/** 默认 true:应用/清除后刷新页面使注入生效 */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/client",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.2",
|
|
4
4
|
"description": "Unified Mearl SDK & CLI for local and remote browsers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"fastest-levenshtein": "^1.0.16",
|
|
53
53
|
"ws": "^8.18.0",
|
|
54
|
-
"@mearl/cloud-types": "2.8.
|
|
54
|
+
"@mearl/cloud-types": "2.8.2"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/node": "^24.9.1",
|